keyctl

title: keyctl(2)

text:
# keyctl(2)

## ИМЯ
keyctl - работа с системой управления ключами ядра

## ОБЗОР

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

```
long keyctl(int operation, ...)
/* для прямого вызова через syscall(2): */
#include <asm/unistd.h>
#include <linux/keyctl.h>
#include <unistd.h>
```

```
long syscall(__NR_keyctl, int operation, __kernel_ulong_t arg2,
             __kernel_ulong_t arg3, __kernel_ulong_t arg4,
             __kernel_ulong_t arg5);
```

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

## ОПИСАНИЕ
keyctl() позволяет программам пользовательского пространства выполнять операции с ключами.

Операция, выполняемая keyctl(), определяется значением аргумента operation. Каждая операция обёрнута библиотекой libkeyutils (из пакета keyutils) в отдельную функцию (описаны далее), чтобы компилятор мог выполнять проверку типов.

Возможные значения operation:

KEYCTL_GET_KEYRING_ID (начиная с Linux 2.6.10)

Отобразить идентификатор специального ключа в идентификатор реального ключа для этого процесса.

Эта операция ищет специальный ключ, чей идентификатор указан в arg2 (приводится к key_serial_t). Если специальный ключ найден, то функция возвращает идентификатор соответствующего реального ключа. В аргументе arg2 могут задаваться следующие значения:

KEY_SPEC_THREAD_KEYRING

Связка ключей вызывающей нити. Смотрите thread-keyring(7).

KEY_SPEC_PROCESS_KEYRING

Связка ключей вызывающего процесса. Смотрите process-keyring(7).

KEY_SPEC_SESSION_KEYRING

Связка ключей сеанса вызывающего. Смотрите session-keyring(7).

KEY_SPEC_USER_KEYRING

Связка ключей по UID вызывающего. Смотрите user-keyring(7).

KEY_SPEC_USER_SESSION_KEYRING

Связка ключей по UID сеанса вызывающего. Смотрите user-session-keyring(7).

KEY_SPEC_REQKEY_AUTH_KEY (начиная с Linux 2.6.16)

Ключ авторизации, созданный request_key(2) и переданный процессу, который был создан для генерации ключа. Этот ключ доступен только в программах, подобных request-key(8), которым передаётся ключ авторизации из ядра, и ключ становится недоступен сразу после того, как запрошенный ключ был инициализирован; смотрите request_key(2).

KEY_SPEC_REQUESTOR_KEYRING (начиная с Linux 2.6.29)

Идентификатор связки ключей назначения у request_key(2). Эта связка ключей доступна только в программах, подобных request-key(8), которым передаётся ключ авторизации из ядра, и ключ становится недоступен сразу после того, как запрошенный ключ был инициализирован; смотрите request_key(2).

Если ключ, указанный в arg2, не существует, то дальнейшая работа зависит от значения аргумента arg3 (приводится к int). Если arg3 содержит ненулевое значение, то — если так надлежит делать (например, когда ищется пользовательский, сеанса пользователя или сеансовый) — создаётся новый ключ и функция возвращает его реальный идентификатор. В противном случае, операция завершается ошибкой ENOKEY.

Если в arg2 задан действительный идентификатор ключа и ключ существует, то эта операция просто возвращает идентификатор ключа. Если ключ не существует, то вызов завершается ошибкой ENOKEY.

Чтобы найти ключ вызывающий должен иметь право поиска в связке ключей.

Аргументы arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_get_keyring_ID(3).

KEYCTL_JOIN_SESSION_KEYRING (начиная с Linux 2.6.10)

Заменить связку ключей сеанса этого процесса новой связкой ключей сеанса.

Если arg2 равно NULL, то создаётся анонимная связка ключей с описанием «_ses» и процесс подписывается на эту связку ключей как на свою связку ключей сеанса, вытесняя предыдущую связку ключей сеанса.

В противном случае, arg2 (приводится к char *) считается описанием (именем) связки ключей и происходит следующее:

- Если связка ключей с таким описанием существует, то процесс, если возможно, попытается подписаться на эту связку ключей как на сеансовую; если это невозможно, то возвращается ошибка. Чтобы подписаться на связку ключей, вызывающий должен иметь право поиска в связке ключей.

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

Аргументы arg3, arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_join_session_keyring(3).

KEYCTL_UPDATE (начиная с Linux 2.6.10)

Изменить полезные данные ключа.

В аргументе arg2 (приводится к key_serial_t) указывается идентификатор изменяемого ключа. Аргумент arg3 (приводится к void *) указывает на новые полезные данные, а в аргументе arg4 (приводится к size_t) содержится размер новых полезных данных в байтах.

Чтобы изменить ключ вызывающий должен иметь право записи в ключ, и запись должна поддерживаться типом ключа.

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

Аргумент arg5 игнорируется.

Эта операция доступна в libkeyutils через функцию keyctl_update(3).

KEYCTL_REVOKE (начиная с Linux 2.6.10)

Отозвать ключ с идентификатором из аргумента arg2 (приводится к key_serial_t). Ключ планируется к удалению сборщиком мусора; его больше нельзя найти, и он недоступен для последующих операций. Дальнейшие попытки использования ключа будут приводить к ошибке EKEYREVOKED.

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

Аргументы arg3, arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_revoke(3).

KEYCTL_CHOWN (начиная с Linux 2.6.10)

Изменить владельца (идентификатор пользователя и группы) ключа.

В аргументе arg2 (приводится к key_serial_t) содержится идентификатор ключа. В аргументе arg3 (приводится к uid_t) содержится идентификатор нового пользователя (или -1, если идентификатор пользователя не меняется). В аргументе arg4 (приводится к gid_t) содержится идентификатор новой группы (или -1, если идентификатор группы не меняется).

Ключ должен давать разрешение на изменения атрибута вызывающему.

Для смены на новый UID или новый GID, если вызывающий не является её членом, у вызывающего должен быть мандат CAP_SYS_ADMIN (смотрите capabilities(7)).

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

Аргумент arg5 игнорируется.

Эта операция доступна в libkeyutils через функцию keyctl_chown(3).

KEYCTL_SETPERM (начиная с Linux 2.6.10)

Изменить права ключа с идентификатором из аргумента arg2 (приводится к key_serial_t) на права, указанные в аргументе arg3 (приводится к key_perm_t).

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

Ключ должен давать разрешение на изменения атрибута независимо от мандатов вызывающего.

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

владение (начиная с Linux 2.6.14)

Это право предоставляется процессу, который владеет ключом (прицеплен с возможностью поиска к одной из связок ключей процесса); смотрите keyrings(7).

пользователь

Это право предоставляется процессу, чей UID файловой системы совпадает с UID ключа.

группа

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

остальные

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

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

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

Каждая маска прав имеет размер в восемь бит, но используются только шесть. Доступные права:

просмотр

Позволяет читать атрибуты ключа.

Это право требуется для операции KEYCTL_DESCRIBE.

Биты прав для каждой категории KEY_POS_VIEW, KEY_USR_VIEW, KEY_GRP_VIEW и KEY_OTH_VIEW.

чтение

Позволяет читать полезные данные ключа.

Это право требуется для операции KEYCTL_READ.

Биты прав для каждой категории KEY_POS_READ, KEY_USR_READ, KEY_GRP_READ и KEY_OTH_READ.

запись

Позволяет изменять или добавлять полезные данные ключа. Для связки ключей позволяет добавление и удаление ключей из связки.

Это право требуется для операций KEYCTL_UPDATE, KEYCTL_REVOKE, KEYCTL_CLEAR, KEYCTL_LINK и KEYCTL_UNLINK.

Биты прав для каждой категории KEY_POS_WRITE, KEY_USR_WRITE, KEY_GRP_WRITE и KEY_OTH_WRITE.

поиск

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

Это право требуется для операций KEYCTL_GET_KEYRING_ID, KEYCTL_JOIN_SESSION_KEYRING, KEYCTL_SEARCH и KEYCTL_INVALIDATE.

Биты прав для каждой категории KEY_POS_SEARCH, KEY_USR_SEARCH, KEY_GRP_SEARCH и KEY_OTH_SEARCH.

связь

Позволяет прицеплять ключ или связку ключей.

Это право требуется для операций KEYCTL_LINK и KEYCTL_SESSION_TO_PARENT.

Биты прав для каждой категории KEY_POS_LINK, KEY_USR_LINK, KEY_GRP_LINK и KEY_OTH_LINK.

setattr (начиная с Linux 2.6.15).

Позволяет изменять UID, GID и маску прав ключа.

Это право требуется для операций KEYCTL_REVOKE, KEYCTL_CHOWN и KEYCTL_SETPERM.

Биты прав для каждой категории KEY_POS_SETATTR, KEY_USR_SETATTR, KEY_GRP_SETATTR и KEY_OTH_SETATTR.

Для удобства, следующие макросы определены как маски всех бит прав для каждой пользовательской категории: KEY_POS_ALL, KEY_USR_ALL KEY_GRP_ALL и KEY_OTH_ALL.

Аргументы arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_setperm(3).

KEYCTL_DESCRIBE (начиная с Linux 2.6.10)

Получить строку, описывающую атрибуты указанного ключа.

Описываемый идентификатор ключа задаётся в arg2 (приводится к key_serial_t). Описывающая строка возвращается в буфере, на который указывает arg3 (приводится к char *); в arg4 (приводится к size_t) задаётся размер этого буфера в байтах.

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

Возвращаемая строка оканчивается null и содержит следующую информацию о ключе:

тип;uid;gid;права;описание

Здесь тип и описание являются строками, uid и gid — десятичным числом в виде строки, а права — шестнадцатеричной маской прав. Описывающая строка записывается в следующем формате:

%s;%d;%d;%08x;%s

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

Запись в буфер производится только если arg3 не равно NULL и указанный размер буфера достаточен для описывающей строки (включая конечный байт null). Чтобы понять, что буфер был мал, проверьте, что возвращаемое значение больше arg4.

Аргумент arg5 игнорируется.

Эта операция доступна в libkeyutils через функцию keyctl_describe(3).

KEYCTL_CLEAR

Стереть содержимое связки ключей (т. е., удалить из неё все ключи).

