package: man-pages-ru

title: _exit(2)

summary: завершает вызывающий процесс

text:
# _exit(2)

## ИМЯ
_exit, _Exit - завершает вызывающий процесс

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

void _exit(int status);

\#include <stdlib.h>

void _Exit(int status);

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

_Exit():

_ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L

## ОПИСАНИЕ
Функция _exit() «безотлагательно» завершает вызывающий процесс. Все открытые дескрипторы файлов, принадлежащие процессу, закрываются. Все его дочерние процессы наследуются init(1) (или ближайшим «собирающим» процессом, определённым вызовом prctl(2) с операцией PR_SET_CHILD_SUBREAPER).Родительскому процессу посылается сигнал SIGCHLD.

Значение status & 0377 возвращается родительскому процессу как код завершаемого процесса; он может быть получен с помощью одной из функций семейства wait(2).

Функция _Exit() эквивалентна _exit().

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Эти функции не выполняют возврат.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD. Функция _Exit() была представлена в C99.

## ЗАМЕЧАНИЯ
Обсуждение эффектов при завершении работы, передачу кода выхода, зомби-процессы, сигналы и т. п., смотрите в exit(3).

Функция _exit() подобна exit(3), но не вызывает никаких функций, зарегистрированных с помощью atexit(3) или on_exit(3). Открытые потоки посредством stdio(3) не сбрасываются. С другой стороны, _exit() закрывает открытые дескрипторы файлов, а это может привести к неопределенной задержке, так как происходит ожидание завершения вывода данных. Если задержка нежелательна, то может быть полезным перед вызовом _exit() вызывать функцию типа tcflush(3). Будет ли отмена ожидания ввод-вывода, а также какие именно ожидающие операции ввода-вывода будут завершены при вызове _exit, зависит от реализации.

### Отличия между библиотекой C и ядром
В glibc до версии 2.3, обёрточная функция _exit() вызывала системный вызов ядра с тем же именем. Начиная с glibc 2.3, обёрточная функция вызывает exit_group(2), чтобы завершить все нити процесса.

## СМОТРИТЕ ТАКЖЕ
execve(2), exit_group(2), fork(2), kill(2), wait(2), wait4(2), waitpid(2), atexit(3), exit(3), on_exit(3), termios(3)


title: _syscall(2)

text:
# _syscall(2)

## ИМЯ
_syscall - выполняет системный вызов, который не поддерживается библиотекой (УСТАРЕЛ)

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

Макрос _syscall

желаемый системный вызов

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

```
_syscallX(type,name,type1,arg1,type2,arg2,…)
```

где

X 0–6, количество аргументов, принимаемых системным вызовом

type — тип возвращаемого значения системного вызова

name — имя системного вызова

typeN — тип N-го аргумента

argN — имя N-го аргумента

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

## ФАЙЛЫ
/usr/include/linux/unistd.h

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

## ЗАМЕЧАНИЯ
Начиная, приблизительно, с ядра 2.6.18, макросы _syscall удалены из заголовочных файлов, используемых в пользовательском пространстве. Вместо них используйте syscall(2). (Для некоторых архитектур, например ia64, макросы _syscall никогда не предоставлялись; на таких архитектурах всегда требуется макрос syscall(2).)

Макрос _syscall() не создаёт прототип. Вам, вероятно, придётся создавать его самостоятельно, особенно пользователям C++.

Для системных вызовов не требуется возвращать только положительный или отрицательный код ошибки. Вам нужно прочитать исходный код, чтобы выяснить как возвращаются ошибки. Обычно, это отрицательный стандартный код ошибки, например, -EPERM. Макрос _syscall() возвращает результат r из системного вызова, если r неотрицательно, но вернёт -1 и установит значение errno равное -r, когда r отрицательно. Коды ошибок смотрите в errno(3).

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

## ПРИМЕР

```
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/unistd.h>       /* поддержка _syscallX */
#include <linux/kernel.h>       /* struct sysinfo */
_syscall1(int, sysinfo, struct sysinfo *, info);
int
main(void)
{

    struct sysinfo s_info;

    int error;

    error = sysinfo(&s_info);

    printf("code error = %d\n", error);

    printf("Uptime = %lds\nLoad: 1 min %lu / 5 min %lu / 15 min %lu\n"

           "RAM: total %lu / free %lu / shared %lu\n"

           "Memory in buffers = %lu\nSwap: total %lu / free %lu\n"

           "Number of processes = %d\n",

           s_info.uptime, s_info.loads[0],

           s_info.loads[1], s_info.loads[2],

           s_info.totalram, s_info.freeram,

           s_info.sharedram, s_info.bufferram,

           s_info.totalswap, s_info.freeswap,

           s_info.procs);

    exit(EXIT_SUCCESS);
}
```

### Результат работы примера

```
code error = 0
uptime = 502034s
Load: 1 min 13376 / 5 min 5504 / 15 min 1152
RAM: total 15343616 / free 827392 / shared 8237056
Memory in buffers = 5066752
Swap: total 27881472 / free 24698880
Number of processes = 40
```

## СМОТРИТЕ ТАКЖЕ
intro(2), syscall(2), errno(3)


accept

title: accept(2)

summary: принять соединение на сокете

text:
# accept(2)

## ИМЯ
accept, accept4 - принять соединение на сокете

## ОБЗОР

```
#include <sys/types.h>          /* См. ЗАМЕЧАНИЯ */
#include <sys/socket.h>
```

```
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE             /* Смотрите feature_test_macros(7) */
#include <sys/socket.h>
```

```
int accept4(int sockfd, struct sockaddr *addr,
            socklen_t *addrlen, int flags);
```

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

Аргумент sockfd — это сокет, который был создан с помощью socket(2), привязанный к локальному адресу с помощью bind(2), и прослушивающий соединения после listen(2).

Аргумент addr — это указатель на структуру sockaddr. В эту структуру помещается адрес ответной стороны в том виде, в каком он известен на коммуникационном уровне. Точный формат адреса, возвращаемого в параметре addr, определяется семейством адресов сокета (см. socket(2) и справочную страницу по соответствующему протоколу). Если addr равен NULL, то ничего не помещается; в этом случае addrlen не используется и также должен быть NULL.

Через аргумент addrlen осуществляется возврат результата: вызывающая сторона должна указать в нём размер (в байтах) структуры, на которую указывает addr; при возврате он будет содержать реальный размер адреса ответной стороны.

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

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

Для того, чтобы получать уведомления о входящих соединениях на сокете, можно использовать select(2), poll(2) или epoll(7). Когда поступает запрос на новое соединение, доставляется доступное для чтения событие и после этого можно вызывать accept(), чтобы получить сокет для этого соединения. Можно также настроить сокет так, чтобы он посылал сигнал SIGIO, когда на нём происходит какая-либо активность; смотрите socket(7).

Если flags равно 0, то вызов accept4() равнозначен accept(). Следующие значения могут быть побитово сложены в flags для получения различного поведения:

SOCK_NONBLOCK

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

SOCK_CLOEXEC

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

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

### Обработка ошибок
В реализации Linux accept() (и accept4()) передаёт уже ожидающие сетевые ошибки на новый сокет, как код ошибки из вызова accept(). Это поведение отличается от других реализаций BSD-сокетов. Для надёжной работы приложения должны отслеживать сетевые ошибки, которые могут появиться при работе с протоколом accept() и обрабатывать их как EAGAIN повторно выполняя вызов. В случае TCP/IP такими ошибками являются ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP и ENETUNREACH.

## ОШИБКИ
EAGAIN или EWOULDBLOCK

Сокет помечен как неблокирующий и нет ни одного соединения, которое можно было бы принять. В POSIX.1-2001 и POSIX.1-2008 допускается в этих случаях возврат ошибки и не требуется, чтобы эти константы имели одинаковое значение, поэтому переносимое приложение должно проверять обе возможности.

EBADF

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

ECONNABORTED

Соединение было прервано.

EFAULT

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

EINTR

Системный вызов прервал сигналом, который поступил до момента прихода допустимого соединения; см. signal(7).

EINVAL

Сокет не слушает соединения или недопустимое значение addrlen (например, отрицательное).

EINVAL

(accept4()) недопустимое значение в flags.

EMFILE

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

ENFILE

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

ENOBUFS, ENOMEM

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

ENOTSOCK

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

EOPNOTSUPP

Тип сокета, на который ссылается дескриптор, отличается от SOCK_STREAM.

EPROTO

Ошибка протокола.

Также, Linux accept() может завершиться с ошибкой если:

EPERM

Правила межсетевого экрана запрещают соединение.

Вдобавок, могут также возвращаться сетевые ошибки на новом сокете и ошибки, могущие возникнуть в протоколе. Различные ядра Linux могут возвращать другие ошибки, например, ENOSR, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT. Значение ошибки ERESTARTSYS можно увидеть при трассировке.

## ВЕРСИИ
Системный вызов accept4() доступен в Linux начиная с версии 2.6.28; поддержка в glibc доступна начиная с версии 2.10.

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

accept4() является нестандартным расширением Linux.

В Linux новый сокет, возвращаемый accept(), не наследует файловые флаги состояния такие как O_NONBLOCK и O_ASYNC от прослушивающего сокета. Это поведение отличается от каноническое реализации сокетов BSD. Переносимые программы не должны полагаться на наследуемость файловых флагов состояния или её отсутствия и всегда должны устанавливать на сокете, полученном от accept(), все требуемые флаги.

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

Возможно не всегда будет ожидание подключения после доставки SIGIO; или select(2), poll(2) или epoll(7) вернут событие доступности чтения, так как подключение может быть удалено из-за асинхронной сетевой ошибкой или другая нить была вызвала раньше accept(). Это это случается, то вызов блокируется, ожидая следующего прибытия подключения. Чтобы быть уверенным, что accept() никогда не заблокируется, сокету sockfd необходимо установить флаг O_NONBLOCK (см. socket(7)).

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

### Тип socklen_t
В первоначальной реализации сокетов в BSD (и в других системах) третий аргумент accept() объявлялся как int *. В стандарте черновика POSIX.1g захотели изменить его на size_t *. В поздних версиях стандарта POSIX и в glibc 2.x используется socklen_t *.

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

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


