title: timerfd_create(2)

summary: таймеры, уведомляющие

text:
# timerfd_create(2)

## ИМЯ
timerfd_create, timerfd_settime, timerfd_gettime - таймеры, уведомляющие через файловые дескрипторы

## ОБЗОР

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

```
int timerfd_create(int clockid, int flags);
```

```
int timerfd_settime(int fd, int flags,
                    const struct itimerspec *new_value,
                    struct itimerspec *old_value);
```

```
int timerfd_gettime(int fd, struct itimerspec *curr_value);
```

## ОПИСАНИЕ
Эти системные вызовы создают и работают с таймером, доставляя уведомления о срабатывании через файловый дескриптор. Они предоставляют альтернативу setitimer(2) или timer_create(2); их преимущество в том, что за файловым дескриптором можно следить с помощью select(2), poll(2) и epoll(7).

Использование данных трёх системных вызовов аналогично timer_create(2), timer_settime(2) и timer_gettime(2) (аналога timer_getoverrun(2) нет, так как его возможности предоставляет read(2) как описано ниже).

### timerfd_create()
Вызов timerfd_create() создаёт новый объект таймера и возвращает файловый дескриптор, который ссылается на этот таймер. В аргументе clockid задаются часы, которые используются для хода таймера; значением должно быть одно из следующих:

CLOCK_REALTIME

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

CLOCK_MONOTONIC

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

CLOCK_BOOTTIME (начиная с Linux 3.15)

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

CLOCK_REALTIME_ALARM (начиная с Linux 3.11)

Эти часы подобны CLOCK_REALTIME, но разбудят систему, если она находится с состоянии ожидания. Для установки таймера по этим часам вызывающий должен иметь мандат CAP_WAKE_ALARM.

CLOCK_BOOTTIME_ALARM (начиная с Linux 3.11)

Эти часы подобны CLOCK_BOOTTIME, но разбудят систему, если она находится с состоянии ожидания. Для установки таймера по этим часам вызывающий должен иметь мандат CAP_WAKE_ALARM.

Текущее значение каждого из этих часов можно получить с помощью clock_gettime(2).

Начиная с Linux 2.6.27, для изменения поведения timerfd_create() можно использовать следующие значения flags (через OR):

TFD_NONBLOCK

Устанавливает флаг состояния файла O_NONBLOCK для нового открытого файлового описания (смотрите open(2)), на которое ссылается новый файловый дескриптор. Использование данного флага делает ненужными дополнительные вызовы fcntl(2) для достижения того же результата.

TFD_CLOEXEC

Устанавливает флаг close-on-exec (FD_CLOEXEC) для нового открытого файлового дескриптора. Смотрите описание флага O_CLOEXEC в open(2) для того, чтобы узнать как это может пригодиться.

До Linux 2.6.26 включительно аргумент flags должен быть равен нулю.

### timerfd_settime()
Вызов timerfd_settime() запускает или останавливает таймер, на который ссылается файловый дескриптор fd.

В аргументе new_value задаётся начальное срабатывание и интервал таймера. Для этого аргумента используется структура itimerspec, содержащая два поля, каждое из которых, в свою очередь, является структурой timespec:

```
struct timespec {

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

    long   tv_nsec;               /* наносекунды */
};
struct itimerspec {

    struct timespec it_interval;  /* интервал для периодического

                                     таймера */

    struct timespec it_value;     /* первое срабатывание */
};
```

В new_value.it_value задаётся первое срабатывание таймера, в секундах и наносекундах. Установка любого из полей new_value.it_value в ненулевое значение включает таймер. Установка обоих полей new_value.it_value в ноль выключает таймер.

Установка одного или обоих полей new_value.it_interval в ненулевое значение задаёт период, в секундах и наносекундах, периодического срабатывания таймера после первого срабатывания. Если оба поля new_value.it_interval равны нулю, то таймер срабатывает только один раз, во время, указанное в new_value.it_value.

По умолчанию, начальное время срабатывания, задаваемое в new_value, считается относительно текущего времени часов таймера на момент вызова (т. е., в new_value.it_value задаётся время относительно текущего значения часов, заданных в clockid). Использование абсолютной задержки можно включить через аргумент flags.

Аргумент flags является битовой маской, которая может включать следующие значения:

TFD_TIMER_ABSTIME

Считать new_value.it_value абсолютным значением часов таймера. Таймер сработает, когда значение часов таймера достигнет значения, указанного в new_value.it_value.

TFD_TIMER_CANCEL_ON_SET

Если этот флаг указан вместе с TFD_TIMER_ABSTIME и часами этого таймера являются CLOCK_REALTIME или CLOCK_REALTIME_ALARM, то помечать этот таймер как отменяемый, если часы реального времени подвергнуться скачкообразному изменению (settimeofday(2), clock_settime(2) или подобными). Когда такие изменения происходят, текущий или будущий вызова read(2) для файлового дескриптора завершается с ошибкой ECANCELED.

Если old_value не равно NULL, то это указатель на структуру itimerspec, и он будет использоваться для возврата текущих на момент вызова настроек таймера; смотрите описание timerfd_gettime() далее.

### timerfd_gettime()
Вызов timerfd_gettime() возвращает в curr_value, которое указывает на структуру itimerspec, текущие настройки таймера, на который ссылается файловый дескриптор fd.

В поле it_value возвращается время до следующего срабатывания таймера. Если оба поля этой структуры равны нулю, то таймер в данный момент не запущен. Это поле всегда содержит относительное значение, независимо от того, был ли указан флаг TFD_TIMER_ABSTIME при настройке таймера.

В поле it_interval возвращается интервал таймера. Если оба поля этой структуры равны нулю, то таймер настроен на однократное срабатывание, на время, заданное в curr_value.it_value.

### Работа с файловым дескриптором таймера
Файловый дескриптор, возвращаемый timerfd_create(), поддерживает следующие операции:

read(2)

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

Если таймер ещё не срабатывал до вызова read(2), то вызов блокирует выполнение до следующего срабатывания таймера, или завершается с ошибкой EAGAIN, если файловый дескриптор был создан неблокирующим (с помощью вызова fcntl(2) и операции F_SETFL с флагом O_NONBLOCK).

Вызов read(2) завершается ошибкой EINVAL, если размер указанного буфера будет меньше 8 байт.

Если используются часы CLOCK_REALTIME или CLOCK_REALTIME_ALARM, таймер является абсолютным (TFD_TIMER_ABSTIME) и при вызове timerfd_settime() указан флаг TFD_TIMER_CANCEL_ON_SET, то read(2) завершается ошибкой ECANCELED, если часы реального времени подвергнуться скачкообразному изменению (это позволяет читающему приложению обнаружить такие скачкообразные изменения часов).

poll(2), select(2) (и подобные)

Файловый дескриптор доступен для чтения (в select(2) аргумент readfds; в poll(2) флаг POLLIN), если произошло одно или более срабатываний таймера.

Файловый дескриптор также поддерживает другие мультиплексные вызовы: pselect(2), ppoll(2) и epoll(7).

ioctl(2)

Поддерживается следующая команда, относящаяся к timerfd:

TFD_IOC_SET_TICKS (начиная с Linux 3.17)

Корректирует количество истечений таймера, которые произошли. Аргументом является указатель на ненулевое 8-байтовое целое (uint64_t*), содержащее новое количество истечений. После установки количества, все ожидающие таймера пробуждаются. Единственная цель данной команды — восстановить истечений для отсечки/восстановления. Данная операция доступна только, если ядро собрано с параметром CONFIG_CHECKPOINT_RESTORE.

close(2)

Если файловый дескриптор больше не требуется, его нужно закрыть. Когда все файловые дескрипторы, связанные с одним объектом таймера, будут закрыты, таймер выключается и ядро освобождает его ресурсы.

### Поведение при fork(2)
После fork(2) потомки наследуют копию файлового дескриптора, созданного timerfd_create(). Файловый дескриптор потомка ссылается на тот же объект таймера, что и файловый дескриптор его родителя, и операция read(2) в потомке будет возвращать информацию о срабатываниях таймера.

### Поведение при execve(2)
Файловый дескриптор, созданный timerfd_create(), сохраняется при execve(2), и продолжает генерировать срабатывания таймера, если он включён.

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

При успешном выполнении timerfd_settime() и timerfd_gettime() возвращают 0; в случае ошибки возвращается -1, а errno устанавливается в соответствующее значение ошибки.

## ОШИБКИ
Вызов timerfd_create() может завершиться со следующими ошибками:

EINVAL

Аргумент clockid не равен CLOCK_MONOTONIC или CLOCK_REALTIME;

EINVAL

Неправильное значение flags или, для Linux 2.6.26 и старее, flags не равно 0.

EMFILE

Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс.

ENFILE

Достигнуто максимальное количество открытых файлов в системе.

ENODEV

Не удалось смонтировать (внутреннее) безымянное устройство inode.

ENOMEM

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

Вызовы timerfd_settime() и timerfd_gettime() могут завершаться со следующими ошибками:

EBADF

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

EFAULT

Указатели new_value, old_value или curr_value являются некорректными.

EINVAL

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

Вызов timerfd_settime() также может завершиться со следующими ошибками:

EINVAL

Значение new_value некорректно инициализировано (одно из tv_nsec вне диапазона от 0 до 999999999).

EINVAL

Значение flags неверно.

## ВЕРСИИ
Данные системные вызовы доступны в Linux начиная с ядра версии 2.6.25. Поддержка в библиотеке glibc появилась в версии 2.8.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данные системные вызовы есть только в Linux.

## ДЕФЕКТЫ
В настоящее время timerfd_create() поддерживает только несколько типов идентификаторов часов, поддерживаемых timer_create(2).

## ПРИМЕР
Следующая программа создаёт таймер и затем следит за его работой. Программа получает до трёх аргументов из командной строки. В первом аргументе задаётся количество секунд до первого срабатывания таймера. Во втором аргументе задаётся интервал таймера в секундах. В третьем аргументе задаётся сколько программа должна позволить сработать таймеру до завершения. Второй и третий аргументы необязательны.