Идентификатор ключа (должен иметь тип связки ключей) задаётся в arg2 (приводится к key_serial_t).

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

Аргументы arg3, arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_clear(3).

KEYCTL_LINK (начиная с Linux 2.6.10)

Прицепить ключ к связке ключей.

Прицепляемый ключ указывается в arg2 (приводится к key_serial_t); связка ключей указывается в arg3 (приводится к key_serial_t).

Если ключ с тем же типом и описанием уже прицеплен к связке ключей, то этот ключ отцепляется от связки ключей.

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

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

Аргументы arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_link(3).

KEYCTL_UNLINK (начиная с Linux 2.6.10)

Отцепить ключ от связки ключей.

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

Если ключ не прицеплен к связке ключей, то возвращается ошибка.

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

Если удаляется последняя ссылка на ключ, то этот ключ планируется к уничтожению.

Аргументы arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_unlink(3).

KEYCTL_SEARCH (начиная с Linux 2.6.10)

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

Идентификатор начала дерева ключей, в котором производится поиск, задаётся в arg2 (приводится к key_serial_t). Поиск выполняется сначала вширь и рекурсивно.

В аргументах arg3 и arg4 задаётся искомый ключ: в arg3 (приводится к char *) содержится тип ключа (строка символов длиной до 32 байт с учётом конечного байта null), а в arg4 (приводится к char *) содержится описание ключа (строка символов до 4096 байт с учётом конечного байта null).

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

Если ключ найден, то его идентификатор возвращается как результат функции.

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

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

Эта операция доступна в libkeyutils через функцию keyctl_search(3).

KEYCTL_READ (начиная с Linux 2.6.10)

Прочитать полезные данные ключа.

Идентификатор ключа, из которого читаются полезные данные, задаётся в arg2 (приводится к key_serial_t). Это может быть идентификатор существующего ключа или любой специальный идентификатор ключа, описанный в KEYCTL_GET_KEYRING_ID.

Полезные данные помещаются в буфер, указываемый в arg3 (приводится к char *); размер буфера должен быть указан в arg4 (приводится к size_t).

Возвращаемые данные будут обработаны для представления согласно типу ключа. Например, связка ключей будет возвращена как массив элементов key_serial_t, представляющих идентификаторы всех ключей связки. Данные типа ключа user будут возвращены как есть. Если для типа ключа эта функция не реализована, то операция завершается ошибкой EOPNOTSUPP.

Если arg3 не равно NULL, то копируется столько полезных данных сколько вмещается в буфер. При успешном выполнении возвращаемое значение всегда равно полному размеру полезных данных. Чтобы удостовериться что буфер был достаточного размера, убедитесь, что возвращаемое значение меньше или равно значению, указанному в arg4.

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

Аргумент arg5 игнорируется.

Эта операция доступна в libkeyutils через функцию keyctl_read(3).

KEYCTL_INSTANTIATE (начиная с Linux 2.6.10)

Положительно инициализировать неинициализированный ключ заданными полезными данными.

Идентификатор инициализированного ключа задаётся в arg2 (приводится к key_serial_t).

Полезные данные ключа задаются в буфере, указанном в arg3 (приводится к void *); размер буфера задаётся в arg4 (приводится к size_t).

Ссылка на полезные данные может быть равна NULL и размер буфера может равняться 0, если это поддерживается типом ключа (например, если это связка ключей).

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

Если arg5 (приводится к key_serial_t) не равно нулю, то с теми же ограничениями и правилами как у KEYCTL_LINK инициализированный ключ прицепляется в связку ключей, идентификатор которой указан в arg5.

Вызывающий должен иметь соответствующий ключ авторизации и после инициализации ключа ключ авторизации отзывается. Иначе говоря, эта операция доступна только из программ, подобных request-key(8). В request_key(2) смотрите описание неинициализированных ключей и их инициализацию.

Эта операция доступна в libkeyutils через функцию keyctl_instantiate(3).

KEYCTL_NEGATE (начиная с Linux 2.6.10)

Отрицательно инициализировать неинициализированный ключ.

Данная операция эквивалентен вызову:

keyctl(KEYCTL_REJECT, arg2, arg3, ENOKEY, arg4);

Аргумент arg5 игнорируется.

Эта операция доступна в libkeyutils через функцию keyctl_negate(3).

KEYCTL_SET_REQKEY_KEYRING (начиная с Linux 2.6.13)

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

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

KEY_REQKEY_DEFL_NO_CHANGE

Не изменять связку ключей по умолчанию. Используется для определения текущей связки ключей по умолчанию (без её изменения).

KEY_REQKEY_DEFL_DEFAULT

Применить действие по умолчанию, то есть использовать связку ключей, привязанную к нити, если есть, в противном случае привязанную к процессу, если есть, иначе привязанную к сеансу, если есть, иначе привязанную к сеансу UID, иначе привязанную к пользователю.

KEY_REQKEY_DEFL_THREAD_KEYRING

В качестве новой связки ключей по умолчанию использовать связку ключей нити (thread-keyring(7)).

KEY_REQKEY_DEFL_PROCESS_KEYRING

В качестве новой связки ключей по умолчанию использовать связку ключей процесса (process-keyring(7)).

KEY_REQKEY_DEFL_SESSION_KEYRING

В качестве новой связки ключей по умолчанию использовать связку ключей сеанса (session-keyring(7)).

KEY_REQKEY_DEFL_USER_KEYRING

В качестве новой связки ключей по умолчанию использовать связку ключей UID (user-keyring(7)).

KEY_REQKEY_DEFL_USER_SESSION_KEYRING

В качестве новой связки ключей по умолчанию использовать связку ключей UID сеанса (user-session-keyring(7)).

KEY_REQKEY_DEFL_REQUESTOR_KEYRING (начиная с Linux 2.6.29)

Использовать связку ключей запрашивающего.

Любые другие значения недопустимы.

Аргументы arg3, arg4 и arg5 игнорируются.

Параметр, контролируемый данной операцией, наследуется потомком при fork(2) и сохраняется при execve(2).

Эта операция доступна в libkeyutils через функцию keyctl_set_reqkey_keyring(3).

KEYCTL_SET_TIMEOUT (начиная с Linux 2.6.16)

Назначить время ожидания ключа.

Идентификатор ключа задаётся в arg2 (приводится к key_serial_t). Время ожидания в секундах отсчитывается от текущего времени и задаётся в arg3 (приводится к unsigned int). Время ожидания изменяется по часам реального времени.

Значение времени ожидания 0 очищается существующее ожидание ключа.

В файле /proc/keys показывается оставшееся время до момента просрочки каждого ключа (это единственной способ узнать время ожидания ключа).

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

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

Данную операцию невозможно применить для задания ожидания отозванного, просроченного или отрицательно инициализированного ключа.

Аргументы arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_set_timeout(3).

KEYCTL_ASSUME_AUTHORITY (начиная с Linux 2.6.16)

Выдать (или отозвать) право вызывающей нити на инициализацию ключа.

В аргументе arg2 (приводится к key_serial_t) указывается ненулевое идентификатор ключа для выдачи права допуска или 0 для отмены права допуска.

Если arg2 не равно нулю, то будет выдано право допуска к указанному идентификатору неинициализированного ключа. Далее этот ключ может быть инициализирован посредством операций KEYCTL_INSTANTIATE, KEYCTL_INSTANTIATE_IOV, KEYCTL_REJECT или KEYCTL_NEGATE. После инициализации ключа, у нити автоматически отменяется право доступа для инициализации ключа.

Право доступа на ключ может быть выдано только, если вызывающая нить содержит в своих связках ключей ключ авторизации, который связан с указанным ключом (иначе говоря, операция KEYCTL_ASSUME_AUTHORITY доступна только из программ, подобных request-key(8); в request_key(2) смотрите описание как используется эта операция). Вызывающий должен иметь право поиска ключа авторизации.

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

