open

title: open(2)

summary: открывает и, возможно, создаёт файл

text:
# open(2)

## ИМЯ
open, openat, creat - открывает и, возможно, создаёт файл

## ОБЗОР

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

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

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

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

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

openat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

## ОПИСАНИЕ
Системный вызов open() открывает файл, на который указывает pathname. Если заданный файл не существует, то он может быть создан open() (если в flags задан O_CREAT).

Возвращаемым значением open() является файловый дескриптор, указывающий на открытый файл — небольшое неотрицательное целое, которое используется в последующих системных вызовах (read(2), write(2), lseek(2), fcntl(2) и т. д.). Файловый дескриптор, возвращаемый при успешном выполнении вызова, будет самым маленьким числом из файловых дескрипторов, которые ещё не открыты процессом.

По умолчанию, новый файловый дескриптор остаётся открытым при вызове execve(2) (т. е., флаг FD_CLOEXEC файлового дескриптора, описанный в fcntl(2), изначально сброшен; для изменения поведения по умолчанию можно использовать флаг O_CLOEXEC, он описан далее). Файловое смещение устанавливается на начало файла (см. lseek(2)).

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

Параметр flags должен содержать один из следующих режимов доступа: O_RDONLY (только для чтения), O_WRONLY (только для записи) или O_RDWR (для чтения и записи).

Также в flags можно указывать флаги создания и состояния файла, объединяя их битовой операцией ИЛИ. Флаги создания файла: O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE и O_TRUNC. Флаги состояния файла — все оставшиеся, перечислены ниже. Различие между двумя этими группами в том, что флаги создания влияют на работу самой операции открытия, а флаги состояния влияют на работу последующих операций ввода-вывода. Флаги состояния можно запросить и (в некоторых случаях) изменить; смотрите fcntl(2).

Полный список флагов создания и флагов состояния файла:

O_APPEND

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

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

O_ASYNC

Включает ввод-вывод, управляемый сигналом: генерирует сигнал (по умолчанию SIGIO, но можно изменить с помощью fcntl(2)), когда становится возможным ввод или вывод для этого файлового дескриптора. Эта возможность доступна только для терминалов, псевдотерминалов, сокетов, каналов (начиная с Linux 2.6) и FIFO. Подробней смотрите fcntl(2). Также смотрите ДЕФЕКТЫ далее.

O_CLOEXEC (начиная с Linux 2.6.23)

Устанавливает флаг close-on-exec на новом файловом дескрипторе. Указание данного флага позволяет программе избежать дополнительной операции fcntl(2) F_SETFD для установки флага FD_CLOEXEC.

Заметим, что использование этого флага обязательно для некоторых многонитиевых программ, так как использование отдельной операции fcntl(2) F_SETFD для установки флага FD_CLOEXEC недостаточно для избежания состязательности, когда одна нить открывает файловый дескриптор, а в тоже время другая нить может выполнять fork(2) и execve(2). В зависимости от порядка выполнения, состязательность может привести к тому, что файловый дескриптор, возвращённый open(), будет ненамеренно передан программе, выполняющейся в созданном с помощью fork(2) потомке (такого рода состязательность, в принципе, возможна для любых системных вызовов, создающих файловый дескриптор, у которого должен быть установлен флаг close-on-exec, и различные другие системные вызовы Linux предоставляют эквивалент флагу O_CLOEXEC, чтобы избежать этой проблемы).

O_CREAT

Если pathname не существует, то создать обычный файл.

Владельцем (ID пользователя) нового файла назначается эффективный идентификатор пользователя процесса.

Группой владельцев (ID группы) нового файла назначается эффективный идентификатор группы процесса (согласно System V) или ID группы родительского каталога (согласно BSD). В Linux это зависит от наличия бита режима set-group-ID на родительском каталоге: если этот бит установлен, то используется правило BSD; в противном случае применяется правило System V. В некоторых файловых системах поведение также зависит от параметров монтирования bsdgroups и sysvgroups, описанных в mount(8)).

В аргументе mode указываются биты файлового режима, которые используются при создании нового файла. Этот параметр должен указываться, если в flags устанавливается O_CREAT или O_TMPFILE; если O_CREAT или O_TMPFILE не указаны, то mode игнорируется. Эффективный режим изменяется согласно umask процесса как обычно: в случае отсутствия списков доступа по умолчанию режим созданного файла будет установлен согласно (mode & ~umask). Заметим, что этот режим будет учтён только при последующих обращениях к созданному файлу; вызов open(), создающий файл только для чтения, может вернуть файловый дескриптор доступный на чтение и запись.

Символьные константы, используемые в mode:

S_IRWXU

00700 пользователь (владелец файла) имеет права на чтение, запись и выполнение файла

S_IRUSR

00400 пользователь имеет права на чтение файла

S_IWUSR

00200 пользователь имеет права на запись в файл

S_IXUSR

00100 пользователь имеет права на выполнение файла

S_IRWXG

00070 группа имеет права на чтение, запись и выполнение файла

S_IRGRP

00040 группа имеет права на чтение файла

S_IWGRP

00020 группа имеет права на запись в файл

S_IXGRP

00010 группа имеет права на выполнение файла

S_IRWXO

00007 все остальные имеют права на чтение, запись и выполнение файла

S_IROTH

00004 все остальные имеют права на чтение файла

S_IWOTH

00002 все остальные имеют права на запись в файл

S_IXOTH

00001 все остальные имеют права на выполнение файла

Согласно POSIX, в случае, если в mode указаны другие биты, их воздействие не определено. В Linux для mode также доступны следующие биты:

S_ISUID

0004000 бит set-user-ID

S_ISGID

0002000 бит set-group-ID (смотрите inode(7)).

S_ISVTX

0001000 закрепляющий бит bit (смотрите inode(7)).

O_DIRECT (начиная с Linux 2.4.10)

Попытаться минимизировать влияние кэширования ввода-вывода при чтении и записи в файл. Обычно, это ухудшает производительность, но полезно для особых случаев, например, когда приложение выполняет кэширование самостоятельно. Файловый ввод-вывод выполняется непосредственно в/из буферов пространства пользователя. При флаге O_DIRECT предпринимаются все усилия для синхронной передачи данных, но это не гарантирует, как с флагом O_SYNC, передачу данных и необходимых метаданных. Чтобы гарантировать синхронный ввод-вывод вместе с O_DIRECT нужно использовать O_SYNC. Дальнейшее описание смотрите далее в разделе ЗАМЕЧАНИЯ.

Семантически похожий интерфейс (но устаревший) для блочных устройств описан в raw(8).

O_DIRECTORY

Если pathname не является каталогом, то завершить вызов с ошибкой. Этот флаг был добавлен в ядро версии 2.1.126, чтобы избежать проблем с «отказом в обслуживании», если opendir(3) был вызван для канала FIFO или ленточного устройства.

O_DSYNC