access

title: access(2)

text:
# access(2)

## ИМЯ
access, faccessat - проверить права доступа пользователя к файлу

## ОБЗОР

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

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

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

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

faccessat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

## ОПИСАНИЕ
access проверяет, имеет ли вызвавший процесс права доступа к файлу pathname. Если pathname является символьной ссылкой, то проверяются права доступа к файлу, на который она ссылается.

Аргумент mode — это маска выполняемых проверок доступа; может быть равна значению F_OK, или состоять из одного или несколько побитово сложенных R_OK, W_OK и X_OK. F_OK проверяет существование файла. R_OK, W_OK и X_OK запрашивают проверку, соответственно, существования файла и возможности его чтения, записи или выполнения.

Проверка осуществляется с использованием реального, а не эффективного идентификатора пользователя (UID) и группы (GID) вызвавшего процесса. Эффективные идентификаторы будут использоваться при действительной попытке выполнения той или иной операции с файлом (например, open(2)). Аналогичным образом, для пользователя root, при проверке используется набор разрешающих мандатов, а не набор эффективных мандатов; для не root-пользователей при проверке используется пустой набор мандатов.

Это дает программам с set-user-ID или снабжённых мандатами простой способ проверить права доступа вызвавшего пользователя. Другими словами, access() не отвечает на вопрос «могу я прочитать/записать/выполнить этот файл?». Он отвечает на немного другой вопрос: «(предположим я исполняемый файл с setuid) может ли пользователь, запустивший меня прочитать/записать/выполнить этот файл?», что даёт программам с set-user-ID возможность не дать злонамеренным пользователям прочитать файлы, которые пользователи не должны читать.

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

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

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

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

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

Значение flags составляется из побитово сложенных следующих значений:

AT_EACCESS

Выполнять проверку, доступа используя эффективный идентификатор пользователя и группы. По умолчанию в faccessat() используются реальные идентификаторы (как в access()).

AT_SYMLINK_NOFOLLOW

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

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

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

## ОШИБКИ
Вызов access() и faccessat() будут завершаться с ошибкой если:

EACCES

Запрошенный тип доступа не удовлетворён или в одном из каталогов в pathname не разрешён поиск. (См. также path_resolution(7).)

ELOOP

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

ENAMETOOLONG

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

ENOENT

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

ENOTDIR

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

EROFS

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

Вызов access() и faccessat() могут завершиться с ошибкой, если:

EFAULT

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

EINVAL

Аргумент mode был задан неверно.

EIO

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

ENOMEM

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

ETXTBSY

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

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

EBADF

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

EINVAL

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

ENOTDIR

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

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

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

faccessat(): POSIX.1-2008.

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

Вызов access() всегда разыменовывает символьные ссылки. Если вам нужно проверить права символьной ссылки, используйте вызов faccessat() с флагом AT_SYMLINK_NOFOLLOW.

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

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

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

Проверяются только биты доступа, но не тип файла или его содержимое. Поэтому, если обнаруживается, что в каталог можно писать, то это, вероятно, означает, что в этом каталоге можно создавать файлы, и что в этот каталог нельзя писать как в файл. Также, файл DOS может быть посчитан как «исполняемый», но вызов execve(2) всё равно не сможет его запустить.

Эти вызовы access() могут некорректно работать на файловых системах NFSv2 со включённым преобразованием UID-ов, потому что это преобразование происходит на сервере и спрятано от клиента, который пытается проверить права (в NFS версии 3 и выше выполняется проверка на сервере). Похожие проблемы могут возникать при монтировании FUSE.

### Отличия между библиотекой C и ядром
Нижележащий системный вызов faccessat() имеет только первые три аргумента. Флаги AT_EACCESS и AT_SYMLINK_NOFOLLOW на самом деле реализованы внутри обёрточной функции glibc faccessat(). Если задан какой-то из этих флагов, то обёрточная функция использует fstatat(2) для определения прав доступа.

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

## ДЕФЕКТЫ
В ядрах версии 2.4 (и более ранних) есть некоторая странность в работе теста X_OK для суперпользователя. Если для всех категорий право исполнения отключено для файла-не каталога, то тест access() возвращает -1 только когда mode задан как X_OK; если в mode также указан флаг R_OK или W_OK, то access() вернёт для таких файлов 0. Ранние версии ядер 2.6 (до 2.6.3 включительно) ведут себя также как ядра 2.4.

В ядрах до версии 2.6.20 эти вызовы игнорировали влияние флага MS_NOEXEC, если он был установлен с помощью mount(2) для содержащей файл файловой системы. Начиная с версия ядра 2.6.20, этот флаг учитывается.

## СМОТРИТЕ ТАКЖЕ
chmod(2), chown(2), open(2), setgid(2), setuid(2), stat(2), euidaccess(3), credentials(7), path_resolution(7), symlink(7)


acct

title: acct(2)

summary: включает или выключает учёт процессов

text:
# acct(2)

## ИМЯ
acct - включает или выключает учёт процессов

## ОБЗОР

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

```
int acct(const char *filename);
```

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

acct():

```
    начиная с glibc 2.21:

        _DEFAULT_SOURCE

    в glibc 2.19 и 2.20:

        _DEFAULT_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)

    до glibc 2.19, включительно:

        _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
```

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

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

## ОШИБКИ
EACCES

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

EFAULT

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

EIO

Ошибка записи в файл filename.

EISDIR

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

ELOOP

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

ENAMETOOLONG

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

ENFILE

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

ENOENT

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

ENOMEM

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

ENOSYS

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

ENOTDIR

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

EPERM

Вызвавшему процессу не хватает прав включить учёт процессов. В Linux для этого требуется мандат CAP_SYS_PACCT.

EROFS

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

EUSERS

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

## СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.3BSD (но не POSIX).

## ЗАМЕЧАНИЯ
Учёт не производится для программ, которые заканчиваются аварийно. В частности, незавершаемые процессы никогда не учитываются.

Структура записей, записываемых в файл учёта, описана в acct(5).

## СМОТРИТЕ ТАКЖЕ
acct(5)


title: add_key(2)

text:
# add_key(2)

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

## ОБЗОР

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

```
key_serial_t add_key(const char *type, const char *description,
                     const void *payload, size_t plen,
                     key_serial_t keyring);
```

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

## ОПИСАНИЕ
Вызов add_key() создаёт или обновляет ключ заданного типа type с описанием description, конструирует его с полезными данными payload и длиной plen, присоединяет его к заданной связке ключей keyring и возвращает его серийный номер.

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

Если в указываемой связке ключей keyring уже есть ключ с таким же type и description то, если тип ключа это поддерживает, ключ будет обновлён, а не создан заново; если нет, то будет создан новый ключ (с другим идентификатором) и он вытеснит ссылку на существующий ключ из связки.

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

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)).

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

"keyring"

Связки ключей — это специальные типы ключей, которые могут содержать ссылки на цепочки других ключей любого типа. Если данный интерфейс используется для создания связки ключей, то значение payload должно быть равно NULL, а plen должно быть равно нулю.

"user"

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

"logon" (начиная с Linux 3.3)

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

Для данного типа ключа значение description должно уточняться префиксом «service», который в description отделяется символом «:» от остальных символов.

"big_key" (начиная с Linux 3.13)

Данный тип ключа подобен "user", но может содержать полезные данные размером до 1 МиБ. Если полезной нагрузки много, то её можно хранить зашифрованной в tmpfs (может вытесняться из памяти), а не в памяти ядра.

Дополнительную информацию об этих типах ключей смотрите в keyrings(7).

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

## ОШИБКИ
EACCES

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

EDQUOT

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

EFAULT

Значение одного или нескольких полей из type, description и payload указывают вне доступного адресного пространства процесса.

EINVAL

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

EINVAL

Некорректное значение полезных данных.

EINVAL

Значение type равно "logon", но значение description не начинается строкой-префиксом в виде "service:".

EKEYEXPIRED

Срок службы связки ключей истёк.

EKEYREVOKED

Связка ключей отозвана.

ENOKEY

Связка ключей не существует.

ENOMEM

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

EPERM

Значение type начинается с точки ('.'). Типы ключей, начинающиеся с точки, зарезервированы для использования в реализации.

EPERM

Значение type равно "keyring" и description начинается с точки ('.'). Связки ключей с описаниями (именами), которые начинаются с точки, зарезервированы для использования реализацией.

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

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

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

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

```
$ ./a.out user mykey "Some payload"
ID ключа = 64a4dca
$ grep '64a4dca' /proc/keys
064a4dca I--Q---    1 perm 3f010000  1000  1000 user    mykey: 12
```

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

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

    key_serial_t key;

    if (argc != 4) {

        fprintf(stderr, "Использование: %s тип описание полезные_данные\n",

                argv[0]);

        exit(EXIT_FAILURE);

    }

    key = add_key(argv[1], argv[2], argv[3], strlen(argv[3]),

                KEY_SPEC_SESSION_KEYRING);

    if (key == -1) {

        perror("add_key");

        exit(EXIT_FAILURE);

    }

    printf("ID ключа = %lx\n", (long) key);

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
keyctl(1), keyctl(2), request_key(2), keyctl(3), keyrings(7), keyutils(7), persistent-keyring(7), process-keyring(7), session-keyring(7), thread-keyring(7), user-keyring(7), user-session-keyring(7)

Файлы исходного кода ядра Documentation/security/keys/core.rst и Documentation/keys/request-key.rst (или, до Linux 4.13, файлы Documentation/security/keys.txt и Documentation/security/keys-request-key.txt).


adjtimex

title: adjtimex(2)

summary: тонкая настройка часов в ядре

text:
# adjtimex(2)

## ИМЯ
adjtimex, ntp_adjtime - тонкая настройка часов в ядре

## ОБЗОР

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

```
int adjtimex(struct timex *buf);
```

```
int ntp_adjtime(struct timex *buf);
```

## ОПИСАНИЕ
В Linux для подстройки часов используется алгоритм Дэвида Л. Миллса (David L. Mills) (смотрите RFC 5905). Системный вызов adjtimex() читает и (необязательно) устанавливает параметры подстройки для этого алгоритма. Он берёт указатель на структуру timex, изменяет параметры ядра согласно значениям (некоторых) её полей и возвращает эту уже обновлённую структуру с текущими значениями параметров ядра. Данная структура объявлена так:

```
struct timex {

    int  modes;      /* выбор режима */

    long offset;     /* смещение по времени; в наносекундах, если

                        установлен флаг состояния STA_NANO, иначе

                        в микросекундах */

    long freq;       /* смещение частоты; единицы измерения */

                        описаны в ЗАМЕЧАНИЯХ */    long maxerror;   /* максимальная ошибка (микросекунды) */

    long esterror;   /* ожидаемая ошибка (микросекунды) */

    int  status;     /* команда/состояние для часов */

    long constant;   /* константа времени PLL (phase-locked loop) */

    long precision;  /* точность часов

                        (микросекунды, только чтение) */

    long tolerance;  /* допуск тактовой частоты (только чтение);

                        единицы измерения описаны в ЗАМЕЧАНИЯХ */

    struct timeval time;

                     /* текущее время (только чтение, кроме

                        ADJ_SETOFFSET); при возврате в time.tv_usec

                        содержатся наносекунды, если установлен флаг

                        STA_NANO, иначе микросекунды */

    long tick;       /* микросекунд между тиками часов */

    long ppsfreq;    /* частота PPS (импульсов в секунду)

                        (только чтение); единицы измерения описаны в

                        ЗАМЕЧАНИЯХ */

    long jitter;     /* искажение PPS (только чтение); в наносекундах,

                        если установлен флаг состояния STA_NANO,

                        иначе в микросекундах

    int  shift;      /* длительность интервала PPS

                        (секунды, только чтение) */

    long stabil;     /* устойчивость PPS (только чтение);

                        единицы измерения описаны в ЗАМЕЧАНИЯХ */

    long jitcnt;     /* счётчик превышений ограничения искажения

                        PPS (только чтение) */

    long calcnt;     /* счётчик интервалов калибровки PPS

                        (только чтение) */

    long errcnt;     /* счётчик ошибок калибровки PPS

                        (только чтение) */

    long stbcnt;     /* счётчик событий превышения ограничения

                        устойчивости PPS (только чтение) */

    int tai;         /* смещение TAI offset, установленное предыдущей

                        операцией ADJ_TAI (секунды, только чтение,

                        начиная с Linux 2.6.26) */

    /* далее идут байты заполнения, для расширения структуры в будущем */
};
```

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

ADJ_OFFSET

Установить смещение по времени из buf.offset. Начиная с Linux 2.6.26, переданное значение ограничивается диапазоном (-0.5s, +0.5s). В старых ядрах, если значение выходит из диапазона, то возвращается ошибка EINVAL.

ADJ_FREQUENCY

Установить смещение по частоте из buf.offset. Начиная с Linux 2.6.26, переданное значение ограничивается диапазоном (-32768000, +32768000) В старых ядрах, если значение выходит из диапазона, то возвращается ошибка EINVAL.

ADJ_MAXERROR

Установить максимальную ошибку времени из buf.maxerror.

ADJ_ESTERROR

Установить ожидаемую ошибку времени из buf.esterror.

ADJ_STATUS

Установить биты состояния часов из buf.status. Описание бит представлено ниже.

ADJ_TIMECONST

Установить константу времени PLL из buf.constant. Если не задан флаг состояния STA_NANO (смотрите ниже), то ядро добавляет к этому значению 4.

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

Добавить buf.time к текущему времени. Если в buf.status указан флаг ADJ_NANO, то значение buf.time.tv_usec считается заданным в наносекундах; в противном случае это микросекунды.

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

Выбрать микросекундной разрешение.

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

Выбрать наносекундной разрешение. Должно быть указано что-то одно: ADJ_MICRO или ADJ_NANO.

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

Установить смещение TAI (атомное международное время) из buf.constant.

ADJ_TAI не должно использоваться вместе с ADJ_TIMECONST, так как последний режим также использует поле buf.constant.

Подробное описание TAI и различия между TAI и UTC смотрите в BIPM

ADJ_TICK

Установить значение тика из buf.tick.

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

ADJ_OFFSET_SINGLESHOT

Старый вариант adjtime(): (постепенно) корректировать время значением, указанным в buf.offset, которое задаётся в микросекундах.

ADJ_OFFSET_SS_READ (работает, начиная с Linux 2.6.28)

Получить (в buf.offset) остаток необходимого откорректированного времени после выполнения операции ADJ_OFFSET_SINGLESHOT. Это возможность была добавлена в Linux 2.6.24, но работала неправильно до Linux 2.6.28.

Обычные пользователи могут задавать в modes значение ноль или ADJ_OFFSET_SS_READ. Только суперпользователь может задавать любые параметры.

Поле buf.status представляет собой битовую маску, используется для установки/получения битов состояния, связанных с реализацией NTP. Одни биты в маске можно и читать, и изменять, другие — только читать.

STA_PLL (чтение-запись)

Включить обновление фазовой подстройки частоты (PLL) через ADJ_OFFSET.

STA_PPSFREQ (чтение-запись)

Включить частотную дисциплину обслуживания PPS (импульсов в секунду).

STA_PPSTIME (чтение-запись)

Включить временную дисциплину обслуживания PPS.

STA_FLL (чтение-запись)

Выбрать режим частотной подстройки частоты (FLL).

STA_INS (чтение-запись)

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

STA_DEL (чтение-запись)

Удалить високосную секунду из последней секунды дня UTC. Удаление високосной секунды будет происходить каждый день пока установлен этот флаг.

STA_UNSYNC (чтение-запись)

Часы не синхронизированы.

STA_FREQHOLD (чтение-запись)

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

Данный флаг отключает маленькие исправления по частоте при корректировке значения ADJ_OFFSET.

STA_PPSSIGNAL (только чтение)

Присутствует сигнал PPS (импульсов в секунду).

STA_PPSJITTER (только чтение)

Превышено искажение сигнала PPS.

STA_PPSWANDER (только чтение)

Превышено отклонение сигнала PPS.

STA_PPSERROR (только чтение)

Ошибка калибровки сигнала PPS.

STA_CLOCKERR (только чтение)

Проблема с аппаратурой часов.

STA_NANO (только чтение; начиная с Linux 2.6.26)

Единица данных (0 = микросекунды, 1 = наносекунды). Устанавливается с помощью ADJ_NANO, очищается с помощью ADJ_MICRO.

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

Режим (0 = фазовая подстройка частоты, 1 = частотная подстройка частоты).

STA_CLK (только чтение; начиная c Linux 2.6.26)

Источник часов (0 = A, 1 = B); не используется.

Попытки установить биты status, помеченные только для чтения, просто игнорируются.

### ntp_adjtime ()
Библиотечная функция ntp_adjtime() (описана в NTP "Kernel Application Program API", KAPI) является более переносимым интерфейсом для выполнения той же задачи, что и adjtimex(). Она идентична adjtime() кроме следующего:

- Константы, используемые в modes, начинаются с «MOD_», а не с «ADJ_», и содержат одинаковые суффиксы (MOD_OFFSET, MOD_FREQUENCY, and so on), кроме:

- MOD_CLKA — синоним ADJ_OFFSET_SINGLESHOT.

- MOD_CLKB — синоним ADJ_TICK.

- Синонима для ADJ_OFFSET_SS_READ в KAPI нет.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении adjtimex() и ntp_adjtime() возвращают состояние часов, а именно одно из следующих значений:

TIME_OK

Часы синхронизированы, подстройки високосной секундой не ожидается.

TIME_INS

Показывает, что в конце дня по UTC будет добавлена високосная секунда.

TIME_DEL

Показывает, что в конце дня по UTC будет удалена високосная секунда.

TIME_OOP

Выполняется вставка високосной секунды.

TIME_WAIT

Выполнена вставка или удаление високосной секунды. Это значение возвращается при следующей операции ADJ_STATUS по очистке флагов STA_INS и STA_DEL.

TIME_ERROR

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

- Установлен STA_UNSYNC или STA_CLOCKERR.

- Флаг STA_PPSSIGNAL сброшен и установлен STA_PPSFREQ или STA_PPSTIME.

- Установлены флаги STA_PPSTIME и STA_PPSJITTER.

- Установлен флаг STA_PPSFREQ и STA_PPSWANDER или STA_PPSJITTER.

Символическое имя TIME_BAD — синоним TIME_ERROR, предоставляется для обратной совместимости.

Заметим, что начиная с Linux 3.4 вызов выполняется асинхронно и возвращаемое значение, обычно, не отражает состояние, изменённое самим вызовом.

При ошибке эти вызовы возвращают -1 и изменяют errno.

## ОШИБКИ
EFAULT

buf не является указателем на доступную для записи область памяти.

EINVAL (до Linux 2.6.26)

Попытка установить buf.freq в значение вне диапазона (-33554432, +33554432).

EINVAL (до Linux 2.6.26)

Попытка установить buf.offset в значение вне разрешённого диапазона. В ядрах до Linux 2.0 допустимым диапазоном был (-131072, +131072). Начиная с Linux 2.0 и новее допустимым диапазоном является (-512000, +512000).

EINVAL

Попытка установить buf.status в значение, отличное от перечисленных выше.

EINVAL

Предпринята попытка установить buf.tick в значение вне диапазона от 900000/HZ до 1100000/HZ, где HZ — частота прерываний системного таймера.

EPERM

Значение buf.modes не равно 0 или ADJ_OFFSET_SS_READ и вызывающий не имеет необходимых прав. В Linux для этого требуется мандат CAP_SYS_TIME.

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

Интерфейс

Атрибут

Значение

ntp_adjtime()

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

MT-Safe

## СООТВЕТСТВИЕ СТАНДАРТАМ
Эти интерфейсы не описаны в POSIX.1

Вызов adjtimex() есть только в Linux и не должен использоваться в переносимых программах.

Предпочтительным программным интерфейсом для службы NTP является ntp_adjtime().

## ЗАМЕЧАНИЯ
В структуре timex, freq, ppsfreq и stabil ppm (частей на миллион) имеет 16-битную дробную часть, что означает, что значение 1 в одном из этих полей в действительности равно 2^-16 ppm, и 2^16=65536 равно 1 ppm. Это действительно как для входных (в случае freq) так и для выходных значений.

