chdir

title: chdir(2)

summary: изменить рабочий каталог

text:
# chdir(2)

## ИМЯ
chdir, fchdir - изменить рабочий каталог

## ОБЗОР
\#include <unistd.h>

int chdir(const char *path);

int fchdir(int fd);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

fchdir():

_XOPEN_SOURCE >= 500

|| /* начиная с glibc 2.12: */ _POSIX_C_SOURCE >= 200809L

|| /* в glibc до версии 2.19 включительно: */ _BSD_SOURCE

## ОПИСАНИЕ
chdir() изменяет текущий рабочий каталог вызвавшего процесса на каталог, указанный в path.

fchdir() идентичен chdir(); разница в том, что каталог указывается в виде открытого файлового дескриптора.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
В зависимости от файловой системы могут также возвращаться другие ошибки. Общий набор ошибок chdir() перечислен ниже:

EACCES

В одном из каталогов префикса path не разрешён поиск (cм. также path_resolution(7)).

EFAULT

Аргумент path указывает за пределы доступного адресного пространства.

EIO

Произошла ошибка ввода-вывода.

ELOOP

Во время определения path встретилось слишком много символьных ссылок.

ENAMETOOLONG

path слишком длинен.

ENOENT

Каталог, указанный в path, не существует.

ENOMEM

Недостаточное количество памяти ядра.

ENOTDIR

Компонент path не является каталогом.

Наиболее распространённые ошибки fchdir():

EACCES

Запрещён поиск в каталоге, на который указывает fd.

EBADF

Значение fd не является правильным файловым дескриптором.

ENOTDIR

Значение fd не указывает на каталог.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD.

## ЗАМЕЧАНИЯ
При работе с относительными путями (те, которые не начинаются с '/') за начало отсчёта принимается текущий рабочий каталог.

Дочерний процесс, созданный посредством fork(2), наследует текущий рабочий каталог родителя. Текущий рабочий каталог не меняется execve(2).

## СМОТРИТЕ ТАКЖЕ
chroot(2), getcwd(3), path_resolution(7)


chmod

package: man-pages-ru

title: chmod(2)

summary: изменяет права доступа к файлу

text:
# chmod(2)

## ИМЯ
chmod, fchmod, fchmodat - изменяет права доступа к файлу

## ОБЗОР

```
#include <sys/stat.h>
```

```
int chmod(const char *pathname, mode_t mode);

int fchmod(int fd, mode_t mode);
#include <fcntl.h>           /* определения констант AT_* */
#include <sys/stat.h>
```

```
int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
```

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

fchmod():

начиная с glibc 2.24:

_POSIX_C_SOURCE >= 199309L в glibc 2.19 по 2.23

_POSIX_C_SOURCE

в glibc 2.16 по 2.19:

_BSD_SOURCE || _POSIX_C_SOURCE

в glibc 2.12 по 2.16:

_BSD_SOURCE || _XOPEN_SOURCE >= 500 ||

_POSIX_C_SOURCE >= 200809L

в glibc 2.11 и старее:

_BSD_SOURCE || _XOPEN_SOURCE >= 500

fchmodat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

## ОПИСАНИЕ
Системные вызовы chmod() и fchmod() изменяют биты режима файла (режим файла состоит из бит прав доступа к файлу плюс биты set-user-ID, set-group-ID и бит закрепления) Данные системные вызовы отличаются только способом указания файла:

- Вызов chmod() изменяет режим файла, задаваемого путём из параметра pathname, который разыменовывается, если является символьной ссылкой.

- Вызов fchown() изменяет режим файла, задаваемого открытым файловым дескриптором fd.

Новый режим файла указывается в mode и представляет собой битовую маску, создаваемую побитовым сложением нуля или более следующих констант:

S_ISUID (04000)

set-user-ID (установить эффективный идентификатор пользователя процесса при execve(2))

S_ISGID (02000)

set-group-ID (установить эффективный идентификатор группы процесса при execve(2); обязательная блокировка, описывается в fcntl(2); выбрать новую группу файла от родительского каталога, описывается в chown(2) и mkdir(2))

S_ISVTX (01000)

закрепляющий бит (ограничительный флаг удаления, описывается в unlink(2))

S_IRUSR (00400)

владелец может читать

S_IWUSR (00200)

владелец может писать

S_IXUSR (00100)

владелец может выполнять файл или искать в каталоге ("поиск" применим к каталогам и означает, что к элементам внутри каталога есть доступ)

S_IRGRP (00040)

группа-владелец может читать

S_IWGRP (00020)

группа-владелец может писать

S_IXGRP (00010)

группа-владелец может выполнять файл или искать в каталоге

S_IROTH (00004)

все остальные могут читать

S_IWOTH (00002)

все остальные могут писать

S_IXOTH (00001)

все остальные могут выполнять файл или искать в каталоге

Эффективный идентификатор пользователя (UID) вызывающего процесса должен совпадать с UID владельца файла или процесс должен быть привилегированным (Linux: у него должен быть мандат CAP_FOWNER).

Если вызывающий процесс не является привилегированным (Linux: не имеет мандата CAP_FSETID), а группа-владелец файла не совпадает с эффективным групповым ID процесса или одним из его дополнительных групповых идентификаторов, то бит S_ISGID будет сброшен, но ошибки при этом не возникнет.

В зависимости от файловой системы в целях безопасности биты выполнения set-user-ID и set-group-ID могут сбрасываться при записи в файл (в Linux это происходит, если записывающий процесс не имеет мандата CAP_FSETID). В некоторых файловых системах только суперпользователь может устанавливать закрепляющий бит, который может иметь специальное назначение. Значения закрепляющего бита, set-user-ID и set-group-ID для каталогов смотрите в inode(7).

В файловых системах NFS ограничивающие права сразу начинают действовать даже уже на открытые файлы, так как контроль доступа выполняется сервером, но открытые файлы находятся в ведении клиента. Распространение прав может откладываться для других клиентов, если у них установлен атрибут кэширования.

### fchmodat()
Системный вызов fchmodat() работает также как системный вызов chmod(), за исключением случаев, описанных здесь.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в chmod()).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как chmod()).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Значение flags может быть 0, или включать следующие флаги:

AT_SYMLINK_NOFOLLOW

Если значение pathname является символьной ссылкой, не разыменовывать её, а изменить права на самой ссылке. Этот флаг пока не реализован.

Смотрите в openat(2) объяснение необходимости fchmodat().

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
В зависимости от файловой системы могут также возвращаться другие ошибки, перечисленные далее.

Наиболее распространённые ошибки chmod() перечислены далее:

EACCES

Поиск запрещён из-за одного из частей префикса пути (См. также path_resolution(7).)

EFAULT

Аргумент pathname указывает за пределы доступного адресного пространства.

EIO

Произошла ошибка ввода-вывода.

ELOOP

Во время определения pathname встретилось слишком много символьных ссылок.

ENAMETOOLONG

Слишком длинное значение аргумента pathname.

ENOENT

Файл не существует.

ENOMEM

Недостаточное количество памяти ядра.

ENOTDIR

Компонент в префиксе пути не является каталогом.

EPERM

Эффективный UID не совпадает с идентификатором владельца файла, а процесс не является привилегированным (Linux: не имеет мандата CAP_FOWNER).

EPERM

Файл помечен как неизменяемый (immutable) или только для добавления (смотрите ioctl_iflags(2)).

EROFS

Указанный файл находится на файловой системе, смонтированной только для чтения.

Общий набор ошибок для fchmod() таков:

EBADF

Файловый дескриптор fd не действителен.

EIO

См. выше.

EPERM

См. выше.

EROFS

См. выше.

В fchmodat() могут возникнуть те же ошибки, что и в chmod(). Также, в fchmodat() могут возникнуть следующие ошибки:

EBADF

Значение dirfd не является правильным файловым дескриптором.

EINVAL

Указано неверное значение в flags.

ENOTDIR

Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

ENOTSUP

В flags указано AT_SYMLINK_NOFOLLOW, но оно не поддерживается.

## ВЕРСИИ
Вызов fchmodat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

## СООТВЕТСТВИЕ СТАНДАРТАМ
chmod(), fchmod(): 4.4BSD, SVr4, POSIX.1-2001i, POSIX.1-2008.

fchmodat(): POSIX.1-2008.

## ЗАМЕЧАНИЯ

### Отличия между библиотекой C и ядром
В этой странице описана обёрточная функция fchmodat() библиотеки GNU C, реализующая POSIX-интерфейс. Данный интерфейс отличается от лежащего в основе системного вызова Linux тем, что имеет аргумент flags.

### Замечания по glibc
В старых ядрах, где fchmodat() отсутствует, обёрточная функция glibc использует chmod(). Если pathname является относительным путём, то glibc собирает путь относительно символической ссылки в /proc/self/fd, которая соответствует аргументу dirfd.

## СМОТРИТЕ ТАКЖЕ
chmod(1), chown(2), execve(2), open(2), stat(2), inode(7), path_resolution(7), symlink(7)


chown

title: chown(2)

summary: изменяет владельца файла

text:
# chown(2)

## ИМЯ
chown, fchown, lchown, fchownat - изменяет владельца файла

## ОБЗОР

```
#include <unistd.h>
```

```
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
#include <fcntl.h>           /* определения констант of AT_* */
#include <unistd.h>
```

```
int fchownat(int dirfd, const char *pathname,
             uid_t owner, gid_t group, int flags);
```

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

fchown(), lchown():

/* начиная с glibc 2.12: */ _POSIX_C_SOURCE >= 200809L

|| _XOPEN_SOURCE >= 500

|| /* версии glibc <= 2.19: */ _BSD_SOURCE

fchownat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

## ОПИСАНИЕ
Данные системные вызовы изменяют владельца и группу для файла. Системные вызовы chown(), fchown() и lchown() отличаются только в том, каким образом задается файл:

- chown() изменяет владельца для файла, задаваемого параметром pathname, который разыменовывается, если является символьной ссылкой.

- fchown() изменяет владельца для файла, задаваемого открытым файловым дескриптором fd.

- lchown() похож на chown() за исключением того, что он не разыменовывает символьные ссылки.

Только привилегированный процесс (Linux: имеющий мандат CAP_CHOWN) может сменить владельца файла. Владелец файла может сменить группу файла на любую группу, в которой он числится. Привилегированный процесс (Linux: с CAP_CHOWN) может задавать произвольную группу.

Если параметр owner или group равен -1, то соответствующий идентификатор не изменяется.

Когда владелец или группа исполняемого файла изменяется непривилегированным пользователем, то биты режима S_ISUID и S_ISGID сбрасываются В POSIX не указано, должно ли это происходить если chown() выполняется суперпользователем; поведение в Linux зависит от версии ядра и начиная с Linux 2.2.13, root рассматривается как обычный пользователь. В случае исполняемого файла вне группы (т. е., у которого не установлен бит S_IXGRP) бит S_ISGID указывает на обязательную блокировку, и не сбрасывается при выполнении chown().

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

### fchownat()
Системный вызов fchownat() работает также как системный вызов chown(), за исключением случаев, описанных здесь.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в chown()).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как chown()).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Аргумент flags представляет собой битовую маску, создаваемую побитовым сложением (OR) следующих значений;

AT_EMPTY_PATH (начиная с Linux 2.6.39)

Если значение pathname равно пустой строке, то выполнять действие над файлом, на который указывает dirfd (который может быть получен с помощью open(2) с флагом O_PATH). В этом случае, dirfd может указывать на файл любого типа, а не только на каталог. Если dirfd равно AT_FDCWD, то вызов выполняет действие над текущим рабочим каталогом. Этот флаг есть только в Linux; для получения его определения определите _GNU_SOURCE.

AT_SYMLINK_NOFOLLOW

Если значение pathname является символьной ссылкой, не разыменовывать её, а изменить владельца самой ссылки, как это делается в lchown() (по умолчанию, fchownat() разыменовывает символьные ссылки как и chown()).

Смотрите в openat(2) объяснение необходимости fchownat().

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
В зависимости от файловой системы могут также возвращаться другие ошибки, перечисленные далее.

Наиболее распространённые ошибки chown() перечислены далее.

EACCES

Поиск запрещён из-за одного из частей префикса пути (См. также path_resolution(7).)