Следующий сеанс работы в оболочке показывает использование программы:

```
$ a.out 3 1 100
0.000: таймер запущен
3.000: read: 1; всего=1
4.000: read: 1; всего=2
^Z                  # нажато control-Z для приостанова программы
[1]+  Stopped                 ./timerfd3_demo 3 1 100
$ fg                # возобновление выполнения после нескольких

                       #секунд
a.out 3 1 100
9.660: read: 5; всего=7
10.000: read: 1; всего=8
11.000: read: 1; всего=9
^C                  # нажато control-C для приостанова программы
```

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

```
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>        /* определение uint64_t */
#define handle_error(msg) \

        do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void
print_elapsed_time(void)
{

    static struct timespec start;

    struct timespec curr;

    static int first_call = 1;

    int secs, nsecs;

    if (first_call) {

        first_call = 0;

        if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)

            handle_error("clock_gettime");

    }

    if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)

        handle_error("clock_gettime");

    secs = curr.tv_sec - start.tv_sec;

    nsecs = curr.tv_nsec - start.tv_nsec;

    if (nsecs < 0) {

        secs--;

        nsecs += 1000000000;

    }

    printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}
int
main(int argc, char *argv[])
{

    struct itimerspec new_value;

    int max_exp, fd;

    struct timespec now;

    uint64_t exp, tot_exp;

    ssize_t s;

    if ((argc != 2) && (argc != 4)) {

        fprintf(stderr, "%s нач-сек [интервал макс-сраб]\n",

                argv[0]);

        exit(EXIT_FAILURE);

    }

    if (clock_gettime(CLOCK_REALTIME, &now) == -1)

        handle_error("clock_gettime");

    /* создаём абсолютный таймер CLOCK_REALTIME с начальным

       срабатыванием и интервалом, заданными из командной строки */

    new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);

    new_value.it_value.tv_nsec = now.tv_nsec;

    if (argc == 2) {

        new_value.it_interval.tv_sec = 0;

        max_exp = 1;

    } else {

        new_value.it_interval.tv_sec = atoi(argv[2]);

        max_exp = atoi(argv[3]);

    }

    new_value.it_interval.tv_nsec = 0;

    fd = timerfd_create(CLOCK_REALTIME, 0);

    if (fd == -1)

        handle_error("timerfd_create");

    if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)

        handle_error("timerfd_settime");

    print_elapsed_time();

    printf("таймер запущен\n");

    for (tot_exp = 0; tot_exp < max_exp;) {

        s = read(fd, &exp, sizeof(uint64_t));

        if (s != sizeof(uint64_t))

            handle_error("read");

        tot_exp += exp;

        print_elapsed_time();

        printf("read: %llu; всего=%llu\n",

                (unsigned long long) exp,

                (unsigned long long) tot_exp);

    }

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
eventfd(2), poll(2), read(2), select(2), setitimer(2), signalfd(2), timer_create(2), timer_gettime(2), timer_settime(2), epoll(7), time(7)


times

package: man-pages-ru

title: times(2)

summary: возвращает времена процесса

text:
# times(2)

## ИМЯ
times - возвращает времена процесса

## ОБЗОР
\#include <sys/times.h>

clock_t times(struct tms *buf);

## ОПИСАНИЕ
Вызов times() сохраняет текущие времена процесса в struct tms, на которую указывает buf. Определение struct tms содержится в <sys/times.h>:

```
struct tms {

    clock_t tms_utime;  /* пользовательское время */

    clock_t tms_stime;  /* системное время */

    clock_t tms_cutime; /* пользовательское время потомков */

