]> err.no Git - util-linux/commitdiff
unshare: new command
authorMikhail Gusarov <dottedmag@dottedmag.net>
Sat, 3 Oct 2009 19:42:08 +0000 (02:42 +0700)
committerKarel Zak <kzak@redhat.com>
Tue, 6 Oct 2009 10:45:42 +0000 (12:45 +0200)
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 <dottedmag@dottedmag.net>
Signed-off-by: Karel Zak <kzak@redhat.com>
TODO
configure.ac
sys-utils/.gitignore
sys-utils/Makefile.am
sys-utils/unshare.1 [new file with mode: 0644]
sys-utils/unshare.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index 27e2b3229835c592d696adbdd2556a6521b7121a..e9f772ae4a6eaf7fe1ffee4237b3d620d32130b4 100644 (file)
--- 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.
index 4f4cbb39a80914dbb9d8cf983e01815624be9edd..07c851fc1a4803f4c4f03daa1e9b86fe1ef2b36f 100644 (file)
@@ -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 <time.h>
 #include <unistd.h>
index 2cc2deef39ffdf86a54dae80547fb7175bdaa095..7985d7a5ab80129ae8bae7d4abf4b45201d92f59 100644 (file)
@@ -39,5 +39,6 @@ sparc64.8
 sparc.8
 switch_root
 tunelp
+unshare
 vidmode.8
 x86_64.8
index e6f7629033b775551cfba4f2e11de70e0c1a6d55..3c0525a94cb4cb9f0a715448453e13cc4b74750c 100644 (file)
@@ -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 (file)
index 0000000..31fcfde
--- /dev/null
@@ -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 <dottedmag@dottedmag.net>
+.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 (file)
index 0000000..df75d17
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * unshare(1) - command-line interface for unshare(2)
+ *
+ * Copyright (C) 2009 Mikhail Gusarov <dottedmag@dottedmag.net>
+ *
+ * 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 <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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 <sys/syscall.h>
+
+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] <program> [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]);
+}