Операции записи файла будут выполнены согласно требованиям целостности синхронизации ввода-вывода data.

К времени возврата из write(2) (и подобных) выходные данные уже переданы в задействованное аппаратное обеспечение вместе со всеми метаданными файла, которые бы потребовались для получения данных (т. е., как если бы за каждым write(2) был выполнен вызов fdatasync(2)). Смотрите ЗАМЕЧАНИЯ далее.

O_EXCL

Гарантирует, что вызов создаст файл: если этот флаг указан вместе с O_CREAT и pathname уже существует, то open() завершается ошибкой EEXIST().

При использовании обоих флагов символьные ссылки не поддерживаются: если pathname является символьной ссылкой, то open() завершается с ошибкой независимо от того, куда указывает ссылка.

Вообще говоря, поведение с O_EXCL не определено, если этот флаг используется без O_CREAT. Есть одно исключение: в Linux 2.6 и более новых O_EXCL можно использовать без O_CREAT, если pathname указывает на блочное устройство. Если блочное устройство используется в системе (например, смонтировано), то open() завершится с ошибкой EBUSY.

Флаг O_EXCL поддерживается для NFS только, если используется NFSv3 или новее с ядром 2.6 или новее. В средах, где в NFS нет поддержки O_EXCL, программы, которые полагаются на это для выполнения задач блокировок, будут создавать состязательность процессов. Переносимым программам, которым нужно произвести атомарную блокировку файла с помощь файла блокировки, необходимо избегать зависимости от поддержки в NFS флага O_EXCL. В качестве решения можно создать уникальный файл в той же файловой системе (например, добавив имя узла и PID в название), чтобы создать ссылку на файл блокировки с помощью link(2). Если link(2) возвращает 0, то блокировка выполнена. В противном случае используйте stat(2), чтобы убедиться, что количество ссылок на уникальный файл возросло до двух. Это также означает, что блокировка была успешной.

O_LARGEFILE

(LFS) Позволяет открывать файлы, чей размер нельзя представить типом off_t (но можно представить типом off64_t). Для получения этого определения должен быть указан макрос _LARGEFILE64_SOURCE (до включения какого-либо заголовочного файла). Установка макроса тестирования возможностей _FILE_OFFSET_BITS в значение 64 (вместо использования O_LARGEFILE) является предпочтительным методом доступа к большим файлам на 32-битных системах (см. feature_test_macros(7)).

O_NOATIME (начиная с Linux 2.6.8)

Не обновлять время последнего доступа к файлу (st_atime в иноде) при вызове read(2) для файла.

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

- Эффективный пользовательский идентификатор процесса совпадает идентификатором владельца файла.

- Вызывающий процесс имеет мандат CAP_FOWNER в своём пользовательском пространстве имён и UID владельца файла отображён в пространстве имён.

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

O_NOCTTY

Если pathname указывает на терминальное устройство (см. tty(4)), то оно не станет управляющим терминалом процесса, даже если процесс такового не имеет.

O_NOFOLLOW

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

Данный флаг является расширением FreeBSD, которое было добавлено в Linux версии 2.1.126, и в последствии был стандартизован в POSIX.1-2008.

Смотрите также далее O_PATH.

O_NONBLOCK или O_NDELAY

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

Заметим, что установка этого флага не влияет на операции poll(2), select(2), epoll(7) и подобные, так как их интерфейсы просто информируют вызывающего о том, что файловый дескриптор «ready», то есть операция ввода-вывода, выполняемая над файловым дескриптором с флагом O_NONBLOCK, точно не заблокируется.

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

Для работы с каналами FIFO также смотрите fifo(7). Обсуждение влияния O_NONBLOCK в сочетании с обязательной файловой блокировкой или арендой (lease) смотрите в fcntl(2).

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

Получить файловый дескриптор, который можно использовать для двух целей: для указания положения в дереве файловой системы и для выполнения операций, работающих исключительно на уровне файловых дескрипторов. Сам файл не открывается и другие файловые операции (например, read(2), write(2), fchmod(2), fchown(2), fgetxattr(2), ioctl(2), mmap(2)) завершатся с ошибкой EBADF.

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

- close(2).

- fchdir(2), если файловый дескриптор указывает на каталог (начиная с Linux 3.5).

- fstat(2) (начиная с Linux 3.6).

- fstatfs(2) (начиная с Linux 3.12).

- Создание дубликата файлового дескриптора (dup(2), fcntl(2) F_DUPFD и т.д.).

- Получение и установка флагов файловых дескрипторов (fcntl(2) F_GETFD и F_SETFD).

- Получение флагов состояния открытого файла с помощью операции fcntl(2) F_GETFL: в возвращаемые флаги будет включён бит O_PATH.

- Передача файлового дескриптора в аргументе dirfd для openat() и других системных вызовов «*at()». К ним относится linkat(2) с флагом AT_EMPTY_PATH (или через procfs с помощью AT_SYMLINK_FOLLOW) даже, если файл не является каталогом.

- Передача файлового дескриптора в другой процесс через доменный сокет UNIX (смотрите SCM_RIGHTS в unix(7)).

Если в flags указан O_PATH, то биты флагов, отличные от O_CLOEXEC, O_DIRECTORYи O_NOFOLLOW, игнорируются.

Открытие файла или каталога при указании флага O_PATH не требует прав на сам объект (но требует права на выполнение каталогов из префикса пути). В зависимости от последующей операции может выполняться проверка определённых прав на файл (например, fchdir(2) требует права на выполнение у каталога, указанного в аргументе файлового дескриптора). Напротив, для получения ссылки на объект файловой системы при открытии с флагом O_RDONLY от вызывающего требуется право на чтение объекта, даже если для последующей операции (например, fchdir(2), fstat(2)) не требуется права чтения объекта.

Если pathname является символьной ссылкой и также указан флаг O_NOFOLLOW, то вызов возвращает файловый дескриптор, указывающий на символьную ссылку. Этот файловый дескриптор можно использовать в аргументе dirfd для вызовов fchownat(2), fstatat(2), linkat(2) и readlinkat(2) с пустым именем пути, чтобы выполнить операцию над символьной ссылкой.

Если pathname ссылается на автоматическую точку монтирования, которая ещё не включилась, и поэтому к ней не примонтированы другие файловые системы, то вызов возвращает файловый дескриптор, указывающий на каталог автомонтирования, не вызывая запуск монтирования. Затем можно использовать вызов fstatfs(2) для определения, является ли автоматическая точка монтирования включённой (.f_type == AUTOFS_SUPER_MAGIC).

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

```
char buf[PATH_MAX];
fd = open("some_prog", O_PATH);
snprintf(buf, PATH_MAX, "/proc/self/fd/%d", fd);
execl(buf, "some_prog", (char *) NULL);

```

Файловый дескриптор с O_PATH также может быть передан в качестве аргумента fexecve(3).