    clock_t tms_cstime; /* системное время потомков */
};
```

В поле tms_utime содержится время ЦП, потраченное для выполнения инструкций вызвавшего процесса. В поле tms_stime содержится время ЦП, потраченное в ядре для выполнения задач вызвавшего процесса.

В поле tms_cutime содержится сумма значений tms_utime и tms_cutime всех ожидающих завершения потомков. В поле tms_cstime содержится сумма значений tms_stime и tms_cstime всех ожидающих завершения потомков.

Времена завершившихся потомков (и их потомков) добавляются в момент когда wait(2) или waitpid(2) возвращают их ID процесса. При этом, времена внуков, которых потомки не ждали, никогда не добавляются.

Все времена считаются в тиках часов.

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

## ОШИБКИ
EFAULT

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

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

## ЗАМЕЧАНИЯ
Количество тиков часов в секунду можно получить с помощью:

```
sysconf(_SC_CLK_TCK);
```

В POSIX.1-1996 символ CLK_TCK (определённый в <time.h>) упомянут как устаревающий. В настоящее время он точно устарел.

В ядрах Linux до версии 2.6.9, если обработчик SIGCHLD равен SIG_IGN, то времена завершившихся потомков автоматически включаются в поля tms_cstime и tms_cutime, хотя в POSIX.1-2001 сказано, что это должно происходить только, если вызвавший процесс вызывал wait(2) для своих потомков. Это несоответствие устранено в Linux 2.6.9 и более новых.

В Linux значение аргумента buf может быть равно NULL. В этом случае times() просто возвращает результат функции. Однако в POSIX не описано такое поведение, и для большинства других реализаций UNIX требуется не равное NULL значение buf.

Заметим, что clock(3) также возвращает значение типа clock_t, но это значение измеряется в единицах CLOCKS_PER_SEC, а не в тиках часов как у times().

«Произвольная точка в прошлом», от которой отсчитывается возвращаемое значение times(), измеряется в разных в версиях ядра Linux по-разному. В Linux 2.4 и старее этой точкой является момент загрузки системы. Начиная с Linux 2.6 эта точка равна (2^32/HZ) - 300 секунд до времени загрузки системы. Из-за переменчивости в разных версиях ядер (и в реализациях UNIX) и с учётом того, что возвращаемое значение может выйти за пределы диапазона clock_t, в переносимом приложении не следует использовать это значение. Для подсчёта прошедшего времени используйте clock_gettime(2).

### Историческая справка
В SVr1-3 результат имеет тип long и члены структуры имеют тип time_t, хотя они хранят тики часов, а не секунды начиная с Эпохи. В V7 используется long для членов структуры, так как тип time_t ещё не существовал.

## ДЕФЕКТЫ
Ограничение Linux в соглашениях системного вызова на некоторых архитектурах (в частности i386) приводит к тому, что в Linux 2.6 есть маленький временной интервал (41 секунда), в котором сразу после загрузки times() может вернуть -1, ложно указывая на существование ошибки. Такая же проблема может возникнуть, когда возвращаемое значение становится больше максимального значения типа clock_t.

## СМОТРИТЕ ТАКЖЕ
time(1), getrusage(2), wait(2), clock(3), sysconf(3), time(7)


tkill

title: tkill(2)

summary: посылает сигнал нити

text:
# tkill(2)

## ИМЯ
tkill, tgkill - посылает сигнал нити

## ОБЗОР

```
int tkill(int tid, int sig);
```

```
int tgkill(int tgid, int tid, int sig);
```

Замечание: В glibc нет обёрточной функции для tkill(); смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
tgkill() отправляет сигнал sig нити с ID tid в группе нитей tgid. Для сравнения, kill(2) может быть использована только для отправки сигнала процессу (т.е., группе нитей) как единому целому и сигнал будет доставлен произвольной нити внутри этого процесса.

Вызов tkill() — устаревший предшественник tgkill(). Он позволяет задавать только идентификатор нити-получателя, что может привести к уведомлению не той нити, если нить завершила работу и её идентификатор используется повторно. Не используйте данный системный вызов.

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

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

## ОШИБКИ
EAGAIN

Достигнут ограничитель ресурса RLIMIT_SIGPENDING и sig содержит сигнал реального времени.

EAGAIN

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

EINVAL

Указан некорректный идентификатор нити, группы или сигнал.

EPERM

Отказано в доступе. См. kill(2) для получения подробностей о необходимом доступе.

ESRCH

Не существует процесса с указанным идентификатором нити (и идентификатором группы).

## ВЕРСИИ
tkill() поддерживается начиная с Linux 2.4.19/2.5.4. tgkill() был добавлен в Linux 2.5.75.

Поддержка tgkill() добавлена в glibc версии 2.30.

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

## ЗАМЕЧАНИЯ
См. описание CLONE_THREAD в clone(2) для пояснения по поводу групп нитей.

В glibc нет обёртки для tkill(); запускайте его с помощью syscall(2). Также, до glibc 2.30 не было обёртки tgkill().

## СМОТРИТЕ ТАКЖЕ
clone(2), gettid(2), kill(2), rt_sigqueueinfo(2)


truncate

title: truncate(2)

summary: обрезает файл до заданного размера

text:
# truncate(2)

## ИМЯ
truncate, ftruncate - обрезает файл до заданного размера

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

\#include <sys/types.h>

int truncate(const char *path, off_t length);

int ftruncate(int fd, off_t length);

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

truncate():

_XOPEN_SOURCE >= 500

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

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

ftruncate():

_XOPEN_SOURCE >= 500

|| /* начиная с glibc 2.3.5: */ _POSIX_C_SOURCE >= 200112L

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

## ОПИСАНИЕ
Функции truncate() и ftruncate() обрезают обычный файл, указанный по имени path или ссылке fd, до размера, указанного в length (в байтах).

Если до этого файл был больше указанного размера, все лишние данные будут утеряны. Если файл был меньше, он будет увеличен, а дополнительная часть будет заполнена нулевыми байтами («\0»).

Смещение файла не изменяется.

Если размер изменился, поля st_ctime и st_mtime (время последнего изменения состояния и время последнего изменения, соответственно; смотрите inode(7)) файла будут обновлены, а биты режимов set-user-ID и set-group-ID могут быть сброшены.

Для ftruncate() файл должен быть открыт на запись; для truncate() файл должен быть доступен на запись.

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

## ОШИБКИ
Для truncate():

EACCES

В одном из каталогов префикса не разрешен поиск, либо указанный файл не доступен на запись для пользователя (смотрите также path_resolution(7)).

EFAULT

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

EFBIG

Аргумент length больше максимально допустимого размера файла (XSI).

EINTR

При блокирующем ожидании завершения вызов был прерван обработчиком сигналов; смотрите fcntl(2) и signal(7).

EINVAL

Аргумент length является отрицательным или больше максимально допустимого размера файла.

EIO

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

EISDIR

Указанный файл является каталогом.

ELOOP

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

ENAMETOOLONG

Компонент имени пути содержит более 255 символов, или весь путь содержит более 1023 символов.

ENOENT

Указанный файл не существует.

ENOTDIR

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

EPERM

Используемая файловая система не поддерживает расширение файла больше его текущего размера.

EPERM

Выполнение операции предотвращено опечатыванием (file seal); смотрите fcntl(2).

EROFS

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

ETXTBSY

Файл является исполняемым файлом, который в данный момент исполняется.

Для ftruncate() действуют те же ошибки, за исключением того, что вместо ошибок, связанных с неправильным path, появляются ошибки, связанные с файловым дескриптором fd:

EBADF

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

EBADF или EINVAL

Дескриптор fd не открыт для записи.

EINVAL

Дескриптор fd не указывает на обычный файл или объект общей памяти POSIX.

EINVAL или EBADF

Файловый дескриптор fd не открыт на запись. В POSIX это допускается и переносимые приложения должны обрабатывать любую ошибку для этого случая (Linux возвращает EINVAL).

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

## ЗАМЕЧАНИЯ
Вызов ftruncate() также может использоваться для установки размера объекта общей памяти POSIX; смотрите shm_open(7).

В ОПИСАНИИ приведена информация для XSI-совместимых систем. Для не XSI-совместимых систем в стандарте POSIX описано два поведения ftruncate(), когда length превышает длину файла (заметим, что truncate() не обязательно быть во всех таких окружениях): или вернуть ошибку, или расширить файл. Подобно большинству реализаций UNIX, Linux соответствует требованию XSI, когда работает с родными файловыми системами. Однако, в некоторых неродных файловых системах не разрешается использовать truncate() и ftruncate() для расширения файла больше его текущей длины: например, в Linux это касается VFAT.

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

На некоторых 32-битных архитектурах интерфейс этих системных вызовов отличается от описанного выше по причинам, указанным в syscall(2).

## ДЕФЕКТЫ
Из-за ошибки в заголовочном файле glibc 2.12 минимальное значение _POSIX_C_SOURCE, требуемое для объявления декларации ftruncate(), было равно 200809L вместо 200112L. В последующих версиях glibc эта ошибка была исправлена.

## СМОТРИТЕ ТАКЖЕ
truncate(1), open(2), stat(2), path_resolution(7)


umask

title: umask(2)

text:
# umask(2)

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

## ОБЗОР
\#include <sys/types.h>

\#include <sys/stat.h>

mode_t umask(mode_t mask);

## ОПИСАНИЕ
umask() устанавливает в вызывающем процессе значение маски (umask) создания режима доступа к файлу равным mask & 0777 (т.е. из mask используются только биты прав доступа к файлу) и возвращает предыдущее значение маски.

Значение umask используется в open(2), mkdir(2) и других системных вызовах, которые создают файлы, для изменения прав, назначаемых на создаваемые файлы или каталоги. В частности, права в umask исключаются из аргумента mode у вызовов open(2) и mkdir(2).

Также, если у родительского каталога указан ACL по умолчанию (смотрите acl(5)), то umask игнорируется, выполняется наследование ACL по умолчанию, бита прав назначаются согласно унаследованному ACL, а биты прав, отсутствующие в аргументе mode, выключаются. Например, следующий ACL по умолчанию эквивалентен umask 022:

u::rwx,g::r-x,o::r-x

Объединение эффекта этого ACL по умолчанию с аргументом mode 0666 (rw-rw-rw-) приводит установке прав на файл 0644 (rw-r--r--).

Константы, которые нужно использовать в mask, описаны в inode(7).

Типичным значением umask в процессе является S_IWGRP | S_IWOTH (восьмеричное 022). Обычно, когда аргумент mode у open(2) задаётся как:

```
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
```

(восьмеричное 0666) при создании файла, права получившегося файла будут:

```
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
```

(так как 0666 & ~022 = 0644; т.е., rw-r--r--).

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Данный системный вызов всегда выполняется успешно и возвращает предыдущее значение маски.

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

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

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

Начиная с Linux 4.7 значение umask любого процесса доступно в поле Umask файла /proc/[pid]/status. Просмотр этого поля в /proc/self/status позволяет процессу узнать свою umask без её изменения.

Настройка umask также влияет на права, назначаемые IPC-объектам POSIX (mq_open(3), sem_open(3), shm_open(3)), FIFO (mkfifo(3)) и доменным сокетам UNIX (unix(7)), создаваемых процессом. Значение umask не влияет на права, назначаемые IPC-объектам System V, создаваемых процессом (с помощью msgget(2), semget(2), shmget(2)).

## СМОТРИТЕ ТАКЖЕ
chmod(2), mkdir(2), open(2), stat(2), acl(5)


umount

title: umount(2)

summary: размонтирует файловую систему

text:
# umount(2)

## ИМЯ
umount, umount2 - размонтирует файловую систему

## ОБЗОР

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

```
int umount(const char *target);
```

```
int umount2(const char *target, int flags);
```

## ОПИСАНИЕ
Вызовы umount() и umount2() удаляют подключение (самого верхнего уровня) к файловой системе, примонтированной к target.

Для размонтирования файловых систем требуются права (Linux: мандат CAP_SYS_ADMIN).

В Linux 2.1.116 добавлен системный вызов umount2(), который, подобно umount(), размонтирует заданный объект, но позволяет указать дополнительные флаги flags, контролирующие поведение операции:

MNT_FORCE (начиная с Linux 2.1.116)

Попросить файловую систему прервать ожидающие запросы перед попыткой размонтирования. Это может позволить выполнить размонтирование без ожидания недоступного сервера, но может привести к потере данных. Если после прерывания запросов некоторые процессы продолжат обращаться к файловой системе, размонтирование не будет выполнено. В Linux 4.12 MNT_FORCE поддерживается только в следующих файловых системах: 9p (начиная с Linux 2.6.16), ceph (начиная с Linux 2.6.34), cifs (начиная с Linux 2.6.12), fuse (начиная с Linux 2.6.16), lustre (начиная с Linux 3.11) и NFS (начиная с Linux 2.1.116).

MNT_DETACH (начиная с Linux 2.4.11)

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

MNT_EXPIRE (начиная Linux 2.6.8)

Пометить точку монтирования как недействительную. Если точка монтирования в это время не используется, то первоначальный вызов umount2() с этим флагом завершится с ошибкой EAGAIN, но пометит точку монтирования как недействительную. Точка монтирования остаётся недействительной до тех пор, пока какой-нибудь процесс не запросит к ней доступ. Второй вызов umount2() с флагом MNT_EXPIRE размонтирует недействительную точку монтирования. Этот флаг нельзя указывать вместе с MNT_FORCE или MNT_DETACH.

UMOUNT_NOFOLLOW (начиная с Linux 2.6.34)

Не следовать по ссылке, если target является символьной ссылкой. Это флаг помогает избежать проблем с безопасностью в программах принадлежащих root и с установленным битом set-user-ID, которые позволяют непривилегированным пользователям размонтировать файловые системы.

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

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

EAGAIN

Вызов umount2() с флагом MNT_EXPIRE успешно пометил незанятую файловую систему как недействительную.

EBUSY

Объект target не может быть размонтирован, так как он занят.

EFAULT

Объект target указывает вне адресного пространства, доступного пользователю.

EINVAL

Значение target не является точкой монтирования.

EINVAL

Вызов umount2() был вызван с флагом MNT_EXPIRE и с MNT_DETACH или MNT_FORCE.

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

Вызов umount2() был сделан с неверным значением флага flags.

ENAMETOOLONG

Значение пути длиннее чем MAXPATHLEN.

ENOENT

Указан пустой путь или одна из его частей не существует.

ENOMEM

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

EPERM

Вызывающий процесс не имеет требуемых привилегий.

## ВЕРСИИ
Флаги MNT_DETACH и MNT_EXPIRE доступны в glibc начиная с версии 2.11.

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

## ЗАМЕЧАНИЯ

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

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

Чтобы umount() также не делал, перед вызовом umount() точка монтирования может быть перемонтирована с помощью вызова mount() с аргументом mount_flags, в который добавлены MS_REC и MS_PRIVATE.

### Историческая справка
Изначально функция umount() вызывалась как umount(device) и возвращала ENOTBLK при попытке работы с любым не блочным устройством. В Linux 0.98p4 был добавлен вызов umount(dir) для поддержки анонимных устройств. В Linux 2.3.99-pre7 был убран вызов umount(device), остался только umount(dir) (теперь устройства могут быть подключены более чем к одной точке, поэтому указания только устройства недостаточно).

## СМОТРИТЕ ТАКЖЕ
mount(2), mount_namespaces(7), path_resolution(7), mount(8), umount(8)


uname

title: uname(2)

text:
# uname(2)

## ИМЯ
uname - получает название и информацию о текущем ядре

## ОБЗОР
\#include <sys/utsname.h>

int uname(struct utsname *buf);

## ОПИСАНИЕ
uname() возвращает информацию о системе в структуру с адресом buf. Структура utsname определена в <sys/utsname.h>:

```
struct utsname {

    char sysname[];    /* название операционной системы

                          (например, «Linux») */

    char nodename[];   /* имя в сети, зависящее от реализации */

    char release[];    /* идентификатор выпуска ОС (например, «2.6.28») */

    char version[];    /* версия ОС */