EFAULT

Аргумент pathname указывает за пределы доступного адресного пространства.

ELOOP

Во время определения pathname встретилось слишком много символьных ссылок.

ENAMETOOLONG

Слишком длинное значение аргумента pathname.

ENOENT

Файл не существует.

ENOMEM

Недостаточное количество памяти ядра.

ENOTDIR

Компонент в префиксе пути не является каталогом.

EPERM

Вызывающий процесс не имеет требуемых прав (см. выше), чтобы изменять владельца и/или группу.

EPERM

Файл помечен как неизменяемый (immutable) или только для добавления (смотрите ioctl_iflags(2)).

EROFS

Указанный файл находится на файловой системе, смонтированной только для чтения.

Общие ошибки fchown() таковы:

EBADF

Значение fd не является правильным открытым файловым дескриптором.

EIO

Во время изменения индексного дескриптора (inode) возникла низкоуровневая ошибка ввода/вывода.

ENOENT

См. выше.

EPERM

См. выше.

EROFS

См. выше.

В fchownat() могут возникнуть те же ошибки, что и в chown(). Также, в fchownat() могут возникнуть следующие ошибки:

EBADF

Значение dirfd не является правильным файловым дескриптором.

EINVAL

Указано неверное значение в flags.

ENOTDIR

Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

## ВЕРСИИ
Вызов fchownat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

## СООТВЕТСТВИЕ СТАНДАРТАМ
chown(), fchown(), lchown(): 4.4BSD, SVr4, POSIX.1-2001, POSIX.1-2008.

Версия из 4.4BSD может использоваться только суперпользователем (то есть, обычные пользователи не могут менять владельцев).

fchownat(): POSIX.1-2008.

## ЗАМЕЧАНИЯ

### Назначение владельца новых файлов
При создании нового файла (например, с помощью open(2) или mkdir(2)), его владельцем будет установлен ID пользователя из файловой системы создающего процесса. Группа файла зависит от нескольких факторов, включая тип файловой системы, параметры монтирования и установлен ли бит режима set-group-ID на родительском каталоге. Если файловая система поддерживает параметры mount(8) -o grpid (тоже что и -o bsdgroups) и -o nogrpid (тоже что и -o sysvgroups), то правила следующие:

- Если файловая система смонтирована с параметром -o grpid, то группой нового файла будет группа родительского каталога.

- Если файловая система смонтирована с параметром -o nogrpid и у родительского каталога нет бита set-group-ID, то группой нового файла будет GID файловой системы того же процесса.

- Если файловая система смонтирована с параметром -o nogrpid и на родительском каталоге установлен бит set-group-ID, то группой нового файла будет группа родительского каталога.

Начиная с Linux 4.12, параметры монтирования -o grpid и -o nogrpid поддерживаются для ext2, ext3, ext4 и XFS. Для файловых систем, не поддерживающих эти параметры монтирования, используются правила как для -o nogrpid.

### Замечания по glibc
В старых ядрах, где fchownat() отсутствует, обёрточная функция glibc использует chown() или lchown(). Если pathname является относительным путём, то glibc собирает путь относительно символической ссылки в /proc/self/fd, которая соответствует аргументу dirfd.

### NFS
Семантика chown() сознательно нарушается в файловых системах NFS, в которых включено отображение UID. Также, нарушается семантика всех системных вызовов, которые обеспечивают доступ к содержимому файлов, так как chown() может привести к немедленному отзыву доступа к уже открытым файлам. Кэширование на клиентской стороне может привести к задержке между сменой доступа пользователю и временем, когда файл действительно станет доступным.

### Историческая справка
Первоначальные версии системных вызовов chown(), fchown() и lchown() в Linux поддерживали только 16-битные идентификаторы пользователей и групп. Позднее в Linux 2.4 были добавлены вызовы chown32(), fchown32() и lchown32(), поддерживающие 32-битные идентификаторы. В glibc обёрточные функции chown(), fchown() и lchown() работают одинаково вне зависимости от версий ядра.

В версиях Linux до 2.1.81 (кроме 2.1.46) chown() не следовал по символьным ссылкам. Начиная с версии Linux 2.1.81 chown() следует по символьным ссылкам, и существует новый системный вызов lchown(), который не следует по символьным ссылкам. Начиная с Linux 2.1.86 этот новый вызов (имеющий тот же смысл, что и старый chown()) имеет тот же самый номер системного вызова, а chown() получил новый номер.

## ПРИМЕР
Следующая программа изменять владельца файла, указанного вторым в командной строке, на значение, указанное в первом аргументе командной строки. Новый владелец может задаваться в виде числового пользовательского ID, или в виде имени пользователя (которое преобразуется в пользовательский ID с помощью getpwnam(3), выполняющего поиск в системном файле паролей).

### Исходный код программы

```
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{

    uid_t uid;

    struct passwd *pwd;

    char *endptr;

    if (argc != 3 || argv[1][0] == '\0') {

        fprintf(stderr, "%s <owner> <file>\n", argv[0]);

        exit(EXIT_FAILURE);

    }

    uid = strtol(argv[1], &endptr, 10);  /* Allow a numeric string */

    if (*endptr != '\0') {         /* Was not pure numeric string */

        pwd = getpwnam(argv[1]);   /* Try getting UID for username */

        if (pwd == NULL) {

            perror("getpwnam");

            exit(EXIT_FAILURE);

        }

        uid = pwd->pw_uid;

    }

    if (chown(argv[2], uid, -1) == -1) {

        perror("chown");

        exit(EXIT_FAILURE);

    }

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
chgrp(1), chown(1), chmod(2), flock(2), path_resolution(7), symlink(7)


chroot

title: chroot(2)

summary: изменить корневой каталог

text:
# chroot(2)

## ИМЯ
chroot - изменить корневой каталог

## ОБЗОР
\#include <unistd.h>

int chroot(const char *path);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

chroot():

Начиная с glibc 2.2.2:

```
_XOPEN_SOURCE && ! (_POSIX_C_SOURCE >= 200112L)

    || /* начиная с glibc 2.20: */ _DEFAULT_SOURCE

    || /* версии glibc <= 2.19: */ _BSD_SOURCE
```

До glibc 2.2.2: не было

## ОПИСАНИЕ
chroot() изменяет корневой каталог вызывающего процесса на тот, что задан аргументом path. Этот каталог будет использоваться для имён файлов, начинающихся с /. Корневой каталог наследуется всеми потомками вызывающего процесса.

Только привилегированный процесс (Linux: с мандатом CAP_SYS_CHROOT в своём пользовательском пространстве имён) может вызвать chroot().

Этот вызов изменяет только составляющую процесса разрешения имён и больше ничего. В частности, он не предназначен для действий повышения безопасности, создания полностью изолированной среды процесса (sandbox) или ограничения системных вызовов файловой системы. В прошлом, chroot() использовался службами для ограничения их самих передачи полученных от недоверенных пользователей путей системным вызовам наподобие open(2). Однако, если каталог перемещается за пределы каталога chroot, атакующий может использовать это в своих интересах и также выйти за пределы каталога chroot. Простейший способ сделать это — выполнить chdir(2) в каталог, который будет перемещён, подождать, когда он переместится, а затем открыть путь, например ../../../etc/passwd.

Если chdir(2) не разрешён, то есть немного более хитрый вариант, работающий при определённых условиях. Если служба позволяет задать «chroot в каталог», то обычно это означает, что если вы хотите предотвратить доступ к файлам удалённых пользователей вне каталога chroot, то вы должны гарантировать, что каталоги никогда не перемещаются за его пределы.

Данный вызов не изменяет текущий рабочий каталог, поэтому после вызова '.' может оказаться вне дерева, являющегося корнем '/'. В частности, суперпользователь может выйти за пределы "тюрьмы chroot" выполнив:

```
mkdir foo; chroot foo; cd ..
```

Данный вызов не закрывает открытые файловые дескрипторы и поэтому через такие дескрипторы можно получить доступ к файлам за пределами дерева chroot.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
В зависимости от файловой системы могут также возвращаться другие ошибки. Общий набор ошибок перечислен ниже:

EACCES

Поиск запрещён из-за одного из частей префикса пути (См. также path_resolution(7).)

EFAULT

Аргумент path указывает за пределы доступного адресного пространства.

EIO

Произошла ошибка ввода-вывода.

ELOOP

Во время определения path встретилось слишком много символьных ссылок.

ENAMETOOLONG

path слишком длинен.

ENOENT

Файл не существует.

ENOMEM

Недостаточное количество памяти ядра.

ENOTDIR

Компонент path не является каталогом.

EPERM

У вызвавшего процесса недостаточно прав.

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.4BSD, SUSv2 (отмечена как УСТАРЕВШАЯ). Эта функция не входит в POSIX.1-2001.

## ЗАМЕЧАНИЯ
Дочерний процесс, созданный посредством fork(2), наследует корневой каталог родительского процесса. При вызове execve(2) корневой каталог остаётся неизменным.

Для определения корневого каталога процесса можно использовать магическую символическую ссылку /proc/[pid]/root; подробности в proc(5).

В FreeBSD есть более ограничивающий системный вызов jail().

## СМОТРИТЕ ТАКЖЕ
chroot(1), chdir(2), pivot_root(2), path_resolution(7), switch_root(8)


title: clock_getres(2)

summary: функции часов и времени

text:
# clock_getres(2)

## ИМЯ
clock_getres, clock_gettime, clock_settime - функции часов и времени

## ОБЗОР
\#include <time.h>

int clock_getres(clockid_t clk_id, struct timespec *res);

int clock_gettime(clockid_t clk_id, struct timespec *tp);

int clock_settime(clockid_t clk_id, const struct timespec *tp);

Компонуется при указании параметра -lrt (только для glibc до версии 2.17).

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

clock_getres(), clock_gettime(), clock_settime():

_POSIX_C_SOURCE >= 199309L

## ОПИСАНИЕ
Функция clock_getres() определяет разрешающую способность (точность) заданных в clk_id часов, и, если res не равно NULL, сохраняет её в struct timespec, указанную в res. Точность часов зависит от реализации и не может быть настроена определённым процессом. Если значение времени, указанное в аргументе tp функции clock_settime(), не кратно res, то оно усекается до кратного res.

Функции clock_gettime() и clock_settime() получают и устанавливают время указанных часов clk_id.

Аргументы res и tp представляют структуру timespec, определённую в <time.h>:

```
struct timespec {

    time_t   tv_sec;        /* секунды */

