Як отримати справжнє ім'я керуючого терміналу?


13

Як можна отримати справжнє ім'я керуючого терміналу (якщо він є, інакше помилка) як ім'я шляху?

Під "справжнім іменем" я маю на увазі "ні" /dev/tty, яке не може бути використане іншими довільними процесами для позначення того ж терміналу. Я вважаю за краще відповідь як простий код оболонки (наприклад, приклад нижче), якщо це можливо, інакше як функція C.

Зауважте, що це повинно працювати, навіть якщо стандартний вхід перенаправлений, так що ttyутиліта не може бути використана: ви отримаєте not a ttyпомилку в такому випадку, оскільки ttyпросто друкує ім'я файлу терміналу, підключеного до стандартного вводу.

У Linux можна використовувати:

echo "/dev/`ps -p $$ -o tty | tail -n 1`"

але це не портативно, оскільки згідно з POSIX, формат імені терміналу не визначений .

Що стосується функцій C, то ctermid (NULL)повертається /dev/tty, що тут марно.

Примітка: згідно з zshдокументацією, це слід робити

zsh -c 'echo $TTY'

але це в даний час (версія 5.0.7) не вдається, коли і стандартний вхід, і стандартний вихід перенаправлені:

$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty

@mikeserv Я думаю, що psрішення охоплює більшість систем (і whoне допомагає більше ps), можливо, трохи більше коду для обробки ідентифікатора поодинці (наприклад, "04"). Мені було цікаво, чи є ще більш портативне рішення.
vinc17

Можливо, це стосується і попередніх парних наборів - можливо, і старих pty пар bsd -style. Не всі птахи мають UNIX 98 типів. Так чи інакше, з man xterm: -Sccn Ця опція дозволяє xtermвикористовуватись як канал вводу-виводу для існуючої програми ... Значення параметра - це кілька літер імені pty, яке слід використовувати у веденому режимі, плюс успадкований номер fd. Якщо опція містить символ "/", вона визначає ім'я pty від fd.
mikeserv

@mikeserv Зверніть увагу , що рішення не працює з psвід BusyBox (який використовується Android, BTW), навіть під GNU / Linux. Що ви маєте на увазі під " xtermвпоратися з цим 04"?
vinc17

busyboxне відповідає POSIX. toyboxоднак, дуже добре.
mikeserv

Відповіді:


8

"Контрольний термінал" ака. CTTY, є distincted від « процес Термінал взаємодіє з».

Стандартним способом проходження шляху ctty є ctermid (3). Після виклику цього, у freebsd, починаючи з випуску 10, шукається фактичний шлях [1], тоді як старіші реалізації Freebsd та glibc [2] безумовно повертають "/ dev / tty"].

ps (1) з пакета linux procps 3.2.8, прочитайте числовий запис у / proc / * / stat [3], а потім вирахуйте ім'я шляху частково відгадуючи [4, 5] через відсутність підтримки системи [6] .

Однак якщо нас чітко не цікавить ctty, але будь-який термінал, пов'язаний зі stdio, tty (1) друкує термінальний шлях, підключений до stdin, який ідентичний ttyname(fileno(stdin))в c, а альтернативою є readlink /proc/self/fd/0.


Менш важлива думка щодо безумовної поведінки "/ dev / tty": Специфікації просто говорять, що рядок, повернутий ctermid, "коли використовується як ім'я шляху, зверніться до поточного керуючого терміналу", а не якийсь прямий "- це шлях поточного потоку термінал управління ". Можна інтерпретувати так, що "/ dev / tty" не є керуючим терміналом, а посилається на термінал керування лише у тому випадку, якщо той самий процес відкриє (3) його. Таким чином, не порушуючи правило "термінал може бути чітким протягом не більше одного сеансу" [7].

Інший наслідок полягає в тому, що коли я без будь-якого керуючого терміналу, ctermid не виходить з ладу - таке відмовлення дозволено спекуляціями [8] -, тому я можу лише усвідомити свою непорочність до моменту, коли не вдасться до наступного відкриття (3), що добре, оскільки специфікації також кажуть, що виклик open (3) на ньому не гарантовано досягає успіху.


Це не більш портативно, ніж psрішення, яке я дав у своєму питанні, оскільки не всі ОС мають /procфайлову систему. Зверніть увагу, що psсам використовує readlink на /proc/self/fd/2(який працює навіть у тому випадку, коли стандартна помилка перенаправлена).
vinc17

1
відредаговано. і ps readlink on / proc / * / fd / 2 не знайти ctty, а шукати додаткову інформацію для того, щоб зіставити числовий термінал на шлях, див. посилання [4] [5].
把 友情 留 在 无

1
Відмінна редакція. Щодо ctty; Я не можу говорити за vinc17, але, хоча ви, ймовірно, завжди можете кудись писати кудись, є лише один файл, який повинен залишатися відкритим, щоб зберегти вашу групу процесів живою.
mikeserv

1
@ Vinc17 - якщо у вас є якийсь - або файл дескриптори відкрити на вашому CTTY , то ви можете прочитати їх tty. stderrце, мабуть, найкраще, тому що він повинен бути відкритим r / w. Отже tty <&2.
mikeserv

1
Те, що даний термінал може бути ctty щонайменше протягом одного сеансу, не робить glibc невідповідним для його ctermid()завжди повернення "/dev/tty". Ця назва завжди посилається на керуючий термінал процесу доступу до нього , який залежить від сеансу. Термінал залежить від сеансу, але ім'я, за яким він отримує доступ, не повинен бути.
PellMel

5