    char machine[];    /* идентификатор аппаратного обеспечения */
#ifdef _GNU_SOURCE

    char domainname[]; /* доменное имя NIS или YP */
#endif
};
```

Размеры массивов в struct utsname не определены (см. ЗАМЕЧАНИЯ); поля завершаются байтом с null ('\0').

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

## ОШИБКИ
EFAULT

Значение buf не определено.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4. Вызов uname() отсутствует в 4.3BSD.

Поле domainname (доменное имя NIS или YP) является расширением GNU.

## ЗАМЕЧАНИЯ
Это системный вызов, и операционная система, предположительно, знает своё имя, номер выпуска и версию. Она также знает, на каком аппаратном обеспечении она работает. Таким образом, четыре поля структуры несут полезную информацию. С другой стороны, поле nodename её не несет: оно указывает имя машины в некой неопределённой сети, но обычно машины находятся в более чем одной сети и имеют несколько имён. Более того, ядро не может каким-либо образом получить информацию о таких вещах, поэтому ему необходимо сообщить что же возвращать в этом поле. То же относится и к дополнительному полю domainname.

С этой целью в Linux используются системные вызовы sethostname(2) и setdomainname(2). Обратите внимание, что хотя не существует стандарта, который бы указывал, что имя машины, установленное sethostname(2), является той же строкой, что возвращается в поле nodename при вызове uname(), для Linux это именно так (в действительности некоторые системы позволяют 256-символьное имя машины и 8-символьное имя узла). То же относится и к setdomainname(2) и полю domainname.

Длина полей в структуре может быть различна. Некоторые операционные системы или библиотеки используют жёстко заданные значения 9, 33, 65 или 257. Другие используют константы SYS_NMLN, _SYS_NMLN, UTSLEN и _UTSNAME_LENGTH. Несомненно, идея использовать эти константы не очень хороша — можно просто использовать sizeof(...). Часто выбирается 257 для того, чтобы имелось достаточно места для хранения имени машины в сети интернет.

Часть информации из структуры utsname может быть получена также через /proc/sys/kernel/ {ostype, hostname, osrelease, version, domainname}.

### Отличия между библиотекой C и ядром
Со временем, увеличение размера структуры utsname последовательно привело к трём версиям uname(): sys_olduname() (слот __NR_oldolduname), sys_uname() (слот __NR_olduname) и sys_newuname() (слот __NR_uname). В первой длина каждого поля равна 9; во второй 65; в третьей также 65, но добавилось поле domainname. Обёрточная функция uname() в glibc скрывает эти подробности от приложений, вызывая самую новую версию системного вызова, предоставляемого ядром.

## СМОТРИТЕ ТАКЖЕ
uname(1), getdomainname(2), gethostname(2), uts_namespaces(7)


unimplemented

title: unimplemented(2)

summary: нереализованные системные вызовы

text:
# unimplemented(2)

## ИМЯ
afs_syscall, break, fattach, fdetach, ftime, getmsg, getpmsg, gtty, isastream, lock, madvise1, mpx, prof, profil, putmsg, putpmsg, security, stty, tuxcall, ulimit, vserver - нереализованные системные вызовы

## ОБЗОР
Нереализованные системные вызовы.

## ОПИСАНИЕ
Данные системные вызовы не реализованы в ядре Linux.

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

## ЗАМЕЧАНИЯ
Заметим, что ftime(3), profil(3) и ulimit(3) реализованы в виде библиотечных функций.

Некоторые системные вызовы, такие как alloc_hugepages(2), free_hugepages(2), ioperm(2), iopl(2) и vm86(2), существуют только для некоторых архитектур.

Некоторые системные вызовы, такие как ipc(2), create_module(2), init_module(2) и delete_module(2), существуют в ядре Linux только, если при сборке ядра включена их поддержка.

## СМОТРИТЕ ТАКЖЕ
syscalls(2)


unlink

title: unlink(2)

text:
# unlink(2)

## ИМЯ
unlink, unlinkat - удаляет имя и, возможно, файл, на который оно ссылается

## ОБЗОР

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

```
int unlink(const char *pathname);
#include <fcntl.h>           /* определения констант of AT_* */
#include <unistd.h>
```

```
int unlinkat(int dirfd, const char *pathname, int flags);
```

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

unlinkat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

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

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

Если имя указывает на символьную ссылку, то будет удалена ссылка.

Если имя указывает на сокет, FIFO или устройство, то имя будет удалено, но процессы, которые открыли любой из этих объектов могут продолжать его использовать.

### unlinkat()
Системный вызов unlinkat() работает также как unlink() или rmdir(2) (в зависимости от того, есть ли флаг AT_REMOVEDIR во flags), за исключением случаев, описанных здесь.

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

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

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

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

AT_REMOVEDIR

По умолчанию, unlinkat() выполняет действие, эквивалентное unlink() с параметром pathname. Если указан флаг AT_REMOVEDIR, то выполняется действие, эквивалентное rmdir(2) с параметром pathname.

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

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

## ОШИБКИ
EACCES

Для эффективного UID процесса нет прав на запись в каталог, содержащийся в pathname, или в одном из каталогов в pathname не разрешён поиск (смотрите также path_resolution(7)).

EBUSY

Файл pathname не может быть удалён, так как он ещё используется системой или другим процессом; например, это точка монтирования или его создал клиент NFS для представления активной, но пока безымянной inode («NFS silly renamed»).

EFAULT

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

EIO

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

EISDIR

pathname ссылается на каталог. (Этого значения нет в POSIX, возвращается в Linux начиная с 2.1.132.)

ELOOP

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

ENAMETOOLONG

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

ENOENT

Компонент pathname не существует, является повисшей ссылкой или pathname пуст.

ENOMEM

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

ENOTDIR

Компонент пути, использованный как каталог в pathname, в действительности таковым не является.

EPERM

Система не разрешает удаление каталогов или для удаления каталогов требуются права, которыми не обладает вызвавший процесс. (Этот код ошибки предусмотрен в POSIX; как описано выше, в Linux в этом случае возвращается EISDIR.)

EPERM (только в Linux)

Файловая система не позволяет удаление файлов.

EPERM или EACCES

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

EPERM

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

EROFS

pathname указывает на файл в файловой системе, доступной только для чтения.

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

EBADF

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

EINVAL

В flags указано неверное значение флага.

EISDIR

Значение pathname ссылается на каталог и в flags не указан AT_REMOVEDIR.

ENOTDIR

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

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

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

unlinkat(): POSIX.1-2008.

## ЗАМЕЧАНИЯ

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

## ДЕФЕКТЫ
Неточности в протоколе NFS могут приводить к неожиданному исчезновению файлов, которые всё ещё используются.

## СМОТРИТЕ ТАКЖЕ
rm(1), unlink(1), chmod(2), link(2), mknod(2), open(2), rename(2), rmdir(2), mkfifo(3), remove(3), path_resolution(7), symlink(7)


unshare

title: unshare(2)

text:
# unshare(2)

## ИМЯ
unshare - отделяет части процесса контекста выполнения

## ОБЗОР

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

```
int unshare(int flags);
```

## ОПИСАНИЕ
Вызов unshare() позволяет процессу (или потоку) отделить части своего контекста выполнения, которые используются совместно с другими процессами (или потоками). Часть контекста выполнения, например пространство имён монтирования, неявно делается общей при создании нового процесса с помощью fork(2) или vfork(2), в то время как другие части, такие как виртуальная память, могут стать общими по явному запросу при создании процесса или потока с помощью clone(2).

Основное предназначение unshare() — позволить процессу контролировать свой общий контекст выполнения без создания нового процесса.

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

CLONE_FILES

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

CLONE_FS

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

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

Этот флаг имеет действие подобное флагу CLONE_NEWCGROUP для clone(2). Отделяет пространство имён cgroup. Для использования CLONE_NEWCGROUP требуется мандат CAP_SYS_ADMIN.

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

Этот флаг имеет действие подобное флагу CLONE_NEWIPC для clone(2). Отделяет пространство имён IPC таким образом, что вызывающий процесс будет иметь свою личную копию пространства имён IPC, неиспользуемую другими процессами. Задание данного флага автоматически устанавливает флаг CLONE_SYSVSEM. Для использования CLONE_NEWIPC требуется мандат CAP_SYS_ADMIN.

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

Этот флаг имеет действие подобное флагу CLONE_NEWNET для clone(2). Отделяет сетевое пространство имён таким образом, что вызывающий процесс будет иметь свою личную копию сетевого пространства имён, неиспользуемую другими процессами. Для использования CLONE_NEWNET требуется мандат CAP_SYS_ADMIN.

CLONE_NEWNS

Этот флаг имеет действие подобное флагу CLONE_NEWNS для clone(2). Отделяет пространство имён монтирования таким образом, что вызывающий процесс будет иметь свою личную копию данного пространства имён, неиспользуемую другими процессами. Задание данного флага автоматически устанавливает флаг CLONE_FS. Для использования CLONE_NEWNS требуется мандат CAP_SYS_ADMIN. Дополнительная информация доступна в mount_namespaces(7).

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

Данный флаг позволяет то же что и CLONE_NEWPID у clone(2). Выполняется отключение от пространства имён PID; вызывающий процесс создаёт новое пространство имён PID для своих потомков, которые до этого не были объединены с существующим процессом. Вызывающий процесс не перемещается в новое пространство имён. Первый потомок, созданный вызывающим процессом, будет иметь ID процесса 1 и считаться init(1) в новом пространстве имён. Также флаг CLONE_NEWPID автоматически подразумевает CLONE_THREAD. Для использования CLONE_NEWPID требуется мандат CAP_SYS_ADMIN. Подробней смотрите pid_namespaces(7).

CLONE_NEWUSER (начиная с Linux 3.8)

Данный флаг позволяет то же что и CLONE_NEWUSER у clone(2). Выполняется отключение от пользовательского пространства имён; вызывающий процесс перемещается в новое пользовательское пространство имён, которое до этого не был общим для существующего процесса. Как потомок процесса, созданный clone(2) с флагом CLONE_NEWUSER, вызывающий получает полный набор мандатов в новом пользовательском пространстве имён.

Для CLONE_NEWUSER требуется, чтобы вызывающий процесс не имел нитей; указание CLONE_NEWUSER автоматически подразумевает CLONE_THREAD. Начиная с Linux 3.9, CLONE_NEWUSER также автоматически подразумевает CLONE_FS. Для CLONE_NEWUSER требуется, чтобы ID пользователя и группы вызывающего процесса отображались в ID пользователя и группы в пользовательском пространстве имён вызывающего процесса на момент вызова.

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

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

Этот флаг имеет действие подобное флагу CLONE_NEWUTS для clone(2). Отделяет пространство имён UTS IPC таким образом, что вызывающий процесс будет иметь свою личную копию пространства имён UTS, неиспользуемую другими процессами. Для использования CLONE_NEWUTS требуется мандат CAP_SYS_ADMIN.

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

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

Также в flags могут быть указаны флаги CLONE_THREAD, CLONE_SIGHAND и CLONE_VM, если вызывающий состоит из одной нити (т. е., он не делит своё адресное пространство с другим процессом или нитью). Иначе данные флаги не работают (также заметим, что указание CLONE_THREAD автоматически подразумевает CLONE_VM, а указание CLONE_VM автоматически подразумевает CLONE_SIGHAND). Если процесс состоит из нескольких нитей, то использование данных флагов приведёт к ошибке.

Если значение flags равно нулю, то unshare() ничего не делает, то есть в контексте выполнения вызывающего процесса ничего не изменяется.

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

## ОШИБКИ
EINVAL

В значении flags установлен недопустимый бит.

EINVAL

В flags указан CLONE_THREAD, CLONE_SIGHAND или CLONE_VM, а вызывающий состоит из нескольких нитей.

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

Указан флаг CLONE_NEWPID в flags, но процесс был ранее вызван unshare() с флагом CLONE_NEWPID.

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

Вызывающий процесс не имеет требуемых привилегий для этой операции.

EPERM

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

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

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

EUSERS (Linux 3.11 по Linux 4.8)

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

## ВЕРСИИ
Системный вызов unshare() был добавлен в ядро Linux версии 2.6.16.

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

## ЗАМЕЧАНИЯ
Не все атрибуты процесса, которые могут использоваться совместно при создании нового процесса с помощью clone(2), могут быть отделены с помощью unshare(). В частности, начиная с ядра 3.8 в unshare() не реализована поддержка флагов, которые были имели обратное действие CLONE_SIGHAND, CLONE_THREAD или CLONE_VM. Эти возможности могут быть добавлены позднее, если потребуется.

## ПРИМЕР
Программа, представленная далее, предоставляет простую реализацию команды unshare(1), которая отключает использование одного или более пространств имён и выполняет команду, переданную в аргументах командной строки. Вот пример использования этой программы; запускается оболочка в новом пространстве имён монтирования и проверяется, что первоначальная оболочка и новая оболочка находятся в разных пространствах имён монтирования:

```
$ readlink /proc/$$/ns/mnt
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash
# readlink /proc/$$/ns/mnt
mnt:[4026532325]
```

Различающийся вывод двух команд readlink(1) показывает, что две оболочки находятся в разных пространствах имён монтирования.

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

```
/* unshare.c

   Простая реализация команды unshare(1): отключение от

   пространств имён и выполнение команды.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
/* Простая функция обработки ошибок: выводит сообщение об ошибке согласно

   значению в «errno» и завершает вызвавший процесс */
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
static void
usage(char *pname)
{

    fprintf(stderr, "Использование: %s [параметры] программа [аргументы…]\n", pname);

    fprintf(stderr, "Параметры:\n");

    fprintf(stderr, "    -i   отключиться от пространства имён IPC\n");

    fprintf(stderr, "    -m   отключиться от пространства имён монтирования\n");

    fprintf(stderr, "    -n   отключиться от сетевого пространства имён\n");

    fprintf(stderr, "    -p   отключиться от пространства имён PID\n");

    fprintf(stderr, "    -u   отключиться от пространства имён UTS\n");

    fprintf(stderr, "    -U   отключиться от пользовательского пространства имён\n");

    exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{

    int flags, opt;

    flags = 0;

    while ((opt = getopt(argc, argv, "imnpuU")) != -1) {

        switch (opt) {

        case 'i': flags |= CLONE_NEWIPC;        break;

        case 'm': flags |= CLONE_NEWNS;         break;

        case 'n': flags |= CLONE_NEWNET;        break;

        case 'p': flags |= CLONE_NEWPID;        break;

        case 'u': flags |= CLONE_NEWUTS;        break;

        case 'U': flags |= CLONE_NEWUSER;       break;

        default:  usage(argv[0]);

        }

    }

    if (optind >= argc)

        usage(argv[0]);

    if (unshare(flags) == -1)

        errExit("unshare");

    execvp(argv[optind], &argv[optind]);

    errExit("execvp");
}
```

## СМОТРИТЕ ТАКЖЕ
unshare(1), clone(2), fork(2), kcmp(2), setns(2), vfork(2), namespaces(7)

Файл Documentation/userspace-api/unshare.rst из дерева исходного кода ядра Linux (или Documentation/unshare.txt до Linux 4.12)


uselib

title: uselib(2)

summary: загрузить динамическую библиотеку

text:
# uselib(2)

## ИМЯ
uselib - загрузить динамическую библиотеку

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

int uselib(const char *library);

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

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

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

## ОШИБКИ
В дополнении к тем кодам ошибок, которые возвращаются вызовами open(2) и mmap(2), также могут быть следующие коды ошибок:

EACCES

На библиотеку, заданную library, нет прав на чтение или исполнение, или вызывающий не имеет прав на поиск в одном из каталогов, указанных в пути. (Смотрите также path_resolution(7).)

ENFILE

Достигнуто максимальное количество открытых файлов в системе.

ENOEXEC

Библиотека, заданная library, имеет неизвестный исполняемый тип; например, в ней нет корректных идентификационных чисел (magic numbers).

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

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

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

Начиная с libc 4.3.2, код запуска дополняется эти имена "/usr/lib", "/lib" и "" перед тем как отказаться от загрузки. В libc 4.3.4 и более поздних эти имена ищутся в каталогах, содержащихся в переменной окружения LD_LIBRARY_PATH, и если они не находятся, то выполняется попытка поиска с добавлением "/usr/lib", "/lib" и "/".

Начиная libc 4.4.4 загружается только библиотека "/lib/ld.so" для того, чтобы она смогла загрузить оставшиеся необходимые библиотеки (используя этот системный вызов). То же происходит и в libc5.

В glibc2 не используется этот вызов.

Начиная с Linux 3.15 данный системный вызов доступен только, если ядро собрано с параметром CONFIG_USELIB.

## СМОТРИТЕ ТАКЖЕ
ar(1), gcc(1), ld(1), ldd(1), mmap(2), open(2), dlopen(3), capabilities(7), ld.so(8)


userfaultfd

title: userfaultfd(2)

text:
# userfaultfd(2)

## ИМЯ
userfaultfd - создаёт файловый дескриптор для обработки страничных ошибок в пользовательском пространстве

## ОБЗОР

```
#include <sys/types.h>
#include <linux/userfaultfd.h>
```

```
int userfaultfd(int flags);
```

Замечание: В glibc нет обёрточной функции для данного системного вызова; смотрите ЗАМЕЧАНИЯ.

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

После настройки объекта userfaultfd приложение может использовать вызов read(2) для получения уведомлений userfaultfd. Чтение из userfaultfd может быть блокирующим и не блокирующим, в зависимости от использованного при создании userfaultfd значения flags или последующих вызовов fcntl(2).

Для изменения поведения userfaultfd() можно использовать следующие значения flags (через OR):

O_CLOEXEC

Включить флаг close-on-exec для нового открытого файлового дескриптора userfaultfd. Смотрите описание флага O_CLOEXEC в open(2).

O_NONBLOCK

Включить не блокирующую работу с объектом userfaultfd. Смотрите описание флага O_NONBLOCK в open(2).

Когда закрывается последний ссылающийся на объект userfaultfd файловый дескриптор, для всех диапазонов памяти, зарегистрированных в этом объекте, снимается регистрация, а все непрочитанные события очищаются.

### Использование
Механизм userfaultfd разработан для того, чтобы позволить нити в многонитевой программе выполнять деление на страницы пользовательского пространства других нитей процесса. При возникновении страничной ошибки в одной из зарегистрированных в объекте userfaultfd областей нить с ошибкой засыпает и генерируется событие, которое можно прочитать через файловый дескриптор userfaultfd. Нить обработки страничных ошибок читает сообщения из этого файлового дескриптора и обслуживает из с помощью операций, описанных в ioctl_userfaultfd(2). В время этого нить обработки страничных ошибок может привести в действие механизм пробуждения спящей нити.

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

Начиная с Linux 4.11, userfaultfd также уведомляет нити обработки страничных ошибок об изменениях в раскладке виртуальной памяти процесса с ошибкой. Также, если процесс с ошибкой вызывает fork(2), то для объекта userfaultfd, связанного с родителем, в дочернем процессе может быть создать дубликат, и отслеживающий userfaultfd также будет уведомлён (смотрите описание UFFD_EVENT_FORK ниже) о файловом дескрипторе, связанном с объектом userfault, который был создан для дочернего процесса, что позволяет отслеживающему userfaultfd выполнять деление на страницы пользовательское пространство дочернего процесса. В отличие от страничных ошибок, которые происходят синхронно и требуют явного или неявного пробуждения, все остальные события доставляются асинхронно и не взаимодействующий процесс возобновляет выполнение сразу же после того как отслеживающий userfaultfd выполняет read(2). Отслеживающий userfaultfd должен корректно синхронизировать вызовы UFFDIO_COPY при обработке событий.

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

### Работа с userfaultfd
После создания объекта userfaultfd с помощью userfaultfd() приложение должно включить его с помощью операции UFFDIO_API вызова ioctl(2). Данная операция позволяет согласовать между ядром и пользовательским пространством версию программного интерфейса поддерживаемых свойств. Эта операция должна быть выполнено самой первой среди других операций ioctl(2), описываемых ниже (в противном случае эти операции завершаются ошибкой EINVAL).

После успешного выполнения UFFDIO_API приложение должно зарегистрировать диапазоны адресов памяти с помощью операции UFFDIO_REGISTER вызова ioctl(2). После успешного выполнения UFFDIO_REGISTER страничная ошибка, возникающая в запрошенном диапазоне и удовлетворяющая режиму, определённому в момент регистрации, будет переслана ядром приложению в пользовательском пространстве. Для решения страничной ошибки приложение может использовать операцию UFFDIO_COPY или UFFDIO_ZEROPAGE вызова ioctl(2).

Начиная с Linux 4.14, если приложение устанавливает бит свойства UFFD_FEATURE_SIGBUS с помощью UFFDIO_API ioctl(2), то уведомления о страничных ошибках не пересылаются в пользовательское пространство. Вместо этого в ошибшийся процесс посылается сигнал SIGBUS. С данным свойством userfaultfd можно использовать в целях надёжности, просто ловя все попытки доступа к областях внутри зарегистрированного адресного диапазона, в котором нет выделенных страниц, не слушая при этом события userfaultfd. При таком доступе к памяти не потребуется процесс слежения за userfaultfd. Например, данное свойство может оказаться полезным приложениям, которые хотят не давать ядру выполнять автоматическое выделение страниц и заполнение дыр в разреженных файлах при обращении к дыре через отображение в памяти.

Свойство UFFD_FEATURE_SIGBUS неявно наследуется при fork(2), если используется вместе с UFFD_FEATURE_FORK.

Подробности о различных операциях ioctl(2) можно найти в ioctl_userfaultfd(2).

Начиная с Linux 4.11 при операции UFFDIO_API можно включить не только события страничной ошибки.

До Linux 4.11 объект userfaultfd мог быть использован только с анонимными частными отображениями памяти. Начиная с Linux 4.11 объект userfaultfd может также использоваться с отображениями общей памяти и hugetlbfs.

### Чтение из структуры userfaultfd
Каждый вызов read(2) из файлового дескриптора userfaultfd возвращает одну или более структур uffd_msg, каждая из которых описывает событие страничной ошибки или событие, требуемое для использования userfaultfd в разобщённом режиме:

```
struct uffd_msg {

    __u8  event;            /* тип события */

    ...

    union {

        struct {

            __u64 flags;    /* флаги, описывающие ошибку */

            __u64 address;  /* ошибочный адрес */

        } pagefault;

        struct {            /* начиная с Linux 4.11 */

            __u32 ufd;      /* файловый дескриптор userfault

                               дочернего процесса */

        } fork;

        struct {            /* начиная с Linux 4.11 */

            __u64 from;     /* старый адрес переотображаемой области */

            __u64 to;       /* новый адрес переотображаемой области */

            __u64 len;      /* начальный размер отображения */

        } remap;

        struct {            /* начиная с Linux 4.11 */

            __u64 start;    /* начальный адрес удаляемой области */

            __u64 end;      /* конечный адрес удаляемой области */

        } remove;

        ...

    } arg;

    /* поля-заполнители не показаны */
} __packed;
```

Если доступно несколько событий и переданный буфер достаточного размера, то read(2) возвращает столько событий сколько влезает в буфер. Если буфер, указанный read(2), меньше размера структуры uffd_msg, то read(2) завершается ошибкой EINVAL.

Поля структуры uffd_msg:

event

Тип события. Тип события влияет на заполняемые поля объединения arg, представляющего детали, требуемые для обработки события. События, не относящиеся к страничным ошибкам, генерируются только когда включено соответствующее свойство при согласовании программного интерфейса с помощью операции UFFDIO_API вызова ioctl(2).

В поле event могут появляться следующие значения:

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

Событие страничной ошибки. Детали ошибки доступны в поле pagefault.

UFFD_EVENT_FORK (начиная с Linux 4.11)

Генерируется, когда процесс с ошибкой вызывает fork(2) (или clone(2) без флага CLONE_VM). Детали ошибки доступны в поле fork.

UFFD_EVENT_REMAP (начиная с Linux 4.11)

Генерируется, когда процесс с ошибкой вызывает mremap(2). Детали ошибки доступны в поле remap.

UFFD_EVENT_REMOVE (начиная с Linux 4.11)

Генерируется, когда процесс с ошибкой вызывает madvise(2) с советом MADV_DONTNEED или MADV_REMOVE. Детали ошибки доступны в поле remove.

UFFD_EVENT_UNMAP (начиная с Linux 4.11)

Генерируется, когда процесс с ошибкой отменяет проецирование диапазона памяти явным образом с помощью munmap(2) или неявно при вызове mmap(2) или mremap(2). Детали ошибки доступны в поле remove.

pagefault.address

Адрес, из-за которого возникла страничная ошибка.

pagefault.flags

Битовая маска флагов, описывающих событие. Для UFFD_EVENT_PAGEFAULT может появляться следующий флаг:

UFFD_PAGEFAULT_FLAG_WRITE

Если адрес в диапазоне, который был зарегистрирован с флагом UFFDIO_REGISTER_MODE_MISSING (смотрите ioctl_userfaultfd(2)) и этот флаг установлен, то это ошибка записи; в противном случае это ошибка чтения.

fork.ufd

С помощью fork(2) был создан потомок, для которого был создан файловый дескриптор, связанный с объектом userfault.

remap.from

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

remap.to

Новый адрес диапазона памяти, который был переотображён с помощью mremap(2).

remap.len

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

remove.start

Начальный адрес диапазона памяти, который был освобождён с помощью madvise(2) или было отменено проецирование.

remove.end

Конечный адрес диапазона памяти, который был освобождён с помощью madvise(2) или было отменено проецирование.

Вызов read(2) с файловым дескриптором userfaultfd может завершиться следующими ошибками:

EINVAL

Объект userfaultfd не был включён с помощью операции UFFDIO_API вызова ioctl(2).

Если в связанном открытом файловом описании указан флаг O_NONBLOCK, то файловый дескриптор userfaultfd можно отслеживать с помощью poll(2), select(2) и epoll(7). При возникновении событий, файловый дескриптор помечается как доступный на чтение. Если флаг O_NONBLOCK не задан, то poll(2) (всегда) показывает, что файл находится в состоянии POLLERR, а select(2) показывает, что файловый дескриптор доступен на чтение и запись.

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

## ОШИБКИ
EINVAL

В flags указано неподдерживаемое значение.

EMFILE

Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс.

ENFILE

Достигнуто максимальное количество открытых файлов в системе.

ENOMEM

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

## ВЕРСИИ
Системный вызов userfaultfd() впервые появился в Linux 4.3.

Поддержка hugetlbfs и общих областей памяти, а также событий, не относящихся к страничным ошибкам, была добавлена в Linux 4.11.

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

## ЗАМЕЧАНИЯ
В glibc нет обёртки для данного системного вызова; запускайте его с помощью syscall(2).

Механизм userfaultfd может быть использован как альтернатива обычному страничному делению пользовательского пространства на основе использования сигнала SIGSEGV и mmap(2). Также он может быть использован для реализации отложенного (lazy) восстановления checkpoint/restore mechanisms, as well as post-copy migration to allow (почти) не прерываемого выполнения при переносе виртуальных машин и контейнеров Linux с одного узла на другой.

## ДЕФЕКТЫ
Если указано UFFD_FEATURE_EVENT_FORK и системный вызов из семейства fork(2) прерывается по сигналу или завершается ошибкой, то может быть создан повисший дескриптор userfaultfd. В этом случае программе слежения за userfaultfd может быть доставлен ложный UFFD_EVENT_FORK.

## ПРИМЕР
Программа, представленная далее, показывает использование механизма userfaultfd. Она создаёт две нити, одна служит обработчиком страничных ошибок процесса для страниц в режиме выделения при необходимости, созданных mmap(2).

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

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

Каждое событие страничной ошибки обрабатывается второй нитью, которая выполняет цикл обработки ввода из файлового дескриптора userfaultfd. При каждом проходе цикла вторая нить сначала вызывает poll(2) для проверки состояния файлового дескриптора, затем читает событие из файлового дескриптора. Все события должны быть UFFD_EVENT_PAGEFAULT, для их обработки нить копирует страницу данных в ошибочную область с помощью операции UFFDIO_COPY вызова ioctl(2).

Результат работы программы:

```
$ ./userfaultfd_demo 3
Адрес, возвращённый mmap() = 0x7fd30106c000
fault_handler_thread():

    poll() вернул: nready = 1; POLLIN = 1; POLLERR = 0

    событие UFFD_EVENT_PAGEFAULT: флаги = 0; адрес = 7fd30106c00f

        (uffdio_copy.copy равно 4096)
Чтение по адресу 0x7fd30106c00f в main(): A
Чтение по адресу 0x7fd30106c40f в main(): A
Чтение по адресу 0x7fd30106c80f в main(): A
Чтение по адресу 0x7fd30106cc0f в main(): A
fault_handler_thread():

    poll() вернул: nready = 1; POLLIN = 1; POLLERR = 0

    событие UFFD_EVENT_PAGEFAULT: флаги = 0; адрес = 7fd30106d00f

        (uffdio_copy.copy равно 4096)
Чтение по адресу 0x7fd30106d00f в main(): B
Чтение по адресу 0x7fd30106d40f в main(): B
Чтение по адресу 0x7fd30106d80f в main(): B
Чтение по адресу 0x7fd30106dc0f в main(): B
fault_handler_thread():

    poll() вернул: nready = 1; POLLIN = 1; POLLERR = 0

    событие UFFD_EVENT_PAGEFAULT: флаги = 0; адрес = 7fd30106e00f

        (uffdio_copy.copy равно 4096)
Чтение по адресу 0x7fd30106e00f в main(): C
Чтение по адресу 0x7fd30106e40f в main(): C
Чтение по адресу 0x7fd30106e80f в main(): C
Чтение по адресу 0x7fd30106ec0f в main(): C
```

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

```
/* userfaultfd_demo.c

   распространяется по лицензии GNU General Public License version 2 и новее.
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <stdio.h>
#include <linux/userfaultfd.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <poll.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <poll.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
static int page_size;
static void *
fault_handler_thread(void *arg)
{

    static struct uffd_msg msg;   /* данные, прочитанные из userfaultfd */

    static int fault_cnt = 0;     /* количество обработанных ошибок */

    long uffd;                    /* файловый дескриптор userfaultfd */

    static char *page = NULL;

    struct uffdio_copy uffdio_copy;

    ssize_t nread;

    uffd = (long) arg;

    /* создаём страницу, которая будет копироваться в ошибочную область */

    if (page == NULL) {

        page = mmap(NULL, page_size, PROT_READ | PROT_WRITE,

                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

        if (page == MAP_FAILED)

            errExit("mmap");

    }

    /* циклически обрабатываем входные сообщения в

       файловом дескрипторе userfaultfd */

    for (;;) {

        /* С помощью poll() проверяем userfaultfd */

        struct pollfd pollfd;

        int nready;

        pollfd.fd = uffd;

        pollfd.events = POLLIN;

        nready = poll(&pollfd, 1, -1);

        if (nready == -1)

            errExit("poll");

        printf("\nfault_handler_thread():\n");

        printf("    poll() вернул: nready = %d; "

                "POLLIN = %d; POLLERR = %d\n", nready,

                (pollfd.revents & POLLIN) != 0,

                (pollfd.revents & POLLERR) != 0);

        /* читаем событие из userfaultfd */

        nread = read(uffd, &msg, sizeof(msg));

        if (nread == 0) {

            printf("EOF в userfaultfd!\n");

            exit(EXIT_FAILURE);

        }

        if (nread == -1)

            errExit("read");

        /* ожидаем только один тип событий; проверяем, что это так */

        if (msg.event != UFFD_EVENT_PAGEFAULT) {

            fprintf(stderr, "Неожидаемый тип события в userfaultfd\n");

            exit(EXIT_FAILURE);

        }

        /* показываем информацию о событии страничной ошибки */

        printf("    событие UFFD_EVENT_PAGEFAULT: ");

        printf("флаги = %llx; ", msg.arg.pagefault.flags);

        printf("адрес = %llx\n", msg.arg.pagefault.address);

        /* копируем страницу, на которую указывает 'page', в ошибочную

           область. Меняем содержимое, которое копируем для того, чтобы

           было более очевидно, что каждая ошибка обрабатывается отдельно. */

        memset(page, 'A' + fault_cnt % 20, page_size);

        fault_cnt++;

        uffdio_copy.src = (unsigned long) page;

        /* мы должны обрабатывать страничные ошибки в единицах страниц(!).

           поэтому округляем адрес ошибки по нижней границы страницы */

        uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address &

                                           ~(page_size - 1);

        uffdio_copy.len = page_size;

        uffdio_copy.mode = 0;

        uffdio_copy.copy = 0;

        if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1)

            errExit("ioctl-UFFDIO_COPY");

        printf("        (uffdio_copy.copy равно %lld)\n",

                uffdio_copy.copy);

    }
}
int
main(int argc, char *argv[])
{

    long uffd;          /* файловый дескриптор userfaultfd */

    char *addr;         /* Начало области, обрабатываемое userfaultfd */

    unsigned long len;  /* Размер области, обрабатываемой userfaultfd */

    pthread_t thr;      /* ID нити, обрабатывающей страничные ошибки */

    struct uffdio_api uffdio_api;

    struct uffdio_register uffdio_register;

    int s;

    if (argc != 2) {

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

        exit(EXIT_FAILURE);

    }

    page_size = sysconf(_SC_PAGE_SIZE);

    len = strtoul(argv[1], NULL, 0) * page_size;

    /* создаём и включаем объект userfaultfd */

    uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);

    if (uffd == -1)

        errExit("userfaultfd");

    uffdio_api.api = UFFD_API;

    uffdio_api.features = 0;

    if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)

        errExit("ioctl-UFFDIO_API");

    /* Копируем частное анонимное отображение. Память будет

       выделена по требованию, то есть реально не выделяется. Когда мы

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

       userfaultfd. */

    addr = mmap(NULL, len, PROT_READ | PROT_WRITE,

                MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (addr == MAP_FAILED)

        errExit("mmap");

    printf("Адрес, возвращённый mmap() = %p\n", addr);

    /* Регистрируем в объекте userfaultfd область памяти отображения

       которое мы только что создали. Запрашиваем режим слежения

       за отсутствующими страницами (т. е., которые пока не

       были заполнены). */

    uffdio_register.range.start = (unsigned long) addr;

    uffdio_register.range.len = len;

    uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;

    if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)

        errExit("ioctl-UFFDIO_REGISTER");

    /* Создаём нить, которая будет обрабатывать события  userfaultfd */

    s = pthread_create(&thr, NULL, fault_handler_thread, (void *) uffd);

    if (s != 0) {

        errno = s;

        errExit("pthread_create");

    }

    /* Теперь главная нить обращается к памяти в отображении c

       интервалом в 1024 байта. Это создаст события в userfaultfd

       для всех страниц в области. */

    int l;

    l = 0xf;    /* Гарантируем, что ошибочный адрес не на границе

                   страницы, чтобы протестировать что, мы правильно

                   обрабатываем этот случай в fault_handling_thread() */

    while (l < len) {

        char c = addr[l];

        printf("Чтение по адресу %p в main(): ", addr + l);

        printf("%c\n", c);

        l += 1024;

        usleep(100000);         /* замедлим программу */

    }

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
fcntl(2), ioctl(2), ioctl_userfaultfd(2), madvise(2), mmap(2)

