use unshare(CLONE_NEWNS) instead of a complicated 'clone(NEWNS) ... waitpid()' operation
[util-vserver.git] / src / vnamespace.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "util.h"
24 #include <lib_internal/sys_unshare.h>
25
26 #include <vserver.h>
27
28 #include <getopt.h>
29 #include <libgen.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <sched.h>
33
34 #define ENSC_WRAPPERS_PREFIX    "vnamespace: "
35 #define ENSC_WRAPPERS_UNISTD    1
36 #define ENSC_WRAPPERS_VSERVER   1
37 #include <wrappers.h>
38
39 #define CMD_HELP                0x1000
40 #define CMD_VERSION             0x1001
41
42 int             wrapper_exit_code  =  255;
43
44 struct option const
45 CMDLINE_OPTIONS[] = {
46   { "help",       no_argument,       0, CMD_HELP },
47   { "version",    no_argument,       0, CMD_VERSION },
48   { "new",        no_argument,       0, 'n' },
49   { "enter",      required_argument, 0, 'e' },
50   { "set",        no_argument,       0, 's' },
51   { "cleanup",    no_argument,       0, 'c' },
52   {0,0,0,0}
53 };
54
55 static void
56 showHelp(int fd, char const *cmd, int res)
57 {
58   WRITE_MSG(fd, "Usage: ");
59   WRITE_STR(fd, cmd);
60   WRITE_MSG(fd,
61             " <operation> [--] [<program> <args>*]\n"
62             "\n"
63             "<operation> can be one of:\n"
64             "    --new|-n          ...  create new namespace and execute <program> there;\n"
65             "                           <program> is mandatory in this case\n"
66             "    --enter|-e <xid>  ...  enter the namespace of context <xid> and execute\n"
67             "                           <program> there; <program> is mandatory in this\n"
68             "                           case\n"
69             "    --set|-s          ...  make current namespace the namespace of the\n"
70             "                           current context\n"
71             "    --cleanup|-c      ...  remove all mounts from the namespace of the\n"
72             "                           current context\n"
73             "\n"
74             "Please report bugs to " PACKAGE_BUGREPORT "\n");
75
76   exit(res);
77 }
78
79 static void
80 showVersion()
81 {
82   WRITE_MSG(1,
83             "vnamespace " VERSION " -- manages filesystem-namespace\n"
84             "This program is part of " PACKAGE_STRING "\n\n"
85             "Copyright (C) 2004 Enrico Scholz\n"
86             VERSION_COPYRIGHT_DISCLAIMER);
87   exit(0);
88 }
89
90 static void
91 newNamespace(void)
92 {
93   int           rc;
94
95   rc = sys_unshare(CLONE_NEWNS);
96   if (rc!=0) {
97     perror("vnamespace: unshare()");
98     exit(wrapper_exit_code);
99   }
100 }
101
102 static void
103 enterNamespace(xid_t xid, uint_least64_t mask)
104 {
105   if (vc_enter_namespace(xid, mask)==-1) {
106     perror("vnamespace: vc_enter_namespace()");
107     exit(255);
108   }
109 }
110
111 static void
112 setNamespace(xid_t xid, uint_least64_t mask)
113 {
114   if (vc_set_namespace(xid, mask)==-1) {
115     perror("vnamespace: vc_set_namespace()");
116     exit(255);
117   }
118 }
119
120 static void
121 cleanupNamespace()
122 {
123   if (vc_cleanup_namespace()==-1) {
124     perror("vnamespace: vc_cleanup_namespace()");
125     exit(255);
126   }
127 }
128
129 int main(int argc, char *argv[])
130 {
131   bool          do_new     = false;
132   bool          do_enter   = false;
133   bool          do_set     = false;
134   bool          do_cleanup = false;
135   xid_t         xid        = VC_NOCTX;
136   int           sum        = 0;
137   
138   while (1) {
139     int         c = getopt_long(argc, argv, "+nsce:", CMDLINE_OPTIONS, 0);
140     if (c==-1) break;
141
142     switch (c) {
143       case CMD_HELP     :  showHelp(1, argv[0], 0);
144       case CMD_VERSION  :  showVersion();
145       case 'n'          :  do_new     = true; break;
146       case 's'          :  do_set     = true; break;
147       case 'c'          :  do_cleanup = true; break;
148       case 'e'          :
149         do_enter = true;
150         xid      = Evc_xidopt2xid(optarg,true);
151         break;
152
153       default           :
154         WRITE_MSG(2, "Try '");
155         WRITE_STR(2, argv[0]);
156         WRITE_MSG(2, " --help' for more information.\n");
157         return 255;
158         break;
159     }
160   }
161
162   sum = ((do_new ? 1 : 0) + (do_enter ? 1 : 0) +
163          (do_set ? 1 : 0) + (do_cleanup ? 1 : 0));
164   
165   if (sum==0)
166     WRITE_MSG(2, "No operation was specified; try '--help' for more information\n");
167   else if (sum>1)
168     WRITE_MSG(2, "Can not specify multiple operations; try '--help' for more information\n");
169   else if (optind==argc && (do_new || do_enter))
170     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
171   else {
172     if      (do_new)     newNamespace();
173     else if (do_set)     setNamespace(VC_SAMECTX, CLONE_NEWNS|CLONE_FS);
174     else if (do_cleanup) cleanupNamespace();
175     else if (do_enter)   enterNamespace(xid, CLONE_NEWNS|CLONE_FS);
176
177     if (optind<argc)
178       EexecvpD(argv[optind], argv+optind);
179
180     return EXIT_SUCCESS;
181   }
182
183   return 255;
184 }