2016-12-08 8 views
1

См. Следующий код.Как найти имя терминала, связанное с процессом, надежно в C?

#include <stdio.h> 
#include <unistd.h> 

int main() 
{ 
    printf("ttyname(0): %s\n", ttyname(0)); 
    printf("ttyname(1): %s\n", ttyname(1)); 
    printf("ttyname(2): %s\n", ttyname(2)); 
    printf("ctermid(NULL): %s\n", ctermid(NULL)); 

    /* Sleep for sometime so that we can manually run the ps command to 
    * see the terminal associated with the process. */ 
    sleep(10); 

    return 0; 
} 

Я скомпилирую и запускаю это следующим образом.

$ gcc foo.c 
$ ./a.out 
ttyname(0): /dev/pts/3 
ttyname(1): /dev/pts/3 
ttyname(2): /dev/pts/3 
ctermid(NULL): /dev/tty 

В другом терминале я запускаю команду ps, чтобы подтвердить имя терминала.

$ ps -ef | grep a.out | grep -v grep 
coder  1498 1473 0 19:19 pts/3 00:00:00 ./a.out 

Все в порядке до сих пор. Моя программа правильно печатает терминал.

Однако моя программа не может выводить информацию о терминале, когда stdin, stdout, а также stderr перенаправляются следующим образом.

$ ./a.out </dev/null> foo.txt 2> /dev/null 

В другом терминале, я бегу ps и я могу видеть, что на самом деле /dev/pts/3 связан witht он процесс.

$ ps -ef | grep a.out | grep -v grep 
coder  1536 1473 0 19:22 pts/3 00:00:00 ./a.out 

Но после ./a.out выходов и проверить свою продукцию в foo.txt, я не вижу эту информацию в плен.

$ cat foo.txt 
ttyname(0): (null) 
ttyname(1): (null) 
ttyname(2): (null) 
ctermid(NULL): /dev/tty 

Поскольку ttyname() не предоставляет какой-либо значимой информации, когда стандартный ввод, стандартный вывод и стандартный поток ошибок перенаправляются и так ctermid() always returns /dev/tty, что я могу сделать, чтобы надежно определить терминал, связанный с процессом? Я идеально ищу решение, которое работает в любой стандартной системе Unix или Linux, но если это невозможно, то конкретные решения Linux также в порядке.

+0

Почему, после перенаправления stdin/out/err на/dev/null, вы думаете, что он все еще привязан к терминалу? – KevinDTimm

+0

@KevinDTimm Я не думаю, что он все еще подключен к терминалу. Это не мой вопрос. Я полностью понимаю, что stdin, stdout и stderr не привязаны к терминалу, когда я перенаправляю их. Но процесс все еще связан с терминалом (как вы можете видеть из вывода 'ps'). Если процесс все еще связан с терминалом, как я могу получить это имя терминала из процесса с помощью кода C? Это мой вопрос. –

+0

Gotcha - проверка – KevinDTimm

ответ

1

моя программа не выход терминала информации, когда стандартный ввод, стандартный вывод, а также STDERR перенаправляются

Ну да, ttyname() возвращает (а) имя терминального устройства, который открыт на указанном файловый дескриптор. Когда дескриптор файла не ссылается на терминал, такого устройства нет. ttyname() документируется для возврата NULL в этом случае и любого другого, в котором указанный файловый дескриптор не связан с терминалом.

Что я могу сделать, чтобы надежно определить терминал, связанный с процессом?

Прежде всего, вам нужно определить, что означает «терминал», связанный с процессом. В принципе, файловые дескрипторы 0, 1 и 2 и, возможно, даже больше могут быть подключены к различным терминальным устройствам. Возможно, нет из них - это процесса, контролирующий терминал, который, я думаю, вероятно, вы действительно ищете.

Если процесс хочет доступа его управляющего терминалом (если предположить, что есть), независимо от перенаправления его стандартных потоков, то он должен открыть устройство с именем строкой, возвращаемой ctermid(), если таковые имеются. То, что glibc ctermid() всегда возвращает "/dev/tty", не имеет значения - поскольку устройства условно называются, что служит синонимом управляющего терминала процесса доступа.

Насколько я могу судить, однако, нет портативного надежного способа определения независимого от процесса имени для любого устройства, включая управляющий терминал. Ядро не работает с точки зрения имен устройств - они живут в файловой системе и предоставляются в качестве удобства для процессов пользовательского пространства. Кроме того, любое устройство может, в принципе, иметь несколько имен файлов, относящихся к нему.

В Linux, однако, вы можете получить основные и младшие номера устройств управляющего терминала процесса от /proc/self/stat. В принципе, вы можете распаковать эти числа и либо

  • преобразовать их в соответствующее обычное имя файла, предположительно с помощью от /proc/devices или

  • отсканировать /dev файловой системы, чтобы найти файл сопоставление устройства, и сообщить свое имя.

Первый из них дешевле, но несколько спекулятивный; последний, если он преуспеет, вернет имя файла устройства, который существует и определенно относится к желаемому устройству.

Вы также можете ознакомиться с рекомендациями здесь: https://unix.stackexchange.com/questions/151812/get-device-node-by-major-minor-numbers-pair, но я обнаружил, что по крайней мере некоторые из них не работают в моей системе.

+0

Стоит отметить, что« * терминал, связанный с процессом * »является дословной цитатой из справочной страницы [ps (1)» ] (https://linux.die.net/man/1/ps). Там он ссылается на управляющий терминал, как сообщает '/ proc/*/stat'. –