Файл Documentation/admin-guide/mm/userfaultfd.rst из дерева исходного кода ядра Linux


ustat

title: ustat(2)

summary: получить статистику по файловой системе

text:
# ustat(2)

## ИМЯ
ustat - получить статистику по файловой системе

## ОБЗОР

```
#include <sys/types.h>
#include <unistd.h>    /* libc[45] */
#include <ustat.h>     /* glibc2 */
```

```
int ustat(dev_t dev, struct ustat *ubuf);
```

## ОПИСАНИЕ
ustat() возвращает информацию о смонтированной файловой системе. В dev указывается номер, который идентифицирует устройство, содержащее нужную файловую систему. Аргумент ubuf является указателем на структуру ustat, которая имеет следующий вид:

```
daddr_t f_tfree;      /* всего свободных блоков */
ino_t   f_tinode;     /* количество свободных индексных дескрипторов */
char    f_fname[6];   /* имя Filsys */
char    f_fpack[6];   /* имя Filsys pack */
```

Обработка последних двух полей, f_fname и f_fpack, не реализована, и они всегда будут заполнены нулевыми символами ('\0').

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

## ОШИБКИ
EFAULT

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

EINVAL

dev не указывает на устройство, содержащее смонтированную файловую систему.

ENOSYS

Смонтированная файловая система, на которую ссылается dev, не поддерживает данную операцию или версия Linux меньше, чем 1.3.16.

