UNSHARE - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-04-11
名称
unshare-取消流程执行上下文的关联
语法
#define _GNU_SOURCE #include <sched.h> int unshare(int flags);
说明
unshare()允许进程(或线程)取消其执行上下文的当前与其他进程(或线程)共享的部分的关联。当使用fork(2)或vfork(2)创建新进程时,执行上下文的一部分(例如mount命名空间)被隐式共享,而其他部分(例如虚拟内存)在创建文件时可能会被显式请求共享。进程或线程使用clone(2)。
unshare()的主要用途是允许进程控制其共享执行上下文,而无需创建新进程。
flags参数是一个位掩码,它指定应共享执行上下文的哪些部分。通过对以下常量中的零个或多个进行"或"运算来指定此参数:
- CLONE_FILES
- 反转clone(2)CLONE_FILES标志的作用。取消共享文件描述符表,以便调用进程不再与任何其他进程共享其文件描述符。
- CLONE_FS
- 反转clone(2)CLONE_FS标志的作用。取消共享文件系统属性,以便调用进程不再与任何其他进程共享其根目录(chroot(2)),当前目录(chdir(2))或umask(umask(2))属性。
- CLONE_NEWCGROUP(since Linux 4.6)
- 该标志与clone(2)CLONE_NEWCGROUP标志具有相同的作用。取消共享cgroup命名空间。使用CLONE_NEWCGROUP需要CAP_SYS_ADMIN功能。
- CLONE_NEWIPC(since Linux 2.6.19)
- 该标志与clone(2)CLONE_NEWIPC标志具有相同的作用。取消共享IPC名称空间,以便调用进程具有IPC名称空间的私有副本,该副本不会与任何其他进程共享。指定此标志也会自动暗示CLONE_SYSVSEM。使用CLONE_NEWIPC需要CAP_SYS_ADMIN功能。
- CLONE_NEWNET(since Linux 2.6.24)
- 该标志与clone(2)CLONE_NEWNET标志具有相同的作用。取消共享网络名称空间,以便将调用进程移到新的网络名称空间中,该名称空间不会与任何以前存在的进程共享。使用CLONE_NEWNET需要CAP_SYS_ADMIN功能。
- CLONE_NEWNS
- 该标志与clone(2)CLONE_NEWNS标志具有相同的作用。取消共享安装名称空间,以便调用进程具有其名称空间的私有副本,该副本不与任何其他进程共享。指定此标志也会自动暗示CLONE_FS。使用CLONE_NEWNS需要CAP_SYS_ADMIN功能。有关更多信息,请参见mount_namespaces(7)。
- CLONE_NEWPID(since Linux 3.8)
- 该标志与clone(2)CLONE_NEWPID标志具有相同的作用。取消共享PID名称空间,以便调用进程为其子级创建一个新的PID名称空间,该名称空间不会与任何先前存在的进程共享。调用过程不会移到新的名称空间中。调用进程创建的第一个子进程将具有进程ID 1,并将在新名称空间中担当init(1)的角色。 CLONE_NEWPID也自动暗示CLONE_THREAD。使用CLONE_NEWPID需要CAP_SYS_ADMIN功能。有关更多信息,请参见pid_namespaces(7)。
- CLONE_NEWTIME(since Linux 5.6)
- 取消共享时间名称空间,以便调用进程为其子级提供一个新的时间名称空间,该名称空间不会与任何先前存在的进程共享。调用过程不会移到新的名称空间中。使用CLONE_NEWTIME需要CAP_SYS_ADMIN功能。有关更多信息,请参见time_namespaces(7)。
- CLONE_NEWUSER(since Linux 3.8)
- 该标志与clone(2)CLONE_NEWUSER标志具有相同的作用。取消共享用户名称空间,以便将调用进程移至新的用户名称空间,该名称空间不与任何先前存在的进程共享。就像由clone(2)使用CLONE_NEWUSER标志创建的子进程一样,调用者在新名称空间中获得了完整的功能集。
- CLONE_NEWUSER要求调用进程未线程化;指定CLONE_NEWUSER会自动隐含CLONE_THREAD。从Linux 3.9开始,CLONE_NEWUSER也自动隐含CLONE_FS。 CLONE_NEWUSER要求在调用时将调用过程的用户ID和组ID映射到调用过程的用户名称空间中的用户ID和组ID。
- 有关用户名称空间的更多信息,请参见user_namespaces(7)。
- CLONE_NEWUTS(since Linux 2.6.19)
- 该标志与clone(2)CLONE_NEWUTS标志具有相同的作用。取消共享UTS IPC名称空间,以便调用进程具有UTS名称空间的私有副本,该副本不会与任何其他进程共享。使用CLONE_NEWUTS需要CAP_SYS_ADMIN功能。
- CLONE_SYSVSEM(since Linux 2.6.26)
- 该标志反转clone(2)CLONE_SYSVSEM标志的作用。取消共享系统V信号量调整(semadj)值,以便调用进程具有一个新的空semadj列表,该列表不与任何其他进程共享。如果这是最后一个引用该进程当前semadj列表的进程,则该列表中的调整将应用于相应的信号量,如semop(2)中所述。
另外,如果调用者是单线程的(即,它不与另一个进程或线程共享其地址空间),则可以在标志中指定CLONE_THREAD,CLONE_SIGHAND和CLONE_VM。在这种情况下,这些标志无效。 (还请注意,指定CLONE_THREAD自动表示CLONE_VM,指定CLONE_VM自动表示CLONE_SIGHAND。)如果进程是多线程的,则使用这些标志将导致错误。
如果将标志指定为零,则unshare()为无操作;否则为false。不会对调用过程的执行上下文进行任何更改。
返回值
成功后,返回零。失败时,将返回-1并将errno设置为指示错误。
错误说明
- EINVAL
- 在标志中指定了无效的位。
- EINVAL
- 在标志中指定了CLONE_THREAD,CLONE_SIGHAND或CLONE_VM,并且调用方是多线程的。
- EINVAL
- 在标志中指定了CLONE_NEWIPC,但未使用CONFIG_SYSVIPC和CONFIG_IPC_NS选项配置内核。
- EINVAL
- 在标志中指定了CLONE_NEWNET,但未使用CONFIG_NET_NS选项配置内核。
- EINVAL
- 在标志中指定了CLONE_NEWPID,但未使用CONFIG_PID_NS选项配置内核。
- EINVAL
- 在标志中指定了CLONE_NEWUSER,但是未使用CONFIG_USER_NS选项配置内核。
- EINVAL
- 在标志中指定了CLONE_NEWUTS,但未使用CONFIG_UTS_NS选项配置内核。
- EINVAL
- 在标志中指定了CLONE_NEWPID,但是该进程先前已使用CLONE_NEWPID标志调用了unshare()。
- ENOMEM
- 无法分配足够的内存来复制需要取消共享的调用方上下文部分。
- ENOSPC(since Linux 3.7)
- CLONE_NEWPID是在标志中指定的,但将超出PID名称空间嵌套深度的限制;参见pid_namespaces(7)。
- ENOSPC(since Linux 4.9; beforehand EUSERS)
- CLONE_NEWUSER是在标志中指定的,并且该调用将导致超出嵌套用户名称空间数量的限制。参见user_namespaces(7)。
- 从Linux 3.11到Linux 4.8,在这种情况下诊断的错误是EUSERS。
- ENOSPC(since Linux 4.9)
- 标志中的值之一指定了新用户名称空间的创建,但是这样做将导致超出/ proc / sys / user中相应文件定义的限制。有关更多详细信息,请参见namespaces(7)。
- EPERM
- 调用过程没有此操作所需的特权。
- EPERM
- 在标志中指定了CLONE_NEWUSER,但是调用者的有效用户ID或有效组ID在父名称空间中没有映射(请参阅user_namespaces(7))。
- EPERM(since Linux 3.9)
- 在标记中指定了CLONE_NEWUSER,并且调用者位于chroot环境中(即,调用者的根目录与它所在的安装名称空间的根目录不匹配)。
- EUSERS(from Linux 3.11 to Linux 4.8)
- 在标志中指定了CLONE_NEWUSER,并且将超出嵌套用户名称空间数量的限制。请参阅上面有关ENOSPC错误的讨论。
版本
unshare()系统调用已添加到内核2.6.16中的Linux中。
遵循规范
unshare()系统调用是特定于Linux的。
备注
并非所有使用克隆(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)命令的不同输出表明,两个外壳程序位于不同的安装名称空间中。
Program source
/* unshare.c A simple implementation of the unshare(1) command: unshare namespaces and execute a command. */ #define _GNU_SOURCE #include <sched.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> /* A simple error-handling function: print an error message based on the value in aqerrnoaq and terminate the calling process */ #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void usage(char *pname) { fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname); fprintf(stderr, "Options can be:\n"); fprintf(stderr, " -C unshare cgroup namespace\n"); fprintf(stderr, " -i unshare IPC namespace\n"); fprintf(stderr, " -m unshare mount namespace\n"); fprintf(stderr, " -n unshare network namespace\n"); fprintf(stderr, " -p unshare PID namespace\n"); fprintf(stderr, " -t unshare time namespace\n"); fprintf(stderr, " -u unshare UTS namespace\n"); fprintf(stderr, " -U unshare user namespace\n"); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int flags, opt; flags = 0; while ((opt = getopt(argc, argv, "CimnptuU")) != -1) { switch (opt) { case aqCaq: flags |= CLONE_NEWCGROUP; break; case aqiaq: flags |= CLONE_NEWIPC; break; case aqmaq: flags |= CLONE_NEWNS; break; case aqnaq: flags |= CLONE_NEWNET; break; case aqpaq: flags |= CLONE_NEWPID; break; case aqtaq: flags |= CLONE_NEWTIME; break; case aquaq: flags |= CLONE_NEWUTS; break; case aqUaq: flags |= CLONE_NEWUSER; break; default: usage(argv[0]); } } if (optind >= argc) usage(argv[0]); if (unshare(flags) == -1) errExit("unshare"); execvp(argv[optind], &argv[optind]); errExit("execvp"); }
另外参见
unshare(1),clone(2),fork(2),kcmp(2),setns(2),vfork(2),名称空间(7)
Linux内核源代码树中的Documentation / userspace-api / unshare.rst(或Linux 4.12之前的Documentation / unshare.txt)
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。