    long     tv_nsec;       /* наносекунды */
};
```

Аргумент clk_id представляет идентификатор определённых часов, над которыми производится действие. Часы могут использоваться системой в целом и поэтому видимы всем процессам или конкретного процессу, если они отсчитывают время только в пределах одного процесса.

Все реализации поддерживают системные часы реального времени, которые имеют идентификатор CLOCK_REALTIME. Их время представляется в секундах и наносекундах с начала Эпохи. Когда их время изменяется, на таймеры с относительными интервалами это никак не влияет, но таймеры с абсолютной точкой во времени учитывают это.

Может быть реализовано много часов. Представление соответствующих значений времени и влияние на таймеры не определено.

В последних версиях glibc и ядра Linux поддерживаются следующие часы:

CLOCK_REALTIME

Часы системы, отсчитывающие реальное (т. е., бытовое) время. Для настройки этих часов требуются соответствующие права. Данные часы подвержены скачкам системного времени (например, если системный администратор вручную изменяет время) и постепенной подгонке, выполняемой adjtime(3) и NTP.

CLOCK_REALTIME_COARSE (начиная с Linux 2.6.32; есть только в Linux)

Более быстрая, но менее точная версия CLOCK_REALTIME. Используйте, если нужны не очень точные метки времени, но очень быстро. Требуется поддержка в архитектуре и, вероятно, поддержка архитектурой этого флага в vdso(7).

CLOCK_MONOTONIC

Часы, которые не могут быть настроены и показывают монотонный ход времени, отсчитываемый, согласно POSIX, «с некой неопределённой начальной точки в прошлом». В Linux этой точкой является количество секунд, прошедших с момента начала загрузки системы.

Часы CLOCK_MONOTONIC не подвержены скачкам системного времени (например, системный администратор вручную изменил время), но на них влияет постепенная подгонка, выполняемая adjtime(3) и NTP. Данные часы не считают время при приостановке системы.

CLOCK_MONOTONIC_COARSE (начиная с Linux 2.6.32; есть только в Linux)

Более быстрая, но менее точная версия CLOCK_MONOTONIC. Используйте, если нужны не очень точные метки времени, но очень быстро. Требуется поддержка в архитектуре и, вероятно, поддержка архитектурой этого флага в vdso(7).

CLOCK_MONOTONIC_RAW (начиная с Linux 2.6.28; есть только в Linux)

Похожи на CLOCK_MONOTONIC, но предоставляют прямой доступ к аппаратным часам, которые не подводятся NTP или постепенной подгонкой, выполняемой adjtime(3). Эти часы останавливаются когда система входит в состояние приостановки.

CLOCK_BOOTTIME (начиная с Linux 2.6.39; есть только в Linux)

Идентичны CLOCK_MONOTONIC, но также содержат любое время, на которое система была приостановлена (suspended). Это позволяет приложениям получить учитывающие приостановку монотонные часы без обращения к сложностям CLOCK_REALTIME, которые могут быть неоднородны, если время изменили с помощью settimeofday(2) или ему подобных.

CLOCK_PROCESS_CPUTIME_ID (начиная с Linux 2.6.12)

Настраиваемые для каждого процесса часы ЦП (измеряют время ЦП, затраченное всеми нитями процесса).

CLOCK_THREAD_CPUTIME_ID (начиная с Linux 2.6.12)

Часы, работающие на ЦП, для каждой нити.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении функции clock_gettime(), clock_settime() и clock_getres() возвращают 0, или -1 в случае ошибки (errno устанавливается в соответствующее значение).

## ОШИБКИ
EFAULT

tp указывает за пределы доступного адресного пространства.

EINVAL

Заданное в clk_id значение не поддерживается на этой системе.

EINVAL

(clock_settime()): tp.tv_sec отрицательно или tp.tv_nsec вне диапазона [0..999,999,999].

EINVAL (начиная с Linux 4.3)

Вызов clock_settime() со значением clk_id равным CLOCK_REALTIME для установки времени в значение меньше текущего значения часов CLOCK_MONOTONIC.

EPERM

Для установки указанных часов с помощью clock_settime() недостаточно прав.

## ВЕРСИИ
Данные системные вызовы впервые появились в Linux 2.6.

## АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).

Интерфейс

Атрибут

Значение

clock_getres(), clock_gettime(), clock_settime()

Безвредность в нитях

MT-Safe

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SUSv2.

## ДОСТУПНОСТЬ
На POSIX-системах, в которых доступны эти функции, символ _POSIX_TIMERS, определённый в <unistd.h>, имеет значение больше 0. Символами _POSIX_MONOTONIC_CLOCK, _POSIX_CPUTIME, _POSIX_THREAD_CPUTIME показывается, что доступны CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID. (см. также sysconf(3).)

## ЗАМЕЧАНИЯ
В POSIX.1 определено следующее:

Установка значения часов CLOCK_REALTIME с помощью clock_settime() не оказывает влияния на нити, которые находятся в состоянии простоя из-за служб, работа которых основана на этих часах, включая функцию nanosleep(); также, это не оказывает влияние на относительные таймеры, основывающиеся на этих часах. В результате, интервал данных служб истечёт, когда истечёт запрошенный относительный интервал, независимо от нового или старого значения часов.

### Отличия между библиотекой C и ядром
На некоторых архитектурах реализация clock_gettime() находится в vdso(7).

### Историческая справка по системам SMP
До того, как в Linux была добавлена поддержка CLOCK_PROCESS_CPUTIME_ID и CLOCK_THREAD_CPUTIME_ID, реализация этих часов в glibc на многих платформах использовала регистры таймеры ЦП (TSC на i386, AR.ITC на Itanium). Эти регистры могут отличаться у разных ЦП и, как следствие, эти часы могут возвращать поддельные результаты, если выполнение процесса переходит на другой ЦП.

Если процессоры в многопроцессорных системах используют разные источники времени, то нет способа поддерживать сверку между регистрами таймера, так как каждый ЦП будет работать со слегка отличающейся частотой. В этом случае clock_getcpuclockid(0) вернёт ENOENT, чтобы указать на это состояние. Двое часов в этом случае будут полезны, только если можно убедиться, что процесс остался на определённом ЦП.

Процессоры в многопроцессорных системах не приступают к работе одновременно и поэтому регистры таймера обычно работают со смещением. Некоторые архитектуры содержат код, который пытается сократить это смещение при загрузке системы. Однако код не может гарантировать точную подстройку смещений. В glibc нет средств для работы с этими смещениями (в отличие от ядра Linux). Обычно, эти смещения малы и поэтому, в большинстве случаев, их влияние незначительно.

Начиная с glibc 2.4, обёрточные функции системных вызовов, описанных на этой странице, не имеют таких проблем, так как используют ядерную реализацию CLOCK_PROCESS_CPUTIME_ID и CLOCK_THREAD_CPUTIME_ID (в системах, которые её предоставляют, то есть Linux 2.6.12 и новее).

## ДЕФЕКТЫ
Согласно POSIX.1-2001, процесс с «соответствующими правами» может настроить часы CLOCK_PROCESS_CPUTIME_ID и CLOCK_THREAD_CPUTIME_ID с помощью clock_settime(). В Linux эти часы не допускают настройку (т. е., процесс не может иметь «соответствующие права»).

## СМОТРИТЕ ТАКЖЕ
date(1), gettimeofday(2), settimeofday(2), time(2), adjtime(3), clock_getcpuclockid(3), ctime(3), ftime(3), pthread_getcpuclockid(3), sysconf(3), time(7), vdso(7), hwclock(8)


title: clock_nanosleep(2)

text:
# clock_nanosleep(2)

## ИМЯ
clock_nanosleep - остановка работы процесса на точно выдержанное время с помощью определённых часов

## ОБЗОР
\#include <time.h>

```
int clock_nanosleep(clockid_t clock_id, int flags,
                    const struct timespec *request,
                    struct timespec *remain);
```

Компонуется при указании параметра -lrt (только для glibc до версии 2.17).

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

clock_nanosleep():

_POSIX_C_SOURCE >= 200112L

## ОПИСАНИЕ
Подобно nanosleep(2), clock_nanosleep() позволяет вызывающей нити приостановить работу на некоторое время с наносекундной точностью. Отличие в том, что вызывающий может выбрать часы, по которым будет отсчитываться интервал, что позволяет задавать интервал абсолютным или относительным значением времени.

Время, передаваемое и возвращаемое этим вызовом, задаётся в структурах timespec, определённых следующим образом:

```
struct timespec {

    time_t tv_sec;        /* секунды */