## ВЕРСИИ
Начиная с версии 2.28, в glibc удалена обёрточная функция этого устаревшего системного вызова.

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4.

## ЗАМЕЧАНИЯ
Вызов ustat() устарел и предоставляется только для совместимости. Во всех новых программах вместо него нужно использовать вызов statfs(2).

### Замечания, касающиеся HP-UX
Версия структуры ustat в HP-UX содержит дополнительное поле f_blksize, которого в других версиях нет. HP предупреждает: в некоторых файловых системах количество свободных индексных дескрипторов (inodes) не изменяется. Для таких файловых систем в поле f_tinode возвращается значение -1. В некоторых файловых системах индексные дескрипторы выделяются динамически. Для таких файловых систем будет возвращено текущее количество свободных индексных дескрипторов.

## СМОТРИТЕ ТАКЖЕ
stat(2), statfs(2)


utime

title: utime(2)

text:
# utime(2)

## ИМЯ
utime, utimes - изменить последнее время доступа и изменения к inode

## ОБЗОР

```
#include <sys/types.h>
#include <utime.h>
```

```
int utime(const char *filename, const struct utimbuf *times);
```

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

```
int utimes(const char *filename, const struct timeval times[2]);
```

## ОПИСАНИЕ
Замечание: современным приложениям лучше использовать интерфейсы, описанные в utimensat(2).

