Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
28
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать

5.2. Системные вызовы dup и dup2

Вызов dup дублирует существующий дескриптор файла, возвращая новый дескриптор, открытый для того же файла или канала:

dup – дублирует дескриптор файла

#include <unistd.h>

int dup (

int fd /* дублируемый дескриптор файла */

);

/* Возвращает новый дескриптор файла или -1 в случае ошибки (код ошибки в переменной errno) */

dup2 – дублирует дескриптор файла

#include <unistd.h>

int dup2 (

int fd, /* дублируемый дескриптор файла */

int fd2 /* используемый дескриптор файла */

);

/* Возвращает новый дескриптор файла или -1 в случае ошибки (код ошибки в переменной errno) */

Оба дескриптора разделяют одно описание файла. Вызов завершается неудачей, если указан некорректный аргумент (дескриптор не открыт) или если нет доступных дескрипторов файлов. Вызов dup возвращает наименьший из доступных дескрипторов, так что если вы знаете, какие дескрипторы открыты, то можете узнать, что будет возвращено. В этом случае легче использовать вызов dup2, который позволяет указать при помощи аргумента fd2, какой дескриптор файла следует возвратить. Если нужно, вызов dup2 закрывает дескриптор fd2, чтобы сделать его доступным. Вызов dup(fd) эквивалентен вызову: fcntl(fd, F_DUPFD, 0), а вызов dup2(fd, fd2) эквивалентен вызову:

close(fd2);

fcntl(fd, F_DUPFD, fd2);

Рассмотрим использование dup2 на примере. Следующая функция формирует канал, создает дочерний процесс, который будет читать данные из канала, делает дескриптор STDIN_FILENO дочернего процесса дескриптором стороны чтения канала и вызывает для чтения данных из канала команду cat. Теперь не нужна специальная программа вроде piperead, которую мы использовали в примере из предыдущего раздела.

void pipewrite2(void)

{

int pfd[2];

pid_t pid;

pipe(pfd);

switch (pid = fork()) {

case -1:

EC_FAIL

case 0: /* дочерний процесс */

dup2(pfd[0], STDIN_FILENO);

close(pfd[0]);

close(pfd[1]);

execlp(“cat”, “cat”, NULL);

EC_FAIL

default: /* родительский процесс */

close(pfd[0]);

write(pfd[1], “hello”, 6);

close(pfd[1]);

waitpid(pid, NULL, 0);

}

return;

EC_CLEANUP_BGN

EC_FLUSH(“pipewrite2”);

EC_CLEANUP_END

}

Результатом выполнения этой программы является строка: hello. Канал может быть организован не только от родительского процесса к дочернему. В следующем примере реализован эквивалент команды $ who | wc, которая позволяет узнать число пользователей, вошедших в систему:

void who_wc(void)

{

int pfd[2];

pid_t pid1, pid2;

pipe(pfd);

switch (pid1 = fork()) {

case -1:

EC_FAIL

case 0: /* первый дочерний процесс */

dup2(pfd[1], STDOUT_FILENO);

close(pfd[0]);

close(pfd[1]);

execlp(“who”, “who”, NULL);

EC_FAIL

/* родительский процесс */

switch (pid2 = fork()) {

case -1:

EC_FAIL

case 0: /* второй дочерний процесс */

dup2(pfd[0], STDIN_FILENO);

close(pfd[0]);

close(pfd[1]);

execlp(“wc”, “wco”, “-1”, NULL);

EC_FAIL

}

/* и опять родительский процесс */

close(pfd[0]);

close(pfd[1]);

waitpid(pid1, NULL, 0);

waitpid(pid2, NULL, 0);

return;

EC_CLEANUP_BGN

EC_FLUSH(“who_wc”);

EC_CLEANUP_END

}

Результатом выполнения этого кода является 1.