Comment obtenir le vrai nom du terminal de contrôle (s'il y en a un, sinon une erreur) comme nom de chemin?
Par "vrai nom", je veux dire non /dev/tty
, qui ne peut pas être utilisé par d'autres processus arbitraires pour se référer au même terminal. Je préfère la réponse comme un simple code shell (comme l'exemple ci-dessous) si possible, sinon comme une fonction C.
Notez que cela doit fonctionner même si l'entrée standard est redirigée, de sorte que l' tty
utilitaire ne peut pas être utilisé: on obtiendrait une not a tty
erreur dans un tel cas, car il tty
suffit d'imprimer le nom de fichier du terminal connecté à l'entrée standard.
Sous Linux, on peut utiliser:
echo "/dev/`ps -p $$ -o tty | tail -n 1`"
mais ce n'est pas portable, car selon POSIX, le format du nom du terminal n'est pas spécifié .
Concernant les fonctions C, ctermid (NULL)
retourne /dev/tty
, ce qui est inutile ici.
Remarque: selon la zsh
documentation, on devrait pouvoir faire
zsh -c 'echo $TTY'
mais cela actuellement (version 5.0.7) échoue lorsque l'entrée standard et la sortie standard sont redirigées:
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty
ps
solution couvre la plupart des systèmes (etwho
n'aide pas plusps
), peut-être avec un peu plus de code pour gérer l'identifiant seul (comme "04"). Je me demandais s'il y avait une solution encore plus portable.man xterm
:-Sccn
Cette option permetxterm
d'être utilisée comme canal d'E / S pour un programme existant ... La valeur de l'option est quelques lettres du nom d'un pty à utiliser en mode esclave, plus le numéro fd hérité. Si l'option contient un caractère «/», elle délimite le nom pty du fd.ps
depuis busybox (qui est utilisé par Android, BTW), même sous GNU / Linux. Que voulez-vous dire par «xterm
peut gérer ça04
»?busybox
n'est pas conforme à POSIX.toybox
, cependant, fait très bien.Réponses:
Le "terminal de contrôle" aka. CTTY, est distincted de « la borne processus d'une interagit avec ».
Le moyen standard d'obtenir le chemin de ctty est ctermid (3). En appelant cela, dans freebsd depuis la version 10, un chemin réel est recherché [1], tandis que les anciennes implémentations de freebsd et de glibc [2] renvoient inconditionnellement "/ dev / tty"].
ps (1) du paquet linux procps 3.2.8, lisez l'entrée numérique dans / proc / * / stat [3], puis déduisez partiellement le chemin en devinant [4, 5] en raison du manque de prise en charge du système [6] .
Cependant, si nous ne sommes pas strictement intéressés par le ctty mais par tout terminal associé à stdio, tty (1) affiche le chemin du terminal connecté à stdin, qui est identique à
ttyname(fileno(stdin))
c, et une alternative estreadlink /proc/self/fd/0
.Pensée moins importante concernant le comportement inconditionnel "/ dev / tty": les spécifications indiquent simplement que la chaîne renvoyée par ctermid "lorsqu'elle est utilisée comme nom de chemin d'accès, se réfère au terminal de contrôle actuel", au lieu d'être simple "est le nom de chemin d'accès du courant terminal de contrôle ". Cela pourrait être interprété comme si "/ dev / tty" n'est pas le terminal de contrôle, mais ne fait référence au terminal de contrôle que si le même processus l'ouvre (3). Ainsi, ne pas enfreindre la règle «un terminal peut être coûteux pendant au plus une session» [7].
Une autre conséquence est que lorsque je suis sans aucun terminal de contrôle, ctermid n'échoue pas - une telle défaillance est autorisée par les spécifications [8] -, donc je ne peux prendre conscience de mon absence de contrôle que jusqu'à l'échec d'une ouverture ultérieure (3), ce qui est correct car les spécifications indiquent également qu'appeler open (3) dessus n'est pas garanti pour réussir.
la source
ps
solution que j'ai donnée dans ma question, car tous les systèmes d'exploitation n'ont pas de système de/proc
fichiers. Notez queps
lui - même utilise un lien de lecture/proc/self/fd/2
(qui fonctionne même si l'erreur standard est redirigée).tty
.stderr
est probablement le meilleur car il est prévu qu'il soit ouvert r / w. Alorstty <&2
.ctermid()
revient toujours"/dev/tty"
. Ce nom fait toujours référence au terminal de contrôle du processus qui y accède , qui varie selon la session. Le terminal est spécifique à la session, mais le nom par lequel il est accessible n'a pas besoin d'être.La spécification POSIX couvre vraiment ses paris en ce qui concerne le Terminal de Contrôle et qu'elle définit ainsi:
/dev/tty
est synonyme du terminal de contrôle associé à un processus.C'est dans la liste des définitions - et c'est tout ce qu'il y a. Mais dans General Terminal Interface , on en dit plus:
Un terminal peut appartenir à un processus en tant que terminal de contrôle. Chaque processus d'une session qui a un terminal de contrôle a le même terminal de contrôle. Un terminal peut être le terminal de contrôle pour au plus une session. Le terminal de contrôle d'une session est alloué par le chef de session d'une manière définie par l'implémentation. Si un chef de session n'a pas de terminal de contrôle et ouvre un fichier de périphérique de terminal qui n'est pas déjà associé à une session sans utiliser l'option O_NOCTTY (voir open ()), il est défini par l'implémentation si le terminal devient le terminal de contrôle de la session chef.
Le terminal de contrôle est hérité par un processus enfant lors d'un appel de fonction fork (). Un processus abandonne son terminal de contrôle lorsqu'il crée une nouvelle session avec le
setsid()
une fonction; d'autres processus restant dans l'ancienne session qui avaient ce terminal comme terminal de contrôle continuent de l'avoir. À la fermeture du dernier descripteur de fichier du système (qu'il se trouve ou non dans la session en cours) associé au terminal de contrôle, il n'est pas spécifié si tous les processus qui avaient ce terminal comme terminal de contrôle cessent d'avoir un terminal de contrôle. Il n'est pas précisé si et comment un chef de session peut réacquérir un terminal de contrôle après que le terminal de contrôle a été abandonné de cette manière. Un processus ne renonce pas à son terminal de contrôle simplement en fermant tous ses descripteurs de fichiers associés au terminal de contrôle si d'autres processus continuent de l'ouvrir.Il reste beaucoup de choses non spécifiées - et honnêtement, je pense que cela a du sens. Bien que le terminal soit une interface utilisateur clé, il y a aussi toutes sortes d'autres choses dans certains cas - comme le matériel réel, ou même une sorte d'imprimante - mais dans beaucoup de cas, ce n'est pratiquement rien du tout - comme un
xterm
qui n'est qu'un émulateur . Il est difficile d'être précis là-bas - et je ne pense pas que ce serait dans l'intérêt de Unix de toute façon, car les terminaux font beaucoup plus que Unix.Quoi qu'il en soit, POSIX est également assez sceptique sur la façon de
ps
se comporter en ce qui concerne le ctty.Il y a l'
-a
interrupteur:Génial. Les chefs de session peuvent être omis. Ce n'est pas très utile.
Et
-t
:<blank>
liste séparée par des virgules. Les identifiants de terminal doivent être donnés dans un format défini par l'implémentation .... ce qui est une autre déception. Mais cela continue à dire à propos des systèmes XSI:
tty04
) ou, si le nom de fichier de l'appareil commence partty
, juste l'identifiant suivant les caractèrestty
(par exemple,04
) .C'est un peu mieux, mais ce n'est pas un chemin. Sur les systèmes XSI, il y a également le
-d
commutateur:... ce qui est au moins clair. Vous pouvez également spécifier le
-o
commutateur de sortie avec latty
chaîne de format, mais, comme vous l'avez noté, son format de sortie est défini par l'implémentation. Pourtant, je pense que c'est aussi bon que possible. Je pense que - avec beaucoup de travail - les commutateurs ci-dessus en combinaison avec d'autres utilitaires peuvent vous donner une assez bonne idée. Pour être tout à fait honnête, je ne sais pas quand / comment ça se casse pour vous - et je n'ai pas pu imaginer une situation dans laquelle cela se produirait. Mais, je pense que probablement si nous ajoutonsfuser
etfind
nous pouvons vérifier le chemin.Le
/dev/null
truc était juste pour montrer que cela pouvait fonctionner quand aucun des sous-coquilles de recherche n'avait de 0,1,2 connecté au ctty. Quoi qu'il en soit, cela imprime:Maintenant, ce qui précède obtient le chemin complet sur ma machine, et j'imagine que ce serait le cas pour la plupart des gens dans la plupart des cas. Je peux aussi imaginer que cela pourrait échouer. C'est juste une heuristique grossière.
Cela pourrait probablement échouer pour de nombreuses autres raisons, mais si vous êtes sur un système qui permet au chef de session de renoncer à tous les descripteurs du ctty et de rester le sid alors comme le permet la spécification, alors cela ne va certainement pas aider. Cela dit, je pense que cela peut obtenir une assez bonne estimation dans la plupart des cas.
Bien sûr, la chose la plus simple à faire si vous avez des descripteurs connectés à votre ctty est juste ...
...ou similaire.
la source