Системный вызов utime() изменяет время доступа и изменения у inode, указанного в filename на значения полей actime и modtime из структуры times, соответственно.

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

Изменение временных меток разрешено если: процесс имеет соответствующие права или эффективный пользовательский идентификатор равен пользовательскому идентификатору файла, или значение times равно NULL и процесс имеет права на запись в файл.

Структура utimbuf выглядит так:

```
struct utimbuf {

    time_t actime;       /* время доступа */

    time_t modtime;      /* время изменения */
};
```

Системный вызов utime() позволяет указывать временные метки с точностью до 1 секунды.

Системный вызов utimes() выполняет подобное действие, но аргумент times указывает на массив, а не на структуру. Элементы массива представляют собой структуры timeval, с помощью которых можно указывать временные метки с точностью до 1 микросекунды . Структура timeval:

```
struct timeval {

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

    long tv_usec;       /* микросекунды */
};
```

В times[0] задаётся новое время доступа, а в times[1] новое время изменения. Если значение times равно NULL, то аналогично utime(), время доступа и изменения файла устанавливаются в текущее время.

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

## ОШИБКИ
EACCES

Запрещён поиск в одном из каталогов пути path (см. также path_resolution(7)).

EACCES

Значение times равно NULL, эффективный пользовательский идентификатор вызывающего процесса не совпадает с владельцем файла, вызывающий не имеет права на запись в файл, и у вызывающего нет привилегий (Linux: не имеет мандата CAP_DAC_OVERRIDE или CAP_FOWNER).

