Требуется ли какая-либо операция перед записью (fd,?

Я написал код ниже

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

int main() {

    int fd = 3;
    char c[100] = "Testing\n";
    ssize_t nbytes = write(fd, (void *) c, strlen(c));
    return 0;
}

компилируется/связывается и выполняется

$ ./io
$ ./io 3> io_3.txt

Первая строка не произвела никакого вывода. Вторая строка дала мне файл io_3.txt, содержащий Testing. Это все ожидаемое поведение (я думаю).

Даже если в моих тестах это дало ожидаемый результат, я не уверен, что во избежание потенциальных проблем, неопределенного поведения и т. д. я должен делать что-либо до первого write, например проверять, используется ли fd=3 (и в этом случае , как... valid">это может применяться), если он надлежащим образом открыт и т. д.

И я не уверен, должен ли я выполнить какое-то действие после последнего write по тем же причинам.

Возможно, то, что я сделал, является «нерискованным», единственная потенциальная проблема заключается в том, что ничего не записывается, что я мог обнаружить, проверив значение nbytes... Я бы не знал.

Любые разъяснения приветствуются.


person sancho.s ReinstateMonicaCellio    schedule 18.05.2020    source источник
comment
Вы должны передать дескриптор открытого файла. Поэтому обычно вы должны использовать open или socket или любой другой допустимый файловый дескриптор. В этом случае вы зависите от вашего интерпретатора оболочки, который сделает за вас какое-то волшебство перед выполнением программы. Это не портативно.   -  person Cheatah    schedule 18.05.2020
comment
УБ нет. Системные вызовы с неоткрытыми аргументами файлового дескриптора возвращают EBADF. Проверка ошибки (отрицательное возвращаемое значение и errno) выявила бы это.   -  person PSkocik    schedule 18.05.2020
comment
Перенаправление fd 3 в файл нормально. Но если fd не открыт для записи, для errno устанавливается значение EBADF.   -  person Tony Tannous    schedule 18.05.2020
comment
@PSkocik - Верно!! Даже если текст действительно записывается в цель перенаправления, nbytes устанавливается в -1, а errno в EBADF.   -  person sancho.s ReinstateMonicaCellio    schedule 19.05.2020


Ответы (1)


Если вы пишете такую ​​программу, выполнение ее без открытия fd 3 является ошибкой использования. Обычно единственными файловыми дескрипторами, которые следует использовать по номеру, не открывая их самостоятельно, являются 0 (stdin), 1 (stdout) и 2 (stderr). Если программе необходимо принимать в качестве входных данных дополнительные предварительно открытые файловые дескрипторы, стандартной идиомой является передача номеров fd в командной строке или переменных среды, а не их жесткое программирование. Например:

int main(int argc, char **argv) {
    if (argc<2 || !isdigit(argv[1][0])) return 1;
    int fd = strtol(argv[1], 0, 0);
    char c[100] = "Testing\n";
    ssize_t nbytes = write(fd, (void *) c, strlen(c));
    return 0;
}

На практике тривиальная программа, подобная вашей, вероятно, безопасна, поскольку запись просто завершается ошибкой, если fd 3 не был открыт. Но как только вы сделаете что-то, что может открыть файловые дескрипторы (возможно, внутренние по отношению к реализации, такие как syslog, или функции даты/времени, открывающие данные часового пояса, или каталоги перевода сообщений и т. д.), может случиться так, что fd 3 теперь ссылается на такие открытый файл, и вы ошибочно пытаетесь записать в него. Использование файловых дескрипторов, подобных этому, является серьезной ошибкой.

person R.. GitHub STOP HELPING ICE    schedule 18.05.2020
comment
Здорово. Насколько я понимаю, ваш расширенный код получает номер FD из argv, но в остальном по-прежнему записывает в FD, открытие которого не гарантируется и, следовательно, может иметь те же проблемы, которые вы описываете. Это правильно? - person sancho.s ReinstateMonicaCellio; 18.05.2020
comment
Да, это правильно. Вы можете проверить (например, с помощью fcntl(fd, F_GETFD)), неисправен ли fd очень рано, до выполнения любых других операций, и выдать ошибку при ошибочном вводе. Но это становится сложнее сделать с нетривиальной программой, в которой могут быть кторы, выполняющие действия, вызывающие открытие файловых дескрипторов. Как правило, если это не граница безопасности (например, программа suid), я бы просто верил, что вызывающая сторона выполнила контракт. - person R.. GitHub STOP HELPING ICE; 19.05.2020