    long   tv_nsec;       /* наносекунды [0 .. 999999999] */
};
```

Аргумент clock_id определяет часы, по которым отсчитывается интервал. Этот аргумент может иметь следующие значения:

CLOCK_REALTIME

Настраиваемые системные часы реального времени.

CLOCK_MONOTONIC

Ненастраиваемые, постоянно идущие вперёд часы, которые отчитывают время с некоторой неопределённой точки в прошлом, которая не изменяется с момент запуска системы.

CLOCK_PROCESS_CPUTIME_ID

Настраиваемые для каждого процесса часы, измеряющие время ЦП, затраченное всеми нитями процесса.

Подробней об этих часах смотрите в clock_getres(2). Также ID часов ЦП, возвращаемый clock_getcpuclockid(3) и pthread_getcpuclockid(3), также может передаваться в clock_id.

Если flags равно 0, то значение, указанное в request, считается относительным интервалом от текущего значения часов, заданных в clock_id.

Если flags равно TIMER_ABSTIME, то значением request считается абсолютное время, отсчитываемое часами, заданными в clock_id. Если request меньше или равно текущему значению часов, то clock_nanosleep() немедленно завершает работу без приостановки работы вызывающий нити.

clock_nanosleep() приостанавливает выполнение вызывающей нити до тех пор, пока не наступит время, указанное в request, или не будет получен сигнал, вызывающий обработчик сигнала, или процесс не завершится.

Если вызов прерывается обработчиком сигнала, то clock_nanosleep() завершается с ошибкой EINTR. Также, если remain не равно NULL и flags не равно TIMER_ABSTIME, то он возвращает в remain остаток непроведённого в остановке времени. Это значение можно использовать в вызове clock_nanosleep() снова и завершить (относительно) приостановку.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
После успешной приостановки на запрошенное время, clock_nanosleep() возвращает 0. Если вызове был прерван обработчиком сигнала или произошла ошибка, то возвращается один из положительных номеров ошибок, перечисленных в разделе ОШИБКИ.

## ОШИБКИ
EFAULT

В request или remain указан неправильный адрес.

EINTR

Сон прерван обработчиком сигнала; смотрите signal(7).

EINVAL

Значение поля tv_nsec не находится в интервале от 0 до 999999999 или tv_sec содержит отрицательное число.

EINVAL

Неверное значение clock_id. (Значение CLOCK_THREAD_CPUTIME_ID нельзя указать в clock_id.)

## ВЕРСИИ
Системный вызов clock_nanosleep() появился в Linux 2.6. Поддержка в glibc появилась в версии 2.1.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008.

## ЗАМЕЧАНИЯ
Если интервал, указанный в request, не кратен степени разрешения используемых часов (см. time(7)), то интервал будет округлён до следующего кратного значения. Также, после окончания интервала приостановки может возникнуть задержка перед тем, как ЦП освободится снова для следующего выполнения вызывающей нити.

Использование абсолютного таймера позволяет избежать проблем с уходом часов, которые описаны в nanosleep(2). (Такие проблемы ухудшаются, если программа пытается перезапустить приостановку на относительный интервал после постоянно прерывания сигналами.) Чтобы избежать этих проблем при использовании относительного интервала, вызовите clock_gettime(2) с нужными часами, добавьте нужный интервал к возвращённому значению времени и вызовите clock_nanosleep() с флагом TIMER_ABSTIME.

clock_nanosleep() никогда не перезапускается после того, как прерван обработчиком сигнала, независимо от значения флага SA_RESTART в sigaction(2).

Аргумент remain не нужен и не используется, если flags равно TIMER_ABSTIME. (Приостановка с абсолютным значением может быть перезапущена с тем же значением аргумента request.)

В POSIX.1 указано, что clock_nanosleep() не влияет на заданные обработчики сигналов или сигнальные маски.

В POSIX.1 указано, что после изменения значения часов CLOCK_REALTIME с помощью clock_settime(2), новое значение часов должно быть использовано для определения времени, на которое была блокирована нить с помощью clock_nanosleep() с абсолютным значением; если по новому значению часов интервал приостановки истёк, то вызов clock_nanosleep() немедленно завершается.

В POSIX.1 указано, что изменение значения часов CLOCK_REALTIME с помощью clock_settime(2) не оказывает влияние на нити, которые заблокированы с помощью clock_nanosleep() с относительным значением интервала.

## СМОТРИТЕ ТАКЖЕ
clock_getres(2), nanosleep(2), restart_syscall(2), timer_create(2), sleep(3), usleep(3), time(7)


clone

title: clone(2)

summary: создать процесс\-потомок

text:
# clone(2)

## ИМЯ
clone, __clone2 - создать процесс-потомок

## ОБЗОР

```
/* Прототип обёрточной функции glibc */
```

```
#define _GNU_SOURCE
#include <sched.h>
```

```
int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, void *newtls, pid_t *ctid */ );
```

```
/* для прототипа неструктурированного системного вызова, смотрите ЗАМЕЧАНИЯ */
```

## ОПИСАНИЕ
Вызов clone() создаёт новый процесс подобно fork(2).

Здесь описана обёрточная функция glibc clone() и используемый ею системный вызов. В основном, описывается обёрточная функция;отличия от системного вызова приводятся в конце данной справочной страницы.

В отличие от fork(2), clone() позволяет процессу-потомку использовать некоторые части контекста выполнения совместно с вызывающим процессом, например: виртуальное адресное пространство, таблица файловых дескрипторов и таблица обработчиков сигналов. Заметим, что в данной справочной странице «вызывающий процесс» обычно соответствует «родительскому процессу». Но смотрите ниже описание CLONE_PARENT.

Одним из вариантов использования вызова clone() является реализация нитей: несколько потоков управления в программе, выполняющиеся одновременно в общем адресном пространстве.

Когда процесс-потомок создаётся с помощью clone(), он начинает выполнение с вызова функции, на которую указывает fn (это отличается от fork(2), где выполнение продолжается в потомке от точки вызова fork(2)). Аргумент arg передаётся в функцию fn.

Когда происходит возврат из функции fn(arg) процесс-потомок завершается. Целое значение, возвращаемое fn, является состоянием выхода процесса-потомка. Процесс-потомок может также быть завершён явным образом с помощью вызова exit(2) или после получения завершающего сигнала.

Аргумент child_stack задаёт положение стека, используемого процессом-потомком. Так как процесс-потомок и вызывающий процесс могут использовать общую память, процесс-потомок не может выполняться в том же стеке, что и вызывающий процесс. Поэтому вызывающий процесс должен установить пространство памяти для стека процесса-потомка и передать указатель на это пространство в вызове clone(). Стеки растут вниз для всех процессоров, на которых работает Linux (за исключением процессоров HP PA), так что child_stack, обычно, указывает на наибольший адрес в пространстве памяти, которое устанавливается для стека процесса-потомка.

Младший байт flags содержит номер сигнала завершения, который посылается родителю, когда работа потомка завершается. Если этот сигнал задаётся как нечто отличное от SIGCHLD, то родительский процесс должен задать параметр __WALL или __WCLONE при ожидании завершения работы потомка с помощью вызова wait(2). Если никакой сигнал не задан, то родительский процесс не извещается сигналом, когда потомок завершается.

Аргумент flags состоит из одной или более данных ниже констант, которые складываются по правилам битового сложения (OR). Флагами задаёт что будет общим между вызывающим процессом и процессом-потомком:

CLONE_CHILD_CLEARTID (начиная с Linux 2.5.49)

Очистить (обнулить) идентификатор (ID) нити потомка, расположенный в ctid в памяти потомка, если потомок существует, и активизировать futex по этому адресу. Соответствующий адрес может быть изменён системным вызовом set_tid_address(2). Используется в библиотеках работы с нитями.

CLONE_CHILD_SETTID (начиная с Linux 2.5.49)

Сохранить ID нити потомка в указанном ctid месте в памяти потомка. Операция сохранения завершается до возврата управления из clone() в пользовательское пространство процесса потомка (заметим, что операция сохранения может не завершиться до возврата clone() в родительском процессе, что произойдёт даже с указанным флагом CLONE_VM).

CLONE_FILES (начиная с Linux 2.0)

Если задан флаг CLONE_FILES, то вызывающий процесс и процесс-потомок используют одну и ту же таблицу файловых дескрипторов. Любые файловые дескрипторы, создаваемые вызывающим процессом или процессом-потомком, также доступны и в другом процессе. Аналогично, если один из процессов закрывает файловый дескриптор или изменяет ассоциированные с ним флаги (с помощью fcntl(2) операцией F_SETFD), то это оказывает влияние и на другой процесс. Если процесс использующий общую таблицу файловых дескрипторов вызывает execve(2), то таблица файловых дескрипторов копируется в отдельную (не общую).

Если флаг CLONE_FILES не задан, то процесс-потомок наследует копии всех файловых дескрипторов, открытых в вызывающем процессе на момент вызова clone(). Последующие операции над файловыми дескрипторами по открытию и закрытию файлов или изменению флагов файловых дескрипторов, выполняемые вызывающим процессом или процессом-потомком, не оказывают эффекта на другой процесс. Заметим, что дублируемые файловые дескрипторы в потомке указывают на те же открытые файловые дескрипторы что и файловые дескрипторы вызывающего процесса и, таким образом, файловые смещения и флаги состояния файла используются совместно (смотрите open(2)).

CLONE_FS (начиная с Linux 2.0)

Если задан флаг CLONE_FS, то вызывающий процесс и процесс-потомок используют одну и ту же информацию о файловой системе. К ней относится корневой каталог файловой системы, текущий рабочий каталог и значение umask. Любой вызов, chroot(2), chdir(2) или umask(2), выполняемый одним процессом, оказывает влияние и на другой.

Если флаг CLONE_FS не задан, то процесс-потомок работает с копией информации о файловой системе вызывающего процесса, снятой на момент вызова clone(). Вызовы chroot(2), chdir(2) или umask(2), выполняемые позже одним из процессов, не оказывают эффект на другой процесс.

CLONE_IO (начиная Linux 2.6.25)

Если задан флаг CLONE_IO, то новый процесс использует общий контекст ввода-вывода с вызывающим процессом. Если этот флаг не установлен, то (как и в fork(2)) новый процесс будет иметь свой отдельный контекст ввода-вывода.

Контекст ввода-вывода — это область ввода-вывода в дисковом планировщике (т. е. то, что планировщик ввода-вывода использует при планировании ввода-вывода процесса). Если процессы используют общий контекст ввода-вывода, то они рассматриваются планировщиком ввода-вывода как один. Следовательно, они совместно делят время доступа к диску. У некоторых планировщиков ввода-вывода, если два процесса используют общий контекст ввода-вывода, то им будет разрешено чередовать доступ к диску. Если несколько нитей выполняют ввод-вывод из одного процесса (например, aio_read(3)), то для них нужно указать CLONE_IO для получения большей производительности ввода-вывода.

Если в ядре не указан параметр сборки CONFIG_BLOCK, то этот флаг ни на что не влияет.

CLONE_NEWCGROUP (начиная с Linux 4.6)

Процесс создаётся в новом пространстве имён cgroup. Если флаг не установлен, то (как и в fork(2)), процесс создаётся в том же пространстве имён cgroup, что и вызывающий процесс. Этот флаг предназначен для реализации контейнеров.

Дополнительную информацию о пространствах имён cgroup смотрите в cgroup_namespaces(7).

Только привилегированный процесс (CAP_SYS_ADMIN) может использовать CLONE_NEWCGROUP.

CLONE_NEWIPC (начиная с Linux 2.6.19)

Если задан флаг CLONE_NEWIPC, то процесс создаётся в новом пространстве имён IPC. Если этот флаг не установлен, то (как и в fork(2)) процесс создаётся в том же пространстве имён IPC что и вызывающий процесс. Этот флаг предназначен для реализации контейнеров.

Пространство имён IPC предоставляет изолированную выборку объектов System V IPC (смотрите sysvipc(7)) и (начиная с Linux 2.6.30) очередей сообщений POSIX (смотрите mq_overview(7)). Общие характеристики этих механизмов IPC в том, что объекты IPC определяются механизмами, а не путями в файловой системе.

Объекты, созданные в пространстве имён IPC, видимы всем другим процессам, которые являются членами этого пространства имён, и невидимы процессам из других пространств имён IPC.

При уничтожении пространства имён IPC (т.е., когда завершается последний процесс из этого пространства имён), все объекты IPC из пространства имён автоматически уничтожаются.

Только привилегированный процесс (CAP_SYS_ADMIN) может использовать CLONE_NEWIPC. Этот флаг нельзя указывать вместе с CLONE_SYSVSEM.

Дополнительную информацию о пространствах имён IPC смотрите в namespaces(7).

CLONE_NEWNET (начиная с Linux 2.6.24)

(Реализация этого флага завершена только в Linux 2.6.29.)

Если задан флаг CLONE_NEWNET, то процесс создаётся в новом сетевом пространстве имён. Если флаг не установлен, то (как и в fork(2)), процесс создаётся в том же сетевом пространстве имён что и вызывающий процесс. Этот флаг предназначен для реализации контейнеров.

Сетевое пространство имён предоставляет изолированное представление сетевого стека (интерфейсы сетевых устройств, стеки протоколов IPv4 и IPv6, таблицы маршрутизации IP, правила межсетевого экрана, дерево каталогов /proc/net и /sys/class/net, сокеты и т. д.). Физическое сетевое устройство может находиться только в одном сетевом пространстве имён. Пара виртуальных сетевых устройств (veth(4)) предоставляет похожую на канал абстракцию, которую можно использовать для создания туннелей между сетевыми пространствами имён и создания моста к физическому сетевому устройству из другого пространства имён.

Когда сетевое пространство имён высвобождается (т. е., когда завершается последний процесс в пространстве имён), его физические сетевые устройства перемещаются обратно в первоначальное сетевое пространство имён (не родительского процесса). Дополнительную информацию о сетевых пространствах имён смотрите в namespaces(7).

Только привилегированный процесс (CAP_SYS_ADMIN) может использовать CLONE_NEWNET.

CLONE_NEWNS (начиная с Linux 2.4.19)

Если указан флаг CLONE_NEWNS, то клонированный потомок запускается в новом пространстве имён монтирования, инициализированном копией пространства имён родителя. Если CLONE_NEWNS не указан, то потомок остаётся в том же пространстве имён монтирования что и родитель.

Только привилегированный процесс (имеющий мандат CAP_SYS_ADMIN) может использовать CLONE_NEWNS. Не допускается совместное использование флагов CLONE_NEWNS и CLONE_FS в одном вызове clone().

Дополнительную информацию о пространствах имён монтирования смотрите в namespaces(7) и mount_namespaces(7).

CLONE_NEWPID (начиная с Linux 2.6.24)

Если задан флаг CLONE_NEWPID, то процесс создаётся в новом пространстве имён PID. Если флаг не установлен, то (как и в fork(2)), процесс создаётся в том же пространстве имён PID, что и вызывающий процесс. Этот флаг предназначен для реализации контейнеров.

Дополнительную информацию о пространствах имён PID смотрите в namespaces(7) и pid_namespaces(7).

Только привилегированный процесс (CAP_SYS_ADMIN) может использовать CLONE_NEWPID. Этот флаг нельзя указывать вместе с CLONE_THREAD или CLONE_PARENT.

CLONE_NEWUSER

(Впервые этот флаг приобрёл значение для clone() в Linux 2.6.23, текущая семантика clone() появилась в Linux 3.5, а оставшиеся части, делающие пространства имён пользователя полностью работоспособными, включены в Linux 3.8.)

Если задан флаг CLONE_NEWUSER, то процесс создаётся в новом пространстве имён пользователя. Если флаг не установлен, то (как и в fork(2)), процесс создаётся в том же пространстве имён пользователя, что и вызывающий процесс.

До Linux 3.8, для использования CLONE_NEWUSER у вызывающего требовалось три мандата: CAP_SYS_ADMIN, CAP_SETUID и CAP_SETGID. Начиная с Linux 3.8, для создания пространства имён пользователя никаких привилегий не требуется.

Этот флаг нельзя указывать вместе с CLONE_THREAD или CLONE_PARENT. По соображениям безопасности, CLONE_NEWUSER нельзя указывать вместе с CLONE_FS.

Дополнительную информацию о пространствах имён пользователя смотрите в namespaces(7) и user_namespaces(7).

CLONE_NEWUTS (начиная с Linux 2.6.19)

Если задан флаг CLONE_NEWUTS, то процесс создаётся в новом пространстве имён UTS, чьи идентификаторы инициализируются копией идентификаторов из пространства имён UTS вызывающего процесса. Если флаг не указан, то (как и в fork(2)), процесс создаётся в том же пространстве имён UTS что и вызывающий процесс. Этот флаг предназначен для реализации контейнеров.

Пространство имён UTS — это набор идентификаторов, возвращаемых uname(2); помимо остальных, сюда включены доменное имя и имя узла, которые изменить с помощью setdomainname(2) и sethostname(2), соответственно. Изменившиеся идентификаторы в пространстве имён UTS видимы всем остальным процессам в том же пространстве имён, но не видимы процессам из других пространств имён UTS.

Только привилегированный процесс (CAP_SYS_ADMIN) может использовать CLONE_NEWUTS.

Дополнительную информацию о пространствах имён UTS смотрите в namespaces(7).

CLONE_PARENT (начиная с Linux 2.3.12)

Если задан флаг CLONE_PARENT, то родитель нового потомка (возвращаемый getppid(2)) будет таким же как и у вызывающего процесса.

Если флаг CLONE_PARENT не задан, то (как и в fork(2)) родителем будет вызывающий процесс.

Заметим, что это тот родительский процесс, который возвращается вызовом getppid(2), и которому приходит сигнал когда потомок завершается, так что если указан флаг CLONE_PARENT, то сигнал будет посылаться родителю вызывающего процесса, а не самому вызывающему процессу.

CLONE_PARENT_SETTID (начиная с Linux 2.5.49)

Сохранить ID нити потомка, расположенный в ptid в памяти родителя (в Linux 2.5.32-2.5.48 для этого использовался флаг CLONE_SETTID). Операция сохранения завершается до возврата управления из clone() в пользовательское пространство.

CLONE_PID (в Linux 2.0 по 2.5.15)

Если задан флаг CLONE_PID, то процесс-потомок создаётся с таким же идентификатором процесса как у вызывающего процесса. Это хорошо для ковыряния в системе, но не более того. Начиная с 2.3.21 этот флаг может быть указан только у процесса загрузки системы (PID 0). Флаг полностью удалён из исходного кода в Linux 2.5.16. Начиная с этой версии, ядро просто игнорирует этот бит, если он установлен в flags.

CLONE_PTRACE (начиная с Linux 2.2)

Если задан флаг CLONE_PTRACE и вызывающий процесс находится в режиме трассировки, то процесс-потомок также будет работать в режиме трассировки (см. ptrace(2)).

CLONE_SETTLS (начиная с Linux 2.5.32)

Дескриптор TLS (локальная память нитей) помещается в newtls.

Назначение newtls и его влияние на результат зависит от архитектуры. На x86 newtls рассматривается как struct user_desc * (смотрите set_thread_area(2)). На x86_64 это новое значение будет присвоено базовому регистру %fs (смотрите описание ARCH_SET_FS в arch_prctl(2)). На архитектурах с отдельным регистром для TLS это новое значение помещается в этот регистр.

CLONE_SIGHAND (начиная с Linux 2.0)

Если задан флаг CLONE_SIGHAND, то вызывающий процесс и процесс-потомок используют одну и ту же таблицу обработчиков сигналов. Если вызывающий процесс или процесс-потомок вызывают sigaction(2) для изменения поведения при получении сигнала, то это поведение изменяется также и в другом процессе. Однако, вызывающий процесс и процесс-потомок имеют различные маски сигналов и списки ожидающих обработки сигналов. Так, один из них может блокировать или деблокировать сигналы, используя sigprocmask(2), и это не будет влиять на другой процесс.

Если флаг CLONE_SIGHAND не указан, то процесс-потомок наследует копию обработчиков событий вызывающего процесса, снятую на момент вызова clone(). Вызовы sigaction(2), выполняемые позже одним из процессов, не оказывают влияния на другой процесс.

Начиная с Linux 2.6.0, аргумент flags должен также включать CLONE_VM, если указан флаг CLONE_SIGHAND

CLONE_STOPPED (начиная с Linux 2.6.0)

Если указан флаг CLONE_STOPPED, то после создания потомок перейдёт в состояние останова (как если бы ему послали сигнал SIGSTOP), и начнёт работу по сигналу SIGCONT.

Этот флаг устарел начиная с Linux 2.6.25 и был удалён в Linux 2.6.38. Начиная с этой версии, ядро просто игнорирует его без ошибки. Начиная с Linux 4.6 используемый под него бит используется для флага CLONE_NEWCGROUP.

CLONE_SYSVSEM (начиная с Linux 2.5.10)

Если указан флаг CLONE_SYSVSEM, то потомок и вызывающий процесс будут иметь общий единый список значений регулировки семафоров System V (semadj) (смотрите semop(2)). В этом случае общий список накапливает значения semadj из общего списка процессов и регулировки семафоров выполняются только когда завершается последний процесс, использующий общий список (или перестаёт пользоваться общим списком с помощью unshare(2)). Если этот флаг не указан, то потомок имеет отдельный список semadj, который первоначально пуст.

CLONE_THREAD (начиная с Linux 2.4.0)

Если указан флаг CLONE_THREAD, то потомок размещается в той же группе нитей, что и вызывающий процесс. Чтобы сделать остаток обсуждения CLONE_THREAD более понятным, термин «нить» используется для ссылки на процессы внутри группы нитей.

Группы нитей были добавлены в Linux 2.4 для поддержки нитей POSIX, описываемых как набор нитей, использующих один и тот же PID. Внутренне общий PID — это так называемый идентификатор группы нитей (TGID). Начиная с Linux 2.4, вызов getpid(2) возвращает идентификатор группы нитей вызывающего процесса.

Внутри группы нити можно различать по их (глобальному) уникальному идентификатору нити (TID). TID новой нити возвращается вызывающему как результат clone(), а нить может узнать свой TID с помощью вызова gettid(2).

Когда вызов clone() делается без CLONE_THREAD, то получаемая нить помещается в новую группу нитей, чей TGID совпадает с TID нити. Эта нить будет лидером новой группы нитей.

Новая нить, созданная с CLONE_THREAD, имеет тот же родительский процесс что и вызвавший clone() (т.е., как CLONE_PARENT), поэтому при вызове getppid(2) возвращается одинаковое значение для всех нитей в группе нитей. Когда нить CLONE_THREAD завершается, нити, создавшей её с помощью clone(), не посылается сигнал SIGCHLD (или другой сигнал завершения); состояние такой нити нельзя получить с помощью wait(2). Про нить говорят, что она отсоединена (detached).

После завершения работы всех нитей в группе нитей родительскому процессу группы нитей посылается сигнал SIGCHLD (или другой завершающий сигнал).

Если в любой из нитей группы нитей выполняется вызов execve(2), то все нити отличные от лидера группы нитей, завершаются и выполняется новая программы в лидере группы нитей.

Если одна из нитей группы нитей создаёт потомка с помощью fork(2), то любая нить группы может вызвать wait(2) для ожидания этого потомка.

Начиная с Linux 2.5.35, аргумент flags должен также включать CLONE_SIGHAND, если указан флаг CLONE_THREAD (также заметим, что начиная с Linux 2.6.0, для CLONE_SIGHAND также требуется включать CLONE_VM).

Расположение и действия сигналов распространяются на весь процесс: если необработанный сигнал доставляется нити, то это влияет (завершение, остановка, продолжение, игнорирование) на все члены группы нитей.

Каждая нить имеет свою маску сигналов, задаваемую sigprocmask(2).

Сигнал может быть направлен процессу и направлен нити. Целью сигнала, направленного процессу, является группа нитей (т. е., TGID), и он доставляется произвольно выбранной нити среди неблокирующих сигнал. Сигнал может быть направлен процессу из ядра по причинам, не относящимся к аппаратному исключению, или быть послан с помощью kill(2) или sigqueue(3). Целью сигнала, направленного нити, является определённая (т. е., указанная в адресе назначения) нить. Сигнал может быть направлен нити вызовом tgkill(2) или pthread_sigqueue(3), или если в работе нити возникло аппаратное исключение при выполнении ей языковой инструкции (например, при доступе к памяти по неправильному адресу возникает SIGSEGV, а исключение в блоке выполнения инструкций с плавающей запятой приводит к SIGFPE).

Вызов sigpending(2) возвращает набор сигналов, который представляет собой объединение ожидающих сигналов, направленных процессу, и сигналов, которые ожидает вызывающая нить.

Если сигнал, оправленный процессу, доставляется группе нитей и у группы нитей установлен обработчик сигнала, то обработчик будет вызван только один раз в произвольно выбранном члене группы нитей, который не блокирует сигнал. Если несколько нитей в группе ждут приёма того же сигнала с помощью sigwaitinfo(2), то ядро произвольно выберет одну из этих нитей для приёма сигнала.

CLONE_UNTRACED (начиная с Linux 2.5.46)

Если указан флаг CLONE_UNTRACED, то выполняющий трассировку процесс не сможет указать CLONE_PTRACE на этом процессе-потомке.

CLONE_VFORK (начиная с Linux 2.2)

Если указан флаг CLONE_VFORK, то выполнение вызывающего процесса приостанавливается до тех пор, пока потомок не освободит ресурсы виртуальной памяти с помощь вызова execve(2) или _exit(2) (как с vfork(2)).

Если флаг CLONE_VFORK не указан, то вызывающий процесс и потомок доступны для планирования после вызова, и приложение не должно полагаться на то, что выполнение производится в каком-то определённом порядке.

CLONE_VM (начиная с Linux 2.0)

Если задан флаг CLONE_VM, то вызывающий и дочерний процесс работают в одном пространстве памяти. В частности, запись в память одним процессом видна другому. Кроме того, выполнение отображения или снятия отображения в память, выполняемая с помощью mmap(2) или munmap(2), одним процессом, влияет на другой.

Если флаг CLONE_VM не установлен, то дочерний процесс выполняется в отдельной копии пространства памяти вызывающего процесс с момента clone(). Запись в память или отображение/снятие отображения файла, выполняемое одним процессом, не влияет на другой (как с fork(2)).

## ЗАМЕЧАНИЯ
Заметим, что обёрточная функция glibc clone() делает некоторые изменения в памяти, на которую указывает child_stack (изменения требуются для правильной настройки стека в потомке) перед запуском системного вызова clone(). Поэтому в случаях, когда clone() используется для рекурсивного создания потомков, не используйте буфер стека родителя в качестве стека потомка.

### Отличия между библиотекой C и ядром
Системный вызов clone() больше похож на fork(2) в том плане, что выполнение в потомке продолжается от места вызова. Таким образом, аргументы fn и arg обёрточной функции clone() отсутствуют.

Другим отличием системного вызова clone() является то, что аргумент child_stack может быть равен NULL, если потомок использует копию родительского стека (копирование-при-записи гарантирует, что потомок получит отдельные копии страниц стека, если один из процессов изменит стек). В этом случае для правильной работы не должен использоваться флаг CLONE_VM (если потомок использует родительскую память из-за указания CLONE_VM, то создания копии при копировании-при-записи не происходит и, вероятно, это вызове хаос).

В системном вызове также другой порядок аргументов, он различен у разных архитектур (описан далее).

Интерфейс внутреннего системного вызова на x86-64 и некоторых других архитектурах (включая sh, tile, ia-64 и alpha):

```
long clone(unsigned long flags, void *child_stack,
           int *ptid, int *ctid,
           unsigned long newtls);
