ИМЯ
unshare -
    отделяет
    части
    процесса
    контекста
    выполнения
ОБЗОР
#define _GNU_SOURCE
#include <sched.h>
int unshare(int flags);
ОПИСАНИЕ
Вызов unshare()
    позволяет
    процессу
    (или потоку)
    отделить
    части
    своего
    контекста
    выполнения,
    которые
    используются
    совместно
    с другими
    процессами
    (или
    потоками).
    Часть
    контекста
    выполнения,
    например
    пространство
    имён
    монтирования,
    неявно
    делается
    общей при
    создании
    нового
    процесса с
    помощью fork(2)
    или vfork(2), в то
    время как
    другие
    части,
    такие как
    виртуальная
    память,
    могут
    стать
    общими по
    явному
    запросу
    при
    создании
    процесса
    или потока
    с помощью
    clone(2).
Основное
    предназначение
    unshare() —
    позволить
    процессу
    контролировать
    свой общий
    контекст
    выполнения
    без
    создания
    нового
    процесса.
Значение
    аргумента
    flags
    представляет
    собой
    битовую
    маску, в
    которой
    указывается
    какие
    части
    контекста
    выполнения
    должны
    перестать
    быть
    общими.
    Значение
    составляется
    из
    нескольких
    следующих
    констант
    (через OR):
  - CLONE_FILES
- Обратный
      эффект
      флагу CLONE_FILES
      для clone(2).
      Отделяет
      таблицу
      файловых
      дескрипторов
      таким
      образом,
      что
      вызывающий
      процесс
      больше не
      имеет
      общих
      файловых
      дескрипторов
      с другими
      процессами.
- CLONE_FS
- Обратный
      эффект
      флагу CLONE_FS
      для clone(2).
      Отделяет
      атрибуты
      файловой
      системы
      таким
      образом,
      что
      вызывающий
      процесс
      больше не
      имеет
      общих
      атрибутов
      корневого
      каталога
      (chroot(2)),
      текущего
      каталога
      (chdir(2)) и umask (umask(2)) с
      другими
      процессами.
- CLONE_NEWCGROUP
    (начиная с Linux
    4.6)
- Этот флаг
      имеет
      действие
      подобное
      флагу CLONE_NEWCGROUP
      для clone(2).
      Отделяет
      пространство
      имён cgroup. Для
      использования
      CLONE_NEWCGROUP
      требуется
      мандат
    CAP_SYS_ADMIN.
- CLONE_NEWIPC
    (начиная с Linux
    2.6.19)
- Этот флаг
      имеет
      действие
      подобное
      флагу CLONE_NEWIPC
      для clone(2).
      Отделяет
      пространство
      имён IPC
      таким
      образом,
      что
      вызывающий
      процесс
      будет
      иметь свою
      личную
      копию
      пространства
      имён IPC,
      неиспользуемую
      другими
      процессами.
      Задание
      данного
      флага
      автоматически
      устанавливает
      флаг CLONE_SYSVSEM.
      Для
      использования
      CLONE_NEWIPC
      требуется
      мандат
    CAP_SYS_ADMIN.
- CLONE_NEWNET
    (начиная с Linux
    2.6.24)
- Этот флаг
      имеет
      действие
      подобное
      флагу CLONE_NEWNET
      для clone(2).
      Отделяет
      сетевое
      пространство
      имён таким
      образом,
      что
      вызывающий
      процесс
      будет
      иметь свою
      личную
      копию
      сетевого
      пространства
      имён,
      неиспользуемую
      другими
      процессами.
      Для
      использования
      CLONE_NEWNET
      требуется
      мандат
    CAP_SYS_ADMIN.
- CLONE_NEWNS
- Этот флаг
      имеет
      действие
      подобное
      флагу CLONE_NEWNS
      для clone(2).
      Отделяет
      пространство
      имён
      монтирования
      таким
      образом,
      что
      вызывающий
      процесс
      будет
      иметь свою
      личную
      копию
      данного
      пространства
      имён,
      неиспользуемую
      другими
      процессами.
      Задание
      данного
      флага
      автоматически
      устанавливает
      флаг CLONE_FS. Для
      использования
      CLONE_NEWNS
      требуется
      мандат CAP_SYS_ADMIN.
      Дополнительная
      информация
      доступна в
      mount_namespaces(7).