Специфікація POSIX дійсно хеджує свої ставки, що стосуються терміналу керування , і який він визначає таким чином:

  • Управління терміналом
    • Питання про те, який із можливих кількох спеціальних файлів, що посилаються на термінал, не розглядається в POSIX.1. Ім'я шляху /dev/tty- синонім керуючого терміналу, пов'язаного з процесом.

Це в списку визначень - і це все, що там є. Але в загальному термінальному інтерфейсі говориться ще про щось:

  • Термінал може належати процесу як його контрольний термінал. Кожен процес сеансу, який має контрольний термінал, має той самий термінал керування. Термінал може бути керуючим терміналом не більше одного сеансу. Керуючий термінал для сеансу розподіляється керівником сесії у визначеному реалізацією порядку. Якщо у лідера сеансу немає керуючого терміналу і відкриває файл термінального пристрою, який вже не асоційований із сеансом без використання параметра O_NOCTTY (див. Open ()), він визначається реалізацією, чи стає термінал контрольним терміналом сеансу. лідер.

  • Термінал управління успадковується дочірнім процесом під час виклику функції fork (). Процес відмовляється від свого керуючого терміналу, коли він створює новий сеанс зsetsid()функція; інші процеси, що залишилися в старій сесії, які мали цей термінал як свій керуючий термінал, продовжують мати його. Після закриття останнього дескриптора файлів у системі (незалежно від того, чи є він у поточному сеансі), пов'язаного з керуючим терміналом, не визначено, чи всі процеси, які мали цей термінал як свій контрольний термінал, перестають мати будь-який керуючий термінал. Не визначається, чи може і як керівник сеансу знову придбати контрольний термінал після того, як контрольний термінал відмовлено таким чином. Процес не відмовляється від свого керуючого терміналу, просто закривши всі його дескриптори файлів, пов'язані з керуючим терміналом, якщо інші процеси продовжують його відкривати.

Там багато що залишилося не визначеним - і чесно кажучи, я думаю, що це має сенс. Незважаючи на те, що термінал є ключовим інтерфейсом користувача, у деяких випадках він також є всілякі інші речі, як-от фактичне обладнання або навіть певний принтер, але у багатьох випадках це практично нічого - як, наприклад, xtermемулятор . Важко конкретизуватись там - і я не думаю, що це все одно зацікавило б Unix, адже термінали роблять набагато більше, ніж Unix.

У будь-якому випадку, POSIX також досить неприємний щодо того, як psслід вести себе, якщо йдеться про ctty.

Там -aвимикач:

  • Запишіть інформацію про всі процеси, пов'язані з терміналами. Впровадження може не опустити лідерів сесій із цього списку.

Чудово. Керівники сесії можуть бути опущені. Це не дуже корисно.

І -t:

  • Запишіть інформацію для процесів, пов'язаних з терміналами, наведеними у списку термінів. Додаток повинен гарантувати, що список термінів є єдиним аргументом у вигляді списку, <blank>розділеного комами, або. Ідентифікатори терміналів надаються у форматі, визначеному реалізацією .

... що є черговим піднесенням. Але це продовжує говорити про системи XSI:

  • У системах, сумісних з XSI, вони мають бути вказані в одній з двох форм: ім'я файлу пристрою (наприклад, tty04) або, якщо ім'я файлу пристрою починається з tty, просто ідентифікатор, що слідує за символами tty (наприклад, 04) .

Це трохи краще, але це не шлях. Також у системах XSI є -dперемикач:

  • Пишіть інформацію для всіх процесів, крім керівників сеансів.

... що принаймні зрозуміло. Ви можете вказати -oвимикач виводу, а також ttyрядок формату, але, як ви зазначили, його вихідний формат визначається реалізацією. Все-таки я думаю, що це так добре, як виходить. Я думаю, що - при багато роботи - перераховані вище перемикачі в поєднанні з деякими іншими комунальними програмами можуть отримати вам досить хороший бал-парк. Якщо чесно кажучи, я не знаю, коли / як це порушується для вас - і я не міг уявити собі ситуацію, в якій це було б. Але, я думаю, ймовірно, якщо ми додамо fuserі findзможемо перевірити шлях.

exec 2<>/dev/null
ctty=$(sh -c 'ps -p "$$" -o tty=' <&2)
sid=$(sh -c 'ps -Ao pid= -o tty=|
      grep '"$ctty$"' | 
      grep -Fv "$(ps -do pid=)"'  <&2)
find / -type c -name "*${ctty##*/}*" \
       -exec fuser -uv {} \; 2>&1  |
grep ".*$ctty.*${sid%%"$ctty"*}"

Цей /dev/nullматеріал полягав лише в тому, щоб показати, що він може працювати, коли жодна з пошукових підрозділів не мала 0,1,2, пов'язаного з ctty. У будь-якому випадку, це друкує:

/dev/pts/3:          mikeserv   3342 F.... (mikeserv)zsh

Тепер вищесказаний отримує повний шлях на моїй машині, і я думаю, це було б для більшості людей у ​​більшості випадків. Я також можу уявити, що це може провалитися. Це просто груба евристика.

Це, можливо, не вдасться з багатьох інших причин, але якщо ви працюєте в системі, яка дозволяє лідеру сесії відмовитись від усіх дескрипторів до ctty і при цьому залишатись sid, як дозволяє специфікація, то це, безумовно, не допоможе. Зважаючи на це, я думаю, що це може отримати досить хорошу оцінку в більшості випадків.

Звичайно, простіше за все, що потрібно робити , якщо у вас є якісь - дескриптори , підключених до CT просто ...

tty <&2

... або подібне.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.