Обработка високосной секунды, возникающая при установке STA_INS и STA_DEL, выполняется ядром в контексте таймера. Следовательно, для установки или удаления високосной секунды потребуется один тик для перехода.

## СМОТРИТЕ ТАКЖЕ
settimeofday(2), adjtime(3), ntp_gettime(3), capabilities(7), time(7), adjtimex(8), hwclock(8)

NTP "Kernel Application Program Interface"


alarm

title: alarm(2)

text:
# alarm(2)

## ИМЯ
alarm - установка будильника для доставки сигнала

## ОБЗОР

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

```
unsigned int alarm(unsigned int seconds);
```

## ОПИСАНИЕ
Системный вызов alarm() размещает сигнал SIGALRM для доставки вызывающему процессу через seconds секунд.

Если значение seconds равно 0, то любой ожидающий будильник будет отменён.

При любом событии ранее запланированный alarm() отменяется.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
alarm() возвращает количество секунд, оставшихся до момента доставки сигнала, запланированного ранее, или ноль, если сигнал не запланирован.

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

## ЗАМЕЧАНИЯ
alarm() и setitimer(2) используют один и тот же таймер; они будут мешать работе друг друга.

Будильники, созданные alarm(), сохраняются при выполнении execve(2) и не наследуются потомками, созданными с помощью fork(2).

sleep(3) может быть реализован через SIGALRM, поэтому лучше не использовать alarm() и sleep(3) одновременно.

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

## СМОТРИТЕ ТАКЖЕ
gettimeofday(2), pause(2), select(2), setitimer(2), sigaction(2), signal(2), timer_create(2), timerfd_create(2), sleep(3), time(7)


title: alloc_hugepages(2)

text:
# alloc_hugepages(2)

## ИМЯ
alloc_hugepages, free_hugepages - выделяет или освобождает огромные страницы

## ОБЗОР

```
void *alloc_hugepages(int key, void *addr, size_t len,
                      int prot, int flag);
```

```
int free_hugepages(void *addr);
```

## ОПИСАНИЕ
Системные вызовы alloc_hugepages() и free_hugepages() появились в Linux 2.5.36 и удалены в 2.5.54. Они существовали только на архитектурах i386 и ia64 (при сборке с параметром CONFIG_HUGETLB_PAGE). В Linux 2.4.20 такие номера системных вызовов остались, но сами вызовы завершаются с ошибкой ENOSYS.

На i386 аппаратура управления памятью умеет работать с обычными страницами (4 КиБ) и огромными страницами (2 или 4 МиБ). Подобно этому, ia64 умеет работать с огромными страницами разных размеров. Эти системные вызовы служат для отображения огромных страниц в память процесса или её освобождения. Огромные страницы блокируются в памяти и не могут быть вытеснены в пространство подкачки.

Аргумент key служит идентификатором. При нулевом значении страницы считаются частными и не наследуются потомками. При положительном значении страницы совместно используются несколькими приложениями посредством одинакового key и наследуются процессами-потомками.

Аргумент addr в free_hugepages() указывает какую страницу нужно освободить: его значением является результат вызова alloc_hugepages(). (Память, на самом деле, освобождается только когда все пользователи её освободят.) Аргумент addr в alloc_hugepages() — это подсказка, которой ядро может и не воспользоваться. Адреса должны быть выровнены соответствующим образом.

Аргумент len задаёт длину требуемого сегмент. Он должен быть кратен размеру огромной страницы.

Аргумент prot определяет тип защиты сегмента памяти. Может быть указано одно из значений: PROT_READ, PROT_WRITE, PROT_EXEC.

Аргумент flag игнорируется, если key не является положительным. В этом случае, если flag — IPC_CREAT, то создаётся новый сегмент огромной страницы, если не существует ни один из указанных идентификаторов. Если флаг не задан, то возвращается ENOENT, если не существует сегмента с заданным идентификатором.

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

## ОШИБКИ
ENOSYS

Системный вызов не поддерживается данным ядром.

## ФАЙЛЫ
/proc/sys/vm/nr_hugepages

Количество настроенных страниц hugetlb. Доступен для чтения и записи.

/proc/meminfo

Выдаёт информацию о числе настроенных страниц hugetlb и их размере в трёх переменных: HugePages_Total, HugePages_Free, Hugepagesize.

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

## ЗАМЕЧАНИЯ
Данные системные вызовы были удалены; они существуют только в ядрах Linux версий с 2.5.36 по 2.5.54. Вместо них теперь можно использовать файловую систему hugetlbfs. Память, поддерживаемая огромными страницами (если есть поддержка в ЦП), получается с помощью mmap(2) в отображаемые файлы этой виртуальной файловой системе.

Максимальное число огромных страниц можно задать в параметре загрузки ядра hugepages=.


title: arch_prctl(2)

text:
# arch_prctl(2)

## ИМЯ
arch_prctl - настроить состояние нити (зависит от архитектуры)

## ОБЗОР

```
#include <asm/prctl.h>
#include <sys/prctl.h>
```

```
int arch_prctl(int code, unsigned long addr);
int arch_prctl(int code, unsigned long *addr);
```

## ОПИСАНИЕ
Вызов arch_prctl() задаёт состояние процесса или нити, зависящие от архитектуры. В аргументе code задаётся подфункция и ей передаётся значение addr; параметр addr рассматривается либо как unsigned long при операциях «установки» (set), либо как unsigned long * при операциях «получения» (get).

Подфункции для x86-64:

ARCH_SET_FS

Установить 64-битную базу для регистра FS равной addr.

ARCH_GET_FS

Вернуть значение 64-битной базы для регистра FS текущей нити в ячейку длинной unsigned long, заданную адресом addr.

ARCH_SET_GS

Установить 64-битную базу для регистра GS равной addr.

ARCH_GET_GS

Вернуть значение 64-битной базы для регистра GS текущей нити в ячейку длинной unsigned long, заданную адресом addr.

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

## ОШИБКИ
EFAULT

В addr задан не выделенный адрес или вне адресного пространства процесса.

EINVAL

code не является допустимой подкомандой.

EPERM

addr лежит вне адресного пространства процесса.

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

## ЗАМЕЧАНИЯ
В настоящее время arch_prctl() поддерживается только на Linux/x86-64 для 64-битных программ.

64-битная база изменяется при загрузке нового 32-битного сегментного селектора.

ARCH_SET_GS выключена в некоторых ядрах.

Переключение контекстов для 64-битных сегментных баз — довольно затратная операция. В качестве оптимизации, если используется 3-битные базовые адреса TLS, arch_prctl() может использовать реальную запись TLS, как при вызове set_thread_area(2), а не изменять сегментный базовый регистр напрямую. Память в первых 2 ГБ адресного пространства может быть выделена через mmap(2) с флагом MAP_32BIT.

Из-за вышеупомянутой оптимизации, использование arch_prctl() и set_thread_area(2) в той же нити опасно, так как они могут перезаписать TLS-записи друг друга.

В glibc версии 2.7 нет прототипа для arch_prctl(). Вам нужно объявлять его самостоятельно. Это может быть исправлено в новых версиях glibc.

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

## СМОТРИТЕ ТАКЖЕ
mmap(2), modify_ldt(2), prctl(2), set_thread_area(2)

Руководство программиста для AMD X86-64


bdflush

title: bdflush(2)

text:
# bdflush(2)

## ИМЯ
bdflush - запускает, сбрасывает на диск или настраивает службу записи буферов кэша

## ОБЗОР

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

```
int bdflush(int func, long *address);
int bdflush(int func, long data);
```

## ОПИСАНИЕ
Замечание: Начиная с Linux 2.6, данный системный вызов считается устаревшим и ничего не делает. Вероятно, он будет удалён в будущих версиях ядра. Сейчас задачу bdflush() выполняет нить ядра pdflush.

bdflush() запускает, сбрасывает на диск или настраивает службу записи буферов кэша. Только процесс с определёнными правами (с мандатом CAP_SYS_ADMIN) может вызвать bdflush().

Если значение func отрицательно или 0, и служба не запущена, то bdflush() запускает службу и не возвращает управление.

Если значение func равно 1, то некоторые «грязные» (dirty) буферы записываются на диск.

Если значение func равно 2 или более и чётно (младший бит равен 0), то в address задаётся адрес ячейки размером с длинное слово, и по этому адресу возвращается для вызывающего процесса параметр настройки с номером (func-2)/2.

Если значение func равно 3 или более и не чётно (младший бит равен 1), то аргумент data является длинным словом, и ядро устанавливает в это значение параметр настройки с номером (func-3)/2.

Набор параметров и разрешённых диапазонов их значений определён в файле fs/buffer.c исходного кода ядра Linux.

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

## ОШИБКИ
EBUSY

Попытка запустить службу, которая уже запущена.

EFAULT

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

EINVAL

Попытка прочитать или записать параметр с неверным номером, или записать неверное значение.

EPERM

Вызывающий процесс не имеет мандата CAP_SYS_ADMIN.

## ВЕРСИИ
Начиная с версии 2.23, в glibc удалена поддержка этого устаревшего системного вызова.

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

## СМОТРИТЕ ТАКЖЕ
sync(1), fsync(2), sync(2)


bind

title: bind(2)

summary: привязывает имя к сокету

text:
# bind(2)

## ИМЯ
bind - привязывает имя к сокету

## ОБЗОР

```
#include <sys/types.h>          /* См. ЗАМЕЧАНИЯ */
#include <sys/socket.h>
```

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

## ОПИСАНИЕ
После создания с помощью socket(2), сокет появляется в адресном пространстве (семействе адресов), но без назначенного адреса. bind() назначает адрес, заданный в addr, сокету, указываемому дескриптором файла sockfd. В аргументе addrlen задаётся размер структуры адреса (в байтах), на которую указывает addr. В силу традиции, эта операция называется «присваивание сокету имени».

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

Правила, используемые при привязке имён, отличаются в разных семействах адресов. Подробности см. в соответствующем справочных страницах в разделе 7. Описание AF_INET находится в ip(7), AF_INET6 в ipv6(7), AF_UNIX в unix(7), AF_APPLETALK в ddp(7), AF_PACKET в packet(7), AF_X25 в x25(7), а AF_NETLINK в netlink(7).

