From: Mikhail Gusarov Date: Sat, 3 Oct 2009 19:42:08 +0000 (+0700) Subject: unshare: new command X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4205f1fda1ac32046125a2e0f3937b666186bfab;p=util-linux unshare: new command New utility allows to run process with separate mount, UTC, IPC or network namespaces. [kzak@redhat.com: - some cosmetic changes in usage() and err() usage - move "if BUILD_UNSHARE" to separate place in Makefile.am - add unshare to .gitignore] Signed-off-by: Mikhail Gusarov Signed-off-by: Karel Zak --- diff --git a/TODO b/TODO index 27e2b322..e9f772ae 100644 --- a/TODO +++ b/TODO @@ -41,10 +41,6 @@ fdisk(s) misc ---- - * add a new command (unshare, clone, or so...) with all kinds of - clone(2) options. - http://thread.gmane.org/gmane.linux.utilities.util-linux-ng/2178 - * add to lib/blkdev.c code for /proc/partitions parsing -- unfortunate we duplicate this code in many places. The parser has to support unlimited size (or 4096 bytes) of partition name. diff --git a/configure.ac b/configure.ac index 4f4cbb39..07c851fc 100644 --- a/configure.ac +++ b/configure.ac @@ -372,6 +372,20 @@ AM_CONDITIONAL(HAVE_BLKID, test "x$have_blkid" = xyes) AC_ARG_VAR([BLKID_LIBS_STATIC], [-l options for linking statically with blkid]) +AC_ARG_ENABLE([unshare], + AS_HELP_STRING([--disable-unshare], [do not build unshare]), + [], enable_unshare=check +) +build_unshare=yes +if test "x$enable_unshare" = xcheck; then + if test "x$linux_os" = xno; then + AC_MSG_WARN([non-linux system; do not build unshare]) + build_unshare=no + fi +elif test "x$enable_unshare" = xno; then + build_unshare=no +fi +AM_CONDITIONAL(BUILD_UNSHARE, test "x$build_unshare" = xyes) UTIL_CHECK_LIB(util, openpty) UTIL_CHECK_LIB(termcap, tgetnum) @@ -563,6 +577,10 @@ dnl fallocate could be available as libc function or as syscall only UTIL_CHECK_SYSCALL([fallocate]) AC_CHECK_FUNCS([fallocate]) +dnl unshare could be available as libc function or as syscall only +UTIL_CHECK_SYSCALL([unshare]) +AC_CHECK_FUNCS([unshare]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include diff --git a/sys-utils/.gitignore b/sys-utils/.gitignore index 2cc2deef..7985d7a5 100644 --- a/sys-utils/.gitignore +++ b/sys-utils/.gitignore @@ -39,5 +39,6 @@ sparc64.8 sparc.8 switch_root tunelp +unshare vidmode.8 x86_64.8 diff --git a/sys-utils/Makefile.am b/sys-utils/Makefile.am index e6f76290..3c0525a9 100644 --- a/sys-utils/Makefile.am +++ b/sys-utils/Makefile.am @@ -38,6 +38,11 @@ sbin_PROGRAMS += switch_root dist_man_MANS += switch_root.8 endif +if BUILD_UNSHARE +usrbin_exec_PROGRAMS += unshare +dist_man_MANS += unshare.1 +endif + if BUILD_ARCH bin_PROGRAMS += arch dist_man_MANS += arch.1 diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1 new file mode 100644 index 00000000..31fcfde7 --- /dev/null +++ b/sys-utils/unshare.1 @@ -0,0 +1,58 @@ +.\" Process this file with +.\" groff -man -Tascii lscpu.1 +.\" +.TH UNSHARE 1 "OCTOBER 2008" Linux "User Manuals" +.SH NAME +unshare \- run program with some namespaces unshared from parent +.SH SYNOPSIS +.B unshare +.RI [ options ] +program +.RI [ arguments ] +.SH DESCRIPTION +Unshares specified namespaces from parent process and then executes specified +program. Unshareable namespaces are: +.TP +.BR "mount namespace" +mounting and unmounting filesystems will not affect rest of the system +(\fBCLONE_NEWNS\fP flag), +.TP +.BR "UTS namespace" +setting hostname, domainname will not affect rest of the system +(\fBCLONE_NEWUTS\fP flag), +.TP +.BR "IPC namespace" +process will have indpendent namespace for System V message queues, semaphore +sets and shared memory segments (\fBCLONE_NEWIPC\fP flag), +.TP +.BR "network namespace" +process will have independent IPv4 and IPv6 stacks, IP routing tables, firewall +rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, sockets +etc. (\fBCLONE_NEWNET\fP flag). +.TP +See the clone(2) for exact semantics of the flags. +.SH OPTIONS +.TP +.BR \-h , " \-\-help" +Print a help message, +.TP +.BR \-m , " \-\-mount" +Unshare the mount namespace, +.TP +.BR \-u , " \-\-uts" +Unshare the UTC namespace, +.TP +.BR \-i , " \-\-ipc" +Unshare the IPC namespace, +.TP +.BR \-n , " \-\-net" +Unshare the network namespace. +.SH SEE ALSO +unshare(2), clone(2) +.SH BUGS +None known so far. +.SH AUTHOR +Mikhail Gusarov +.SH AVAILABILITY +The unshare command is part of the util-linux-ng package and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/. diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c new file mode 100644 index 00000000..df75d177 --- /dev/null +++ b/sys-utils/unshare.c @@ -0,0 +1,119 @@ +/* + * unshare(1) - command-line interface for unshare(2) + * + * Copyright (C) 2009 Mikhail Gusarov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nls.h" + +#ifndef CLONE_NEWSNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif + +#ifndef HAVE_UNSHARE +# include + +static int unshare(int flags) +{ + return syscall(SYS_unshare, flags); +} +#endif + +static void usage(int status) +{ + FILE *out = status == EXIT_SUCCESS ? stdout : stderr; + + fprintf(out, _("Usage: %s [options] [args...]\n"), + program_invocation_short_name); + + fputs(_("Run program with some namespaces unshared from parent\n\n" + " -h, --help usage information (this)\n" + " -m, --mount unshare mounts namespace\n" + " -u, --uts unshare UTS namespace (hostname etc)\n" + " -i, --ipc unshare System V IPC namespace\n" + " -n, --net unshare network namespace\n"), out); + + fprintf(out, _("\nFor more information see unshare(1).\n")); + exit(status); +} + +int main(int argc, char *argv[]) +{ + struct option longopts[] = { + { "help", no_argument, 0, 'h' }, + { "mount", no_argument, 0, 'm' }, + { "uts", no_argument, 0, 'u' }, + { "ipc", no_argument, 0, 'i' }, + { "net", no_argument, 0, 'n' }, + }; + + int unshare_flags = 0; + + int c; + + setlocale(LC_MESSAGES, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + while((c = getopt_long(argc, argv, "hmuin", longopts, NULL)) != -1) { + switch(c) { + case 'h': + usage(EXIT_SUCCESS); + case 'm': + unshare_flags |= CLONE_NEWNS; + break; + case 'u': + unshare_flags |= CLONE_NEWUTS; + break; + case 'i': + unshare_flags |= CLONE_NEWIPC; + break; + case 'n': + unshare_flags |= CLONE_NEWNET; + break; + default: + usage(EXIT_FAILURE); + } + } + + if(optind >= argc) + usage(EXIT_FAILURE); + + if(-1 == unshare(unshare_flags)) + err(EXIT_FAILURE, _("unshare failed")); + + execvp(argv[optind], argv + optind); + + err(EXIT_FAILURE, _("exec %s failed"), argv[optind]); +}