O_SYNC

Операции записи файла будут выполнены согласно требованиям целостности синхронизации ввода-вывода file (по сравнению с целостностью синхронизации ввода-вывода data, предоставляемой O_DSYNC).

На момент возврата из write(2) (или подобной функции) выходные данные и все метаданные файла уже переданы в задействованное аппаратное обеспечение (т. е., как если бы за каждым write(2) был выполнен вызов fsync(2)). Смотрите ЗАМЕЧАНИЯ далее.

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

Создание безымянного временного обычного файла. В аргументе pathname указывается каталог; безымянная inode будет создана в файловой системе этого каталога. Всё записанное в полученный файл будет потеряно при закрытии последнего файлового дескриптора, если файлу не будет назначено имя.

Флаг O_TMPFILE должен быть указан вместе с O_RDWR или O_WRONLY и, необязательно, O_EXCL. Если O_EXCL не указан, то можно использовать linkat(2) для ссылки на временный файл в файловой системе, сделав его постоянным с помощью кода:

```
char path[PATH_MAX];
fd = open("/path/to/dir", O_TMPFILE | O_RDWR,

                        S_IRUSR | S_IWUSR);
/* Файловый ввод-вывод в «fd»… */
snprintf(path, PATH_MAX,  "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file",

                        AT_SYMLINK_FOLLOW);

```

В этом случае аргументом mode у open() определяется режим доступа к файлу как с O_CREAT.

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

Есть два основных случая использования O_TMPFILE:

- Дополнительное свойство tmpfile(3): свободное от состязательности создание временных файлов, которые: автоматически удаляются при закрытии; недоступны по имени; не подвержены атаке через символьные ссылки; не требуют от вызывающего подбирать уникальное имя.

- Создание файла, который изначально не видим, и который затем заполняется данными и позволяет изменять атрибуты в файловой системе (fchown(2), fchmod(2), fsetxattr(2) и т. д.) до автоматического встраивания в файловую систему в полностью законченном виде (с помощью linkat(2) как описано ранее).

Для O_TMPFILE требуется поддержка в файловой системе; она есть только в нескольких файловых системах Linux. В первой реализации поддержка предоставлялась в файловых системах ext2, ext3, ext4, UDF, Minix и shmem. Поддержка других файловых систем появлялась так: XFS (Linux 3.15); Btrfs (Linux 3.16); F2FS (Linux 3.16); ubifs (Linux 4.9).

O_TRUNC

Если файл уже существует и является обычным файлом и режим доступа позволяет писать в этот файл (т.е. установлен флаг O_RDWR или O_WRONLY), то его длина будет урезана до нуля. Если файл является FIFO или терминальным устройством, то этот флаг игнорируется. В других случаях действие флага O_TRUNC не определено.

### creat()
Вызов creat() эквивалентен вызову open() с значением flags O_CREAT|O_WRONLY|O_TRUNC.

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

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

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

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

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

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

EACCES

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

EDQUOT

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

EEXIST

pathname уже существует, то были указаны O_CREAT и O_EXCL.

EFAULT

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

EFBIG

Смотрите EOVERFLOW.

EINTR

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

EINVAL

Файловая система не поддерживает флаг O_DIRECT. Подробности смотрите в ЗАМЕЧАНИЯ.

EINVAL

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

EINVAL

В flags указан O_TMPFILE, но не указан O_WRONLY или O_RDWR.

EINVAL

В flags указан O_CREAT и последний компонент («основная часть» (basename)) нового файла pathname некорректен (например, содержит недопустимые в нижележащей файловой системе символы).

EISDIR

pathname указывает на каталог и тип доступа подразумевает запись ( то есть установлен флаг O_WRONLY или O_RDWR).

EISDIR

Значение pathname ссылается на существующий каталог, в flags указан O_TMPFILE и один из O_WRONLY или O_RDWR, но версия ядра не предоставляет свойство O_TMPFILE.

ELOOP

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

ELOOP

Значение pathname является символьной ссылкой и в flags установлен O_NOFOLLOW, но отсутствует O_PATH.

EMFILE

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

ENAMETOOLONG

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

ENFILE

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

ENODEV

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

ENOENT

Не задан O_CREAT и файл с указанным именем не существует.

ENOENT

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

ENOENT

Значение pathname ссылается на несуществующий каталог, в flags указан O_TMPFILE и один из O_WRONLY или O_RDWR, но версия ядра не предоставляет свойство O_TMPFILE.

ENOMEM

Типом файла с именем является FIFO, но память для буфера FIFO невозможно выделить, так как достигнуто жёсткое пользовательское ограничение на выделение памяти для каналов и вызывающий не имеет дополнительных прав; смотрите pipe(7).

ENOMEM

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

ENOSPC

Файл pathname должен быть создан, но на устройстве его содержащем нет места для нового файла.

ENOTDIR

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

ENXIO

Установлены O_NONBLOCK | O_WRONLY , именованный файл имеет тип FIFO и ни один процесс не открыл FIFO на чтение.

ENXIO

Файл является специальным файлом устройства, но соответствующее устройство не существует.

ENXIO

Файл является доменным сокетом UNIX.

EOPNOTSUPP

Файловая система, содержащая pathname, не поддерживает O_TMPFILE.

EOVERFLOW

pathname ссылается на обычный файл, который слишком велик для открытия. Обычно, это случается когда приложение, скомпилированное на 31-битной платформе без -D_FILE_OFFSET_BITS=64, пытается открыть файл размером более (1<<31)-1 байт; смотрите также описание O_LARGEFILE ранее. Эта ошибка определена в POSIX.1; в ядрах до версии 2.6.24 Linux в этом случае выдавал ошибку EFBIG.

EPERM

Задан флаг O_NOATIME, но эффективный ID пользователя вызывающего процесса не совпадает с владельцем файла и вызывающий не имеет прав.

EPERM

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

EROFS

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

ETXTBSY

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

ETXTBSY

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

ETXTBSY

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

EWOULDBLOCK

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

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

EBADF

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

ENOTDIR

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

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

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

openat(): POSIX.1-2008.

Флаги O_DIRECT, O_NOATIME, O_PATH и O_TMPFILE есть только в Linux. Для их определения может потребоваться задать _GNU_SOURCE.

Флаги O_CLOEXEC, O_DIRECTORY и O_NOFOLLOW не указаны в POSIX.1-2001, но есть в POSIX.1-2008. Начиная с glibc 2.12, их определения можно получить определив или _POSIX_C_SOURCE со значением большим и равным 200809L, или _XOPEN_SOURCE со значением большим и равным 700. В glibc 2.11 и старее их определения можно получить определив _GNU_SOURCE.

Как было отмечено в feature_test_macros(7), такие макросы тестирования свойств как _POSIX_C_SOURCE, _XOPEN_SOURCE и _GNU_SOURCE, должны быть определены до включения любых заголовочных файлов.

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