- CLONE_NEWPID
    (начиная с Linux
    3.8)
- Данный
      флаг
      позволяет
      то же что и
      CLONE_NEWPID у clone(2).
      Выполняется
      отключение
      от
      пространства
      имён PID;
      вызывающий
      процесс
      создаёт
      новое
      пространство
      имён PID для
      своих
      потомков,
      которые до
      этого не
      были
      объединены
      с
      существующим
      процессом.
      Вызывающий
      процесс
      не
      перемещается
      в новое
      пространство
      имён.
      Первый
      потомок,
      созданный
      вызывающим
      процессом,
      будет
      иметь ID
      процесса 1
      и
      считаться
      init(1) в новом
      пространстве
      имён. Также
      флаг CLONE_NEWPID
      автоматически
      подразумевает
      CLONE_THREAD. Для
      использования
      CLONE_NEWPID
      требуется
      мандат CAP_SYS_ADMIN.
      Подробней
      смотрите
      pid_namespaces(7).
- CLONE_NEWUSER
    (начиная с Linux
    3.8)
- Данный
      флаг
      позволяет
      то же что и
      CLONE_NEWUSER у clone(2).
      Выполняется
      отключение
      от
      пользовательского
      пространства
      имён;
      вызывающий
      процесс
      перемещается
      в новое
      пользовательское
      пространство
      имён,
      которое до
      этого не
      был общим
      для
      существующего
      процесса.
      Как
      потомок
      процесса,
      созданный
      clone(2) с флагом
      CLONE_NEWUSER,
      вызывающий
      получает
      полный
      набор
      мандатов в
      новом
      пользовательском
      пространстве
      имён.
  
  - Для CLONE_NEWUSER
      требуется,
      чтобы
      вызывающий
      процесс не
      имел нитей;
      указание
      CLONE_NEWUSER
      автоматически
      подразумевает
      CLONE_THREAD.
      Начиная с Linux
      3.9, CLONE_NEWUSER также
      автоматически
      подразумевает
      CLONE_FS. Для CLONE_NEWUSER
      требуется,
      чтобы ID
      пользователя
      и группы
      вызывающего
      процесса
      отображались
      в ID
      пользователя
      и группы в
      пользовательском
      пространстве
      имён
      вызывающего
      процесса
      на момент
      вызова.
- Дополнительную
      информацию
      о
      пространствах
      имён
      пользователя
      смотрите в
      user_namespaces(7).
  - CLONE_NEWUTS
    (начиная с Linux
    2.6.19)
- Этот флаг
      имеет
      действие
      подобное
      флагу CLONE_NEWUTS
      для clone(2).
      Отделяет
      пространство
      имён UTS IPC
      таким
      образом,
      что
      вызывающий
      процесс
      будет
      иметь свою
      личную
      копию
      пространства
      имён UTS,
      неиспользуемую
      другими
      процессами.
      Для
      использования
      CLONE_NEWUTS
      требуется
      мандат
    CAP_SYS_ADMIN.
- CLONE_SYSVSEM
    (начиная с Linux
    2.6.26)
- С данным
      флагом
      выполняется
      обратное
      действие
      clone(2) с флагом
      CLONE_SYSVSEM.
      Выполняется
      отмена
      изменения
      значений
      семафоров
      System V (semadj) таким
      образом,
      что
      вызывающий
      процесс
      получает
      новый
      пустой
      список semadj,
      который не
      является
      общим ни с
      одним
      другим
      процессом.
      Если это
      последний
      процесс,
      который
      ссылается
      на текущий
      список semadj
      процесса,
      то
      изменения
      (adjustments) в этом
      списке
      применяются
      к
      соответствующим
      семафорам
      как
      описано в
      semop(2).
