Added vspace, like vnamespace but generic.
[util-vserver.git] / src / vspace.c
1 // $Id$    --*- 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_unshare.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   { "mask",       required_argument, 0, 'm' },
53
54   { "mount",      no_argument,       0, 'M' },
55   { "fs",         no_argument,       0, 'F' },
56   { "ipc",        no_argument,       0, 'I' },
57   { "uts",        no_argument,       0, 'U' },
58   { "user",       no_argument,       0, 'S' },
59   {0,0,0,0}
60 };
61
62 static void
63 showHelp(int fd, char const *cmd, int res)
64 {
65   WRITE_MSG(fd, "Usage: ");
66   WRITE_STR(fd, cmd);
67   WRITE_MSG(fd,
68             " <operation> <spaces>* [--] [<program> <args>*]\n"
69             "\n"
70             "<operation> can be one of:\n"
71             "    --new|-n          ...  create new spaces and execute <program> there;\n"
72             "                           <program> is mandatory in this case\n"
73             "    --enter|-e <xid>  ...  enter the spaces of context <xid> and execute\n"
74             "                           <program> there; <program> is mandatory in this\n"
75             "                           case\n"
76             "    --set|-s          ...  assign the current spaces to the current context\n"
77             "\n"
78             "<spaces>* specifies the spaces to manipulate.\n"
79             "It can be any combination of:\n"
80             "    --mask <mask>     ...  specify a mask of spaces\n"
81             "    --mount           ...  the mount namespace\n"
82             "    --fs              ...  the fs_struct\n"
83             "    --ipc             ...  the IPC namespace\n"
84             "    --uts             ...  the uts namespace\n"
85             "    --user            ...  the user namespace\n"
86             "\n"
87             "Please report bugs to " PACKAGE_BUGREPORT "\n");
88
89   exit(res);
90 }
91
92 static void
93 showVersion()
94 {
95   WRITE_MSG(1,
96             "vspace " VERSION " -- manages spaces\n"
97             "This program is part of " PACKAGE_STRING "\n\n"
98             "Copyright (C) 2004 Enrico Scholz\n"
99             "Copyright (C) 2007 Daniel Hokka Zakrisson\n"
100             VERSION_COPYRIGHT_DISCLAIMER);
101   exit(0);
102 }
103
104 static void
105 newSpaces(uint_least64_t mask)
106 {
107   if (sys_unshare((int) mask) == -1) {
108     perror(ENSC_WRAPPERS_PREFIX "unshare()");
109     exit(wrapper_exit_code);
110   }
111 }
112
113 static void
114 enterSpaces(xid_t xid, uint_least64_t mask)
115 {
116   if (vc_enter_namespace(xid, mask)==-1) {
117     perror(ENSC_WRAPPERS_PREFIX "vc_enter_namespace()");
118     exit(wrapper_exit_code);
119   }
120 }
121
122 static void
123 setSpaces(xid_t xid, uint_least64_t mask)
124 {
125   if (vc_set_namespace(xid, mask)==-1) {
126     perror(ENSC_WRAPPERS_PREFIX "vc_set_namespace()");
127     exit(wrapper_exit_code);
128   }
129 }
130
131 int main(int argc, char *argv[])
132 {
133   bool                  do_new     = false;
134   bool                  do_enter   = false;
135   bool                  do_set     = false;
136   uint_least64_t        mask       = 0;
137   xid_t                 xid        = VC_NOCTX;
138   int                   sum        = 0;
139   
140   while (1) {
141     int         c = getopt_long(argc, argv, "+nsce:m:" "MFIUS", CMDLINE_OPTIONS, 0);
142     if (c==-1) break;
143
144     switch (c) {
145       case CMD_HELP     :  showHelp(1, argv[0], 0);
146       case CMD_VERSION  :  showVersion();
147       case 'n'          :  do_new     = true; break;
148       case 's'          :  do_set     = true; break;
149       case 'e'          :
150         do_enter = true;
151         xid      = Evc_xidopt2xid(optarg,true);
152         break;
153       case 'm'          :
154         if (!isNumberUnsigned(optarg, &mask, true)) {
155           WRITE_MSG(2, "Invalid mask '");
156           WRITE_STR(2, optarg);
157           WRITE_MSG(2, "'; try '--help' for more information\n");
158           return wrapper_exit_code;
159         }
160         break;
161       case 'M'          :  mask |= CLONE_NEWNS;         break;
162       case 'F'          :  mask |= CLONE_FS;            break;
163       case 'I'          :  mask |= CLONE_NEWIPC;        break;
164       case 'U'          :  mask |= CLONE_NEWUTS;        break;
165       case 'S'          :  mask |= CLONE_NEWUSER;       break;
166
167       default           :
168         WRITE_MSG(2, "Try '");
169         WRITE_STR(2, argv[0]);
170         WRITE_MSG(2, " --help' for more information.\n");
171         return 255;
172         break;
173     }
174   }
175
176   sum = ((do_new ? 1 : 0) + (do_enter ? 1 : 0) +
177          (do_set ? 1 : 0));
178   
179   if (sum==0)
180     WRITE_MSG(2, "No operation was specified; try '--help' for more information\n");
181   else if (sum>1)
182     WRITE_MSG(2, "Can not specify multiple operations; try '--help' for more information\n");
183   else if (mask==0)
184     WRITE_MSG(2, "Must specify at least one space; try '--help' for more information\n");
185   else if (optind==argc && (do_new || do_enter))
186     WRITE_MSG(2, "No command specified; try '--help' for more information\n");
187   else {
188     if      (do_new)     newSpaces(mask);
189     else if (do_set)     setSpaces(VC_SAMECTX, mask);
190     else if (do_enter)   enterSpaces(xid, mask);
191
192     if (optind<argc)
193       EexecvpD(argv[optind], argv+optind);
194
195     return EXIT_SUCCESS;
196   }
197
198   return 255;
199 }