Результат работы комбинации флагов O_RDONLY | O_TRUNC в разных реализациях разный (нигде не определён). Во многих системах файл усекается.

Заметим, что open() может открывать специальные файлы устройств, но creat() не может их создавать; вместо этого используйте mknod(2).

Если файл только что был создан, его поля st_atime, st_ctime, st_mtime (время последнего доступа, последней смены состояния и последнего изменения, соответственно; см. stat(2)) устанавливаются в значение текущего времени, и оно совпадает с полями st_ctime и st_mtime родительского каталога. Или же, если файл изменяется из-за установленного флага O_TRUNC, то его поля st_ctime и st_mtime устанавливаются в значение текущего времени.

Файлы в каталоге /proc/[pid]/fd представляют открытые файловые дескрипторы процесса с PID равным pid. Файлы в каталоге /proc/[pid]/fdinfo представляют дополнительную информацию об этих файловых дескрипторах. Подробное описание данных каталогов можно найти в proc(5).

В заголовочном файле Linux <asm/fcntl.h> не определён O_ASYNC; вместо него определён синоним FASYNC (как в BSD).

### Открытые файловые описания
Термин «открытое файловое описание» (open file description) используется в POSIX для указания на записи в системной таблице открытых файлов. В других контекстах, этот объект также называется «открытый файловый объект» (open file object), «описатель файла» (file handle), «»табличная запись открытого файла (open file table entry) или struct file (с точки зрения разработчика ядра).

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

При каждом open() файла создаётся новое файловое описание; таким образом, может быть несколько открытых файловых описаний, соответствующих inode файла.

Для проверки того, что два файловых дескриптора (одного процесса или разных) ссылаются на одно файловое описание, в Linux можно использовать вызов kcmp(2) с операцией KCMP_FILE.

### Синхронизированный ввод-вывод
В POSIX.1-2008 способность «синхронизированного ввода-вывода» описана в виде различных вариантов синхронизированного ввода-вывода и для open() определяет флаги управления поведением O_SYNC, O_DSYNC и O_RSYNC. Независимо от того, имеется ли в реализации данная способность, она должна, как минимум, поддерживать использование флага O_SYNC для обычных файлов.

В Linux реализованы O_RSYNC и O_DSYNC, но не O_RSYNC. Несколько некорректно в glibc определён O_RSYNC со значением как у O_SYNC (O_RSYNC определён в заголовочном файле Linux <asm/fcntl.h> для HP PA-RISC, но не используется).

Флаг O_SYNC предоставляет выполнение целостного синхронизованного ввод-вывода file, то есть операции записи передают данные и все связанные метаданные в задействованное аппаратное обеспечение. Флаг O_DSYNC предоставляет выполнение целостного синхронизованного ввод-вывода data, то есть операции записи передают данные в задействованное аппаратное обеспечение, но обновляются только те метаданные, которые требуются для выполнения последующего чтения. Полнота целостности данных может сократить количество дисковых операций, которые требуются приложениям, не требующим гарантий целостности файлов.

Чтобы понять разницу между двумя типами обеспечения целостности рассмотрим две части метаданных файла: метка времени последнего изменения файла (st_mtime) и длину файла. Все операции записи обновляют метку времени последнего изменения файла, но только при записи, которая добавляет данные в конец файла, будет изменена длина файла. Метка времени последнего изменения файла не требуется для корректного чтения файла, чего не скажешь о длине. Таким образом, O_DSYNC гарантирует только запись обновлений о метаданных длины файла (в то время как O_SYNC также всегда записывает метаданные о метки времени последнего изменения файла).

До Linux версии 2.6.33 в Linux реализован только флаг O_SYNC для open(). Однако, когда этот флаг указан, большинство файловых систем в действительности предоставляют эквивалент выполнения целостности синхронизированного ввода-вывода data (т. е., на самом деле O_SYNC был реализован как эквивалент O_DSYNC).

Начиная с Linux 2.6.33, предоставляет корректная поддержка O_SYNC. Однако для обеспечения обратной двоичной совместимости, O_DSYNC был определён с тем же значением что и старый O_SYNC, а O_SYNC был определён как новое значение флага (два бита), которое включает значение флага O_DSYNC. Это позволяет приложениям, скомпилированным с новыми заголовочными файлами получать, по крайней мере, семантику O_DSYNC ядер pre-2.6.33.

### Отличия между библиотекой C и ядром
Начиная с версии 2.26, обёрточная функция glibc open() используется системный вызов openat(), а не системный вызов ядра open(). На некоторых архитектурах это происходит в glibc с версиями ранее 2.26.

### NFS
В протоколе, по которому работает NFS, существует множество недоработок, оказывающих влияние на многое, в том числе на работу с O_SYNC и O_NDELAY.

В файловых системах NFS с включённым проецированием UID, open() может вернуть файловый дескриптор, но, например, запросы read(2) будут отклонены с ошибкой EACCES. Это происходит из-за того, что клиент выполняет open() проверяя одни права, но сервер выполняет проецирование UID только при запросах чтения и записи.

### FIFO
Открытие на чтение или запись конца FIFO приводит к блокировке то тех пор, пока другой конец не также не будет открыт (другим процессом или нитью). Подробности смотрите в fifo(7).

### Режим доступа к файлу
В отличие от других значений, указываемых в flags, значения режима доступа O_RDONLY, O_WRONLY и O_RDWR, не определяются отдельными битами. Точнее, они задаются двумя первыми битами flags, и имеют значения 0, 1 и 2, соответственно. Другими словами, комбинация O_RDONLY | O_WRONLY приводит к логической ошибке и точно не работает как O_RDWR.

В Linux зарезервирован специальный нестандартный режим доступа 3 (11 двоичное) в flags, при котором: проверяются права на чтение и запись к файлу и возвращается файловый дескриптор, который не может использоваться для чтения или записи. Данный нестандартный режим доступа используется некоторыми драйверами Linux для получения файлового дескриптора, который будет использоваться в ioctl(2) только для специальных операций с устройством.

### Обоснование openat() и остального программного интерфейса файлового дескриптора каталога
Вызов openat() и другие системные вызовы и библиотечные функции, использующие файловый дескриптор каталога в качестве аргумента (т. е., execveat(2), faccessat(2), fanotify_mark(2), fchmodat(2), fchownat(2), fstatat(2), futimesat(2), linkat(2), mkdirat(2), mknodat(2), name_to_handle_at(2), readlinkat(2), renameat(2), statx(2), symlinkat(2), unlinkat(2), utimensat(2), mkfifoat(3) и scandirat(3)) решают две проблемы старых интерфейсов, которые были до них. Вот объяснение, применимое к вызову openat(), а объяснение для других интерфейсов аналогично.