ENOENT

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

EPERM

Значение times не равно NULL, эффективный пользовательский идентификатор вызывающего процесса не совпадает с владельцем файла и у вызывающего нет привилегий (Linux: не имеет мандата CAP_FOWNER).

EROFS

path располагается на файловой системе, доступной только для чтения.

## СООТВЕТСТВИЕ СТАНДАРТАМ
utime(): SVr4, POSIX.1-2001. В POSIX.1-2008 вызов utime() помечен как устаревший.

utimes(): 4.3BSD, POSIX.1-2001.

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

## СМОТРИТЕ ТАКЖЕ
chattr(1), touch(1), futimesat(2), stat(2), utimensat(2), futimens(3), futimes(3), inode(7)


utimensat

title: utimensat(2)

text:
# utimensat(2)

## ИМЯ
utimensat, futimens - изменение временных меток файла с наносекундной точностью

## ОБЗОР

```
#include <fcntl.h> /* определения констант AT_* */
#include <sys/stat.h>
```

```
int utimensat(int dirfd, const char *pathname,
              const struct timespec times[2], int flags);
```

```
int futimens(int fd, const struct timespec times[2]);
```

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

utimensat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

futimens():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_GNU_SOURCE

## ОПИСАНИЕ
Вызовы utimensat() и futimens() обновляют временные метки файла с наносекундной точностью. Этим они отличаются от utime(2) и utimes(2), которые имеют секундную и микросекундную точность, соответственно.

В вызове utimensat() файл задаётся в pathname по имени. В вызове futimens() файл указывается в виде открытого файлового дескриптора в fd.

У обоих вызовов новые временные метки файла указываются в массиве times: в times[0] задаётся новое «время последнего доступа» (atime); в times[1] задаётся новое «время последнего изменения» (mtime). В каждом элементе times указывается время в виде количества секунд и наносекунд, прошедших с начала эпохи (1970-01-01 00:00:00 +0000 (UTC)). Эта информация представляет собой структуру следующего формата:

```
struct timespec {

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

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

Обновлённые временные метки файла устанавливаются в самое большое значение, поддерживаемое файловой системой, но не больше чем указанное время.

Если в поле tv_nsec одной из структур timespec указано специальное значение UTIME_NOW, то соответствующая временная метка файла устанавливается в значение текущего времени. Если в поле tv_nsec одной из структур timespec указано специальное значение UTIME_OMIT, то соответствующая временная метка файла не изменяется. В обоих случаях значение поля tv_sec игнорируется.

Если значение times равно NULL, то значение обеих временных меток становится равным текущему времени.

### Права доступа
Чтобы установить временные метки файла равными текущему времени (т.е., значение times равно NULL, или оба значения поля tv_nsec равно UTIME_NOW) требуется одно из:

1.

вызывающий должен иметь право на запись в файл;

2.

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

3.

вызывающий должен иметь соответствующие права.

Чтобы установить временные метки файла равными не текущему времени (т. е., значение times не равно NULL, или оба значения поля tv_nsec не равны UTIME_NOW или UTIME_OMIT) требуется выполнение условия 2 или 3.

Если в обоих значениях поле tv_nsec равно UTIME_OMIT, то проверки владения файлом и права доступа к нему не выполняются, и временные метки файла не изменяются, но всё равно могут проверяться другие условия возникновения ошибок.

### Особенности utimensat()
Если в pathname указано относительное значение имени, то по умолчанию оно отсчитывается от каталога, на который ссылается открытый файловый дескриптор, dirfd (а не от текущего рабочего каталога вызывающего процесса, как это делается в utimes(2) для относительных имён). В openat(2) объяснено почему это может быть полезно.

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

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

Значение поля flags представляет собой битовую маску и может равняться 0 или содержать следующую константу (определена в <fcntl.h>):

AT_SYMLINK_NOFOLLOW

Если pathname указывает на символьную ссылку, то обновляются временные метки ссылки, а не файла, на который она ссылается.

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

## ОШИБКИ
EACCES

Значение times равно NULL, или в обоих значениях поле tv_nsec равно UTIME_NOW или:

- эффективный пользовательский идентификатор вызывающего процесса не совпадает с идентификатором владельца файла, вызывающий не имеет права на запись в файл, и у вызывающего нет привилегий (Linux: не имеет мандата CAP_FOWNER или CAP_DAC_OVERRIDE);

- файл помечен как неизменяемый (immutable) (см. chattr(1)).

EBADF

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

EBADF

(utimensat()) В pathname содержится относительный путь, но значение dirfd не равно AT_FDCWD и не является правильным файловым дескриптором.

EFAULT

Значение times указывает на некорректный адрес; или dirfd равно AT_FDCWD и pathname равно NULL или содержит некорректный адрес.

EINVAL

Некорректное значение flags.

EINVAL

Некорректное значение в одном из полей tv_nsec (значение вне диапазона от 0 до 999999999 и не равно UTIME_NOW или UTIME_OMIT) или некорректное значение в одном из полей tv_sec.

EINVAL

Значение pathname равно NULL, dirfd не равно AT_FDCWD и flags содержит AT_SYMLINK_NOFOLLOW.

ELOOP

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

ENAMETOOLONG

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

ENOENT

(utimensat()) Компонент пути pathname не ссылается на существующий каталог или файл, или в pathname указана пустая строка.

ENOTDIR

(utimensat()) В pathname содержится относительный путь, но значение dirfd не равно AT_FDCWD или не является файловым дескриптором, ссылающимся на каталог; или один из компонентов pathname не является каталогом.

EPERM

Вызывающий пытается изменить одну или обе временные метки на значение, отличное от текущего времени, или изменить одну из временных меток на текущее время, а другую оставить неизменной (т. е., значение times не равно NULL, у обоих значений поле tv_nsec не равно UTIME_NOW, и у обоих значений поле tv_nsec не равно UTIME_OMIT) и:

- эффективный пользовательский идентификатор не совпадает с идентификатором владельца файла, а вызывающий не имеет привилегий (Linux: не имеет мандата CAP_FOWNER);

- файл помечен как только для добавления или как неизменяемый (см. chattr(1)).

EROFS

Файл расположен в файловой системе, доступной только для чтения.

ESRCH

(utimensat()) В одном из каталогов префикса pathname не разрешён поиск.

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

Поддержка futimens() появилась в glibc 2.6.

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

Интерфейс

Атрибут

Значение

utimensat(), futimens()

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

MT-Safe

## СООТВЕТСТВИЕ СТАНДАРТАМ
Вызовы futimens() и utimensat() определены в POSIX.1-2008.

## ЗАМЕЧАНИЯ
Вызов utimensat() заменяет устаревший futimesat(2).

В Linux, временные метки нельзя изменять у файлов, помеченных как неизменяемые (immutable), а у файлов, помеченных как только для добавления, можно изменить метку только на значение текущего времени (это соответствует сложившемуся исторически поведению в Linux вызовов utime(2) и utimes(2)).

Если оба поля tv_nsec равны UTIME_OMIT, то вызов utimensat() реализации Linux завершается без ошибки, даже, если файл, на который ссылается dirfd и pathname, не существует.

### Отличия между библиотекой C и ABI ядра
В Linux, futimens() представляет собой библиотечную функцию на основе системного вызова utimensat(). Для этого в Linux-версии системного вызова utimensat() реализовано нестандартное свойство: если значение pathname равно NULL, то вызов изменяет временные метки файла на который ссылается файловый дескриптор dirfd (который может указывать на файл любого типа). С помощью этого свойства вызов futimens(fd, times) реализован как:

```
utimensat(fd, NULL, times, 0);
```

Однако заметим, что обёрточная функция glibc для utimensat() не позволяет передачу NULL в качестве значения pathname — в этом случае возвращается ошибка EINVAL.

## ДЕФЕКТЫ
В ядрах до версии 2.6.26 в utimensat() и futimens() есть несколько дефектов. Эти дефекты приводят к несоответствию с черновиком спецификации POSIX.1 или к рассогласованию со старым поведением в Linux.

- В POSIX.1 определено, что если в одном из значений времени поле tv_nsec содержит значение UTIME_NOW или UTIME_OMIT, то значение соответствующего поля tv_sec должно игнорироваться. Вместо этого требуется, чтобы значение поля tv_sec равнялось 0 (иначе выдаётся ошибка EINVAL).

- Различные дефекты возникают при рассмотрении имеющихся прав и значений: случай, когда у обоих значений поле tv_nsec равно UTIME_NOW, не всегда рассматривается равным указанию в times значения NULL, и случай, когда одно значение tv_nsec равно UTIME_NOW, а другое — UTIME_OMIT, не рассматривается равным указанию в times указателя на массив структур, содержащий произвольные значения времени. В результате в некоторых случаях: а) временные метки файлов могут быть обновлены процессом, который не имеет прав на это; б) временные метки файлов не могут быть обновлены процессом, хотя он имеет на это право; в) в случае ошибки возвращается неправильное значение в errno.

- В POSIX.1 сказано, что процесс имеющий права на запись в файл, для установки временных меток в текущее время может выполнить вызов со значением times равным NULL, или с times, указывающим на массив структур, в котором у обоих значений времени поле tv_nsec равно UTIME_NOW. Однако futimens() вместо этого проверяет права на запись у файлового дескриптора.

## СМОТРИТЕ ТАКЖЕ
chattr(1), touch(1), futimesat(2), openat(2), stat(2), utimes(2), futimes(3), inode(7), path_resolution(7), symlink(7)