Повторное открытие дескрипторов файлов stdout и stdin после их закрытия
Я пишу функцию, которая, учитывая аргумент, либо перенаправляет stdout в файл, либо читает stdin из файла. Для этого я закрываю дескриптор файла, связанный с stdout или stdin, поэтому, когда я открываю файл, он открывается под дескриптором, который я только что закрыл. Это работает, но проблема в том, что как только это будет сделано, мне нужно восстановить stdout и stdin, чтобы они действительно были.
Что я могу сделать для stdout открыто ( "/dev/tty", O_WRONLY); Но я не уверен, почему это работает, и что еще более важно, я не знаю эквивалентного утверждения для stdin.
Итак, для stdout
close(1);
if (creat(filePath, O_RDWR) == -1)
{
exit(1);
}
и для stdin
close(0);
if (open(filePath, O_RDONLY) == -1)
{
exit(1);
}
Ответы
Ответ 1
Вы должны использовать dup() и dup2() для клонирования дескриптора файла.
int stdin_copy = dup(0);
int stdout_copy = dup(1);
close(0);
close(1);
int file1 = open(...);
int file2 = open(...);
< do your work. file1 and file2 must be 0 and 1, because open always returns lowest unused fd >
close(file1);
close(file2);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);
Однако, есть небольшая деталь, с которой вы, возможно, захотите быть осторожной (от человека dup):
Два дескриптора не разделяют флаги дескриптора файла ( крупный на execflag). Флаг close-on-exec (FD_CLOEXEC; см. Fcntl (2)) для дубликата дескриптора выключено.
Если это проблема, возможно, вам придется восстановить флаг close-on-exec, возможно, используя dup3() вместо dup2(), чтобы избежать условий гонки.
Кроме того, имейте в виду, что если ваша программа многопоточна, другие потоки могут случайно записать/прочитать ваш переназначенный stdin/stdout.
Ответ 2
Я думаю, что вы можете "сохранить" дескрипторы перед перенаправлением:
int save_in, save_out;
save_in = dup(STDIN_FILENO);
save_out = dup(STDOUT_FILENO);
Позже вы можете использовать dup2
для их восстановления:
/* Time passes, STDIN_FILENO isn't what it used to be. */
dup2(save_in, STDIN_FILENO);
Я не делаю никаких ошибок в этом примере - вы должны.
Ответ 3
Вы можете создать дочерний процесс и настроить перенаправление только внутри дочернего элемента. Затем подождите, пока ребенок закончит работу, и продолжите работу в родительском процессе. Таким образом, вам не нужно беспокоиться о том, чтобы полностью изменить свое перенаправление.
Просто найдите примеры кода, используя fork() и wait().