Во-первых, openat() позволяет приложению избежать условий состязательности, которые могут возникнуть, когда open() открывает файлы в каталогах, отличных от текущего рабочего каталога. Состязательность возникает из-за того, что один из компонентов префикса каталога, указанного open(), может измениться одновременно с вызовом open(). Например, предположим, что мы хотим создать файл dir1/dir2/xxx.dep и существует файл dir1/dir2/xxx. Проблема находится между шагами проверки существования и созданием файла, указываемые dir1 или dir2 (которые могут быть символическими ссылками) места могут измениться. Этой состязательности можно избежать открыв файловый дескриптор каталога назначения, и затем указав этот файловый дескриптор в аргументе dirfd вызова (скажем) fstatat(2) и openat(). Также, использование файлового дескриптора dirfd имеет другие преимущества:

- файловый дескриптор — это стабильная ссылка на каталог, даже если каталог будет переименован; и

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

Во-вторых, openat() позволяет реализовать отдельный «текущий рабочий каталог» для каждой нити посредством файлового дескриптора, сопровождаемого приложением. Эта возможность также может быть получена с использованием /proc/self/fd/dirfd, но менее эффективно.

### O_DIRECT
Флаг O_DIRECT может накладывать ограничения по выравниванию на длину и адрес буфера пользовательского пространства и смещения файла при вводе-выводе. В Linux ограничения по выравниванию различны у разных файловых систем и версий ядра, и даже могут отсутствовать. Однако сейчас не существует независимого от файловой системы интерфейса приложения для выявления этих ограничений на определённый файл или файловую систему. Некоторые файловые системы предоставляют свои собственные интерфейсы для этого, например, операция XFS_IOC_DIOINFO в xfsctl(3).

В Linux 2.4 размеры передачи, выравнивание пользовательского буфера и файлового смещения должны быть кратны размеру логического блока файловой системы. Начиная с Linux 2.6 достаточно выравнивания по 512-байтовой границе. Размер логического блока можно определить с помощью ioctl(2) и операции BLKSSZGET или с помощью команды:

```
    blockdev --getss
```

Ввод-вывод с O_DIRECT никогда не должен запускаться одновременно с системным вызовом fork(2), если буфер памяти является закрытым отображением (т. е., любым отображениям, созданным с помощью mmap(2) с флагом MAP_PRIVATE; к ним относится память, выделенная под кучу и статически выделенные буферы). Любой подобный ввод-вывод, предоставленный через асинхронный интерфейс или из другой нити процесса, должен выполниться полностью до вызова fork(2). В противном случае, может произойти повреждение данных и непредсказуемое поведение в процессе родителя и потомка.Данное ограничение не действует, если буфер памяти для ввода-вывода с O_DIRECT был создан с помощью shmat(2) или mmap(2) с флагом MAP_SHARED. И при этом это ограничение не действует, когда буфер памяти был помечен (advised) как MADV_DONTFORK с помощью madvise(2), если точно известно, что он не будет доступен потомку после fork(2).

Флаг O_DIRECT появился в SGI IRIX, где ограничения на выравнивание подобны Linux 2.4. В IRIX также есть вызов fcntl(2) для запроса значений соответствующего выравнивания и размеров. В FreeBSD 4.x появился флаг с таким же именем, но без ограничений на выравнивание.

Поддержка O_DIRECT добавлена в ядро Linux версии 2.4.10. Более старые ядра Linux просто игнорируют этот флаг. В некоторых файловых системах этот флаг может быть не реализован и open() завершается ошибкой EINVAL при его использовании.

Приложения должны избегать смешивания O_DIRECT и обычных операций ввода-вывода в один файл и особенно перекрывать байтовые области. Даже когда файловая система правильно обрабатывает проблемы с когерентностью в такой ситуации, общая пропускная способность ввода-вывода, вероятно, будет медленнее чем при использовании какого-то одного из этих режимов отдельно. Аналогично приложения должны избегать смешивания mmap(2) и прямого ввода-вывода для одинаковых файлов.

Поведение O_DIRECT на NFS отличается от локальных файловых систем. Старые ядра и ядра, настроенные определёнными способами, могут не поддерживать такую комбинацию. Протокол NFS не поддерживает передачу флага на сервер, поэтому ввод-вывод с O_DIRECT будет пропускать кэширование страниц только на клиенте; сервер всё равно может выполнить кэширование ввода-вывода. Клиент просит сервер выполнять операции ввода-вывода синхронно для сохранения синхронной семантики O_DIRECT. Некоторые серверы будут выполнять это плохо при определённых условиях, особенно если размер данных ввода-вывода невелик. Некоторые серверы также могут быть настроены на отправку ложного ответа клиентам о том, что ввод-вывод произведён на носитель; это позволяет избежать потери производительности, но есть риск потери целостности данных в случае проблем с электропитанием сервера. В Linux клиент NFS не устанавливает ограничений по выравниванию при вводе-выводе с O_DIRECT.

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

## ДЕФЕКТЫ
На данный момент невозможно включить сигнальное управление вводом-выводом, указав O_ASYNC при вызове open(); чтобы установить этот флаг используйте fcntl(2).

Для определения поддержки ядром O_TMPFILE нужно проверять два различных кода ошибок — EISDIR и ENOENT.

При указании флагов O_CREAT и O_DIRECTORY в flags, и при этом указанный в pathname файл не существует, open() создаст обычный файл (то есть флаг O_DIRECTORY будет проигнорирован).

## СМОТРИТЕ ТАКЖЕ
chmod(2), chown(2), close(2), dup(2), fcntl(2), link(2), lseek(2), mknod(2), mmap(2), mount(2), open_by_handle_at(2), read(2), socket(2), stat(2), umask(2), unlink(2), write(2), fopen(3), acl(5), fifo(7), inode(7), path_resolution(7), symlink(7)


package: man-pages-ru

title: open_by_handle_at(2)

summary: получение описателя для пути и

text:
# open_by_handle_at(2)

## ИМЯ
name_to_handle_at, open_by_handle_at - получение описателя для пути и открытие файла через описатель

## ОБЗОР

```
#define _GNU_SOURCE         /* Смотрите feature_test_macros(7) */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
```

```
int name_to_handle_at(int dirfd, const char *pathname,
                      struct file_handle *handle,
                      int *mount_id, int flags);
```

```
int open_by_handle_at(int mount_fd, struct file_handle *handle,
                      int flags);
```

## ОПИСАНИЕ
Функциональное назначение openat(2) было разделено на две части и добавлено в системные вызовы name_to_handle_at() и open_by_handle_at(): name_to_handle_at() возвращает описатель с произвольной формой(opaque), который соответствует указанному файлу; open_by_handle_at() открывает файл по описателю, который был возвращён предыдущим вызовом name_to_handle_at() и возвращает дескриптор открытого файла.

### name_to_handle_at()
Системный вызов name_to_handle_at() возвращает файловый описатель и идентификатор монтирования для файла, указанного в аргументах dirfd и pathname. Файловый описатель возвращается через аргумент handle, который является указателем на следующую структуру:

```
struct file_handle {

    unsigned int  handle_bytes;   /* размер f_handle [in, out] */

    int           handle_type;    /* тип описателя [out] */

    unsigned char f_handle[0];    /* идентификатор файла (размер

                                     задаёт вызывающий) [out] */
};
```

Вызывающий должен выделить память достаточного размера под структуру описателя, возвращаемого в f_handle. Перед вызовом поле handle_bytes должно содержать размер выделенной памяти для f_handle (константа MAX_HANDLE_SZ, определённая в <fcntl.h>, равна максимально ожидаемому размеру описателя файла. Это не гарантированное верхнее ограничение, так как файловые системы в будущем могут потребовать больше места). При успешном выполнении поле handle_bytes обновляется и содержит количество байт действительно занятых под f_handle.

Вызывающий может определить требуемый размер структуры file_handle указав при вызове значение handle->handle_bytes равное нулю; в этому случае вызов завершается с ошибкой EOVERFLOW, а в поле handle->handle_bytes записывается требуемый размер; затем вызывающий может использовать эту информацию для выделения памяти под структуру правильного размера (смотрите ПРИМЕР ниже). Здесь нужно учесть, что EOVERFLOW может указывать на то, что файловый описатель недоступен для этого заданного имени в файловой системе, которая, обычно, поддерживает поиск файловых описателей. На данный случай указывает то, что ошибка EOVERFLOW возвращается без увеличившегося значения handle_bytes.

Все остальные поля, кроме handle_bytes структуры file_handle, вызывающий должен считать неизвестными: поля handle_type и f_handle требуются только в последующих вызовах open_by_handle_at().

Аргумент flags представляет собой битовую маску (OR) из комбинации нуля или более флагов AT_EMPTY_PATH и AT_SYMLINK_FOLLOW, описанных ниже.

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

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

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

- Если значение pathname — непустая строка, содержащая относительный путь и dirfd равно файловому дескриптору, указывающему на каталог, то pathname рассматривается относительно каталога, на который указывает dirfd, и описатель возвращается для файла, на который он указывает (смотрите в openat(2) объяснение полезности «файловых дескрипторов каталогов»).

- Если значение pathname — пустая строка и значение flags равно AT_EMPTY_PATH, то dirfd может быть открытым файловым дескриптором, указывающим на файл любого типа, или AT_FDCWD, означающим текущий рабочий каталог, и описатель возвращается для файла, на который он указывает.

В аргументе mount_id возвращается идентификатор точки монтирования в файловой системе, соответствующий pathname. Это значение соответствует первому полю одной из записей в /proc/self/mountinfo. Открытие пути из пятого поля этой записи возвращает файловый дескриптор этой точки монтирования; этот файловый дескриптор можно использовать в последующем вызове open_by_handle_at(). Аргумент mount_id возвращается при успешном выполнении, а также при ошибке EOVERFLOW().

По умолчанию, name_to_handle_at() не разыменовывает pathname, если это символическая ссылка, и поэтому возвращается описатель самой ссылки. Если в flags указан AT_SYMLINK_FOLLOW, то pathname разыменовывается, если это символическая ссылка (то есть вызов возвращает описатель файла, на который указывает ссылка).

Системный вызов name_to_handle_at() не вызывает монтирования, если конечная часть пути является автоматической точкой монтирования. Если файловая система поддерживает файловые описатели и автоматические точки монтирования, то вызов name_to_handle_at() для автоматической точки монтирования завершится ошибкой EOVERFLOW без увеличения значения handle_bytes. Это может происходить с NFS начиная с версии Linux 4.13, когда задействованный каталог находится в отдельной файловой системе на сервере. В этом случае автомонтирование можно получить добавлением «/» в конец пути.

### open_by_handle_at()
Системный вызов open_by_handle_at() открывает файл, на который указывает handle, файловый описатель, полученный от предшествующего вызова name_to_handle_at().

Аргумент mount_fd — это файловый дескриптор любого объекта (файла, каталога и т. д.) в смонтированной файловой системе, в которой должен находиться handle. Может быть равен специальному значению AT_FDCWD, которое обозначает текущий рабочий каталог вызывающего.

Значение аргумента flags как у open(2). Если handle указывает на символическую ссылку, то вызывающий должен указать флаг O_PATH, и символическая ссылка не разыменовывается; флаг O_NOFOLLOW игнорируется.

Для вызова open_by_handle_at() вызывающий должен иметь мандат CAP_DAC_READ_SEARCH.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении name_to_handle_at() возвращает 0, а open_by_handle_at() возвращает неотрицательный файловый дескриптор.

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

## ОШИБКИ
Вызовы name_to_handle_at() и open_by_handle_at() могут завершиться с теми же ошибками что и openat(2). Также могут возникать следующие ошибки:

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

EFAULT

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

EINVAL

Значение flags содержит некорректно установленный бит.

EINVAL

Значение handle->handle_bytes больше MAX_HANDLE_SZ.

ENOENT

Значение pathname равно пустой строке, но в flags не указано значение AT_EMPTY_PATH.

ENOTDIR

Файловый дескриптор, указанный в dirfd, не ссылается на каталог и это не тот случай, когда flags содержит AT_EMPTY_PATH и pathname равно пустой строке.

EOPNOTSUPP

Файловая система не поддерживает преобразование пути в файловый описатель.

EOVERFLOW

Значение handle->handle_bytes, переданное в вызов, слишком мало. При этой ошибке handle->handle_bytes присваивается требуемый размер для описателя.

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

EBADF

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

EFAULT

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

EINVAL

Значение handle->handle_bytes больше MAX_HANDLE_SZ или равно нулю.

ELOOP

Значение handle указывает на символическую ссылку, но в flags не указан O_PATH.

EPERM

Вызывающий не имеет мандата CAP_DAC_READ_SEARCH.

ESTALE

Значение handle некорректно. Эта ошибка возникает, например, из-за удаления файла.

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

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

В FreeBSD есть относительно похожая пара системных вызовов getfh() и openfh().

## ЗАМЕЧАНИЯ
Файловый описатель может быть сгенерирован с помощью name_to_handle_at() в одном процессе и использован в вызовах open_by_handle_at() в другом.

Некоторые файловые системы не поддерживают трансляцию путей в файловые описатели, например: /proc, /sys и различные сетевые файловые системы.

Файловый описатель может стать некорректным («просроченным»), если файл удалён, или по другим причинам, относящимся к файловой системе. Для некорректных описателей open_by_handle_at() возвращает ошибку ESTALE.

Данные системные вызовы предназначены для использования в файловых серверах пространства пользователя. Например, сервер пользовательского пространства NFS может генерировать файловый описатель и передавать его клиенту NFS. Позднее, когда клиент захочет открыть файл, он может передать описатель обратно серверу. Такого рода возможность позволяет файловому серверу пространства пользователя работать без формирования состояния (stateless fashion) для файлов, которые они обслуживают.