Также в flags
    могут быть
    указаны
    флаги CLONE_THREAD,
    CLONE_SIGHAND и CLONE_VM,
    если
    вызывающий
    состоит из
    одной нити
    (т. е., он не
    делит своё
    адресное
    пространство
    с другим
    процессом
    или нитью).
    Иначе
    данные
    флаги не
    работают (также
    заметим,
    что
    указание
    CLONE_THREAD
    автоматически
    подразумевает
    CLONE_VM, а
    указание
    CLONE_VM
    автоматически
    подразумевает
    CLONE_SIGHAND). Если
    процесс
    состоит из
    нескольких
    нитей, то
    использование
    данных
    флагов
    приведёт к
    ошибке.
Если
    значение
    flags равно
    нулю, то unshare()
    ничего не
    делает, то
    есть в
    контексте
    выполнения
    вызывающего
    процесса
    ничего не
    изменяется.
ВОЗВРАЩАЕМОЕ
  ЗНАЧЕНИЕ
При
    успешном
    выполнении
    возвращается
    0. При ошибке
    возвращается
    -1, а errno
    присваивается
    значение
    ошибки.
ОШИБКИ
  - EINVAL
- В значении
      flags
      установлен
      недопустимый
      бит.
- EINVAL
- В flags указан
      CLONE_THREAD, CLONE_SIGHAND или
      CLONE_VM, а
      вызывающий
      состоит из
      нескольких
      нитей.
- EINVAL
- Указан
      флаг CLONE_NEWIPC в
      flags, но ядро
      собрано
      без
      параметров
      CONFIG_SYSVIPC и CONFIG_IPC_NS.
- EINVAL
- Указан
      флаг CLONE_NEWNET в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_NET_NS.
- EINVAL
- Указан
      флаг CLONE_NEWPID в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_PID_NS.
- EINVAL
- Указан
      флаг CLONE_NEWUSER в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_USER_NS.
- EINVAL
- Указан
      флаг CLONE_NEWUTS в
      flags, но ядро
      собрано
      без
      параметра
      CONFIG_UTS_NS.
- EINVAL
- Указан
      флаг CLONE_NEWPID в
      flags, но
      процесс
      был ранее
      вызван unshare() с
      флагом CLONE_NEWPID.
- ENOMEM
- Не удалось
      выделить
      достаточно
      памяти для
      копирования
      части
      контекста
      вызывающего,
      которая
      должна
      быть
      отделена.
- ENOSPC
    (начиная с Linux
    3.7)
- В флагах
      указан CLONE_NEWPID,
      но вызов
      привёл бы к
      превышению
      ограничения
      на
      количество
      вложенных
      имён PID;
      смотрите
      pid_namespaces(7).
- ENOSPC
    (начиная с Linux
    4.9; до этого
    EUSERS)
- Флаг CLONE_NEWUSER
      указан в flags,
      и вызов
      привёл бы к
      превышению
      ограничения
      на
      количество
      вложенных
      пользовательских
      пространств
      имён.
      Смотрите
      user_namespaces(7).
  
  - В этом
      случае в Linux 3.11
      по Linux 4.8
      возвращалась
      ошибка EUSERS.
  - ENOSPC
    (начиная с Linux
    4.9)
- Одним из
      значений в
      flags
      задаётся
      создание
      нового
      пространства
      пространства
      имён
      пользователя,
      но это
      превысило
      бы
      ограничение,
      определённое
      в
      соответствующем
      файле в
      каталоге
      /proc/sys/user.
      Дополнительную
      информацию
      смотрите в
      namespaces(7).
- EPERM
- Вызывающий
      процесс не
      имеет
      требуемых
      привилегий
      для этой
      операции.
- EPERM
- Флаг CLONE_NEWUSER
      указан в flags,
      но
      эффективный
      пользовательский
      ID или
      эффективный
      ID группы
      вызывающего
      не
      отображён
      в
      родительское
      пространство
      имён
      (смотрите
      user_namespaces(7)).
- EPERM
    (начиная с Linux
    3.9)