```

На x86-32 и некоторых других распространённых архитектурах (включая score, ARM, ARM 64, PA-RISC, arc, Power PC, xtensa и MIPS) порядок последних двух аргументов обратный:

```
long clone(unsigned long flags, void *child_stack,
          int *ptid, unsigned long newtls,
          int *ctid);
```

На архитектурах cris и s390 порядок первых двух аргументов обратный:

```
long clone(void *child_stack, unsigned long flags,
           int *ptid, int *ctid,
           unsigned long newtls);
```

На архитектуре microblaze есть дополнительный аргумент:

```
long clone(unsigned long flags, void *child_stack,
           int stack_size,         /* Size of stack */
           int *ptid, int *ctid,
           unsigned long newtls);
```

### blackfin, m68k и sparc
Соглашение по передаче аргументов на blackfin, m68k и sparc отличается от описанного выше. Подробности смотрите в исходном коде ядра (и glibc).

### ia64
На ia64 используется другой интерфейс:

```
int __clone2(int (*fn)(void *),
             void *child_stack_base, size_t stack_size,
             int flags, void *arg, ...
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
```

Прототип, показанный выше, относится к обёрточной функции glibc; прототип системного вызова можно описать следующим образом (одинаков с прототипом clone() на microblaze):

```
long clone2(unsigned long flags, void *child_stack_base,
            int stack_size,         /* Size of stack */
            int *ptid, int *ctid,
            unsigned long tls);
```

Системный вызов __clone2() работает также как и clone() за исключением того, что child_stack_base указывает на самый нижний адрес области стека потомка, и в stack_size задаётся размер стека, указываемого в child_stack_base.

### Linux версии 2.4 и более ранние
В Linux 2.4 и более ранних clone() не принимал аргументов ptid, tls и ctid.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении в вызывающую исполняемую нить возвращается ID нити дочернего процесса. Иначе в контекст вызывающего возвращается -1, дочерний процесс не создаётся и errno устанавливается в соответствующее значение.

## ОШИБКИ
EAGAIN

Уже выполняется максимальное количество процессов; смотрите fork(2).

EINVAL

Указан флаг CLONE_SIGHAND, но нет CLONE_VM (начиная с Linux 2.6.0).

EINVAL

Указан флаг CLONE_THREAD, но нет CLONE_SIGHAND (начиная с Linux 2.5.35).

EINVAL

Указан флаг CLONE_THREAD, но текущий процесс до этого вызвал unshare(2) с флагом CLONE_NEWPID или использовал setns(2) для своего отсоединения от пространства имён PID.

EINVAL

Указаны оба флага, CLONE_FS и CLONE_NEWNS, в flags.

EINVAL (начиная с Linux 3.9)

Указаны оба флага, CLONE_NEWUSER и CLONE_FS, в flags.

EINVAL

Указаны оба флага, CLONE_NEWIPC и CLONE_SYSVSEM, в flags.

EINVAL

Указан один или оба флага, CLONE_NEWPID или CLONE_NEWUSER, и один или оба флага, CLONE_THREAD или CLONE_PARENT, в flags.

EINVAL

Возвращается обёрточной функцией glibc clone(), если fn или child_stack равны NULL.

EINVAL

Указан флаг CLONE_NEWIPC в flags, но ядро собрано без параметров CONFIG_SYSVIPC и CONFIG_IPC_NS.

EINVAL

Указан флаг CLONE_NEWNET в flags, но ядро собрано без параметра CONFIG_NET_NS.

EINVAL

Указан флаг CLONE_NEWPID в flags, но ядро собрано без параметра CONFIG_PID_NS.

EINVAL

Указан флаг CLONE_NEWUSER в flags, но ядро собрано без параметра CONFIG_USER_NS.

EINVAL

Указан флаг CLONE_NEWUTS в flags, но ядро собрано без параметра CONFIG_UTS_NS.

EINVAL

Значение child_stack не выровнено по нужной границе для этой архитектуры. Например, на aarch64 child_stack должно быть кратно 16.

ENOMEM

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

ENOSPC (начиная с Linux 3.7)

В флагах указан CLONE_NEWPID, но вызов привёл бы к превышению ограничения на количество вложенных имён PID; смотрите pid_namespaces(7).

ENOSPC (начиная с Linux 4.9; до этого EUSERS)

Флаг CLONE_NEWUSER указан в flags, и вызов привёл бы к превышению ограничения на количество вложенных пользовательских пространств имён. Смотрите user_namespaces(7).

В этом случае в Linux 3.11 по Linux 4.8 возвращалась ошибка EUSERS.

ENOSPC (начиная с Linux 4.9)

Одним из значений в flags задаётся создание нового пространства пространства имён пользователя, но это превысило бы ограничение, определённое в соответствующем файле в каталоге /proc/sys/user. Дополнительную информацию смотрите в namespaces(7).

EPERM

Указан флаг CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID или CLONE_NEWUTS, но процесс не имеет достаточно прав (нет мандата CAP_SYS_ADMIN).

EPERM

Указан флаг CLONE_PID, но ID процесса не равен 0 (эта ошибка возникает только в Linux 2.5.15 и старее).

EPERM

Флаг CLONE_NEWUSER указан в flags, но эффективный пользовательский ID или эффективный ID группы вызывающего не отображён в родительское пространство имён (смотрите user_namespaces(7)).

EPERM (начиная с Linux 3.9)

В flags был указан флаг CLONE_NEWUSER и вызывающий выполняется в окружении chroot (т. е. корневой каталог вызывающего не совпадает с корневым каталогом пространства имён монтирования, в котором он находится).

ERESTARTNOINTR (начиная с Linux 2.6.17)

Системный вызов был прерван сигналом и перезапущен (может быть замечено только при трассировке).

EUSERS (с Linux 3.11 по Linux 4.8)

Флаг CLONE_NEWUSER указан в flags, и вызов привёл бы к превышению ограничения на количество вложенных пользовательских пространств имён. Смотрите описание ошибки ENOSPC, представленное выше.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Вызов clone() есть только в Linux и не должен использоваться в переносимых программах.

## ЗАМЕЧАНИЯ
Системный вызов kcmp(2) можно использовать для проверки того, что два процесса совместно используют различные ресурсы, такие как таблицу файловых дескрипторов, семафор System V для отмены операций или виртуальное адресное пространство.

Обработчики, зарегистрированные с помощью pthread_atfork(3), не выполняются во время вызова clone().

Для ядер версий Linux 2.4.x, флаг CLONE_THREAD не делает родителем новой нити того же родителя что и у вызывающего процесса. Однако для ядер версий 2.4.7-2.4.18 флаг CLONE_THREAD неявно подразумевает флаг CLONE_PARENT (как в ядре Linux 2.6.0 и новее).

Некоторое время существовал флаг CLONE_DETACHED (начиная с 2.5.32): родитель не хочет получать сигнал завершения потомка. В Linux 2.6.2 необходимость указывать этот флаг вместе с CLONE_THREAD отпала. Этот флаг ещё определён, но не оказывает никакого действия.

На архитектуре i386 clone() не должен вызываться через vsyscall, а запускаться явно с помощью int $0x80.

## ДЕФЕКТЫ
Версии библиотеки GNU C с 2.3.4 и по 2.24 включительно содержат обёрточную функцию для getpid(2), которая выполняет кэширование значений PID. Это кэширование основано на поддержке обёрточной функции glibc для clone(), но ограничения в реализации полагаются, что кэш в некоторых случаях не устаревает до определённой даты. В частности, если сигнал был доставлен потомку сразу после вызова clone(), то вызов getpid(2) обработчике сигнала может вернуть PID вызывающего процесса («родителя»), если у обёртки clone пока не было шанса изменить кэш PID в потомке (в этом описании игнорируется случай, где потомок был создал с использованием CLONE_THREAD, когда getpid(2) должен вернуть то же значение в потомок и в процесс, вызывавший clone(), так как вызывающий и потомок находятся в одной группе нитей. Проблема просроченного кэша также не возникает, если в аргументе flags содержится CLONE_VM). Чтобы узнать правду, было иногда необходимо использовать такой код:

```
#include <syscall.h>
pid_t mypid;
mypid = syscall(SYS_getpid);
```

Из-за проблем просроченного кэша (stale-cache), а также других, упомянутых в getpid(2), свойство кэширования PID было удалено в glibc 2.25.

## ПРИМЕР
Следующая программа демонстрирует использование clone() для создания дочернего процесса, который выполняется в отдельном пространстве имён UTS. Потомок изменяет имя узла в своём пространстве имён UTS. И предок и потомок затем выводят системное имя узла, чтобы можно было убедиться в неодинаковости пространств имён. Пример использования этой программы смотрите в setns(2).

### Исходный код программы

```
#define _GNU_SOURCE
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sched.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
static int              /* Начало функции клонированного

                           потомка */
childFunc(void *arg)
{

    struct utsname uts;

    /* Изменяем имя узла в пространстве имён UTS потомка */

    if (sethostname(arg, strlen(arg)) == -1)

        errExit("sethostname");

    /* Получаем и показывает имя узла */

    if (uname(&uts) == -1)

        errExit("uname");

    printf("uts.nodename in child:  %s\n", uts.nodename);

    /* Перед сном оставим пространство имён открытым.

       Это позволяет поэкспериментировать — например, другой

       процесс может подключиться к пространству имён. */

    sleep(200);

    return 0;           /* Завершение работы потомка */
}
#define STACK_SIZE (1024 * 1024)    /* Размер стека клонированного

                                       потомка */
int
main(int argc, char *argv[])
{

    char *stack;                    /* Начало буфера стека */

    char *stackTop;                 /* Конец буфера стека */

    pid_t pid;

    struct utsname uts;

    if (argc < 2) {

        fprintf(stderr, "Usage: %s <child-hostname>\n", argv[0]);

        exit(EXIT_SUCCESS);

    }

    /* Выделение стека для потомка */

    stack = malloc(STACK_SIZE);

    if (stack == NULL)

        errExit("malloc");

    stackTop = stack + STACK_SIZE;  /* Считаем, что стек растёт вниз */

    /* Создаём потомка с собственным пространством имён UTS;

       потомок начинает выполнение с childFunc() */

    pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);

    if (pid == -1)

        errExit("clone");

    printf("clone() returned %ld\n", (long) pid);

    /* Предок попадает сюда */

    sleep(1);           /* Даём время потомку изменить своё имя узла */

    /* Показываем имя узла в пространстве имён UTS предка. Оно будет

       отличаться от имени узла в пространстве имён UTS потомка. */

    if (uname(&uts) == -1)

        errExit("uname");

    printf("uts.nodename in parent: %s\n", uts.nodename);

    if (waitpid(pid, NULL, 0) == -1)    /* Ждём потомка */

        errExit("waitpid");

    printf("child has terminated\n");

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
fork(2), futex(2), getpid(2), gettid(2), kcmp(2), set_thread_area(2), set_tid_address(2), setns(2), tkill(2), unshare(2), wait(2), capabilities(7), namespaces(7), pthreads(7)


close

title: close(2)

summary: закрывает файловый дескриптор

text:
# close(2)

## ИМЯ
close - закрывает файловый дескриптор

## ОБЗОР

```
#include <unistd.h>
```

```
int close(int fd);
```

## ОПИСАНИЕ
Функция close() закрывает файловый дескриптор, который после этого не ссылается ни на один и файл и может быть использован повторно. Все блокировки (см. fcntl(2)), связанные с соответствующим файлом и принадлежащие процессу, снимаются (независимо от того, какой файловый дескриптор был ли использован для установки блокировки).

Если fd является последней копией какого-либо файлового дескриптора, ссылающегося на используемое описание открытого файла, (см. open(2)), то ресурсы, связанные с описанием открытого файла, освобождаются; если файловый дескриптор был последней ссылкой на файл, удалённый с помощью unlink(2), то файл окончательно удаляется.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении функции close() возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EBADF

Значение fd не является допустимым открытым файловым дескриптором.

EINTR

Вызов close() был прерван по сигналу; см. signal(7).

EIO

Произошла ошибка ввода-вывода.

ENOSPC, EDQUOT

Для NFS об этих ошибках, обычно, не сообщается при первой записи, которая превысила доступное пространство памяти, а только в последующем write(), fsync(2) или close().

Смотрите в ЗАМЕЧАНИЯХ почему close() нельзя вызывать снова после ошибки.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.

## ЗАМЕЧАНИЯ
Выполнение закрытия без ошибок не гарантирует, что данные были успешно записаны на диск, так как в ядре используется буферный кэш для отложенных записей. Как правило, файловые системы не записывают буферы при закрытии файла. Если требуется гарантировать физическую запись на используемый диск, то можно использовать fsync(2) (дальше всё будет зависеть от аппаратной составляющей диска).

Флаг файлового дескриптора закрытие-при-exec можно использовать для гарантии того, что файловый дескриптор автоматически закроется при успешном выполнении execve(2); подробности смотрите в fcntl(2).

Вероятно неблагоразумно закрывать дескрипторы файла, в то время как они могут использоваться системными вызовами других нитей того же процесса. Так как файловый дескриптор может использоваться повторно, есть некоторые неясные условия возникновения гонок, которые могут вызвать непреднамеренные побочные эффекты.

### Обработка ошибки, возвращённой close()
Аккуратный программист всегда проверяет возвращаемое close() значение, так как очень вероятно, что об ошибках предыдущей операции write(2) будет сообщено только при последнем вызове close(), который освобождает описание открытого файла. Невыполнение проверки возвращаемого значение при закрытии файла может привести к неучтённой потере данных. Это особенно часто встречается с NFS и дисковыми квотами.

Однако заметим, что возвращаемая ошибка должна использоваться только для диагностики (т. е., предупредить приложение, что, возможно, есть незаконченные операции ввода-вывода или произошла ошибка ввода-вывода) или исправления (например, повторной записи файла или создания резервной копии).

Повторный вызов close() после получения ошибки делать не стоит, так как это может привести к закрытию повторно использованного файлового дескриптора другой нити. Это может произойти из-за того, что ядро Linux всегда освобождает файловый дескриптор в самом начале операции закрытия, делая его доступным для повторного использования; шаги, которые могут вернуть ошибку, такие как сброс данных в файловую систему или устройство, происходят только после операции закрытия.

Многие другие реализации поступают схожим образом и всегда закрывают файловый дескриптор (за исключением случая EBADF, означающего некорректный файловый дескриптор) даже, если они затем возвратят ошибку close(). В POSIX.1 ничего не сказано на этот счёт, но есть планы узаконить такое поведение в следующем выпуске стандарта.

Аккуратный программист, который хочет узнать об ошибках ввода-вывода, перед close() вызовет fsync(2).

Ошибка EINTR является особым случаем. Про EINTR в POSIX.1-2013 сказано:

Если close() прерван сигналом, который будет обработан, то вызов должен вернуть -1, а errno присвоить значение EINTR; при этом состояние fildes не определено.

Этим допускается режим работы, действующий в Linux и многих других реализациях, где как и при других ошибках, которые может вернуть close(), файловый дескриптор гарантированно закрывается. Однако, это также допускает и другой режим: реализация возвращает ошибку EINTR и оставляет файловый дескриптор открытым (согласно документации, так делает close() в HP-UX). Вызывающий должен позднее ещё раз вызвать close() для закрытия файлового дескриптора, чтобы не допустить утечек файловых дескрипторов. Такое расхождение в поведении реализаций является сложным препятствием для переносимых приложений, так как во многих реализациях close() не должен вызываться ещё раз после получения ошибки EINTR и, по крайней мере, в одной close() нужно вызвать снова. Есть планы разгадать эту загадку в следующей большой версии стандарта POSIX.1.

## СМОТРИТЕ ТАКЖЕ
fcntl(2), fsync(2), open(2), shutdown(2), unlink(2), fclose(3)


connect

title: connect(2)

summary: инициирует соединение на сокете

text:
# connect(2)

## ИМЯ
connect - инициирует соединение на сокете

## ОБЗОР

```
#include <sys/types.h>          /* Смотрите ЗАМЕЧАНИЯ */

#include <sys/socket.h>
```

```
int connect(int sockfd, const struct sockaddr *addr,
            socklen_t addrlen);
```

## ОПИСАНИЕ
Системный вызов connect() устанавливает соединение с сокетом, заданным файловый дескриптором sockfd, ссылающимся на адрес addr. Аргумент addrlen определяет размер addr. Формат адреса в addr определяется адресным пространством сокета sockfd; подробнее можно узнать в socket(2).

Если сокет sockfd имеет тип SOCK_DGRAM, то адрес addr является адресом по умолчанию, куда посылаются датаграммы, и единственным адресом, откуда они принимаются. Если сокет имеет тип SOCK_STREAM или SOCK_SEQPACKET, то данный системный вызов попытается установить соединение с другим сокетом, заданным параметром addr.

Обычно сокеты с протоколами, основанными на соединении, могут устанавливать соединение connect() только один раз; сокеты с протоколами без установления соединения могут использовать connect() многократно, чтобы изменить адрес назначения. Сокеты без установления соединения могут прекратить связь с другим сокетом, установив член sa_family структуры sockaddr в AF_UNSPEC (в Linux поддерживается, начиная с ядра версии 2.2).

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Если соединение или привязка прошла успешно, возвращается ноль. При ошибке возвращается -1, а errno устанавливается должным образом.

## ОШИБКИ
Ниже приведены только общие ошибки сокетов. Могут также появляться коды ошибок, существующие в конкретном домене.

EACCES

Для доменных сокетов UNIX, которые идентифицируются по имени пути: нет прав на запись в файл сокета, или в одном из каталогов пути запрещён поиск. (См. также path_resolution(7).)

EACCES, EPERM

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

EADDRINUSE

Локальный адрес уже используется.

EADDRNOTAVAIL

(доменные сокеты Интернета) Сокет, указанный sockfd, ранее не был привязан к адресу и при попытке привязать его к эфемеридному порту, было определено, что все номера в диапазоне эфемеридных портов уже используются. Смотрите обсуждение /proc/sys/net/ipv4/ip_local_port_range в ip(7).

EAFNOSUPPORT

Адрес имеет некорректное семейство адресов в поле sa_family.

EAGAIN

Для неблокирующих доменных сокетов UNIX сокет не блокируется и соединение не может быть выполнено немедленно. Для других семейств сокетов в кэше маршрутизации недостаточно элементов.

EALREADY

Сокет является неблокирующим, а предыдущая попытка установить соединение ещё не завершилась.

EBADF

Значение sockfd не является правильным открытым файловым дескриптором.

ECONNREFUSED

Вызов connect() не нашёл слушающий удалённый адрес для потокового сокета.

EFAULT

Адрес структуры сокета находится за пределами пользовательского адресного пространства.

EINPROGRESS

Сокет является неблокирующим, а соединение не может быть установлено немедленно (доменные сокеты UNIX вместо этого возвращают ошибку EAGAIN). Можно использовать select(2) или poll(2), чтобы закончить соединение, установив ожидание возможности записи в сокет. После того, как select(2) сообщит о такой возможности, используйте getsockopt(2), чтобы прочитать флаг SO_ERROR на уровне SOL_SOCKET, чтобы определить, успешно ли завершился connect() (в этом случае SO_ERROR равен нулю) или неудачно (тогда SO_ERROR равен одному из обычных кодов ошибок, перечисленных здесь, и объясняет причину неудачи).

EINTR

Системный вызов был прерван пойманным сигналом; см. signal(7).

EISCONN

Соединение на сокете уже произошло.

ENETUNREACH

Сеть недоступна.

ENOTSOCK

Файловый дескриптор sockfd указывает не на каталог.

EPROTOTYPE

Тип сокета не поддерживается запрошенным протоколом связи. Это ошибка может возникать при попытке подключить доменный датаграммный сокет UNIX к потоковому сокету.

ETIMEDOUT

Произошел тайм-аут во время ожидания соединения. Сервер, возможно, очень занят и не может принимать новые соединения. Заметьте, что для IP-сокетов тайм-аут может быть очень длинным, если на сервере разрешено использование syncookies.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD, (connect() впервые появился 4.2BSD).

## ЗАМЕЧАНИЯ
В POSIX.1 не требуется включение <sys/types.h>, и этот заголовочный файл не требуется в Linux. Однако, для некоторых старых реализаций (BSD) требует данный файл, и в переносимых приложениях для предосторожности, вероятно, лучше его указать.

Описание типа socklen_t смотрите в accept(2).

Если вызов connect() завершается с ошибкой, то состояние сокета считается неопределённым. Переносимые приложения должны закрывать сокет и для переподключения создавать новый.

## ПРИМЕР
Пример использования connect() показан в getaddrinfo(3).

## СМОТРИТЕ ТАКЖЕ
accept(2), bind(2), getsockname(2), listen(2), socket(2), path_resolution(7)


title: copy_file_range(2)

text:
# copy_file_range(2)

## ИМЯ
copy_file_range - копирует часть данных из одного файла в другой

## ОБЗОР

```
#define _GNU_SOURCE
#include <unistd.h>
```

```
ssize_t copy_file_range(int fd_in, loff_t *off_in,
                        int fd_out, loff_t *off_out,
                        size_t len, unsigned int flags);
```

## ОПИСАНИЕ
Системный вызов copy_file_range() выполняет внутриядерное копирование между двумя файловыми дескрипторами без дополнительных накладных расходов по передаче данных из ядра в пользовательское пространство и затем обратно в ядро. Он копирует до len байт данных из файлового дескриптора fd_in источника в файловый дескриптор fd_out приёмника, перезаписывая существующие данные внутри запрашиваемой области файла назначения.

Следующая семантика применяется к off_in и подобная ей к off_out:

- Если off_in равно NULL, то байты читаются из fd_in начиная с файлового смещения, а файловое смещение корректируется на количество скопированных байт.

- Если off_in не равно NULL, то off_in должно указывать на буфер, задающий начальное смещение в fd_in, из которого будут читаться байты. Файловое смещение fd_in не изменяется, но off_in изменяется соответствующим образом.

Значения fd_in и fd_out могут ссылаться на один и тот же файл. Если это так, то диапазонам источника и приёмника нельзя перекрываться.

Аргумент flags предназначен для будущих расширений, а пока его значение должно быть равно 0.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении copy_file_range() возвращает количество скопированных между файлами байт. Оно может быть меньше запрашиваемой длины. Если файловое смещение fd_in в конце или за концом файла, то байты не копирются и copy_file_range() возвращает ноль.

В случае ошибки copy_file_range() возвращает -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EBADF

Один или оба файловых дескриптора недействительны.

EBADF

Дескриптор fd_in не открыт на чтение или дескриптор fd_out не открыт на запись.

EBADF

В открытом файловом описании, на которое ссылается файловый дескриптор fd_out, установлен флаг O_APPEND (смотрите open(2)).

EFBIG

Попытка записать в позицию вне максимально поддерживаемого ядром файлового смещения.

EFBIG

Попытка записи диапазона, который превышает разрешённый максимальный размер файла. Максимальный размер файла различается в реализациях файловых систем и может отличаться от разрешённого максимального файлового смещения.

EFBIG

Попытка записи, выходящее за ограничение ресурса процесса на размер файла. Также это может вызвать получение процессом сигнала SIGXFSZ.

EINVAL

Аргумент flags не равен 0.

EINVAL

Значения fd_in и fd_out ссылаются на один и тот же файл и диапазоны источника и приёмника перекрываются.

EINVAL

Значение fd_in или fd_out указывает на необычный файл.

EIO

Во время копирования возникла низкоуровневая ошибка ввода-вывода.

EISDIR

Значение fd_in или fd_out указывает на каталог.

ENOMEM

Не хватает памяти.

ENOSPC

Недостаточно места на файловой системе назначения для завершения копирования.

EOVERFLOW

Запрошенный диапазон источника и приёмника слишком большой для представления в указанном типе данных.

EPERM

Значение fd_out ссылается на файл с постоянными данными (immutable).

TXTBSY

Значение fd_in или fd_out указывает на активный файл подкачки.

EXDEV

Файлы, на которые ссылаются file_in и file_out, находятся не в одной смонтированной файловой системе (до Linux 5.3).

## ВЕРСИИ
Системный вызов copy_file_range() впервые появился в Linux 4.5, но если он недоступен, в glibc 2.27 предоставляется эмуляция в пользовательском пространстве.

В ядре версии 5.3 произошли значительные перемены. Уточнены области API, которые были нечётно определены, и границы API теперь строже проверяются, по сравнению с ранними ядрами. Приложения должны следовать поведению и требованиям ядер 5.3.

В Linux 5.3 появилась поддержка копирования между файловыми системами. В старых ядрах при попытках копирования между файловыми системами возвращается ошибка -EXDEV.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Системный вызов copy_file_range() является нестандартным расширением Linux и GNU.

## ЗАМЕЧАНИЯ
Если файл file_in является разреженным (sparse), то copy_file_range() может расширить дыры, существующие в запрашиваемой области. Пользователи могут получить преимущество от вызова copy_file_range() в цикле, и используя операции lseek(2) SEEK_DATA и SEEK_HOLE для поиска расположений сегментов данных.

Вызов copy_file_range() даёт файловым системам возможность реализовать «ускорение копирования», например, использовать ссылочные связи (т. е., две или более инод, использующих общие указатели для одного копирования-при-записи дисковых блоков) или копирование-на-сервере (server-side-copy, в случае использования NFS).

## ПРИМЕР

```
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
/ * В версиях glibc до 2.27, мы должны ссылаться на copy_file_range ()

 используя syscall(2) * /
static loff_t
copy_file_range(int fd_in, loff_t *off_in, int fd_out,

                loff_t *off_out, size_t len, unsigned int flags)
{

    return syscall(__NR_copy_file_range, fd_in, off_in, fd_out,

                   off_out, len, flags);
}
int
main(int argc, char **argv)
{

    int fd_in, fd_out;

    struct stat stat;

    loff_t len, ret;

    if (argc != 3) {

        fprintf(stderr, "Использование: %s <источник> <приёмник>\n", argv[0]);

        exit(EXIT_FAILURE);

    }

    fd_in = open(argv[1], O_RDONLY);

    if (fd_in == -1) {

        perror("открытие (argv[1])");

        exit(EXIT_FAILURE);

    }

    if (fstat(fd_in, &stat) == -1) {

        perror("fstat");

        exit(EXIT_FAILURE);

    }

    len = stat.st_size;

    fd_out = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0644);

    if (fd_out == -1) {

        perror("открытие (argv[2])");

        exit(EXIT_FAILURE);

    }

    do {

        ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0);

        if (ret == -1) {

            perror("copy_file_range");

            exit(EXIT_FAILURE);

        }

        len -= ret;

    } while (len > 0 && ret > 0);

    close(fd_in);

    close(fd_out);

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
lseek(2), sendfile(2), splice(2)


title: create_module(2)

summary: создать элемент загружаемого модуля

text:
# create_module(2)

## ИМЯ
create_module - создать элемент загружаемого модуля

## ОБЗОР

```
#include <linux/module.h>
```

```
caddr_t create_module(const char *name, size_t size);
```

Замечание: В заголовочных файлах glibc этой системный вызов отсутствует; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Замечание: Данный системный вызов доступен только в ядрах до Linux 2.6.

create_module() пытается создать элемент загружаемого модуля и зарезервировать память ядра, которая необходима для хранения модуля. Данный системный вызов требует особых прав.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается адрес в ядре, где будет располагаться модуль. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EEXIST

Модуль с таким именем уже существует.

EFAULT

name вне доступного программного адресного пространства.

EINVAL

Запрашиваемый размер мал даже для информационного заголовка модуля.

ENOMEM

Ядро не может выделить непрерывный блок памяти, необходимый для модуля.

ENOSYS

create_module() не поддерживается в этой версии ядра (например, в 2.6 или более поздних).

EPERM

Вызывающий не имеет прав (не имеет мандата CAP_SYS_MODULE).

## ВЕРСИИ
Данный системный вызов есть только в Linux до версии 2.4; он был удалён в Linux 2.6.

## СООТВЕТСТВИЕ СТАНДАРТАМ
create_module() есть только в Linux.

## ЗАМЕЧАНИЯ
Устаревший системный вызов, не поддерживается glibc. В заголовочных файлах glibc он не объявлен, но в недавнем прошлом версии glibc до 2.23 экспортировали ABI для этого системного вызова. Поэтому, чтобы получить данный системный вызов достаточно вручную объявить интерфейс в своём коде; или же можно вызвать его через syscall(2).

## СМОТРИТЕ ТАКЖЕ
delete_module(2), init_module(2), query_module(2)


title: delete_module(2)

summary: выгружает модуль ядра

text:
# delete_module(2)

## ИМЯ
delete_module - выгружает модуль ядра

## ОБЗОР

```
int delete_module(const char *name, int flags);
```

Замечание: В заголовочных файлах glibc этой системный вызов отсутствует; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Вызов delete_module() пытается удалить неиспользуемый загруженный модуль с именем name. Если у модуля есть функция exit, то она выполняется перед выгрузкой. Аргумент flags используется для изменения поведения системного вызова — это описано далее. Данный системный вызов требует особых прав.

Удаление модуля выполняется по следующим правилам:

1.

Если какой-то другой модуль зависит от выгружаемого (т.е., использует его символы), то вызов завершается с ошибкой.

2.

В противном случае, если счётчик ссылок на модуль (т.е. количество процессов, использующих модуль в данный момент) равно нулю, то модуль немедленно выгружается.

3.

Если у модуля ненулевой счётчик ссылок, то поведение зависит от битов, установленных в flags. Обычно (смотрите ЗАМЕЧАНИЯ) всегда указывается флаг O_NONBLOCK, а иногда добавляется O_TRUNC.

Различные комбинации значений в flags дают разный эффект:

flags == O_NONBLOCK

Вызов сразу завершается с ошибкой.

flags == (O_NONBLOCK | O_TRUNC)

Модуль немедленно выгружается, независимо от того, равен счётчик ссылок 0 или нет.

(flags & O_NONBLOCK) == 0

Если в flags не указан O_NONBLOCK, то выполняются следующие шаги:

- Модуль помечается, что больше ссылаться на него запрещается.

- Если счётчик ссылок модуля не равен нулю, то вызывающий переходит в непрерываемое состояние сна (TASK_UNINTERRUPTIBLE) до тех пор, пока счётчик ссылок не станет равным 0 — в этот момент вызов разблокируется.

- Модуль выгружается как обычно.

Флаг O_TRUNC имеет ещё один эффект на правила, описанные выше. По умолчанию, если модуль имеет функцию init, но не имеет функции exit, то попытка удаления модуля завершается с ошибкой. Однако, если указан O_TRUNC, то это требование не учитывается.

Использовать флаг O_TRUNC опасно! Если ядро не собрано с параметром CONFIG_MODULE_FORCE_UNLOAD, то этот флаг просто игнорируется (обычно параметр CONFIG_MODULE_FORCE_UNLOAD включают). Использование этого флага приводит к примешиванию (taints) в ядре (TAINT_FORCED_RMMOD).

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается ноль. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EBUSY

Модуль не «живой» (т.е., он всё ещё инициализируется или уже помечен для удаления); или модуль имеет функцию init, но не имеет функции exit и в flags не указан флаг O_TRUNC.

EFAULT

Значение name указывает на расположение вне доступного адресного пространства процесса.

ENOENT

Модуль с таким именем не существует.

EPERM

Вызывающий не имеет прав (не имеет мандата CAP_SYS_MODULE), или отключена выгрузка модулей (смотрите /proc/sys/kernel/modules_disabled в proc(5)).

EWOULDBLOCK

Другие модули зависят от этого модуля; или в flags указан флаг O_NONBLOCK, но счётчик ссылок модуля не равен 0 и в flags не указан флаг O_TRUNC.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Вызов delete_module() есть только в Linux.

## ЗАМЕЧАНИЯ
Системный вызов delete_module() не поддерживается glibc. В заголовочных файлах glibc он не объявлен, но в недавнем прошлом glibc до версии 2.23 экспортировал ABI для этого системного вызова. Поэтому чтобы получить данный системный вызов достаточно вручную объявить интерфейс в своём коде; или же вы можете вызвать его через syscall(2).

Непрерываемый сон, который может начаться, если в flags не указан флаг O_NONBLOCK, считается нежелательным, так как спящий процесс находится в неубиваемом состоянии. В Linux 3.7 указание O_NONBLOCK необязательно, но в будущих ядрах, он, вероятно, станет обязательным.

### Linux версии 2.4 и более ранние
В Linux версии 2.4 и более ранних системный вызов принимал один аргумент:

int delete_module(const char *name);

Если значение name равно NULL, то все неиспользуемые модули, помеченные для автоматической вычистки, удаляются.

Есть и некоторые другие отличия в поведении delete_module() в Linux 2.4 и более ранних, но они пока не описаны в этой справочной странице.

## СМОТРИТЕ ТАКЖЕ
create_module(2), init_module(2), query_module(2), lsmod(8), modprobe(8), rmmod(8)


dup

title: dup(2)

summary: создать дубликат файлового дескриптора

text:
# dup(2)

## ИМЯ
dup, dup2, dup3 - создать дубликат файлового дескриптора

## ОБЗОР

```
#include <unistd.h>
```

```
int dup(int oldfd);
int dup2(int oldfd, int newfd);
#define _GNU_SOURCE             /* Смотрите feature_test_macros(7) */
#include <fcntl.h>              /* Определение констант O_* */
#include <unistd.h>
```

```
int dup3(int oldfd, int newfd, int flags);
```

## ОПИСАНИЕ
Системный вызов dup() создаёт копию файлового дескриптора oldfd, используя для нового дескриптора самый маленький свободный номер файлового дескриптора.

После успешного выполнения старый и новый файловые дескрипторы являются взаимозаменяемыми. Они указывают на одно и то же открытое файловое описание (смотрите open(2)) и поэтому имеют общее файловое смещение и флаги состояния файла; например, если файловое смещение изменить с помощью lseek(2) через один из файловых дескрипторов, то смещение изменится и для другого.

Эти два файловых дескриптора имеют различные флаги дескриптора файла (флаг close-on-exec). Флаг close-on-exec (FD_CLOEXEC; см. fcntl(2)) у копии дескриптора сбрасывается.

### dup2()
Системный вызов dup2() выполняет ту же задачу, что и dup(), но вместо использования самого маленького неиспользуемого номера файлового дескриптора, он использует номер файлового дескриптора, указанного в newfd. Если файловый дескриптор newfd уже открыт, то он закрывается перед повторным использованием.

Шаги по закрытию и повторному использованию файлового дескриптора newfd выполняются атомарно. Это важно, так как попытка реализовать подобное с помощью close(2) и dup() привело бы к состязательности, в силу чего newfd мог быть задействован повторно между этими двумя шагами. Такое повторное использование может произойти, из-за прерывания основной программы обработчиком сигналов, который выделяет файловый дескриптор, или из-за параллельной нити, выделяющей файловый дескриптор.

Также заметим следующее:

- Если oldfd является некорректным файловым дескриптором, то вызов завершается с ошибкой, а newfd не закрывается.

- Если oldfd является корректным файловым дескриптором, а номер newfd совпадает с oldfd, то dup2() не делает ничего и возвращает значение newfd.

### dup3()
dup3() похож на dup2(). Отличия заключаются в следующем:

- Вызывающий может принудительно установить флаг close-on-exec flag у нового файлового дескриптора, указав O_CLOEXEC в flags. Зачем это может быть нужно смотрите в open(2).

- Если oldfd равно newfd, то dup3() выдает ошибку EINVAL.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
В случае успеха данные системные вызовы возвращают новый файловый дескриптор или -1, если произошла ошибка (в этом случае errno устанавливается должным образом).

## ОШИБКИ
EBADF

Значение oldfd не является открытым файловым дескриптором.

EBADF

Значение newfd находится вне допустимого диапазона файловых дескрипторов (смотрите описание RLIMIT_NOFILE в getrlimit(2)).

EBUSY

(только в Linux) Может случиться в dup2() или dup3() при возникновении состязательности вызовов open(2) и dup().

EINTR

Вызов dup2() или dup3() был прерван каким-либо сигналом. Смотрите signal(7).

EINVAL

(dup3()) flags содержит некорректное значение.

EINVAL

(dup3()) oldfd было равно newfd.

EMFILE

Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс (смотрите описание RLIMIT_NOFILE в getrlimit(2)).

## ВЕРСИИ
Вызов dup3() был добавлен в Linux версии 2.6.27; поддержка в glibc доступна с версии 2.9.

## СООТВЕТСТВИЕ СТАНДАРТАМ
dup(), dup2(): POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.

dup3() есть только в Linux.

## ЗАМЕЧАНИЯ
Ошибка, которую возвращает dup2(), отличается от той, что возвращает fcntl(…, F_DUPFD, …), когда newfd находится вне допустимых пределов. На некоторых системах dup2() также иногда возвращает EINVAL — как F_DUPFD.

Если был открыт newfd, то любые ошибки, о которых было бы сообщено close(2), теряются. Если это важно, то (если программа однонитевая и не выделяет файловые дескрипторы в обработчиках сигналов) правильней будет не закрывать newfd перед вызовом dup2(), из-за состязательности, описанной выше. Вместо этого можно использовать, например, такой код:

```
    /* Получить копию «newfd», которую затем можно

       использовать для проверки ошибок close(); ошибка EBADF

       означает, что «newfd» не открыт. */

    tmpfd = dup(newfd);

    if (tmpfd == -1 && errno != EBADF) {

        /* обработка неожидаемой ошибки dup() */

    }

    /* атомарное копирование «oldfd» в «newfd» */

    if (dup2(oldfd, newfd) == -1) {

        /* обработка ошибки dup2() */

    }

    /* теперь проверим ошибки close() у файла, на который изначально

       ссылался «newfd» */

    if (tmpfd != -1) {

        if (close(tmpfd) == -1) {

            /* обработка ошибок закрытия */

        }

    }
```

## СМОТРИТЕ ТАКЖЕ
close(2), fcntl(2), open(2)