Если pathname указывает на символическую ссылку и в flags отсутствует AT_SYMLINK_FOLLOW, то name_to_handle_at() возвращает описатель ссылки (а не файла, на который она ссылается). Процесс, получивший описатель, может позднее выполнить операции над символической ссылкой, преобразовав описатель в файловый дескриптор, используя open_by_handle_at() с флагом O_PATH, и затем передав файловый дескриптор через аргумент dirfd в системные вызовы readlinkat(2) и fchownat(2).

### Получение постоянного идентификатора файловой системы
Идентификаторы монтирования в /proc/self/mountinfo могут быть использованы повторно после размонтирования и монтирования файловой системы. Поэтому, идентификатор монтирования, возвращаемый name_to_handle_at() (в *mount_id), не должен считаться постоянным идентификатором соответствующей файловой системы. Однако, приложение может использовать информацию в записи mountinfo, которая соответствует идентификатору монтирования, для получения постоянного идентификатора.

Например, можно использовать имя устройства в пятом поле записи mountinfo для поиска соответствующего устройству UUID через символические ссылки в /dev/disks/by-uuid (более удобный способ получения UUID — использовать библиотеку libblkid(3)). Этот процесс может быть и обратным — используя UUID найти имя устройства, и затем получить соответствующую точку монтирования, чтобы создать аргумент mount_fd, используемый для open_by_handle_at().

## ПРИМЕР
Две представленные далее программы демонстрируют использование name_to_handle_at() и open_by_handle_at(). Первая программа (t_name_to_handle_at.c) использует name_to_handle_at() для получения файлового описателя и идентификатора монтирования для файла, указанного в аргументе командной строки; описатель и идентификатор монтирования записываются в стандартный вывод.

Вторая программа (t_open_by_handle_at.c) читает идентификатор монтирования и файловый описатель из стандартного ввода. Затем программа, используя описатель, применяет open_by_handle_at() для открытия файла. Если указан необязательный параметр командной строки, то аргумент mount_fd для open_by_handle_at() создаётся из открытия каталога, указанного в аргументе. В противном случае mount_fd заполняется результатом сканированием /proc/self/mountinfo в целях найти запись, чей идентификатор монтирования совпадает с идентификатором монтирования из стандартного ввода, и открывается каталог монтирования, указанный в этой записи (эти программы не учитывают, что идентификатор монтирования не постоянен).

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

```
$ echo 'Can you please think about it?' > cecilia.txt
$ ./t_name_to_handle_at cecilia.txt > fh
$ ./t_open_by_handle_at < fh
open_by_handle_at: Operation not permitted
$ sudo ./t_open_by_handle_at < fh      # требуется CAP_SYS_ADMIN
Read 31 bytes
$ rm cecilia.txt
```

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

```
$ stat --printf="%i\n" cecilia.txt     # вывести номер иноды
4072121
$ rm cecilia.txt
$ echo 'Can you please think about it?' > cecilia.txt
$ stat --printf="%i\n" cecilia.txt     # проверить номер иноды
4072121
$ sudo ./t_open_by_handle_at < fh
open_by_handle_at: Stale NFS file handle
```

### Исходный код программы: t_name_to_handle_at.c

```
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

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

    struct file_handle *fhp;

    int mount_id, fhsize, flags, dirfd, j;

    char *pathname;

    if (argc != 2) {

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

        exit(EXIT_FAILURE);

    }

    pathname = argv[1];

    /* выделяем место под структуру file_handle */

    fhsize = sizeof(*fhp);

    fhp = malloc(fhsize);

    if (fhp == NULL)

        errExit("malloc");

    /* выполняем первоначальный вызов name_to_handle_at() для

       определения требуемого размера файлового описателя */

    dirfd = AT_FDCWD;           /* для вызовов name_to_handle_at() */

    flags = 0;                  /* для вызовов name_to_handle_at() */

    fhp->handle_bytes = 0;

    if (name_to_handle_at(dirfd, pathname, fhp,

                &mount_id, flags) != -1 || errno != EOVERFLOW) {

        fprintf(stderr, "Unexpected result from name_to_handle_at()\n");

        exit(EXIT_FAILURE);

    }

    /* перераспределяем структуру file_handle с правильным размером */

    fhsize = sizeof(struct file_handle) + fhp->handle_bytes;

    fhp = realloc(fhp, fhsize);         /* копируем fhp->handle_bytes */

    if (fhp == NULL)

        errExit("realloc");

    /* получаем файловый описатель из пути, который

       указан в командной строке */

    if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)

        errExit("name_to_handle_at");

    /* пишем идентификатор монтирования, размер файлового описателя

       и файловый описатель в stdout

       для повторного использования в t_open_by_handle_at.c */

    printf("%d\n", mount_id);

    printf("%d %d   ", fhp->handle_bytes, fhp->handle_type);

    for (j = 0; j < fhp->handle_bytes; j++)

        printf(" %02x", fhp->f_handle[j]);

    printf("\n");

    exit(EXIT_SUCCESS);
}
```

### Исходный код программы: t_open_by_handle_at.c