Реальная структура, передаваемая через addr, зависит от семейства адресов. Структура sockaddr определяется так:

```
struct sockaddr {

    sa_family_t sa_family;

    char        sa_data[14];
}
```

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

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

## ОШИБКИ
EACCES

Адрес защищён, или пользователь не является суперпользователем.

EADDRINUSE

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

EADDRINUSE

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

EBADF

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

EINVAL

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

EINVAL

Некорректное значение addrlen, или в addr указан некорректный адрес для этого доменного сокета.

ENOTSOCK

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

Следующие ошибки только для сокетов домена UNIX (AF_UNIX):

EACCES

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

EADDRNOTAVAIL

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

EFAULT

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

ELOOP

При определении addr превышено количество переходов по символьной ссылке.

ENAMETOOLONG

Аргумент addr слишком большой.

ENOENT

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

ENOMEM

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

ENOTDIR

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

EROFS

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

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

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

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

## ДЕФЕКТЫ
Не описываются возможности, связанные с работой прозрачных прокси.

## ПРИМЕР
Пример использования bind() с сокетами домена Internet можно найти в getaddrinfo(3).

Следующий пример показывает как привязать потоковый сокет к домену UNIX (AF_UNIX) и принимать соединения:

```
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MY_SOCK_PATH "/somepath"
#define LISTEN_BACKLOG 50
#define handle_error(msg) \

    do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{

    int sfd, cfd;

    struct sockaddr_un my_addr, peer_addr;

    socklen_t peer_addr_size;

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);

    if (sfd == -1)

        handle_error("socket");

    memset(&my_addr, 0, sizeof(struct sockaddr_un));

                        /* Очистка структуры */

    my_addr.sun_family = AF_UNIX;

    strncpy(my_addr.sun_path, MY_SOCK_PATH,

            sizeof(my_addr.sun_path) - 1);

    if (bind(sfd, (struct sockaddr *) &my_addr,

            sizeof(struct sockaddr_un)) == -1)

        handle_error("bind");

    if (listen(sfd, LISTEN_BACKLOG) == -1)

        handle_error("listen");

    /* Теперь мы можем принимать входящие соединения по одному

       с помощью accept(2) */

    peer_addr_size = sizeof(struct sockaddr_un);

    cfd = accept(sfd, (struct sockaddr *) &peer_addr,

                 &peer_addr_size);

    if (cfd == -1)

        handle_error("accept");

    /* Код обработки входящего соединения(й)... */

    /* Если имя пути сокета, MY_SOCK_PATH, больше не требуется,

       то его нужно удалить с помощью unlink(2) или remove(3) */
}
```

## СМОТРИТЕ ТАКЖЕ
accept(2), connect(2), getsockname(2), listen(2), socket(2), getaddrinfo(3), getifaddrs(3), ip(7), ipv6(7), path_resolution(7), socket(7), unix(7)


bpf

title: bpf(2)

text:
# bpf(2)

## ИМЯ
bpf - выполняет команду с расширенной картой BPF или программу

## ОБЗОР

```
#include <linux/bpf.h>
int bpf(int cmd, union bpf_attr *attr, unsigned int size);
```

## ОПИСАНИЕ
Системный вызов bpf() выполняет набор операций, связанных с расширенными пакетными фильтрами Беркли (Berkeley Packet Filters). Расширенные BPF (или eBPF) подобны первоначальным («классическим») BPF (cBPF), которые используются для фильтрации сетевых пакетов. Перед загрузкой программы cBPF и eBPF анализируются ядром на предмет их безвредности для работающей системы.

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

### Структура/архитектура расширенных BPF
Карты eBPF — это обобщённая структура данных, которая позволяет хранить данных различных типов. Типы данных, в общем случае, считаются двоичными объектами (binary blobs), поэтому пользователь просто указывает размер ключа и размер значения при создании карты. Другими словами, ключ/значение задаваемой карты могут иметь произвольную структуру.

Пользовательский процесс может создать несколько карт (с парами ключ/значение нераспознаваемых байт данных (opaque bytes of data)) и работать с ними через файловые дескрипторы. Несколько программ eBPF могут получать доступ к одним и тем же картам параллельно. Решение, что хранить в картах, полностью отдано пользовательскому процессу и программе eBPF.

Существует специальный карточный тип, называемый программным массивом (program array). В данном типе карты хранятся файловые дескрипторы, указывающие на другие программы eBPF. Когда выполняется поиск в карте программный поток в этом месте перенаправляется в начало другой программы eBPF и не возвращается в вызывающую программу. Уровень вложенности ограничен 32, поэтому бесконечные циклы невозможны. Во время выполнения программные файловые дескрипторы, хранящиеся в карте, не могут быть изменены, поэтому функциональность программы можно изменить только на основе специальных требований. Все программы, на которые есть ссылки из карты программного массива, должны заранее загружаться в ядро с помощью bpf(). Если поиск по карте завершился с ошибкой, то текущая программа продолжает выполняться. Подробней смотрите далее в описании BPF_MAP_TYPE_PROG_ARRAY.

Обычно, программы eBPF загружаются пользовательским процессом и выгружаются при его завершении. В некоторых случаях, например, tc-bpf(8), программа продолжает работать внутри ядра даже после того, как процесс загрузивший программу, закончил работать. В этом случае ссылку на программу eBPF после того, как файловый дескриптор был закрыт программой из пользовательского пространства, содержит подсистема tc. То есть, будет ли специальная программа продолжать работать внутри ядра, зависит от того, будет ли она присоединена к указанной подсистеме ядра после загрузки через bpf().

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

Программы eBPF могут быть присоединены к различным событиям. Эти события могут возникать при поступлении сетевых пакетов, это могут быть события трассировки, события распределения по сетевым очередям (для программ eBPF, присоединённых к классификатору tc(8)) и другие типы событий, которые могут быть добавлены в будущем. Новое событие активирует выполнение программы eBPF, которое может сохранить информацию о событии в картах eBPF. Кроме сохранения данных, программы eBPF могут вызывать фиксированный набор вспомогательных функций ядра.

Программа eBPF может быть присоединена к нескольким событиям, а различные программы eBPF могут иметь доступ к одной карте:

```
tracing     tracing    tracing    packet      packet     packet
event A     event B    event C    on eth0     on eth1    on eth2

 |             |         |          |           |          ^

 |             |         |          |           v          |

 --> tracing <--     tracing      socket    tc ingress   tc egress

      prog_1          prog_2      prog_3    classifier    action

      |  |              |           |         prog_4      prog_5

   |---  -----|  |------|          map_3        |           |

 map_1       map_2                              --| map_4 |--
```

### Аргументы
В аргументе cmd указывается операция, которая будет выполнена системным вызовом bpf(). Для каждой операции в attr задаётся соответствующий аргумент, который является объединением типа bpf_attr (смотрите далее). В аргументе size указывается размер объединения, на который ссылается attr.

Значением cmd может быть одно из:

BPF_MAP_CREATE

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

BPF_MAP_LOOKUP_ELEM

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

BPF_MAP_UPDATE_ELEM

Создать или обновить элемент (пару ключ/значение) в указанной карте.

BPF_MAP_DELETE_ELEM

Найти и удалить элемент по ключу в указанной карте.

BPF_MAP_GET_NEXT_KEY

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

BPF_PROG_LOAD

Проверить и загрузить программу eBPF; возвращается новый файловый дескриптор, связанный с программой. Для нового файлового дескриптора флаг close-on-exec (смотрите fcntl(2)) устанавливается автоматически.

Объединение bpf_attr состоит из различных анонимных структур, которые используются в различных командах bpf():

```
union bpf_attr {

    struct {    /* используется в BPF_MAP_CREATE */

        __u32         map_type;

        __u32         key_size;    /* размер ключа в байтах */

        __u32         value_size;  /* размер значения в байтах */

        __u32         max_entries; /* максимальное количество

                                      элементов в карте */

    };

    struct {    /* используется в командах BPF_MAP_*_ELEM

                   и BPF_MAP_GET_NEXT_KEY */

        __u32         map_fd;

        __aligned_u64 key;

        union {

            __aligned_u64 value;

            __aligned_u64 next_key;

        };

        __u64         flags;

    };

    struct {    /* используется в BPF_PROG_LOAD */

        __u32         prog_type;

        __u32         insn_cnt;

        __aligned_u64 insns;      /* 'const struct bpf_insn *' */

        __aligned_u64 license;    /* 'const char *' */

        __u32         log_level;  /* уровень детализации

                                     при проверке */

        __u32         log_size;   /* размер пользовательского

                                     буфера */

        __aligned_u64 log_buf;    /* буфер 'char *'

                                     выделяемый пользователем */

        __u32         kern_version;

                                  /* проверяется, если

                                     prog_type=kprobe

                                     (начиная с Linux 4.1) */

    };
} __attribute__((aligned(8)));
```

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

Каждый тип карты имеет следующие атрибуты:

- тип

- максимальное количество элементов

- размер ключа в байтах

- размер значения в байтах

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

BPF_MAP_CREATE

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

```
int
bpf_create_map(enum bpf_map_type map_type,

               unsigned int key_size,

               unsigned int value_size,

               unsigned int max_entries)
{

    union bpf_attr attr = {

        .map_type    = map_type,

        .key_size    = key_size,

        .value_size  = value_size,

        .max_entries = max_entries

    };

    return bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
}

```

Новая карта имеет тип, указанный в map_type, и атрибуты, в соответствии с key_size, value_size и max_entries. При успешном выполнении этой операции возвращается файловый дескриптор. При ошибке возвращается -1 и в errno записывается EINVAL, EPERM или ENOMEM.

Атрибуты key_size и value_size будут использоваться механизмом проверки при загрузке программы для проверки того, что программа вызывает вспомогательные функции bpf_map_*_elem() с корректно инициализированным key и что программа не обращается к элементу карты value за пределами, задаваемыми value_size. Например, когда карта создана с key_size равным 8 и программа eBPF вызывает

