New import
[util-vserver.git] / src / vspace.c
1 // $Id: vspace.c 2817 2008-10-31 04:45:26Z dhozac $    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // Copyright (C) 2007 Daniel Hokka Zakrisson
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; version 2 of the License.
9 //  
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //  
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23
24 #include "util.h"
25 #include <lib_internal/sys_clone.h>
26
27 #include <vserver.h>
28
29 #include <getopt.h>
30 #include <libgen.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <sched.h>
34
35 #define ENSC_WRAPPERS_PREFIX    "vspace: "
36 #define ENSC_WRAPPERS_UNISTD    1
37 #define ENSC_WRAPPERS_VSERVER   1
38 #include <wrappers.h>
39
40 #define CMD_HELP                0x1000
41 #define CMD_VERSION             0x1001
42
43 int             wrapper_exit_code  =  255;
44
45 struct option const
46 CMDLINE_OPTIONS[] = {
47   { "help",       no_argument,       0, CMD_HELP },
48   { "version",    no_argument,       0, CMD_VERSION },
49   { "new",        no_argument,       0, 'n' },
50   { "enter",      required_argument, 0, 'e' },
51   { "set",        no_argument,       0, 's' },
52   { "index",      required_argument, 0, 'i' },
53   { "mask",       required_argument, 0, 'm' },
54   { "default",    no_argument,       0, 'd' },
55   { "~default",   no_argument,       0, 'd' | 0x10000 },
56
57   { "mount",      no_argument,       0, 'M' },
58   { "~mount",     no_argument,       0, 'M' | 0x10000 },
59   { "fs",         no_argument,       0, 'F' },
60   { "~fs",        no_argument,       0, 'F' | 0x10000 },
61   { "ipc",        no_argument,       0, 'I' },
62   { "~ipc",       no_argument,       0, 'I' | 0x10000 },
63   { "uts",        no_argument,       0, 'U' },
64   { "~uts",       no_argument,       0, 'U' | 0x10000 },
65   { "user",       no_argument,       0, 'S' },
66   { "~user",      no_argument,       0, 'S' | 0x10000 },
67   { "pid",        no_argument,       0, 'P' },
68   { "~pid",       no_argument,       0, 'P' | 0x10000 },
69   { "net",        no_argument,       0, 'N' },
70   { "~net",       no_argument,       0, 'N' | 0x10000 },
71   {0,0,0,0}
72 };
73
74 static void
75 showHelp(int fd, char const *cmd, int res)
76 {
77   WRITE_MSG(fd, "Usage: ");
78   WRITE_STR(fd, cmd);
79   WRITE_MSG(fd,
80             " <operation> <spaces>* [--] [<program> <args>*]\n"
81             "\n"
82             "<operation> can be one of:\n"
83             "    --new|-n          ...  create new spaces and execute <program> there;\n"
84             "                           <program> is mandatory in this case\n"
85             "    --enter|-e <xid>  ...  enter the spaces of context <xid> and execute\n"
86             "                           <program> there; <program> is mandatory in this\n"
87             "                           case\n"
88             "    --set|-s          ...  assign the current spaces to the current context\n"
89             "\n"
90             "<spaces>* specifies the spaces to manipulate.\n"
91             "It can be any combination of:\n"
92             "    --mask <mask>     ...  specify a mask of spaces\n"
93             "    --default         ...  the default spaces for this kernel\n"
94             "    --mount           ...  the mount namespace\n"
95             "    --fs              ...  the fs_struct\n"
96             "    --ipc             ...  the IPC namespace\n"
97             "    --uts             ...  the uts namespace\n"
98             "    --user            ...  the user namespace\n"
99             "    --pid             ...  the pid namespace\n"
100             "    --net             ...  the network namespace\n"
101             "\n"
102             "Please report bugs to " PACKAGE_BUGREPORT "\n");
103
104   exit(res);
105 }
106
107 static void
108 showVersion()
109 {
110   WRITE_MSG(1,
111             "vspace " VERSION " -- manages spaces\n"
112             "This program is part of " PACKAGE_STRING "\n\n"
113             "Copyright (C) 2004 Enrico Scholz\n"
114             "Copyright (C) 2007 Daniel Hokka Zakrisson\n"
115             VERSION_COPYRIGHT_DISCLAIMER);
116   exit(0);
117 }
118
119 static void
120 newSpaces(uint_least64_t mask)
121 {
122   pid_t pid;
123
124   mask &= ~CLONE_FS;
125
126   signal(SIGCHLD, SIG_DFL);
127
128 #ifdef NDEBUG
129   pid = sys_clone((int) mask | CLONE_VFORK|SIGCHLD, 0);
130 #else
131   pid = sys_clone((int) mask | SIGCHLD, 0);
132 #endif
133
134   switch (pid) {
135     case -1     :
136       perror(ENSC_WRAPPERS_PREFIX "clone()");
137       exit(wrapper_exit_code);
138     case 0      :
139       break;
140     default     :
141       vc_exitLikeProcess(pid, wrapper_exit_code);
142   }
143 }
144
145 static void
146 enterSpaces(xid_t xid, uint_least64_t mask, uint32_t index)
147 {
148   if (vc_enter_namespace(xid, mask, index)==-1) {
149     perror(ENSC_WRAPPERS_PREFIX "vc_enter_namespace()");
150     exit(wrapper_exit_code);
151   }
152 }
153
154 static void
155 setSpaces(xid_t xid, uint_least64_t mask, uint32_t index)
156 {
157   if (vc_set_namespace(xid, mask, index)==-1) {
158     perror(ENSC_WRAPPERS_PREFIX "vc_set_namespace()");
159     exit(wrapper_exit_code);
160   }
161 }
162
163 int main(int argc, char *argv[])
164 {
165   bool                  do_new     = false;
166   bool                  do_enter   = false;
167   bool                  do_set     = false;
168   uint_least64_t        mask       = 0;
169   uint32_t              index      = 0;
170   xid_t                 xid        = VC_NOCTX;
171   int                   sum        = 0;
172   
173   while (1) {
174     int                 c = getopt_long(argc, argv, "+nsce:m:" "MFIUSPN", CMDLINE_OPTIONS, 0);
175     uint_least64_t      thisbit = 0;
176     if (c==-1) break;
177
178     switch (c & 0xFFFF) {
179       case CMD_HELP     :  showHelp(1, argv[0], 0);
180       case CMD_VERSION  :  showVersion();
181       case 'n'          :  do_new     = true; break;
182       case 's'          :  do_set     = true; break;
183       case 'e'          :
184         do_enter = true;
185         xid      = Evc_xidopt2xid(optarg,true);
186         break;
187       case 'i'          :  {
188         unsigned long   index_l;
189         if (!isNumberUnsigned(optarg, &index_l, true)) {
190           WRITE_MSG(2, "Invalid index '");
191           WRITE_STR(2, optarg);
192           WRITE_MSG(2, "'; try '--help' for more information\n");
193           return wrapper_exit_code;
194         }
195         index = (uint32_t)index_l;
196         break;
197       }
198       case 'm'          :  {
199         unsigned long   mask_l;
200         if (!isNumberUnsigned(optarg, &mask_l, true)) {
201           WRITE_MSG(2, "Invalid mask '");
202           WRITE_STR(2, optarg);
203           WRITE_MSG(2, "'; try '--help' for more information\n");
204           return wrapper_exit_code;
205         }
206         mask = mask_l;
207         break;
208       }
209       case 'M'          :  thisbit = CLONE_NEWNS;       break;
210       case 'F'          :  thisbit = CLONE_FS;          break;
211       case 'I'          :  thisbit = CLONE_NEWIPC;      break;
212       case 'U'          :  thisbit = CLONE_NEWUTS;      break;
213       case 'S'          :  thisbit = CLONE_NEWUSER;     break;
214       case 'P'          :  thisbit = CLONE_NEWPID;      break;
215       case 'N'          :  thisbit = CLONE_NEWNET;      break;
216       case 'd'          :
217         thisbit = vc_get_space_default();
218         if (thisbit == (__typeof__(thisbit)) -1) {
219           thisbit = vc_get_space_mask();
220           if (thisbit == (__typeof__(thisbit)) -1)
221             thisbit = 0;
222         }
223         break;
224
225       default           :
226         WRITE_MSG(2, "Try '");
227         WRITE_STR(2, argv[0]);
228         WRITE_MSG(2, " --help' for more information.\n");
229         return 255;
230         break;
231     }
232     /* ~ option used */
233     if (c & 0xFFFF0000)
234       mask &= ~thisbit;
235     else
236       mask |= thisbit;
237   }
238
239   sum = ((do_new ? 1 : 0) + (do_enter ? 1 : 0) +
240          (do_set ? 1 : 0));
241   
242   if (sum==0)
243     WRITE_MSG(2, "No operation was specified; try '--help' for more information\n");
244   else if (sum>1)
245     WRITE_MSG(2, "Can not specify multiple operations; try '--help' for more information\n");
246   else if (optind==argc && (do_new || do_enter))
247     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
248   else {
249     if      (do_new)     newSpaces(mask);
250     else if (do_set)     setSpaces(VC_SAMECTX, mask, index);
251     else if (do_enter)   enterSpaces(xid, mask, index);
252
253     if (optind<argc)
254       EexecvpD(argv[optind], argv+optind);
255
256     return EXIT_SUCCESS;
257   }
258
259   return 255;
260 }