```
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
/* сканируем /proc/self/mountinfo в поиске строки, чей идентификатор

   монтирования совпадает с 'mount_id' (простейший способ,

   это установить и использовать библиотеку

   «libmount», предоставляемую проектом «util-linux»).

   Открываем соответствующий путь монтирования и возвращаем

   полученный файловый дескриптор. */
static int
open_mount_path_by_id(int mount_id)
{

    char *linep;

    size_t lsize;

    char mount_path[PATH_MAX];

    int mi_mount_id, found;

    ssize_t nread;

    FILE *fp;

    fp = fopen("/proc/self/mountinfo", "r");

    if (fp == NULL)

        errExit("fopen");

    found = 0;

    linep = NULL;

    while (!found) {

        nread = getline(&linep, &lsize, fp);

        if (nread == -1)

            break;

        nread = sscanf(linep, "%d %*d %*s %*s %s",

                       &mi_mount_id, mount_path);

        if (nread != 2) {

            fprintf(stderr, "Bad sscanf()\n");

            exit(EXIT_FAILURE);

        }

        if (mi_mount_id == mount_id)

            found = 1;

    }

    free(linep);

    fclose(fp);

    if (!found) {

        fprintf(stderr, "Could not find mount point\n");

        exit(EXIT_FAILURE);

    }

    return open(mount_path, O_RDONLY);
}
int
main(int argc, char *argv[])
{

    struct file_handle *fhp;

    int mount_id, fd, mount_fd, handle_bytes, j;

    ssize_t nread;

    char buf[1000];
#define LINE_SIZE 100

    char line1[LINE_SIZE], line2[LINE_SIZE];

    char *nextp;

    if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {

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

        exit(EXIT_FAILURE);

    }

    /* Стандартный ввод содержит идентификатор монтирования и

       информацию о файловом описателе:

         Строка 1: <идентификатор монтирования>

         Строка 2: <handle_bytes> <handle_type>

                    <байты описателя в шестнад. системе счисления>

    */

    if ((fgets(line1, sizeof(line1), stdin) == NULL) ||

           (fgets(line2, sizeof(line2), stdin) == NULL)) {

        fprintf(stderr, "Missing mount_id / file handle\n");

        exit(EXIT_FAILURE);

    }

    mount_id = atoi(line1);

    handle_bytes = strtoul(line2, &nextp, 0);

    /* получаем handle_bytes, теперь мы можем выделить место

       под структуру file_handle */

    fhp = malloc(sizeof(struct file_handle) + handle_bytes);

    if (fhp == NULL)

        errExit("malloc");

    fhp->handle_bytes = handle_bytes;

    fhp->handle_type = strtoul(nextp, &nextp, 0);

    for (j = 0; j < fhp->handle_bytes; j++)

        fhp->f_handle[j] = strtoul(nextp, &nextp, 16);

    /* получаем файловый дескриптор для точки монтирования, или

       открываем путь, указанный в командной строке, или сканируем

       /proc/self/mounts в поиске монтирования, которое совпадает с

       «mount_id», который мы получили из stdin. */

    if (argc > 1)

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

    else

        mount_fd = open_mount_path_by_id(mount_id);

    if (mount_fd == -1)

        errExit("opening mount fd");

    /* открываем файл, используя описатель и точку монтирования */

    fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);

    if (fd == -1)

        errExit("open_by_handle_at");

    /* пытаемся прочитать несколько байт из файла */

    nread = read(fd, buf, sizeof(buf));

    if (nread == -1)

        errExit("read");

    printf("Read %zd bytes\n", nread);

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
open(2), libblkid(3), blkid(8), findfs(8), mount(8)

Документация libblkid и libmount в последнем выпуске util-linux https://www.kernel.org/pub/linux/utils/util-linux/


outb

title: outb(2)

summary: ввод/вывод в порт

text:
# outb(2)

## ИМЯ
outb, outw, outl, outsb, outsw, outsl, inb, inw, inl, insb, insw, insl, outb_p, outw_p, outl_p, inb_p, inw_p, inl_p - ввод/вывод в порт

## ОБЗОР

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

```
unsigned char inb(unsigned short int port);
unsigned char inb_p(unsigned short int port);
unsigned short int inw(unsigned short int port);
unsigned short int inw_p(unsigned short int port);
unsigned int inl(unsigned short int port);
unsigned int inl_p(unsigned short int port);
```

```
void outb(unsigned char value, unsigned short int port);
void outb_p(unsigned char value, unsigned short int port);
void outw(unsigned short int value, unsigned short int port);
void outw_p(unsigned short int value, unsigned short int port);
void outl(unsigned int value, unsigned short int port);
void outl_p(unsigned int value, unsigned short int port);
```

```
void insb(unsigned short int port, void *addr,
           unsigned long int count);
void insw(unsigned short int port, void *addr,
           unsigned long int count);
void insl(unsigned short int port, void *addr,
           unsigned long int count);
void outsb(unsigned short int port, const void *addr,
           unsigned long int count);
void outsw(unsigned short int port, const void *addr,
           unsigned long int count);
void outsl(unsigned short int port, const void *addr,
           unsigned long int count);
```

## ОПИСАНИЕ
Это семейство вызовов используется для низкоуровневой работы с портами ввода/вывода. Вызовы out* выполняют запись в порт, а вызовы in* выполняют чтение из порта; вызовы с суффиксом b работают с данными шириной один байт, а вызовы с суффиксом w работают с данными шириной в одно слово; вызовы с суффиксом _p ждут завершения операции ввода-вывода.

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

Вы должны скомпилировать свою программу с флагами -O, -O2 и им подобными. Данные вызовы определены в виде встроенных макросов и не будут подставляться без включённой оптимизации, что приводит к появлению неразрешаемых ссылок в процессе компоновки программы.

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

## СООТВЕТСТВИЕ СТАНДАРТАМ
Вызовы outb() и ему подобные зависят от конкретного оборудования. Аргумент value передаётся первым, а port — вторым, что является обратным порядком по сравнению с большинством реализаций этих вызовов в DOS.

## СМОТРИТЕ ТАКЖЕ
ioperm(2), iopl(2)


pause

title: pause(2)

summary: ждать сигнала

text:
# pause(2)

## ИМЯ
pause - ждать сигнала

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

int pause(void);

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

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

## ОШИБКИ
EINTR

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

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

## СМОТРИТЕ ТАКЖЕ
kill(2), select(2), signal(2), sigsuspend(2)


title: pciconfig_read(2)

summary: работа с информацией

text:
# pciconfig_read(2)

## ИМЯ
pciconfig_read, pciconfig_write, pciconfig_iobase - работа с информацией устройства PCI

## ОБЗОР

```
#include <pci.h>
```

```
int pciconfig_read(unsigned long bus, unsigned long dfn,
          unsigned long off, unsigned long len, void *buf);
int pciconfig_write(unsigned long bus, unsigned long dfn,
          unsigned long off, unsigned long len, void *buf);
int pciconfig_iobase(long which, unsigned long bus,
          unsigned long devfn);
```

## ОПИСАНИЕ
Всё взаимодействие с устройствами PCI, в основном, уже выполнено в ядре на уровне PCI, и поэтому данные вызовы, обычно, ненужны при вызове из пользовательского пространства.

pciconfig_read()

Выполняет чтение в буфер buf из устройства dev со смещением off.

pciconfig_write()

Выполняет запись буфера buf в устройство dev со смещением off.

pciconfig_iobase()

Принимает пару шина/функция_устройства и возвращает физический адрес или смещения в памяти (для таких вещей как prep, это 0xc0000000), базы ввода-вывода для циклов PIO, или промежутки (holes) ISA, если они есть.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
pciconfig_read()

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

pciconfig_write()

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

pciconfig_iobase()

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

## ОШИБКИ
EINVAL

Неправильное значение len. Не применимо к pciconfig_iobase().

EIO

Ошибка ввода-вывода.

ENODEV

Для pciconfig_iobase() значение «рукава (hose)» равно NULL. Для других вызовов не удаётся найти слот.

ENOSYS

Данные вызовы в системе не реализованы (не определён макрос CONFIG_PCI).

EOPNOTSUPP

Данное значение верно только для pciconfig_iobase(). Возвращается, если указано неверное значение which.

EPERM

Пользователь не имеет мандата CAP_SYS_ADMIN. Не применимо к pciconfig_iobase().

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данные вызовы есть только в Linux, они доступны начиная с версии 2.0.26/2.1.11.

## СМОТРИТЕ ТАКЖЕ
capabilities(7)