```
bpf_map_lookup_elem(map_fd, fp - 4)

```

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

```
    bpf_map_lookup_elem(map_fd, void *key)

```

ожидается чтение 8 байт из места, указанного key, но начальный адрес fp - 4 (где fp — вершина стека) выходит за границы стека.

Аналогично, когда карта создаётся с value_size равным 1 и программа eBPF содержит

```
value = bpf_map_lookup_elem(...);
*(u32 *) value = 1;

```

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

В настоящее время поддерживаются следующие значения map_type:

```
enum bpf_map_type {

    BPF_MAP_TYPE_UNSPEC,  /* 0 зарезервирован для карты неправильного типа */

    BPF_MAP_TYPE_HASH,

    BPF_MAP_TYPE_ARRAY,

    BPF_MAP_TYPE_PROG_ARRAY,

    BPF_MAP_TYPE_PERF_EVENT_ARRAY,

    BPF_MAP_TYPE_PERCPU_HASH,

    BPF_MAP_TYPE_PERCPU_ARRAY,

    BPF_MAP_TYPE_STACK_TRACE,

    BPF_MAP_TYPE_CGROUP_ARRAY,

    BPF_MAP_TYPE_LRU_HASH,

    BPF_MAP_TYPE_LRU_PERCPU_HASH,

    BPF_MAP_TYPE_LPM_TRIE,

    BPF_MAP_TYPE_ARRAY_OF_MAPS,

    BPF_MAP_TYPE_HASH_OF_MAPS,

    BPF_MAP_TYPE_DEVMAP,

    BPF_MAP_TYPE_SOCKMAP,

    BPF_MAP_TYPE_CPUMAP,
};

```

Для map_type выбирается одна из доступных реализаций карт в ядре. Для всех типов карт программы eBPF получают доступ через одни и те же вспомогательные функции bpf_map_lookup_elem() и bpf_map_update_elem(). Подробности о различных типах карт приведены далее.

BPF_MAP_LOOKUP_ELEM

Команда BPF_MAP_LOOKUP_ELEM ищет элемент с заданным key в карте, на которую ссылается файловый дескриптор fd.

```
int
bpf_lookup_elem(int fd, const void *key, void *value)
{

    union bpf_attr attr = {

        .map_fd = fd,

        .key    = ptr_to_u64(key),

        .value  = ptr_to_u64(value),

    };

    return bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}

```

Если элемент найден, то возвращается ноль и значение элемента сохраняется в value, которое должно указывать на буфер размером value_size байт.

Если элемент не найден, то возвращается -1, а в errno записывается ENOENT.

BPF_MAP_UPDATE_ELEM

Команда BPF_MAP_UPDATE_ELEM создаёт или обновляет элемент с заданными key/value в карте, на которую ссылается файловый дескриптор fd.

```
int
bpf_update_elem(int fd, const void *key, const void *value,

                uint64_t flags)
{

    union bpf_attr attr = {

        .map_fd = fd,

        .key    = ptr_to_u64(key),

        .value  = ptr_to_u64(value),

        .flags  = flags,

    };

    return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}

```

В аргументе flags должно быть указано одно из:

BPF_ANY

Создать новый элемент или обновить существующий.

BPF_NOEXIST

Создать новый элемент, только если он не существует.

BPF_EXIST

Обновить существующий элемент.

При успешном выполнении операции возвращается ноль. При ошибке возвращается -1, а в errno записывается EINVAL, EPERM, ENOMEM или E2BIG. Значение E2BIG показывает, что количество элементов в карте достигло ограничения max_entries, заданного при создании карты. Значение EEXIST устанавливается, если в flags указано BPF_NOEXIST и элемент с key уже существует в карте. Значение ENOENT устанавливается, если в flags указано BPF_EXIST и элемент с key не существует в карте.

BPF_MAP_DELETE_ELEM

Команда BPF_MAP_DELETE_ELEM удаляет элемент с ключом key из карты, на которую ссылается файловый дескриптор fd.

```
int
bpf_delete_elem(int fd, const void *key)
{

    union bpf_attr attr = {

        .map_fd = fd,

        .key    = ptr_to_u64(key),

    };

    return bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}

```

При успешном выполнении возвращается ноль. Если элемент не найден, то возвращается -1, а errno присваивается значение ENOENT.

BPF_MAP_GET_NEXT_KEY

Команда BPF_MAP_GET_NEXT_KEY ищет элемент по ключу key в карте, на которую указывает файловый дескриптор fd, и присваивает указателю next_key ключ следующего элемента.

```
int
bpf_get_next_key(int fd, const void *key, void *next_key)
{

    union bpf_attr attr = {

        .map_fd   = fd,

        .key      = ptr_to_u64(key),

        .next_key = ptr_to_u64(next_key),

    };

    return bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
}

```

Если key найден, то операция возвращает ноль и устанавливает указатель next_key равным ключу следующего элемента. Если key не найден, то операция возвращает ноль и устанавливает указатель next_key равным ключу первого элемента. Если key — последний элемент, то возвращается -1 и errno присваивается значение ENOENT. Другие возможные значения errno: ENOMEM, EFAULT, EPERM и EINVAL. Данный метод можно использовать для обхода всех элементов в карте.

close(map_fd)

Данный вызов удаляет карту, на которую ссылается файловый дескриптор map_fd. Когда программа пользовательского пространства, создавшая карту, завершает работу, все карты удаляются автоматически (но смотрите ЗАМЕЧАНИЯ).

### Типы карт eBPF
Поддерживаются следующие типы карт:

BPF_MAP_TYPE_HASH

Карты в виде хэш-таблицы имеют следующие характеристики:

- Карты создаются и уничтожаются программами пользовательского пространства. Из пользовательских и eBPF программ можно выполнять операции поиска, обновления и удаления.

- За выделение/освобождения места для пар ключ/значение отвечает ядро.

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

- Функция map_update_elem() выполняет атомарную замену существующего элемента.

Карты в виде хэш-таблицы оптимизированы под скоростной поиск.

BPF_MAP_TYPE_ARRAY

Карты в виде массива имеют следующие характеристики:

- Оптимизированы под самый быстрый поиск. В будущем механизм проверки/компилятор JIT смогут распознавать операции lookup(), которые выдают ключ-константу и оптимизировать его в указатель-константу. Также возможно оптимизировать ключ не константу в явный указатель арифметически, так как указатели и value_size являются константами на всём протяжении жизни программы eBPF. Другими словами, array_map_lookup_elem() может быть «встроена» механизмом проверки/компилятором JIT, одновременно сохраняя доступ к этой карте из пространства пользователя.

- Место под все элементы массива выделяется заранее и заполняется нулями при инициализации.

- Ключом является индекс массива, и он всегда занимает четыре байта.

- Функция map_delete_elem() завершается с ошибкой EINVAL, так как элементы нельзя удалять.

- Функция map_update_elem() заменяет элементы не атомарным образом; для атомарных обновлений нужно использовать карту в виде хэш-таблицы. Однако есть особый случай при работе и с массивами: можно использовать встроенную атомарную функцию __sync_fetch_and_add() для работы с 32 и 64-битными атомарными указателями. Например, это можно использовать, если само значение целиком представляет собой одиночный счётчик, или если есть структура с несколькими счётчиками, то функцию можно применять для отдельных счётчиков. Это довольно часто полезно для агрегирования событий и учёта.

Возможные варианты использования карт в виде массивов:

- «Глобальные» переменные eBPF: массив из одного элемента 1, чей ключ (индекс) равен 0, а значение — набор «глобальных» переменных, в которых программы eBPF могут хранить состояние между событиями.

- Агрегация событий трассировки в постоянный набор блоков (buckets).

- Учёт сетевых событий, например, количество и размер пакетов.

BPF_MAP_TYPE_PROG_ARRAY (начиная с Linux 4.2)

Карта в виде программного массива — специальный вариант карты в виде массива, в которой значения содержат только файловые дескрипторы, указывающие на другие программы eBPF. То есть key_size и value_size должны занимать по четыре байта. Данная карта используется вместе с функцией bpf_tail_call().

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

```
void bpf_tail_call(void *context, void *prog_map,

                   unsigned int index);

```

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

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

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

### Программы eBPF
Команда BPF_PROG_LOAD используется для загрузки программы eBPF в ядро. Возвращаемым значением является новый файловый дескриптор, связанный с этой программой eBPF.

```
char bpf_log_buf[LOG_BUF_SIZE];
int
bpf_prog_load(enum bpf_prog_type type,

              const struct bpf_insn *insns, int insn_cnt,

              const char *license)
{

    union bpf_attr attr = {

        .prog_type = type,

        .insns     = ptr_to_u64(insns),

        .insn_cnt  = insn_cnt,

        .license   = ptr_to_u64(license),

        .log_buf   = ptr_to_u64(bpf_log_buf),

        .log_size  = LOG_BUF_SIZE,

        .log_level = 1,

    };

    return bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
}
```

Значением prog_type может быть один из типов программ:

```
enum bpf_prog_type {

    BPF_PROG_TYPE_UNSPEC,        /* 0 используется как некорректное

                                    значение типа программы */

    BPF_PROG_TYPE_SOCKET_FILTER,

    BPF_PROG_TYPE_KPROBE,

    BPF_PROG_TYPE_SCHED_CLS,

    BPF_PROG_TYPE_SCHED_ACT,
};

```

Дополнительную информацию о типах программ eBPF смотрите далее.

Остальные поля bpf_attr заполняются следующим образом:

- Поле insns — массив инструкций struct bpf_insn.

- Поле insn_cnt — количество инструкций в программе, на которую ссылается insns.

- Поле license — строка лицензии, которая должна быть совместима с GPL, чтобы можно было вызывать вспомогательные функции, помеченные как gpl_only (условия лицензии такие же как и для модулей ядра, то есть также можно использовать двойные лицензии, например «Dual BSD/GPL»).

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

- Поле log_size — размер буфера, на который указывает log_buf. Если размер буфера недостаточен для хранения всех сообщений от механизма проверки, то возвращается -1, а errno присваивается ENOSPC.

- Поле log_level — степень подробности отчёта механизма проверки. Значение ноль означает, что механизм проверки не будет вести журнал; в этом случае значение log_buf должно быть равно указателю NULL, а log_size равно нулю.