Если идентификатор в arg2 равен 0, то имеющееся в настоящее время право выдачи очищается (отменяется и возвращается 0.

Механизм KEYCTL_ASSUME_AUTHORITY позволяет программе, такой как request-key(8) выдать необходимые права для инициализации нового неинициализированного ключа, который был создан предшествующим вызовом request_key(2). Дополнительную информацию смотрите в request_key(2) и в файле исходного кода ядра Documentation/security/keys-request-key.txt.

Аргументы arg3, arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_assume_authority(3).

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

Получить метку безопасности LSM (модуль безопасности Linux) указанного ключа.

В arg2 (приводится к key_serial_t) задаётся идентификатор ключа, чью метку безопасности нужно получить. Метка безопасности (завершается байтом null) будет помещена в буфер, указанный в аргументе arg3 (приводится к char *); размер буфера должен быть указан в arg4 (приводится к size_t).

Если arg3 равно NULL или размер буфера, указанный в arg4, мал, то в качестве результата функции возвращается полный размер строки метки безопасности (включая конечный байт null) и в буфер ничего не копируется.

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

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

unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Если в данный момент LSM не работает, то в буфер помещается пустая строка.

Аргумент arg5 игнорируется.

Эта операция доступна в libkeyutils через функции keyctl_get_security(3) и keyctl_get_security_alloc(3).

KEYCTL_SESSION_TO_PARENT (начиная с Linux 2.6.32)

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

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

Связка ключей должна существовать и позволять вызывающему выполнять сцепку. Родительский процесс должен быть с одной нитью и иметь те же действующие права как этот процесс и не быть set-user-ID или set-group-ID. UID связки ключей сеанса родительского процесса (если есть), а также UID связки ключей сеанса вызывающего должны совпадать с действующим UID вызывающего.

Факт того, что эта операция затрагивает родительский процесс, позволяет программе, такой как оболочка, запускать дочерний процесс, который с помощью этой операции изменит связку ключей сеанса оболочки (это то, что делает команда new_session keyctl(1)).

Аргументы arg2, arg3, arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_session_to_parent(3).

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

Пометить ключ как отрицательно инициализированный и задать таймер действия ключа. Эта операция предоставляет собой надмножество возможности операции KEYCTL_NEGATE, представленной ранее.

Идентификатор отрицательно инициализируемого ключа указывается в arg2 (приводится к key_serial_t). В arg3 (приводится к unsigned int) указывается срок жизни ключа в секундах. В arg4 (приводится к unsigned int) указывается ошибка, возвращаемая при нахождении этого ключа — обычно равно EKEYREJECTED, EKEYREVOKED или EKEYEXPIRED.

Если arg5 (приводится к key_serial_t) не равно нулю, то с теми же ограничениями и правилами как у KEYCTL_LINK отрицательно инициализированный ключ прицепляется в связку ключей, идентификатор которой указан в arg5.

Вызывающий должен иметь соответствующий ключ авторизации. Иначе говоря, эта операция доступна только из программ, подобных request-key(8). Смотрите request_key(2).

Вызывающий должен иметь соответствующий ключ авторизации и после инициализации ключа ключ авторизации отзывается. Иначе говоря, эта операция доступна только из программ, подобных request-key(8). В request_key(2) смотрите описание неинициализированных ключей и их инициализацию.

Эта операция доступна в libkeyutils через функцию keyctl_reject(3).

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

Инициализировать неинициализированный ключ заданными полезными данными, указанными в векторе буферов.

Эта операция подобна KEYCTL_INSTANTIATE, но полезные данные указываются в виде массива структур iovec:

```
struct iovec {

    void  *iov_base;    /* начальный адрес буфера */

    size_t iov_len;     /* размер буфера (в байтах) */
};

```

Указатель на вектор полезных данных передаётся в arg3 (приводится к const struct iovec *). Количество элементов в векторе задаётся в arg4 (приводится к unsigned int).

Значение аргумента arg2 (идентификатор ключа) и arg5 (идентификатор связки ключей) рассматриваются также как у KEYCTL_INSTANTIATE.

Эта операция доступна в libkeyutils через функцию keyctl_instantiate_iov(3).

KEYCTL_INVALIDATE (начиная с Linux 3.5)

Пометить ключ как недействительный.

Идентификатор ключа, отмечаемого недействительным, задаётся в arg2 (приводится к key_serial_t).

Чтобы сделать ключ недействительным, вызывающий должен иметь на ключ право поиска.

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

Ключи, помеченный как недействительные, сразу становятся невидимыми для обычных операций с ключами, хотя их видно в /proc/keys (отмечены флагом «i») до действительного удаления.

Аргументы arg3, arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_invalidate(3).

KEYCTL_GET_PERSISTENT (начиная с Linux 3.13)

Получить постоянную связку ключей (persistent-keyring(7)) заданного пользователя и прицепить её к указанную связку ключей.

Идентификатор пользователя указывается в arg2 (приводится к uid_t). Если указано значение -1, то используется реальный идентификатор пользователя вызывающего. Идентификатор связки ключей назначения указывается в arg3 (приводится к key_serial_t).

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

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

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

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

Каждый раз при выполнении операции KEYCTL_GET_PERSISTENT срок действия постоянной связки ключей сбрасывается в значение:

```
/proc/sys/kernel/keys/persistent_keyring_expiry

```

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

Постоянные связки ключей были добавлены в ядро Linux версии 3.13.

Аргументы arg4 и arg5 игнорируются.

Эта операция доступна в libkeyutils через функцию keyctl_get_persistent(3).

KEYCTL_DH_COMPUTE (начиная с Linux 4.7)

Вычислить открытый и закрытый ключ Диффи-Хеллмана, возможно применяя к результату функцию формирования ключа (key derivation function, KDF).

В аргументе arg2 передаётся указатель на набор параметров, содержащих серийные номера трёх ключей "user", используемых в вычислении Диффи-Хеллмана, упакованных в следующую структуру:

```
struct keyctl_dh_params {

    int32_t private; /* локальный закрытый ключ */

    int32_t prime; /* основание, известное обеим сторонам */

    int32_t base;  /* базовое целое: из общего генератора

                      или из открытого ключа удалённой стороны */
};

```

Для каждого из трёх указанных в структуре ключей у вызывающего должно быть право на чтение. Полезные данные этих ключей используются для вычисления результата Диффи-Хеллмана по формуле:

база ^ закрытый mod основание

Если база это общий генератор, то результатом будет локальный открытый ключ. Если база это открытый ключ удалённой стороны, то результатом будет общий закрытый ключ.

Аргумент arg3 (приводится к char *) указывает на буфер, в который помещается результат вычисления. Размер буфера задаётся в arg4 (приводится к size_t).

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

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

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

Если аргумент arg5 равен NULL, то возвращается сам результат DH. В противном случае (начиная с Linux 4.12), значение равно указателю на структуру, в которой задаются параметры для применения в операции KDF:

```
struct keyctl_kdf_params {

    char *hashname;     /* имя алгоритма хэширования */

    char *otherinfo;    /* SP800-56A OtherInfo */

    __u32 otherinfolen; /* размер данных otherinfo */

    __u32 __spare[8];   /* зарезервировано */
};

```

В поле hashname содержится строка, завершающаяся null, которой задаётся имя хэша (доступно в программном интерфейсе шифрования ядра; список хэшей сложно описать; в файле «Kernel Crypto API Architecture» можно найти как компонуются имена хэшей из алгоритмов шифрования и шаблонов с типом CRYPTO_ALG_TYPE_SHASH с учётом доступного исходного кода ядра и настроек) для применения к результату DH в операции KDF.

Поле otherinfo содержит данные OtherInfo, описанные в SP800-56A, раздел 5.8.1.2, зависящие от алгоритма. Эти данные объединяются с результатом операции DH и предоставляются как входные операции KDF. Его размер указывается в поле otherinfolen и ограничивается константой KEYCTL_KDF_MAX_OI_LEN, которая определена в security/keys/internal.h и равна 64.

Поле __spare в настоящее время не используется. Оно игнорировалось до Linux 4.13 (но всё равно доступно из пользовательского пространства, так как копируется в ядро), и, начиная с Linux 4.13, должно содержать нули.

Реализация KDF соответствует SP800-56A, а также SP800-108 (счётчик KDF).

Эта операция доступна в libkeyutils (начиная с версии 1.5.10) через функции keyctl_dh_compute(3) и keyctl_dh_compute_alloc(3).

KEYCTL_RESTRICT_KEYRING (начиная с Linux 4.12)

Применить ограничение прицепить ключ к связке ключей с идентификатором, указанном в arg2 (приводится к типу key_serial_t). Вызывающий должен иметь право setattr на ключ. Если arg3 равно NULL, то все попытки добавить ключ в связку ключей блокируются; в противном случае он содержит указатель на строку с именем типа ключа, а в аргументе arg4 содержится указатель на строку, описывающую ограничения, присущие типу. В Linux 4.12 из ограничений определено только «asymmetric»:

builtin_trusted

Позволить прицеплять во встроенную связку ключей («.builtin_trusted_keys») только ключи, которые подписаны ключом.

builtin_and_secondary_trusted

Позволить прицеплять во вторичную связку ключей («.secondary_trusted_keys») только ключи, которые подписаны ключом, или как расширение, ключ во встроенную связку ключей, поскольку последний присоединен с первой.

ключ_или_связка:ключ

ключ_или_связка:ключ:chain

Если ключ задан идентификатором ключа типа «asymmetric», то разрешены только ключи, подписанные этим ключом.

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

Если указана «:chain» то разрешены ключи, которые подписаны ключами из связки назначения (то есть, связки ключей с идентификатором из аргумента arg2).

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

Аргумент arg5 игнорируется.

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

KEYCTL_GET_KEYRING_ID

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

KEYCTL_JOIN_SESSION_KEYRING

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

KEYCTL_DESCRIBE

Размер описания (включая конечный байт null), безотносительно к указанному размеру буфера.

KEYCTL_SEARCH

Идентификатор найденного ключа.

KEYCTL_READ

Количество данных, доступных из ключа, безотносительно к указанному размеру буфера.

KEYCTL_SET_REQKEY_KEYRING

Идентификатор предыдущей связки ключе по умолчанию, в которую неявно цепляются запрашиваемые ключи (одна из KEY_REQKEY_DEFL_USER_*).

KEYCTL_ASSUME_AUTHORITY

Равно 0, если был указан идентификатор равный 0, или идентификатор ключа авторизации, совпадающий с указанным ключом, если указан ненулевой идентификатор ключа.

KEYCTL_GET_SECURITY

Размер описания строки метки безопасности LSM (включая конечный байт null), безотносительно к указанному размеру буфера.

KEYCTL_GET_PERSISTENT

Идентификатор постоянной связки ключей.

KEYCTL_DH_COMPUTE

Количество байт, скопированных в буфер, или требуемый размер буфера, если arg4 равно 0.

Остальные операции

Ноль.

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

## ОШИБКИ
EACCES

Запрошенная операция не разрешена.

EAGAIN

Значение operation равно KEYCTL_DH_COMPUTE и при инициализации модуля шифрования возникла ошибка.

EDEADLK

Значение operation равно KEYCTL_LINK и запрошенная связь привела бы зацикливанию.

EDEADLK

Значение operation равно KEYCTL_RESTRICT_KEYRING и запрошенная связь привела бы зацикливанию.

EDQUOT

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

EEXIST

Значение operation равно KEYCTL_RESTRICT_KEYRING и связка ключей из аргумента arg2 уже содержит набор ограничений.

EFAULT

Значение operation равно KEYCTL_DH_COMPUTE и возникла ошибки в одной из следующих операций:

- копирования struct keyctl_dh_params, указанном в аргументе arg2,из пользовательского пространства

- копирования struct keyctl_kdf_params, указанном в аргументе arg5 не равном NULL,из пользовательского пространства (случай, когда ядро поддерживает выполнение операции KDF над результатом операции DH)

- копирования данные, указанных в поле hashname с типом struct keyctl_kdf_params из пользовательского пространства

- копирования данные, указанных в поле otherinfo с типом struct keyctl_kdf_params из пользовательского пространства и поле otherinfolen не равно нулю

- копирования результата в пользовательское пространство

EINVAL

Значение operation равно KEYCTL_SETPERM и в arg3 указан неверный бит прав.

EINVAL

Значение operation равно KEYCTL_SEARCH и размер описания в arg4 (включая конечный байт null) превышает 4096 байт. Размер строки (включая конечный байт null), указанный в arg3 (тип ключа) или arg4 (описание ключа) превышает ограничение (32 байта и 4096 байта, соответственно).

EINVAL (ядра Linux до 4.12)

Значение operation равно KEYCTL_DH_COMPUTE и аргумент arg5 не равен NULL.

EINVAL

Значение operation равно KEYCTL_DH_COMPUTE и указанный размер свёртки алгоритма хэширования равен нулю.

EINVAL

Значение operation равно KEYCTL_DH_COMPUTE, но указанный размер буфера недостаточен для размещения результата. Укажите 0 в качестве размера буфера, чтобы получить минимальный размер буфера.

EINVAL

Значение operation равно KEYCTL_DH_COMPUTE и указанное имя хэша в поле hashname структуры struct keyctl_kdf_params, на которую указывает аргумент arg5, слишком велико (ограничение зависит от реализации и различно в разных версиях ядра, но считается достаточно большим для всех допустимых имён алгоритмов).

EINVAL

Значение operation равно KEYCTL_DH_COMPUTE и поле __spare структуры struct keyctl_kdf_params, на которую указывает аргумент arg5, содержит ненулевое значение.

EKEYEXPIRED

Найден или указан просроченный ключ.

EKEYREJECTED

Найден или указан отклонённый (rejected) ключ.

EKEYREVOKED

Найден или указан отозванный ключ.

ELOOP

Значение operation равно KEYCTL_LINK и запрошенная связь привела бы к превышению количества вложенных друг в друга связок ключей.

EMSGSIZE

Значение operation равно KEYCTL_DH_COMPUTE и длина буфера превышает KEYCTL_KDF_MAX_OUTPUT_LEN (в данный момент равна 1024) или поле otherinfolen структуры struct keyctl_kdf_parms, переданной в arg5, превышает KEYCTL_KDF_MAX_OI_LEN (в данный момент равно 64).

ENFILE (ядра Linux до 3.13)

Значение operation равно KEYCTL_LINK и связка ключей заполнена (до Linux 3.13 доступное место для хранения связей связки ключей было ограничено одной страницей памяти; начиная с Linux 3.13 жёсткого ограничения нет).

ENOENT

Значение operation равно KEYCTL_UNLINK и отцепляемый ключ не прицеплен к связке ключей.

ENOENT

Значение operation равно KEYCTL_DH_COMPUTE и алгоритм хэширования, указанный в поле hashname структуры struct keyctl_kdf_params, на которую указывает аргумент arg5, не найден.

ENOENT

Значение operation равно KEYCTL_RESTRICT_KEYRING и тип из аргумента arg3 не поддерживает ограничения установленным ключом сцепления.

ENOKEY

Искомый ключ не найден или указан неверный ключ.

ENOKEY

Значение operation равно KEYCTL_GET_KEYRING_ID, ключ, указанный arg2, не существует и значение arg3 равно нулю (то есть, не создавать ключ, если он не существует).

ENOMEM

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

ENOTDIR

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

EOPNOTSUPP

Значение operation равно KEYCTL_READ и тип ключа не поддерживает чтение (например, тип "login").

EOPNOTSUPP

Значение operation равно KEYCTL_UPDATE и тип ключа не поддерживает обновление.

EOPNOTSUPP

Значение operation равно KEYCTL_RESTRICT_KEYRING, тип из аргумента arg3 равен «asymmetric» и ключ, указанный в определении ограничения, предоставляемый аргументом arg4, имеет тип не «asymmetric» или «keyring».

EPERM

Значение operation равно KEYCTL_GET_PERSISTENT, в arg2 указан UID, отличающийся от реального или действующего UID вызывающей нити, и вызывающий не имеет мандата CAP_SETUID.

EPERM

Значение operation равно KEYCTL_SESSION_TO_PARENT и: не один из UID (GID) родительского процесса не совпадают с действующим UID (GID) вызывающего процесса; UID существующей связки ключей сеанса родителя или UID связки ключей сеанса вызывающего не совпадает с действующим UID вызывающего; родительский процесс состоит из нескольких нитей; родительский процесс это init(1) или нить ядра.

ETIMEDOUT

Значение operation равно KEYCTL_DH_COMPUTE и истёк срок инициализации модулей шифрования.

## ВЕРСИИ
Этот системный вызов впервые появился в Linux 2.6.10.

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

## ЗАМЕЧАНИЯ
Для этого системного вызова нет обёрточной функции в glibc. Обёрточная функция предоставляется библиотекой libkeyutils. Для вызова нужно выполнить компоновку с библиотекой, указав -lkeyutils. Несмотря на то, что можно вызывать системные вызова напрямую, для выполнения отдельных операций, вероятно, лучше использовать различные библиотечные функции, описанные выше.

## ПРИМЕР
Программа, показанная далее, предоставляет сокращённый набор возможностей программы request-key(8) из пакета keyutils. Для информирования программа записывает различные данные в файл журнала.

Согласно request_key(2), программа request-key(8) вызывается с аргументами командной строки, которые описывают инициализируемый ключ. Программа из примера запрашивает и протоколирует эти аргументы. Программа авторизует на инициализацию запрашиваемого ключа и затем инициализирует этот ключ.

Следующий сеанс оболочки показывает использование этой программы. В сеансе мы компилируем программу, а затем используем её как временную замены стандартной программы request-key(8) (заметим, что временное отключение стандартной программы request-key(8) может быть небезопасно на некоторых системах). После того, как наша программа установлена, мы показываем её работу с request_key(2) для запроса ключа.

```
$ cc -o key_instantiate key_instantiate.c -lkeyutils
$ sudo mv /sbin/request-key /sbin/request-key.backup
$ sudo cp key_instantiate /sbin/request-key
$ ./t_request_key user mykey somepayloaddata
Идентификатор ключа равен 20d035bf
$ sudo mv /sbin/request-key.backup /sbin/request-key
```

Заглянув в файл журнала, созданный программой, мы увидим аргументы командной строки, переданные нашей программе:

```
$ cat /tmp/key_instantiate.log
Время: Mon Nov  7 13:06:47 2016
Аргументы командной строки:

  argv[0]:            /sbin/request-key

  operation:          create

  key_to_instantiate: 20d035bf

  UID:                1000

  GID:                1000

  thread_keyring:     0

  process_keyring:    0

  session_keyring:    256e6a6
Описание ключа:      user;1000;1000;3f010000;mykey
Полезные данные ключа авторизации:     somepayloaddata
Связка ключей назначения:  256e6a6
Описание ключа авторизации: .request_key_auth;1000;1000;0b010000;20d035bf
```

Последние несколько строк вывода показывают, что программа смогла получить:

- описание инициализируемого ключа, которое содержит имя ключа (mykey);

- полезные данные ключа авторизации, которые содержат данные (somepayloaddata), переданные в request_key(2);

- связку ключей назначения, которая была указана в вызове request_key(2); и

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

Пример программы в request_key(2) задаёт связку ключей назначения как KEY_SPEC_SESSION_KEYRING. Просмотрев содержимое /proc/keys, мы можем увидеть, что он транслировался в идентификатор связки ключей назначения (0256e6a6), показанный в журнале выше; мы также может увидеть только что созданный ключ с именем mykey и идентификатором 20d035bf.

```
$ cat /proc/keys | egrep 'mykey|256e6a6'
0256e6a6 I--Q---  194 perm 3f030000  1000  1000 keyring  _ses: 3
20d035bf I--Q---    1 perm 3f010000  1000  1000 user     mykey: 16
```

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

```
/* key_instantiate.c */
#include <sys/types.h>
#include <keyutils.h>
#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#ifndef KEY_SPEC_REQUESTOR_KEYRING
#define KEY_SPEC_REQUESTOR_KEYRING      -8
#endif
int
main(int argc, char *argv[])
{

    FILE *fp;

    time_t t;

    char *operation;

    key_serial_t key_to_instantiate, dest_keyring;

    key_serial_t thread_keyring, process_keyring, session_keyring;

    uid_t uid;

    gid_t gid;

    char dbuf[256];

    char auth_key_payload[256];

    int akp_size;       /* размер auth_key_payload */

    fp = fopen("/tmp/key_instantiate.log", "w");

    if (fp == NULL)

        exit(EXIT_FAILURE);

    setbuf(fp, NULL);

    t = time(NULL);

    fprintf(fp, "Время: %s\n", ctime(&t));

    /*

     * ядро передаёт постоянный набор аргументов в программу,

     * которую выполняет execs; получаем их.

     */

    operation = argv[1];

    key_to_instantiate = atoi(argv[2]);

    uid = atoi(argv[3]);

    gid = atoi(argv[4]);

    thread_keyring = atoi(argv[5]);

    process_keyring = atoi(argv[6]);

    session_keyring = atoi(argv[7]);

    fprintf(fp, "Аргументы командной строки:\n");

    fprintf(fp, "  argv[0]:            %s\n", argv[0]);

    fprintf(fp, "  operation:          %s\n", operation);

    fprintf(fp, "  key_to_instantiate: %lx\n",

            (long) key_to_instantiate);

    fprintf(fp, "  UID:                %ld\n", (long) uid);

    fprintf(fp, "  GID:                %ld\n", (long) gid);

    fprintf(fp, "  thread_keyring:     %lx\n", (long) thread_keyring);

    fprintf(fp, "  process_keyring:    %lx\n", (long) process_keyring);

    fprintf(fp, "  session_keyring:    %lx\n", (long) session_keyring);

    fprintf(fp, "\n");

    /*

     * выдаём право на инициализацию ключа с именем в argv[2]

     */

    if (keyctl(KEYCTL_ASSUME_AUTHORITY, key_to_instantiate) == -1) {

        fprintf(fp, "Ошибка KEYCTL_ASSUME_AUTHORITY: %s\n",

                strerror(errno));

        exit(EXIT_FAILURE);

    }

    /*

     * получаем описание ключа, который был инициализирован

     */

    if (keyctl(KEYCTL_DESCRIBE, key_to_instantiate,

                dbuf, sizeof(dbuf)) == -1) {

        fprintf(fp, "Ошибка KEYCTL_DESCRIBE: %s\n", strerror(errno));

        exit(EXIT_FAILURE);

    }

    fprintf(fp, "Описание ключа:      %s\n", dbuf);

    /*

     * получаем полезные данные ключа авторизации, который

     * в действительности содержит данные, переданные в request_key()

     */

    akp_size = keyctl(KEYCTL_READ, KEY_SPEC_REQKEY_AUTH_KEY,

                      auth_key_payload, sizeof(auth_key_payload));

    if (akp_size == -1) {

        fprintf(fp, "Ошибка KEYCTL_READ: %s\n", strerror(errno));

        exit(EXIT_FAILURE);

    }

    auth_key_payload[akp_size] = '\0';

    fprintf(fp, "Полезные данные ключа авторизации:     %s\n", auth_key_payload);

    /*

     * из любопытства, получим идентификатор ключа авторизации и

     * выведем его.

     */

    auth_key = keyctl(KEYCTL_GET_KEYRING_ID,

            KEY_SPEC_REQKEY_AUTH_KEY);

    if (auth_key == -1) {

        fprintf(fp, "Ошибка KEYCTL_GET_KEYRING_ID: %s\n",

                strerror(errno));

        exit(EXIT_FAILURE);

    }

    fprintf(fp, "Идентификатор ключа авторизации:          %lx\n", (long) auth_key);

    /*

     * получим идентификатор ключа связки ключей назначения request_key(2).

     */

    dest_keyring = keyctl(KEYCTL_GET_KEYRING_ID,

                          KEY_SPEC_REQUESTOR_KEYRING);

    if (dest_keyring == -1) {

        fprintf(fp, "Ошибка KEYCTL_GET_KEYRING_ID: %s\n",

                strerror(errno));

        exit(EXIT_FAILURE);

    }

    fprintf(fp, "Связка ключей назначения:  %lx\n", (long) dest_keyring);

    /*

     * получим описание ключа авторизации. Это

     * позволит увидеть тип ключа, UID, GID, права,

     * и описание (имя) ключа. Среди прочего,

     * мы увидим, что имя ключа представляет шестнадцатеричную

     * строку идентификатора инициализированного ключа.

     */

    if (keyctl(KEYCTL_DESCRIBE, KEY_SPEC_REQKEY_AUTH_KEY,

                dbuf, sizeof(dbuf)) == -1) {

        fprintf(fp, "Ошибка KEYCTL_DESCRIBE: %s\n", strerror(errno));

        exit(EXIT_FAILURE);

    }

    fprintf(fp, "Описание ключа авторизации: %s\n", dbuf);

    /*

     * Инициализируем ключ с помощью переданных данных из

     * полезной нагрузки ключа авторизации.

     */

    if (keyctl(KEYCTL_INSTANTIATE, key_to_instantiate,

               auth_key_payload, akp_size + 1, dest_keyring) == -1) {

        fprintf(fp, "Ошибка KEYCTL_INSTANTIATE: %s\n",

                strerror(errno));

        exit(EXIT_FAILURE);

    }

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
keyctl(1), add_key(2), request_key(2), keyctl(3), keyctl_assume_authority(3), keyctl_chown(3), keyctl_clear(3), keyctl_describe(3), keyctl_describe_alloc(3), keyctl_dh_compute(3), keyctl_dh_compute_alloc(3), keyctl_get_keyring_ID(3), keyctl_get_persistent(3), keyctl_get_security(3), keyctl_get_security_alloc(3), keyctl_instantiate(3), keyctl_instantiate_iov(3), keyctl_invalidate(3), keyctl_join_session_keyring(3), keyctl_link(3), keyctl_negate(3), keyctl_read(3), keyctl_read_alloc(3), keyctl_reject(3), keyctl_revoke(3), keyctl_search(3), keyctl_session_to_parent(3), keyctl_set_reqkey_keyring(3), keyctl_set_timeout(3), keyctl_setperm(3), keyctl_unlink(3), keyctl_update(3), recursive_key_scan(3), recursive_session_key_scan(3), capabilities(7), credentials(7), keyrings(7), keyutils(7), persistent-keyring(7), process-keyring(7), session-keyring(7), thread-keyring(7), user-keyring(7), user_namespaces(7), user-session-keyring(7), request-key(8)

Файл из дерева исходного кода ядра Documentation/security/keys/ (до Linux 4.13 — Documentation/security/keys.txt).


kill

package: man-pages-ru

title: kill(2)

summary: послать сигнал процессу

text:
# kill(2)

## ИМЯ
kill - послать сигнал процессу

## ОБЗОР

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

```
int kill(pid_t pid, int sig);
```

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

kill(): _POSIX_C_SOURCE

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

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

Если значение pid равно 0, то sig посылается каждому процессу, который входит в группу вызывающего процесса.

Если значение pid равно -1, то sig посылается каждому процессу, которым вызывающий процесс имеет право отправлять сигналы, за исключением процесса с номером 1 (init), подробности смотрите далее.

Если значение pid меньше -1, то sig посылается каждому процессу, который входит в группу процессов, чей ID равен -pid.

Если значение sig равно 0, то никакой сигнал не посылается, но выполняется проверка существования и права; это можно использовать для проверки существования процесса или группы процессов с заданным ID и допустимости отправки сигнала вызывающим.

Чтобы процесс мог посылать сигнал, он должен быть привилегированным (в Linux: иметь мандат CAP_KILL в пользовательском пространстве имён процесса назначения), либо реальный или эффективный идентификатор пользователя посылающего процесса должен быть равен реальному или сохранённому идентификатору пользователя процесса, которому отправляется сигнал. Для сигнала SIGCONT посылающий и получающий процессы должны принадлежать одному сеансу (сложилось исторически; правила разные; смотрите ЗАМЕЧАНИЯ).

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

## ОШИБКИ
EINVAL

Указан некорректный сигнал.

EPERM

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

ESRCH

Процесс-получатель или группа процессов не существует. Заметим, что существующий процесс может быть в состоянии зомби — процесс, завершивший выполнение, но которого ещё не дождались с помощью wait(2).

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

## ЗАМЕЧАНИЯ
Процессу init с идентификатором 1 можно послать только те сигналы, для которых он явно установил обработчики сигналов. Так сделано, чтобы быть уверенным, что в случае какой-либо нештатной ситуации работа системы не будет завершена аварийно.

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

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

### Замечания, касающиеся Linux
В различных версиях ядра Linux применяются разные правила, касающиеся прав доступа, которые требуются для непривилегированного процесса, чтобы посылать сигнал другому процессу. В ядрах с 1.0 по 1.2.2 сигнал может быть послан, если эффективный идентификатор пользователя отправителя совпадает с эффективным идентификатором пользователя цели или реальный идентификатор пользователя отправителя совпадает с реальным идентификатором пользователя цели. В ядрах с версии 1.2.3 по 1.3.77 сигнал может быть послан, если эффективный идентификатор пользователя отправителя совпадает или с реальным или с эффективным идентификатором пользователя цели. Текущие правила, которые соответствуют стандартам POSIX.1, были введены, начиная с ядра версии 1.3.78.

## ДЕФЕКТЫ
В ядрах 2.6 до 2.6.7 включительно есть дефект: когда посылаются сигналы группе процессов, вызов kill() завершается с ошибкой EPERM, если вызывающий не имеет право посылать сигнал любому (но не всем) члену группы процессов. Хотя возвращается ошибка, сигнал всё равно доставляется всем процессам, которым вызывающий имеет право послать сигнал.

## СМОТРИТЕ ТАКЖЕ
kill(1), _exit(2), signal(2), tkill(2), exit(3), killpg(3), sigqueue(3), capabilities(7), credentials(7), signal(7)

branch: sisyphus


link

title: link(2)

summary: создаёт новое имя файла

text:
# link(2)

## ИМЯ
link, linkat - создаёт новое имя файла

## ОБЗОР

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

```
int link(const char *oldpath, const char *newpath);
```

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

```
int linkat(int olddirfd, const char *oldpath,
           int newdirfd, const char *newpath, int flags);
```

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

linkat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

## ОПИСАНИЕ
link() создаёт новую ссылку (также называемую жёсткую ссылку) на существующий файл.

Если newpath существует, то он не будет перезаписан.

Это новое имя может использоваться как и старое для любых операций; оба имени ссылаются на один файл (и имеют одинаковые права и владельцев) и невозможно сказать какое имя считать "изначальным".

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

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

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

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

Значение newpath интерпретируется как oldpath, за исключением того, что относительный путь интерпретируется относительно каталога, на который ссылается файловый дескриптор newdirfd.

Следующие значения можно побитово (OR) объединять в flags:

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

Если значение oldpath равно пустой строке, то создаётся ссылка на файл, на который указывает olddirfd (который может быть получен с помощью open(2) с флагом O_PATH). В этом случае olddirfd может указывать на файл любого типа кроме каталога. Это, обычно, не работает, если файл имеет счётчик ссылок равный нулю (исключение — файлы, созданные с флагом O_TMPFILE и без O_EXCL). Вызывающий должен иметь мандат CAP_DAC_READ_SEARCH, чтобы использовать этот флаг. Данный флаг есть только в Linux; для получения его определения определите _GNU_SOURCE.

AT_SYMLINK_FOLLOW (начиная с Linux 2.6.18)

По умолчанию, linkat() не разыменовывает oldpath, если это символьная ссылка (подобно link()). В flags можно указать флаг AT_SYMLINK_FOLLOW, и тогда значение oldpath будет разыменовано, если это символьная ссылка. Если смонтирована procfs, то это может быть использовано как альтернатива AT_EMPTY_PATH, например:

```
linkat(AT_FDCWD, "/proc/self/fd/<fd>", newdirfd,

       newname, AT_SYMLINK_FOLLOW);

```

До версии ядра 2.6.18 аргумент flags не использовался и должен был быть равен 0.

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

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

## ОШИБКИ
EACCES

Нет прав на запись в каталог, содержащий newpath, или в одном из каталогов пути до oldpath или newpath не разрешён поиск (см. также path_resolution(7)).

EDQUOT

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

EEXIST

newpath уже существует.

EFAULT

Значения oldpath и newpath указывают за пределы доступного адресного пространства.

EIO

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

ELOOP

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

EMLINK

На файл, на который указывает oldpath, уже создано максимальное количество ссылок. Например, для файловой системы ext4(5), в которой не используется свойство dir_index, ограничение по количеству жёстких ссылок на файл равно 65000; в btrfs(5) — 65535 ссылок.

ENAMETOOLONG

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

ENOENT

Компонент каталога в oldpath или newpath не существует или является повисшей ссылкой.

ENOMEM

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

ENOSPC

На устройстве, содержащем файл, нет места для создания нового элемента каталога.

ENOTDIR

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

EPERM

oldpath является каталогом.

EPERM

Файловая система, содержащая oldpath и newpath, не поддерживает создание жёстких ссылок.

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

Вызывающий не имеет прав для создания жёстких ссылок на этот файл (смотрите описание /proc/sys/fs/protected_hardlinks в proc(5)).

EPERM

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

EROFS

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

EXDEV

oldpath и newpath находятся не в одной смонтированной файловой системе (Linux позволяет монтировать файловую систему в несколько точек, но link() не работает с отличающими точками монтирования, даже если в них смонтирована идентичная файловая система).

В linkat() дополнительно могут возникнуть следующие ошибки:

EBADF

В olddirfd или newdirfd указаны неправильные файловые дескрипторы.

EINVAL

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

ENOENT

Флаг AT_EMPTY_PATH указан в flags, но вызывающий не имеет мандата CAP_DAC_READ_SEARCH.

ENOENT

Предпринята попытка сделать ссылку на файл /proc/self/fd/NN, который соответствует файловому дескриптору, созданному с помощью

open(path, O_TMPFILE | O_EXCL, mode);

Смотрите open(2).

ENOENT

Значение oldpath является относительным путём и olddirfd ссылается на каталог, который был удалён, или newpath является относительным путём и newdirfd ссылается на каталог, который был удалён.

ENOTDIR

Значение oldpath содержит относительный путь и olddirfd содержит файловый дескриптор, указывающий на файл, а не на каталог; или произошло тоже самое с newpath и newdirfd.

EPERM

Значение AT_EMPTY_PATH было указано в flags, значение oldpath равно пустой строке и olddirfd указывает на каталог.

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

## СООТВЕТСТВИЕ СТАНДАРТАМ
link(): SVr4, 4.3BSD, POSIX.1-2001 (но смотрите ЗАМЕЧАНИЯ), POSIX.1-2008.

linkat(): POSIX.1-2008.

## ЗАМЕЧАНИЯ
Жёсткие ссылки, создаваемые link(), не могут располагаться в разных файловых системах. Если это необходимо, используйте symlink(2).

В POSIX.1-001 сказано, что link() должен разыменовывать oldpath, если он является символьной ссылкой. Однако, начиная с ядра версии 2.0, Linux также не поступает: если oldpath является символьной ссылкой, то newpath создаётся как (жёсткая) ссылка на файл этой символьной ссылки (т.е., newpath становится символьной ссылкой на файл, содержащий ссылку на oldpath). Некоторые другие реализации поступают также как Linux. В POSIX.1-2008 изменено описание link(), теперь разыменование символьной ссылки oldpath зависит от реализации. Для точного управления по обработке символьных ссылок при создании используйте linkat().

### Замечания по glibc
В старых ядрах, где linkat() отсутствует (и если не указан флаг AT_SYMLINK_NOFOLLOW), обёрточная функция glibc использует link(). Если oldpath и newpath являются относительными путями, то glibc собирает пути относительно символической ссылки в /proc/self/fd, которая соответствует аргументам olddirfd и newdirfd.

## ДЕФЕКТЫ
В файловых системах NFS возвращаемый код может быть неправильным, если сервер NFS выполнит создание ссылки и завершит работу до возврата результата операции. Используйте stat(2), чтобы выяснить была ли создана ссылка.

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


listen

title: listen(2)

summary: слушать соединения на сокете

text:
# listen(2)

## ИМЯ
listen - слушать соединения на сокете

## ОБЗОР

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

```
int listen(int sockfd, int backlog);
```

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

Аргумент sockfd является файловым дескриптором, который ссылается на сокет типа SOCK_STREAM или SOCK_SEQPACKET.

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

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

## ОШИБКИ
EADDRINUSE

Другой сокет уже слушает на этом же порту.

EADDRINUSE

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

EBADF

Аргумент sockfd не является допустимым файловым дескриптором.

ENOTSOCK

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

EOPNOTSUPP

Тип сокета не поддерживает операцию listen().

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

## ЗАМЕЧАНИЯ
Для принятия соединений должны быть выполнены следующие шаги:

1.

Создать сокет с помощью socket(2).

2.

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

3.

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

4.

Принять подключения с помощью accept(2).

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

Поведение аргумента backlog на TCP-сокетах изменилось в Linux 2.2. Теперь вместо количества неоконченных запросов на соединение он задает размер очереди для полностью (completely) установленных соединений, ожидающих, пока процесс примет их. Максимальный размер очереди для неполных сокетов может быть задан через /proc/sys/net/ipv4/tcp_max_syn_backlog. Когда разрешено использование syncookies, логический максимальный размер отсутствует и эта настройка игнорируется. Подробности см. в tcp(7).

Если значение аргумента backlog больше, чем значение /proc/sys/net/core/somaxconn, то он без предупреждения обрезается до этой величины; значение по умолчанию в данном файле равно 128. В ядрах до версии 2.4.25, этот предел указывался в константе SOMAXCONN и имел значение 128.

## ПРИМЕР
См. bind(2).

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


listxattr

title: listxattr(2)

summary: выводит список названий расширенных

text:
# listxattr(2)

## ИМЯ
listxattr, llistxattr, flistxattr - выводит список названий расширенных атрибутов

## ОБЗОР

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

```
ssize_t listxattr(const char *path, char *list, size_t size);
ssize_t llistxattr(const char *path, char *list, size_t size);
ssize_t flistxattr(int fd, char *list, size_t size);
```

## ОПИСАНИЕ
Расширенные атрибуты представляют собой пару имя:значение и связываются с записями inode (файлы, каталоги, символьные ссылки и т.п.). Они являются расширениями к обычным атрибутам, связанным со всеми записями inode в системе (например, данные stat(2)). Полное описание модели расширенных атрибутов можно найти в xattr(7).

listxattr() получает список названий расширенных атрибутов, связанных с заданным путем path в файловой системе. Список помещается в list вызывающего, который выделил для этого буфер размером size (задаётся в байтах). Список представляет собой набор названий (заканчивающихся null) один за одним. Названия расширенных атрибутов, к которым вызывающий процесс не может иметь доступ, могут отсутствовать в списке. Возвращается длина списка list.

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

flistxattr() идентичен listxattr(), отличием является то, что используется открытый файл, на который указывает fd (возвращаемом open(2)), а не указанный в path.

Одиночный расширенный атрибут name является строкой, заканчивающейся null. Имя включает префикс пространства имен; их может быть несколько, разрозненные пространства связаны с отдельной записью inode.

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

### Пример
Список названий возвращается в виде неупорядоченного массива символьных строк, заканчивающихся null (названия атрибутов разделяются байтами null ('\0')), например:

```
user.name1\0system.name1\0user.name2\0
```

Файловые системы, реализующие ACL стандарта POSIX с помощью расширенных атрибутов, могут возвращать такой список:

```
system.posix_acl_access\0system.posix_acl_default\0
```

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

## ОШИБКИ
E2BIG

Размер списка имён расширенных атрибутов превышает максимально допустимый; список невозможно получить. Это может случиться в файловых системах, которые поддерживают бесконечное количество расширенных атрибутов на файл, например XFS. Смотрите ДЕФЕКТЫ.

ENOTSUP

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

ERANGE

Размер size буфера list слишком мал для хранения результата.

Также могут возникать ошибки, описанные в stat(2).

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

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

## ДЕФЕКТЫ
Как упоминалось в xattr(7), в VFS есть ограничение в 64 КБ на размер списка имён расширенных атрибутов, возвращаемый listxattr(7). Если полный размер имён атрибутов, прикреплённых к файлу, превышает это ограничение, то становится невозможно получить список имён атрибутов.

## ПРИМЕР
В следующей программе показано использование listxattr() и getxattr(2). Для файла, чьё имя указывается параметром в командной строке, выводится список файловых атрибутов и их значения.

Для упрощения кода при выполнении программы ключи атрибутов и значения считаются константами. В реальной программе нужно учитывать и обрабатывать изменения при выполнении программы. Например, количество байт, необходимое для ключей атрибутов, может увеличиваться между двумя вызовами listxattr(). В приложении нужно предусмотреть эту возможность с помощью цикла, который повторяет вызов (возможно, ввести задаваемое максимальное количество попыток) с большим буфером каждый раз при ошибке ERANGE. Вызовы getxattr(2) могут обрабатываться схожим образом.

В следующем выводе был создан файл, заданы некоторые расширенные файловые атрибуты и показан вывод атрибутов с помощью программы-примера.

### Пример вывода

```
$ touch /tmp/foo
$ setfattr -n user.fred -v chocolate /tmp/foo
$ setfattr -n user.frieda -v bar /tmp/foo
$ setfattr -n user.empty /tmp/foo
$ ./listxattr /tmp/foo
user.fred: chocolate
user.frieda: bar
user.empty: <нет значения>
```

### Исходный код программы (listxattr.c)

```
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/xattr.h>
int
main(int argc, char *argv[])
{

    ssize_t buflen, keylen, vallen;

    char *buf, *key, *val;

    if (argc != 2) {

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

        exit(EXIT_FAILURE);

    }

    /*

     * Определение длины буфера.

     */

    buflen = listxattr(argv[1], NULL, 0);

    if (buflen == -1) {

        perror("listxattr");

        exit(EXIT_FAILURE);

    }

    if (buflen == 0) {

        printf("%s не имеет атрибутов.\n", argv[1]);

        exit(EXIT_SUCCESS);

    }

    /*

     * Выделение буфера.

     */

    buf = malloc(buflen);

    if (buf == NULL) {

        perror("malloc");

        exit(EXIT_FAILURE);

    }

    /*

     * Копирование списка ключей атрибутов в буфер.

     */

    buflen = listxattr(argv[1], buf, buflen);

    if (buflen == -1) {

        perror("listxattr");

        exit(EXIT_FAILURE);

    }

    /*

     * Циклический проход по списку строк (завершающихся 0) с

     * ключей атрибутов. Используется оставшаяся длина буфера для

     * определения конца списка.

     */

    key = buf;

    while (buflen > 0) {

        /*

         * Вывод ключа атрибута.

         */

        printf("%s: ", key);

        /*

         * Определение длины значения.

         */

        vallen = getxattr(argv[1], key, NULL, 0);

        if (vallen == -1)

            perror("getxattr");

        if (vallen > 0) {

            /*

             * Выделение буфера под значения.

             * Один доп. байт нужен для добавляемого 0x00.

             */

            val = malloc(vallen + 1);

            if (val == NULL) {

                perror("malloc");

                exit(EXIT_FAILURE);

            }

            /*

             * Копирование значения в буфер.

             */

            vallen = getxattr(argv[1], key, val, vallen);

            if (vallen == -1)

                perror("getxattr");

            else {

                /*

                 * Вывод значения атрибута.

                 */

                val[vallen] = 0;

                printf("%s", val);

            }

            free(val);

        } else if (vallen == 0)

            printf("<нет значения>");

        printf("\n");

        /*

         * Переход к следующему ключу атрибута.

         */

        keylen = strlen(key) + 1;

        buflen -= keylen;

        key += keylen;

    }

    free(buf);

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
getfattr(1), setfattr(1), getxattr(2), open(2), removexattr(2), setxattr(2), stat(2), symlink(7), xattr(7)


llseek

title: llseek(2)

text:
# llseek(2)

## ИМЯ
_llseek - установить позицию чтения/записи в файле

## ОБЗОР

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

```
int _llseek(unsigned int fd, unsigned long offset_high,
            unsigned long offset_low, loff_t *result,
            unsigned int whence);
```

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

## ОПИСАНИЕ
Системный вызов _llseek() изменяет смещение в описании открытого файла, связанного с файловым дескриптором fd, на значение (offset_high<<32) | offset_low байт относительно начала файла, текущего смещения файла или конца файла, в зависимости от того, равен ли параметр whence одному из значений SEEK_SET, SEEK_CUR или SEEK_END, соответственно. Функция возвращает получившеюся позицию в файле в аргументе result.

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

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

## ОШИБКИ
EBADF

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

EFAULT

Проблема с копированием результатов в пространство пользователя.

EINVAL

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

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

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

## СМОТРИТЕ ТАКЖЕ
lseek(2), open(2), lseek64(3)


title: lookup_dcookie(2)

summary: возвращает путь элемента каталога

text:
# lookup_dcookie(2)

## ИМЯ
lookup_dcookie - возвращает путь элемента каталога

## ОБЗОР
int lookup_dcookie(u64 cookie, char *buffer, size_t len);

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

Для успешного выполнения lookup_dcookie() ядро должно удерживать ссылку маркёра на элемент каталога.

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

## ОШИБКИ
EFAULT

Неверный буфер.

EINVAL

При поиске в ядре не было зарегистрированных отображённых элементов маркёра/каталога или маркёр ссылается на некорректный элемент каталога.

ENAMETOOLONG

Имя не помещается в буфере.

ENOMEM

Ядро не может выделить память для временного буфера для пути.

EPERM

Процесс не имеет мандата CAP_SYS_ADMIN для поиска значений маркёра.

ERANGE

Буфер не был достаточно велик для хранения пути элемента каталога.

## ВЕРСИИ
Доступен, начиная с Linux 2.5.43. В версии 2.5.70 добавлено возвращение ошибки ENAMETOOLONG.

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

## ЗАМЕЧАНИЯ
Вызов lookup_dcookie() является специальным системным вызовом, в данный момент используется только программой профилирования oprofile(1). Она полагается на регистрацию драйвером ядра маркёра для элементов каталога.

Возвращаемый путь может заканчиваться строкой « (deleted)», если элемент каталога был удалён.

## СМОТРИТЕ ТАКЖЕ
oprofile(1)


lseek

title: lseek(2)

text:
# lseek(2)

## ИМЯ
lseek - изменяет файловое смещение, используемое при чтении/записи

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

\#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

## ОПИСАНИЕ
Вызов lseek() изменяет файловое смещение в описании открытого файла, связанного с файловым дескрипторов fd, на значение аргумента offset в соответствии с директивой whence, которая может принимать одно из следующих значений:

SEEK_SET

Установить файловое смещение равным offset (в байтах).

SEEK_CUR

Установить файловое смещение равным текущему положению плюс offset (в байтах).

SEEK_END

Установить файловое смещение равным размеру файла плюс offset (в байтах).

Вызов lseek() позволяет задавать смещение, которое будет находиться за существующим концом файла (но это не изменяет размер файла). Если позднее по этому смещению будут записаны данные, то последующее чтение в промежутке («дырке») от конца файла до этого смещения, будет возвращать нулевые байты ('\0'), пока в этот промежуток действительно не будут записаны данные.

### Перемещения по данным файла и промежутки
Начиная с версии 3.1, в Linux поддерживаются следующие дополнительные значения whence:

SEEK_DATA

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

SEEK_HOLE

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

В обоих, показанных выше, случаях, lseek() завершится с ошибкой, если offset указывает за конец файла.

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

Для поддержки этих операций промежуток представляется последовательностью нулей, которые (обычно) физически не занимают места на носителе. Однако файловая система может не сообщать о промежутках, поэтому эти операции — не гарантируемый механизм отображения пространства носителя в файл (более того, последовательность нулей, которая на самом деле была записана на носитель, может не посчитаться промежутком). В простейшей реализации, файловая система может поддержать эти операции так: при SEEK_HOLE всегда возвращать смещение конца файла, а при SEEK_DATA всегда возвращать значение offset (т.е., даже если расположение, указанное offset, является промежутком, это можно считать данными, состоящими из последовательности нулей).

Чтобы получить определения SEEK_DATA и SEEK_HOLE из <unistd.h>, нужно задать макрос тестирования свойств _GNU_SOURCE.

Операции SEEK_HOLE и SEEK_DATA поддерживаются следующими файловыми системами:

- Btrfs (начиная с Linux 3.1)

- OCFS (начиная с Linux 3.2)

- XFS (начиная с Linux 3.5)

- ext4 (начиная с Linux 3.8)

- tmpfs(5) (начиная с Linux 3.8)

- NFS (начиная с Linux 3.18)

- FUSE (начиная с Linux 4.5)

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

## ОШИБКИ
EBADF

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

EINVAL

Неправильное значение whence. Получается, что возвращаемое файловое смещение стало бы отрицательным или указывало бы за конец поверхности носителя.

ENXIO

Значение whence равно SEEK_DATA или SEEK_HOLE, а файловое смещение указывает за конец файла.

EOVERFLOW

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

ESPIPE

Значение fd связано с каналом, сокетом или FIFO.

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

Значения SEEK_DATA и SEEK_HOLE являются нестандартными расширениями, которые также есть в Solaris, FreeBSD и DragonFly BSD; их предложили включить в следующую редакцию POSIX (выпуск 8).

## ЗАМЕЧАНИЯ
Описание взаимосвязи между файловыми дескрипторами, открытыми файловыми описаниями и файлами смотрите в open(2).

Если установлен флаг состояние файла O_APPEND в открытом файловом описании, то write(2) всегда перемещает файловое смещение в конец файла, независимо от использования lseek().

Тип данных off_t представляет собой знаковый целочисленный тип, определён в POSIX.1.

Некоторые устройства не могут выполнять смещения и в POSIX не указано какие устройства должны поддерживать lseek().

В Linux при использовании lseek() на устройствах терминалов возвращается ошибка ESPIPE.

## СМОТРИТЕ ТАКЖЕ
dup(2), fallocate(2), fork(2), open(2), fseek(3), lseek64(3), posix_fallocate(3)


madvise

title: madvise(2)

text:
# madvise(2)

## ИМЯ
madvise - отсылает предложения по использованию памяти

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

int madvise(void *addr, size_t length, int advice);

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

madvise():

Начиная с glibc 2.19:

_DEFAULT_SOURCE

Начиная с glibc 2.19:

_BSD_SOURCE

## ОПИСАНИЕ
Системный вызов madvise() используется, чтобы дать совет или указать направление ядру о диапазоне адресов, начинающемся с адреса addr и имеющем размер length байт. В большинстве случаев, целью такого совета является повышение производительности системы или приложения.

Первоначально, системный вызов поддерживал набор «стандартных» значений advice, которые также доступны и в некоторых других реализациях (однако отметим, что madvise() отсутствует в POSIX). В последствии было добавлено несколько значений advice, имеющихся только в Linux.

### Стандартные значения предложений
Значения advice, перечисленные далее, позволяют приложению указать ядру как оно будет использовать некоторые отображённые или общие области памяти, чтобы ядро могло выбрать подходящие методы упреждающего чтения и кэширования. Эти значения advice не влияют на семантику приложения (за исключением MADV_DONTNEED), но могут повлиять на его производительность. Все перечисленные здесь значения advice имеют аналоги в определённой POSIX функции posix_madvise(3) и имеют тот же смысл, за исключением MADV_DONTNEED.

В advice помещается нужное предложения, одно из:

MADV_NORMAL

Нет никаких специальных указаний. Используется по умолчанию.

MADV_RANDOM

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

MADV_SEQUENTIAL

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

MADV_WILLNEED

Ожидать доступа в ближайшем будущем (здесь можно применить упреждающее чтение нескольких страниц).

MADV_DONTNEED

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

После успешного выполнения операции MADV_DONTNEED семантика доступа к памяти в заданной области изменяется: последующий доступ к страницам в области будет успешным, но будет приводить к или повторному заполнению памяти актуальным содержимым из нижележащего отображённого файла (для общих отображений файла, общих анонимных отображений и методов на основе shmem, таких как сегментов общей памяти System V) или к заполнению нулями страниц по требованию у частных анонимных отображений.

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

Операция MADV_DONTNEED не может применяться к заблокированным страницам, страницам Huge TLB или страницам VM_PFNMAP (страницы, помеченные внутренним флагом ядра VM_PFNMAP представляют собой специальные области памяти, которые не управляются из подсистемы виртуальной памяти; обычно, эти страницы создаются драйверами устройств, которые отображают страницы в пользовательское пространство).

### Значения предложений, имеющиеся только в Linux
Следующие значения advice имеются только в Linux и не имеют аналога в определённой POSIX функции posix_madvise(3), а также могут не иметь аналога и в других реализациях интерфейса madvise(). Заметим, что некоторые из этих операций изменяют семантику доступа к памяти.

MADV_REMOVE (начиная с Linux 2.6.16)

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

Указываемый адресный диапазон должен быть общим и доступным на запись отображением. Этот флаг не может применять к заблокированным страницам, страницам Huge TLB или страницам VM_PFNMAP.

В первоначальной реализации MADV_REMOVE поддерживался только в tmpfs(5), но начиная с Linux 3.5 все файловые системы, поддерживающие fallocate(2) с режимом FALLOC_FL_PUNCH_HOLE, также поддерживают MADV_REMOVE. Hugetlbfs возвращает ошибку EINVAL, а другие файловые системы возвращают ошибку EOPNOTSUPP.

MADV_DONTFORK (начиная с Linux 2.6.16)

Сделать недоступными страницы в указанном диапазоне для потомка после fork(2). Это полезно для предотвращения изменения физического расположения страницы копирования-при-записи, если родитель будет изменять её после fork(2) (перемещение таких страниц вызывает проблемы для оборудования, обращающегося к страницам через DMA).

MADV_DOFORK (начиная с Linux 2.6.16)

Отменить действие MADV_DONTFORK, восстановить поведение по умолчанию, в силу чего происходит наследование отображения после fork(2).

MADV_HWPOISON (начиная с Linux 2.6.32)

Испортить страницы в диапазоне, заданном addr и length, и обрабатывать последующие ссылки на эти страницы как при аппаратном повреждении памяти. Данная операция доступна только для привилегированных (CAP_SYS_ADMIN) процессов. Она может привести к тому, что вызывающий процесс получит SIGBUS и отображение страницы удалится.

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

MADV_MERGEABLE (начиная с Linux 2.6.32)

Включает слияние одинаковых страниц ядра (Kernel Samepage Merging, KSM) для страниц в диапазоне, указанном addr и length. Ядро периодически сканирует области пользовательской памяти, которые были помечены для слияния, разыскивая станицы с одинаковым содержимым. Такие страницы заменяются единственной страницей, защищённой от записи (которая автоматически копируется, если позднее процесс захочет изменить содержимое страницы). При KSM слияние выполняется только для частных анонимных страниц (смотрите mmap(2)).

Возможность KSM предназначена для приложений, которые генерируют много экземпляров одинаковых данных (например, для систем виртуализации, таких как KVM). Эта возможность может нагрузить процессор; используйте осторожно. Дополнительную информацию можно найти в файле исходного кода ядра Documentation/admin-guide/mm/ksm.rst.

Операции MADV_MERGEABLE и MADV_UNMERGEABLE доступны только, если ядро собрано с параметром CONFIG_KSM.

MADV_UNMERGEABLE (начиная с Linux 2.6.32)

Отменить действие ранее применённой операции MADV_MERGEABLE для указанного диапазона; KSM разделяет ранее объединённые страницы в диапазоне, заданном addr и length.

MADV_SOFT_OFFLINE (начиная с Linux 2.6.33)

Программно отключить страницы в диапазоне, указанном addr и length. Память каждой страницы в указанном диапазоне сохраняется (т. е., при следующем доступе будет выдано то же содержимое, но в новых физических границах страницы) и первоначальная страница отключается (т. е., больше не используется и не участвует при обычном управлении памятью). Эффект операции MADV_SOFT_OFFLINE обычно незаметен (т. е., не изменяет семантику) для вызывающего процесса.

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

MADV_HUGEPAGE (начиная с Linux 2.6.38)

Включает прозрачность огромных страниц (Transparent Huge Pages, THP) для страниц в диапазоне, указанном addr и length. В настоящий момент, THP работает только для закрытых (private) анонимных страниц (смотрите mmap(2)). Ядро будет периодически сканировать области, помеченные как кандидаты в огромные страницы, для замены их огромными страницами. Ядро также будет непосредственно выделять огромные страницы, если область выравнена на аппаратный (naturally) размер огромной страницы при создании (смотрите posix_memalign(2)).

В основном, эта возможность предназначена для приложений, которые используют большие отображения данных и доступ к большим областям этой памяти за один приём (например, системы виртуализации, такие как QEMU). С её помощью можно очень легко занять память (например, на 2 МБ отображение, из которого нужен только 1 байт, будет потрачено 2 МБ реальной памяти вместо одной 4 КБ страницы). Дополнительную информацию смотрите в файле Documentation/admin-guide/mm/transhuge.rst из исходного кода ядра.

Операции MADV_HUGEPAGE и MADV_NOHUGEPAGE доступны только, если ядро собрано с параметром CONFIG_TRANSPARENT_HUGEPAGE.

MADV_NOHUGEPAGE (начиная с Linux 2.6.38)

Проверить, что память адресного пространства, указанного в addr и length, не будет свёрнута в огромные страницы.

MADV_DONTDUMP (начиная с Linux 3.4)

Исключить из дампа памяти страницы диапазона, задаваемого значениями addr и length. Это полезно в приложениях, которые занимают большие области в памяти, про которые известно, что они ничем не помогут будучи в дампе памяти. Действие MADV_DONTDUMP имеет преимущество над битовой маской, которая устанавливается в файле /proc/[pid]/coredump_filter (смотрите core(5)).

MADV_DODUMP (начиная с Linux 3.4)

Отменяет действие, установленное ранее MADV_DONTDUMP.

MADV_FREE (начиная с Linux 4.5)

Приложению больше не требуются страницы в диапазоне, задаваемом addr и len, поэтому ядро может освободить эти страницы, но освобождение может быть отложено до тех пор, пока не понадобится память. Для каждой страницы, помеченной как свободная, но ещё не освобождённая, операция освобождения будет отменена, если вызывающий выполнит запись в эту страницу. После успешного выполнения операции MADV_FREE все повисшие данные (т. е., изменённые (dirty) и не записанные страницы) будут потеряны в момент освобождения страниц ядром. Однако последующая запись в страницы в этом диапазоне будет успешной и поэтому ядро не сможет освободить эти изменённые страницы и вызывающий всегда может видеть только что записанные данные. Если последующей записи не было, то ядро может освободить страницы в любой момент. После освобождения страниц диапазона при последующем доступе вызывающий может видеть страницы заполненные нулями по требованию.

Операция MADV_FREE может применяться только при частным анонимным страницам (смотрите mmap(2)). В Linux до версии 4.12 страницы задаваемого диапазона в системе без подкачки освобождаются сразу, независимо от необходимости в памяти.

MADV_WIPEONFORK (начиная с Linux 4.14)

Выдать дочернему процессу заполненную нулями память в этом диапазоне после fork(2). Это позволяет при ветвлении (forking) серверов стереть важные данные процесса (например, начальные значения PRNG, данные шифрования и т. п.) у дочерних процессов.

Операция MADV_WIPEONFORK применима только к частным анонимным страницам (смотрите mmap(2)).

В потомке, созданном fork(2), значение MADV_WIPEONFORK остаётся у указанного адресного диапазона. Это значение стирается при execve(2).

MADV_KEEPONFORK (начиная с Linux 4.14)

Отменяет действие, установленное ранее MADV_WIPEONFORK.

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

## ОШИБКИ
EACCES

В advice указан MADV_REMOVE, но описанный диапазон адресов не является общей памятью с разрешением на записи

EAGAIN

Ресурс ядра временно недоступен.

EBADF

Отображение существует, то область отображения не является файловой.

EINVAL

Значение параметра addr не выровнено по границе страницы или параметр length содержит отрицательное число.

EINVAL

Значение advice недопустимо.

EINVAL

Значение advice равно MADV_DONTNEED или MADV_REMOVE, а указанный адресный диапазон включает заблокированные, Huge TLB или VM_PFNMAP страницы.

EINVAL

Значение advice равно MADV_MERGEABLE или MADV_UNMERGEABLE, но ядро было собрано без параметра CONFIG_KSM.

EINVAL

Значение advice равно MADV_FREE или MADV_WIPEONFORK, но в указанном адресном диапазоне содержится файл, Huge TLB, диапазоны MAP_SHARED или VM_PFNMAP.

EIO

(для MADV_WILLNEED) Выделение страницы в данной области превысило бы максимальный размер постоянно находящихся в памяти страниц для процесса (rss).

ENOMEM

(для MADV_WILLNEED) Недостаточно памяти: не удалось выделить страницу

ENOMEM

Адреса в указанном диапазоне в настоящее время не отображены, или лежит вне адресного пространства процесса.

EPERM

В переменной advice содержится MADV_HWPOISON, но вызывающий не имеет мандата CAP_SYS_ADMIN.

## ВЕРСИИ
Начиная с Linux 3.18 поддержка данного системного вызова необязательна, она зависит от того, собрано ли ядро с параметром CONFIG_ADVISE_SYSCALLS.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Вызов madvise() не включён ни в один стандарт. Версии этого системного вызова, реализующие широкий набор значений advice, существуют во многих других системах. В них, обычно, реализуются, как минимум, флаги перечисленные в Стандартные значения предложений, хотя и с некоторыми различиями в семантике.

В POSIX-2001 описана функция posix_madvise(3) с константами POSIX_MADV_NORMAL, POSIX_MADV_RANDOM, POSIX_MADV_SEQUENTIAL, POSIX_MADV_WILLNEED и POSIX_MADV_DONTNEED, и т. п., реализующая поведение близкое к флагам с именами, перечисленным выше.

## ЗАМЕЧАНИЯ

### Замечания, касающиеся Linux
Для реализации Linux требуется, чтобы адрес addr был выровнен на границу страницы, а значение length может быть нулевым. Если какие-то части указанного адресного диапазона не отображены, то версия Linux madvise() игнорирует их и вызов применяется к оставшейся области (но возвращается значение ENOMEM, как и должно).

## СМОТРИТЕ ТАКЖЕ
getrlimit(2), mincore(2), mmap(2), mprotect(2), msync(2), munmap(2), prctl(2), posix_madvise(3), core(5)