ADR-060 — Descellement couche-0-vX : famille termios/tty (pour la libc et air-terminal)
Statut : Accepté (2026-07-02, par délégation d’autonomie BDFL ; gravé pour revue a posteriori). RFC de structure (ADR-015). Companion de ADR-051 (descellement précédent, même mécanique), ADR-021 (conventions couche 0), ADR-046 / ADR-047 (libc). Prépare l’objet couche 1 air-terminal (ADR-061).
Catégorie : Couche 0 (extension du socle / re-sceau, comme ADR-051).
Contexte
Clore la couche 1 pour la libc exige termios — l’interface POSIX de discipline de ligne
(POSIX.1-1988, racines System V ~1983), terminal-agnostique et stable. La couche 0 scellée ne
l’a pas encore. Deux consommateurs l’imposent : la famille libc termios (#20 de l’audit musl ;
tcgetattr/tcsetattr/PTY pour OpenSSH — prompts en mode raw, sshd alloue des PTY), et isatty
(requis par stdio, dérivé de TCGETS). C’est donc un descellement additif de plus, dans l’esprit
d’ADR-051 : jalons antérieurs conservés, on ajoute une famille, on re-scelle en couche-0-vX.
Le type Termios (air-sys-types/src/terminal.rs, #[repr(C)], NCCS/ControlChar/bitflags/
BaudRate, identique x86_64/aarch64 — asm-generic) existe déjà (branche feat/termios-couche0).
Il manque les wrappers d’ioctls typés + le PTY + les tests 100 %.
Décision
Desceller la couche 0 et y ajouter la famille termios/tty complète (passe unique — éviter un
second re-sceau), sous forme de fonctions dédiées typées (jamais d’ioctl(fd, REQ, …) générique —
ADR-021 conv. 3), dans un module air-sys-syscall/src/terminal.rs, consommant le type Termios
d’air-sys-types. Les 5 groupes :
| Groupe | Fonctions typées (ioctl noyau) | Rôle |
|---|---|---|
| Attributs | tcgetattr (TCGETS), tcsetattr(action) (TCSETS/TCSETSW/TCSETSF) | cœur termios (raw/canonique) |
| Contrôle de ligne | tcsendbreak (TCSBRK/TCSBRKP), tcdrain, tcflush (TCFLSH), tcflow (TCXONC) | les tc* POSIX |
| Taille fenêtre | get_winsize/set_winsize (TIOCGWINSZ/TIOCSWINSZ) | plein écran, SIGWINCH |
| PTY | ouvrir /dev/ptmx, pty_number (TIOCGPTN), pty_unlock (TIOCSPTLCK), pty_peer (TIOCGPTPEER) | allocation maître/esclave (sshd, air-terminal) |
| Session / job-control | tcgetpgrp/tcsetpgrp (TIOCGPGRP/TIOCSPGRP), set_ctty (TIOCSCTTY), clear_ctty (TIOCNOTTY), session_id (TIOCGSID) | terminal de contrôle, groupes de premier plan |
Conventions couche 0 (ADR-021) — à respecter strictement :
- Fonctions dédiées typées, une par opération ; pas de wrapper ioctl générique.
Option<T>au lieu des sentinelles (ex.tcsetpgrp(fd, Pid)typé ; jamais de-1magique).EINTRremonté à l’appelant (tcdrainpeut le rendre) — aucun retry auto en couche 0.- RAII pour les FD du PTY (
OwnedFd) ; aucune fuite.Result<T, Errno>(Errno =NonZeroI32). - Pas d’alloc dans le happy path (buffer
Termios/winsizesur la pile,#[repr(C)]). - Identique x86_64/aarch64 (
asm-generic— pas de divergence de disposition). - Couverture 100 % (lignes + branches), y compris chemins
EFAULT/ENOTTY(harnais + PTY réel).
Ce qui reste en couche 1 (dérivé, pas couche 0) : isatty (= tcgetattr réussit / ENOTTY),
ttyname (= /proc/self/fd), et l’objet ergonomique air-terminal (ADR-061).
Conséquences
- Re-sceau
couche-0-vX(version suivante ; marqueur appliqué à l’atterrissage du code, jalons antérieurs conservés, comme ADR-051). Mise à jour du registre de scellement couche 0. - Débloque
stdio(isatty) et la famille libctermios, et l’objet couche 1air-terminal(ADR-061). - UNSUPPORTED.md : les ioctls tty legacy non wrappés (ex.
TIOCSTIinjection — dangereux ;TCGETA/TCSETAtermio pré-POSIX) restent hors périmètre, justifiés.
Alternatives rejetées
- Wrapper ioctl générique
ioctl(fd, TCGETS, &mut t): viole ADR-021 conv. 3 (typage per-op). - Descellement minimal puis additif : deux re-sceaux au lieu d’un ; la passe complète (doctrine « clore proprement ») est préférée.