- В flags был
      указан
      флаг CLONE_NEWUSER и
      вызывающий
      выполняется
      в
      окружении
      chroot (т. е.
      корневой
      каталог
      вызывающего
      не
      совпадает
      с корневым
      каталогом
      пространства
      имён
      монтирования,
      в котором
      он
      находится).
- EUSERS (Linux 3.11
    по Linux 4.8)
- Флаг CLONE_NEWUSER
      указан в flags,
      и вызов
      привёл бы к
      превышению
      ограничения
      на
      количество
      вложенных
      пользовательских
      пространств
      имён.
      Смотрите
      описание
      ошибки ENOSPC,
      представленное
      выше.
ВЕРСИИ
Системный
    вызов unshare()
    был
    добавлен в
    ядро Linux
    версии 2.6.16.
СООТВЕТСТВИЕ
  СТАНДАРТАМ
Системный
    вызов unshare()
    есть
    только в Linux.
ЗАМЕЧАНИЯ
Не все
    атрибуты
    процесса,
    которые
    могут
    использоваться
    совместно
    при
    создании
    нового
    процесса с
    помощью clone(2),
    могут быть
    отделены с
    помощью unshare().
    В
    частности,
    начиная с
    ядра 3.8 в unshare()
    не
    реализована
    поддержка
    флагов,
    которые
    были имели
    обратное
    действие
    CLONE_SIGHAND, CLONE_THREAD или
    CLONE_VM. Эти
    возможности
    могут быть
    добавлены
    позднее,
    если
    потребуется.
ПРИМЕР
Программа,
    представленная
    далее,
    предоставляет
    простую
    реализацию
    команды unshare(1),
    которая
    отключает
    использование
    одного или
    более
    пространств
    имён и
    выполняет
    команду,
    переданную
    в
    аргументах
    командной
    строки. Вот
    пример
    использования
    этой
    программы;
    запускается
    оболочка в
    новом
    пространстве
    имён
    монтирования
    и
    проверяется,
    что
    первоначальная
    оболочка и
    новая
    оболочка
    находятся
    в разных
    пространствах
    имён
    монтирования:
  
$ readlink /proc/$$/ns/mnt
mnt:[4026531840]
$ sudo ./unshare -m /bin/bash
# readlink /proc/$$/ns/mnt
mnt:[4026532325]
Различающийся
    вывод двух
    команд readlink(1)
    показывает,
    что две
    оболочки
    находятся
    в разных
    пространствах
    имён
    монтирования.
Исходный
  код
  программы
/* unshare.c
   Простая реализация команды unshare(1): отключение от
   пространств имён и выполнение команды.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
/* Простая функция обработки ошибок: выводит сообщение об ошибке согласно
   значению в «errno» и завершает вызвавший процесс */
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)
static void
usage(char *pname)
{
    fprintf(stderr, "Использование: %s [параметры] программа [аргументы…]\n", pname);
    fprintf(stderr, "Параметры:\n");
    fprintf(stderr, "    -i   отключиться от пространства имён IPC\n");
    fprintf(stderr, "    -m   отключиться от пространства имён монтирования\n");
    fprintf(stderr, "    -n   отключиться от сетевого пространства имён\n");
    fprintf(stderr, "    -p   отключиться от пространства имён PID\n");
    fprintf(stderr, "    -u   отключиться от пространства имён UTS\n");
    fprintf(stderr, "    -U   отключиться от пользовательского пространства имён\n");
    exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
    int flags, opt;
    flags = 0;
    while ((opt = getopt(argc, argv, "imnpuU")) != -1) {
        switch (opt) {
        case 'i': flags |= CLONE_NEWIPC;        break;
        case 'm': flags |= CLONE_NEWNS;         break;
        case 'n': flags |= CLONE_NEWNET;        break;
        case 'p': flags |= CLONE_NEWPID;        break;
        case 'u': flags |= CLONE_NEWUTS;        break;
        case 'U': flags |= CLONE_NEWUSER;       break;
        default:  usage(argv[0]);
        }
    }
    if (optind >= argc)
        usage(argv[0]);
    if (unshare(flags) == -1)
        errExit("unshare");
    execvp(argv[optind], &argv[optind]);
    errExit("execvp");
}