При применении close(2) к файловому дескриптору, полученному от BPF_PROG_LOAD, происходит выгрузка программы eBPF (но смотрите ЗАМЕЧАНИЯ).

Карты доступны из программ eBPF и используются для обмена данными между программами eBPF, а также между программами eBPF и приложениями пользовательского пространства. Например, программы eBPF могут обрабатывать различные события (kprobe, пакеты) и сохранять свои данные в карте, а затем программы пользовательского пространства могут выбирать данные из карты. И наоборот, программы пользовательского пространства могут использовать карту в качестве механизма настройки, заполняя карту значениями, читаемыми программой eBPF, которая затем, согласно этим значениям, изменяет своё поведение на лету.

### Типы программ eBPF
Типом программы eBPF (prog_type) определяется поднабор вспомогательных функций ядра, который программа может вызывать. Тип программы также определяет входящие данные программы (контекст) — в виде формата struct bpf_context (который представляет собой двоичный объект данных, передаваемый в программу eBPF первым параметром).

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

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

Поддерживаются следующие типы программ:

BPF_PROG_TYPE_SOCKET_FILTER (начиная с Linux 3.19)

В настоящее время, набор функций для BPF_PROG_TYPE_SOCKET_FILTER такой:

```
bpf_map_lookup_elem(map_fd, void *key)

                    /* поиск ключа в map_fd */
bpf_map_update_elem(map_fd, void *key, void *value)

                    /* обновление ключа/значения */
bpf_map_delete_elem(map_fd, void *key)

                    /* удаление ключа из map_fd */

```

Аргумент bpf_context представляет собой указатель на struct __sk_buff.

BPF_PROG_TYPE_KPROBE (начиная с Linux 4.1)

[Будет описано]

BPF_PROG_TYPE_SCHED_CLS (начиная с Linux 4.1)

[Будет описано]

BPF_PROG_TYPE_SCHED_ACT (начиная с Linux 4.1)

[Будет описано]

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

Начиная с Linux 3.19, следующий вызов присоединяет программу prog_fd к сокету sockfd, который был создан вызовом socket(2) ранее:

```
setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF,

           &prog_fd, sizeof(prog_fd));
```

Начиная с Linux 4.1, следующий вызов можно использовать для присоединения программы eBPF, на которую ссылается файловый дескриптор prog_fd, к файловому дескриптору событий perf event_fd, созданному вызовом perf_event_open(2) ранее:

```
ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
```

## ПРИМЕРЫ

```
/* пример bpf+sockets:

 * 1. создать карту в виде массива из 256 элементов

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

 *    r0 = skb->data[ETH_HLEN + offsetof(struct iphdr, protocol)]

 *    map[r0]++

 * 3. присоединить prog_fd к неструктурированному сокету от setsockopt()

 * 4. напечатать количество пакетов TCP/UDP, принимаемых каждую секунду

 */
int
main(int argc, char **argv)
{

    int sock, map_fd, prog_fd, key;

    long long value = 0, tcp_cnt, udp_cnt;

    map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key),

                            sizeof(value), 256);

    if (map_fd < 0) {

        printf("ошибка при создании карты '%s'\n", strerror(errno));

        /* вероятно, запущена без прав root */

        return 1;

    }

    struct bpf_insn prog[] = {

        BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),        /* r6 = r1 */

        BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol)),

                                /* r0 = ip->proto */

        BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),

                                /* *(u32 *)(fp - 4) = r0 */

        BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),       /* r2 = fp */

        BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),      /* r2 = r2 - 4 */

        BPF_LD_MAP_FD(BPF_REG_1, map_fd),           /* r1 = map_fd */

        BPF_CALL_FUNC(BPF_FUNC_map_lookup_elem),

                                /* r0 = map_lookup(r1, r2) */

        BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),

                                /* if (r0 == 0) goto pc+2 */

        BPF_MOV64_IMM(BPF_REG_1, 1),                /* r1 = 1 */

        BPF_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0),

                                /* lock *(u64 *) r0 += r1 */

        BPF_MOV64_IMM(BPF_REG_0, 0),                /* r0 = 0 */

        BPF_EXIT_INSN(),                            /* вернуть r0 */

    };

    prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog,

                            sizeof(prog) / sizeof(prog[0]), "GPL");

    sock = open_raw_sock("lo");

    assert(setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd,

                      sizeof(prog_fd)) == 0);
пакетов    for (;;) {

        key = IPPROTO_TCP;

        assert(bpf_lookup_elem(map_fd, &key, &tcp_cnt) == 0);

        key = IPPROTO_UDP;

        assert(bpf_lookup_elem(map_fd, &key, &udp_cnt) == 0);

        printf("TCP %lld UDP %lld пакетов\n", tcp_cnt, udp_cnt);

        sleep(1);

    }

    return 0;
}
```

Другой рабочий код можно найти в каталоге samples/bpf дерева исходного кода ядра.

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

BPF_MAP_CREATE

Новый файловый дескриптор, связанный с картой eBPF.

BPF_PROG_LOAD

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

Все остальные команды

Ноль.

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

## ОШИБКИ
E2BIG

Программа eBPF слишком большая или достигнуто ограничение max_entries (максимальное количество элементов) в карте.

EACCES

Для BPF_PROG_LOAD: хотя все инструкции программы корректны, программа считается ошибочной, так как признана небезопасной. Это может возникать из-за доступа к запрещённой области или неинициализированного стека/регистра или функциональные ограничения не совпадают с типами или выполняется невыровненный доступ к памяти. В этом случае рекомендуется вызвать bpf() ещё раз с log_level = 1 и посмотреть log_buf на предмет причины, указанной механизмом проверки.

EBADF

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

EFAULT

Значение одного из указателей (key, value, log_buf или insns) находится вне доступного адресного пространства.

EINVAL

Значение cmd не распознано ядром.

EINVAL

Для BPF_MAP_CREATE: некорректное значение атрибутов или map_type.

EINVAL

Для команд BPF_MAP_*_ELEM: некоторые поля union bpf_attr, не используемые этой командой, не обнулены.

EINVAL

Для BPF_PROG_LOAD: попытка загрузить некорректную программу. Программы eBPF могут быть признаны некорректными из-за нераспознанных инструкций, использования зарезервированных полей, переходов за пределы диапазона, бесконечных циклов или вызовов неизвестных функций.

ENOENT

Для BPF_MAP_LOOKUP_ELEM и BPF_MAP_DELETE_ELEM: элемент с заданным key не найден.

ENOMEM

Невозможно выделить достаточно памяти.

EPERM

Вызов запущен без необходимых прав (без мандата CAP_SYS_ADMIN).

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

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

## ЗАМЕЧАНИЯ
В текущей реализации для всех команд bpf() требуется, чтобы у вызывающего был мандат CAP_SYS_ADMIN.

Объекты eBPF (карты и программы) могут использоваться несколькими процессами одновременно. Например, после fork(2) потомок наследует файловые дескрипторы, ссылающиеся на одинаковые объекты eBPF. Также, файловые дескрипторы, ссылающиеся на объекты eBPF, можно передавать через доменные сокеты UNIX. Файловые дескрипторы, ссылающиеся на объекты eBPF, можно дублировать обычным образом с помощью dup(2) и подобных вызовов. Объекты eBPF уничтожаются только после закрытия всех файловых дескрипторов, ссылающихся на объект.

Программы eBPF можно писать на специализированной версии языка C, которая компилируется (с помощью компилятора clang) в байт-код eBPF. В этой версии C отсутствуют различные свойства, например, глобальные переменные, функции с переменным числом аргументов, числа с плавающей запятой и нельзя передавать структуры в качестве аргументов. Примеры можно найти в файлах samples/bpf/*_kern.c из дерева исходного кода ядра.

В ядре имеется оперативный компилятор (JIT), который с целью производительности транслирует байт-код eBPF в машинный код. В ядрах Linux до версии 4.15 по умолчанию компилятор JIT отключён, но эта возможность контролируется записью следующих строк целых чисел в файл /proc/sys/net/core/bpf_jit_enable:

0

Выключить компиляцию JIT (по умолчанию).

1

Обычная компиляция.

2

Режим отладки. Генерируемый код операций сбрасывается в виде шестнадцатеричных чисел в журнал ядра. Затем его можно дизассемблировать с помощью программы tools/net/bpf_jit_disasm.c, которая находится в дереве исходного кода ядра.

Начиная с Linux 4.15, ядро можно настраивать через параметр CONFIG_BPF_JIT_ALWAYS_ON. В этом случае компилятор JIT всегда включён и bpf_jit_enable устанавливается в 1 и это нельзя изменить (данный параметр ядра был добавлен для предотвращения одной из атак «Спектр», направленной на интерпретатор BPF).

В настоящее время компилятор JIT для eBPF доступен на следующих архитектурах:

- x86-64 (начиная с Linux 3.18; cBPF начиная с Linux 3.0);

- ARM32 (начиная с Linux 3.18; cBPF начиная с Linux 3.4);

- SPARC 32 (начиная с Linux 3.18; cBPF начиная с Linux 3.5);

- ARM-64 (начиная с Linux 3.18);

- s390 (начиная с Linux 4.1; cBPF начиная с Linux 3.7);

- PowerPC 64 (начиная с Linux 4.8; cBPF начиная с Linux 3.1);

- SPARC 64 (начиная с Linux 4.12);

- x86-32 (начиная с Linux 4.18);

- MIPS 64 (начиная с Linux 4.18; cBPF начиная с Linux 3.16);

- riscv (начиная с Linux 5.1).

## СМОТРИТЕ ТАКЖЕ
seccomp(2), bpf-helpers(7), socket(7), tc(8), tc-bpf(8)

Классический и расширенный BPF описаны в файле исходного кода ядра Documentation/networking/filter.txt.


brk

title: brk(2)

summary: изменяет размер сегмента данных

text:
# brk(2)

## ИМЯ
brk, sbrk - изменяет размер сегмента данных

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

int brk(void *addr);

void *sbrk(intptr_t increment);

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

brk(), sbrk():

Начиная с glibc 2.19:

```
_DEFAULT_SOURCE ||

    (_XOPEN_SOURCE >= 500) &&

    ! (_POSIX_C_SOURCE >= 200112L)
```

В glibc с 2.12 по 2.19:

```
_BSD_SOURCE || _SVID_SOURCE ||

    (_XOPEN_SOURCE >= 500) &&

    ! (_POSIX_C_SOURCE >= 200112L)
```

До glibc 2.12:

_BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE >= 500

## ОПИСАНИЕ
Вызов brk() и sbrk() изменяет расположение маркера окончания программы (program break), который определяет конец сегмента данных процесса (т.е., маркер окончания — это первая точка после конца сегмента неинициализированных данных). Увеличение маркера окончания программы позволяет процессу выделить память; уменьшение маркера приводит к освобождению памяти.

brk() устанавливает конец сегмента данных в значение, указанное в аргументе addr, если это значение является приемлемым, система имеет достаточно памяти и процесс не достиг максимально возможного размера своего сегмента данных (см. setrlimit(2)).

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

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

При успешном выполнении sbrk() возвращает предыдущий маркер окончания программы. Если маркер окончания был увеличен, то это значение указывает на начало новой выделенной памяти. В случае ошибки возвращается (void *) -1, а errno становится равной ENOMEM.

## СООТВЕТСТВИЕ СТАНДАРТАМ
4.3BSD; SUSv1, помечены как УСТАРЕВШИЕ в SUSv2, удалены из POSIX.1-2001.

## ЗАМЕЧАНИЯ
Не используйте brk() и sbrk(): для выделения памяти функции malloc(3) являются более переносимыми и удобными.

В различных системах используются различные типы для аргумента sbrk(). Обычно это int, ssize_t, ptrdiff_t, intptr_t.

### Отличия между библиотекой C и ядром
Возвращаемое brk() значение, описанное выше, является частью поведения обёрточной функции glibc к системному вызову Linux brk(). В большинстве других реализаций возвращаемое brk() значение то же самое; это значение также описано в SUSv2. Однако, реальный системный вызов Linux в случае успешного завершения возвращает новый маркер окончания программы. При ошибке системный вызов возвращает текущий маркер окончания. Обёрточная функция glibc делает то же самое (т. е., проверяет меньше ли новый маркер чем addr), возвращая значения 0 и -1, как описано выше.

В Linux, вызов sbrk() реализован в виде библиотечной функции, которая использует системный вызов brk() и ведёт внутренний учёт для возврата старого значения маркера окончания.

## СМОТРИТЕ ТАКЖЕ
execve(2), getrlimit(2), end(3), malloc(3)


cacheflush

title: cacheflush(2)

text:
# cacheflush(2)

## ИМЯ
cacheflush - выталкивает содержимое кэша инструкций и/или данных

## ОБЗОР

```
#include <asm/cachectl.h>
```

```
int cacheflush(char *addr, int nbytes, int cache);
```

## ОПИСАНИЕ
cacheflush() выталкивает содержимое указанного кэша(ей) обратно в пользовательское адресное пространство в диапазоне с addr по (addr+nbytes-1). Параметр cache может принимать одно из значений:

ICACHE

Выталкивает кэш инструкций.

DCACHE

Записать обратно в память и объявить недействительными задетые достоверные строки кэша.

BCACHE

Тоже что и (ICACHE|DCACHE).

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

## ОШИБКИ
EFAULT

Некоторая часть или весь диапазон адресов с addr по (addr+nbytes-1) недоступен.

EINVAL

Значение cache не равно ICACHE, DCACHE или BCACHE (но смотрите ДЕФЕКТЫ).

## СООТВЕТСТВИЕ СТАНДАРТАМ
В прошлом, данный системный вызов был доступен во всех вариантах UNIX на MIPS включая RISC/os, IRIX, Ultrix, NetBSD, OpenBSD и FreeBSD (и также в некоторых ОС не-UNIX MIPS), поэтому существование этого вызова в ОС на MIPS является стандартом де-факто.

### Предостережение
Вызов cacheflush() не должен использоваться в переносимых программах. В Linux, этот вызов сперва появился на архитектуре MIPS, но в настоящее время Linux предоставляет системный вызов cacheflush() и на других архитектурах, но с другими аргументами.

## ДЕФЕКТЫ
Ядра Linux до версии 2.6.11 игнорируют аргументы addr и nbytes, что делает этот вызов относительно дорогим — всегда очищается весь кэш.

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


capget

title: capget(2)

summary: установка/получение мандатов нити(ей)

text:
# capget(2)

## ИМЯ
capget, capset - установка/получение мандатов нити(ей)

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

int capget(cap_user_header_t hdrp, cap_user_data_t datap);

int capset(cap_user_header_t hdrp, const cap_user_data_t datap);

## ОПИСАНИЕ
Данные системные вызовы представляют собой низкоуровневый интерфейс ядра для получения и установки мандатов нити. Кроме того, что эти системные вызовы есть только в Linux, из-за них, вероятно, изменится программный интерфейс ядра; с каждой новой версией ядра эти вызовы используются всё чаще (в частности, типы cap_user_*_t), но старые программы работают как и прежде.

Переносимыми интерфейсами являются cap_set_proc(3) и cap_get_proc(3); если возможно, в приложениях используйте именно их.

### Подробная информация
На данный момент в ядре определены следующие структуры:

```
#define _LINUX_CAPABILITY_VERSION_1  0x19980330
#define _LINUX_CAPABILITY_U32S_1     1

        /* V2 добавлена в Linux 2.6.25; устарело */
#define _LINUX_CAPABILITY_VERSION_2  0x20071026
#define _LINUX_CAPABILITY_U32S_2     2

        /* V3 добавлена в Linux 2.6.26 */
#define _LINUX_CAPABILITY_VERSION_3  0x20080522
#define _LINUX_CAPABILITY_U32S_3     2
typedef struct __user_cap_header_struct {

   __u32 version;

   int pid;
} *cap_user_header_t;
typedef struct __user_cap_data_struct {

   __u32 effective;

   __u32 permitted;

   __u32 inheritable;
} *cap_user_data_t;
```

Поля effective, permitted и inheritable — это битовые маски мандатов, определённых в capabilities(7). Заметим, что значения CAP_* являются индексами битов и требуется сдвиг битов перед выполнением операции ИЛИ над битовыми полями. Чтобы определить структуры для передачи в системный вызов, используйте имена struct __user_cap_header_struct и struct __user_cap_data_struct, так как посредством typedef описаны только указатели.

Ядра до версии 2.6.25 предъявляют 32-битные мандаты с версией _LINUX_CAPABILITY_VERSION_1. В Linux 2.6.25+ добавлены 64-битные наборы мандатов с версией _LINUX_CAPABILITY_VERSION_2. Однако имеется незначительная проблема в программном интерфейсе и в Linux 2.6.26 добавлена _LINUX_CAPABILITY_VERSION_3 для её исправления.

Заметим, что в 64-битных мандатах используются datap[0] и datap[1], в то время как в 32-битных только datap[0].

В ядрах, которые поддерживают файловые мандаты (поддержка мандатов VFS) эти системные вызовы ведут себя немного по-другому. Данная поддержка добавлена как необязательная в Linux 2.6.24 и стала постоянной (не отключаемой) в Linux 2.6.33.

С помощью вызова capget() можно выполнить проверку мандатов любого процесса, указав его ID в поле hdrp->pid.

Подробную информацию о данных смотрите в capabilities(7).

### Ядро с поддержкой мандатов VFS
Для мандатов VFS используется расширенный атрибут файла (смотрите xattr(7)), позволяющий присоединять мандаты к исполняемым файлам. Данная модель привилегий делает устаревшей ядерную поддержку асинхронного назначения мандатов одного процесса другому. То есть в ядрах с мандатами VFS при вызове capset() разрешены только значения hdrp->pid равные 0 или gettid(2), что приводит к тому же результату.

### Ядро без поддержки мандатов VFS
В старых ядрах без поддержки мандатов VFS вызов capset(), если вызывающий имеет мандат CAP_SETPCAP, можно использовать для изменения не только собственными мандатами вызывающего, то и мандатами других нитей. Вызов работает с мандатами нити, указанной в в поле pid из hdrp, если оно не равно нулю, или мандатами вызывающей нити, когда pid равно 0. Если pid указывает на процесс с одной нитью, то значением pid может быть обычным идентификатором процесса; работа с нитью в многонитиевом процессе требует ID нити такого же типа, что и возвращается gettid(2). У capset() pid также может быть: -1 — выполнить изменение у всех нитей, за исключением вызывающей и init(1); меньше -1 — выполнить изменение всех членов группы процесса, чей ID равен -pid.

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

Вызовы завершаются с ошибкой EINVAL и изменяют поле version в hdrp на предпочитаемое ядром значение _LINUX_CAPABILITY_VERSION_?, если указано неподдерживаемое значение version. Таким способом можно проверить какая версия мандатов является предпочтительной.

## ОШИБКИ
EFAULT

Неправильный адрес памяти. Значение hdrp не должно быть равно NULL. Значение datap может быть NULL только, когда пользователь пытается определить предпочтительную версию формата мандатов, поддерживаемую ядром.

EINVAL

Один из аргументов неправилен.

EPERM

Была сделана попытка добавить мандат к списку разрешённых, эффективных или унаследованных мандатов, но это не разрешено согласно списку разрешённых.

EPERM

Вызывающий процесс пытается использовать capset() для изменения мандатов не своей нити, но ему не хватает на это прав. Для ядер, поддерживающих мандаты VFS, это всегда запрещено. Для ядер без поддержки VFS требуется мандат CAP_SETPCAP. (Неправильная работа ядер до версии 2.6.11 приводила к тому, что эта ошибка также возникала, если нить без данного мандата пыталась изменить свои собственные мандаты, указывая в поле pid ненулевое значение (т.е. значение, возвращаемое getpid(2)), а не 0).

ESRCH

Такой нити нет.

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

## ЗАМЕЧАНИЯ
Переносимый интерфейс для запроса и установки мандатов предоставляется библиотекой libcap, которая доступна по адресу:

http://git.kernel.org/cgit/linux/kernel/git/morgan/libcap.git

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