ncontext.c (8380B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2004-2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // Copyright (C) 2006 Daniel Hokka Zakrisson <daniel@hozac.com> 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.h" 26 #include "lib_internal/util.h" 27 #include "lib_internal/jail.h" 28 29 #include <vserver.h> 30 #include <getopt.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <sys/socket.h> 34 #include <sys/un.h> 35 #include <assert.h> 36 #include <signal.h> 37 #include <sys/types.h> 38 39 40 #define ENSC_WRAPPERS_PREFIX "ncontext: " 41 #define ENSC_WRAPPERS_UNISTD 1 42 #define ENSC_WRAPPERS_VSERVER 1 43 #define ENSC_WRAPPERS_FCNTL 1 44 #define ENSC_WRAPPERS_SOCKET 1 45 #define ENSC_WRAPPERS_IOSOCK 1 46 #include <wrappers.h> 47 48 #define CMD_HELP 0x1000 49 #define CMD_VERSION 0x1001 50 #define CMD_NID 0x4000 51 #define CMD_CREATE 0x4001 52 #define CMD_MIGRATE 0x4002 53 #define CMD_DISCONNECT 0x4003 54 #define CMD_SILENT 0x4004 55 #define CMD_SYNCSOCK 0x4005 56 #define CMD_SYNCMSG 0x4006 57 #define CMD_MIGRATESELF 0x4007 58 #define CMD_SILENTEXIST 0x4008 59 60 61 struct option const 62 CMDLINE_OPTIONS[] = { 63 { "help", no_argument, 0, CMD_HELP }, 64 { "version", no_argument, 0, CMD_VERSION }, 65 { "nid", required_argument, 0, CMD_NID }, 66 { "create", no_argument, 0, CMD_CREATE }, 67 { "migrate", no_argument, 0, CMD_MIGRATE }, 68 { "migrate-self", no_argument, 0, CMD_MIGRATESELF }, 69 { "disconnect", no_argument, 0, CMD_DISCONNECT }, 70 { "silent", no_argument, 0, CMD_SILENT }, 71 { "silentexist", no_argument, 0, CMD_SILENTEXIST }, 72 { "syncsock", required_argument, 0, CMD_SYNCSOCK }, 73 { "syncmsg", required_argument, 0, CMD_SYNCMSG }, 74 { 0,0,0,0 }, 75 }; 76 77 struct Arguments { 78 bool do_create; 79 bool do_migrate; 80 bool do_migrateself; 81 bool do_disconnect; 82 bool is_silentexist; 83 int verbosity; 84 nid_t nid; 85 char const * sync_sock; 86 char const * sync_msg; 87 }; 88 89 int wrapper_exit_code = 255; 90 91 static void 92 showHelp(int fd, char const *cmd, int res) 93 { 94 WRITE_MSG(fd, "Usage:\n "); 95 WRITE_STR(fd, cmd); 96 WRITE_MSG(fd, 97 " --create [--nid <nid>] <opts>* [--] <program> <args>*\n "); 98 WRITE_STR(fd, cmd); 99 WRITE_MSG(fd, 100 " [(--migrate --nid <nid>)|--migrate-self] <opts>* [--] <program> <args>*\n" 101 "\n" 102 "<opts> can be:\n" 103 " --disconnect ... start program in background\n" 104 " --silent ... be silent\n" 105 " --silentexist ... be silent when context exists already; useful\n" 106 " for '--create' only\n" 107 " --syncsock <filename>\n" 108 " ... before executing the program, send a message\n" 109 " to the socket and wait until it closes.\n" 110 " <filename> must be a SOCK_STREAM unix socket\n" 111 " --syncmsg <message>\n" 112 " ... use <message> as synchronization message; by\n" 113 " default, 'ok' will be used\n" 114 "\n" 115 "'ncontext --create' exits with code 254 iff the context exists already.\n" 116 "\n" 117 "Please report bugs to " PACKAGE_BUGREPORT "\n"); 118 119 exit(res); 120 } 121 122 static void 123 showVersion() 124 { 125 WRITE_MSG(1, 126 "ncontext " VERSION " -- manages the creation of network contexts\n" 127 "This program is part of " PACKAGE_STRING "\n\n" 128 "Copyright (C) 2004-2006 Enrico Scholz\n" 129 "Copyright (C) 2006 Daniel Hokka Zakrisson\n" 130 VERSION_COPYRIGHT_DISCLAIMER); 131 exit(0); 132 } 133 134 #include "context-sync.hc" 135 136 static inline ALWAYSINLINE void 137 tellContext(nid_t nid, bool do_it) 138 { 139 char buf[sizeof(nid_t)*3+2]; 140 size_t l; 141 142 if (!do_it) return; 143 144 l = utilvserver_fmt_long(buf,nid); 145 146 WRITE_MSG(1, "New network context is "); 147 Vwrite (1, buf, l); 148 WRITE_MSG(1, "\n"); 149 } 150 151 static int 152 connectExternalSync(char const *filename) 153 { 154 int fd; 155 struct sockaddr_un addr; 156 157 if (filename==0) return -1; 158 159 ENSC_INIT_UNIX_SOCK(addr, filename); 160 161 fd = Esocket(PF_UNIX, SOCK_STREAM, 0); 162 Econnect(fd, &addr, sizeof(addr)); 163 164 return fd; 165 } 166 167 static void 168 doExternalSync(int fd, char const *msg) 169 { 170 char c; 171 172 if (fd==-1) return; 173 174 if (msg) EsendAll(fd, msg, strlen(msg)); 175 Eshutdown(fd, SHUT_WR); 176 177 if (TEMP_FAILURE_RETRY(recv(fd, &c, 1, MSG_NOSIGNAL))!=0) { 178 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unexpected external synchronization event\n"); 179 exit(wrapper_exit_code); 180 } 181 182 Eclose(fd); 183 } 184 185 static inline ALWAYSINLINE int 186 doit(struct Arguments const *args, char *argv[]) 187 { 188 int p[2][2]; 189 pid_t pid = initSync(p, args->do_disconnect); 190 191 if (pid==0) { 192 nid_t nid; 193 int ext_sync_fd = connectExternalSync(args->sync_sock); 194 195 doSyncStage0(p, args->do_disconnect); 196 197 if (args->do_create) { 198 nid = vc_net_create(args->nid); 199 if (nid==VC_NOCTX) { 200 switch (errno) { 201 case EEXIST : 202 if (!args->is_silentexist) 203 perror(ENSC_WRAPPERS_PREFIX "vc_net_create()"); 204 return 254; 205 default : 206 perror(ENSC_WRAPPERS_PREFIX "vc_net_create()"); 207 return wrapper_exit_code; 208 } 209 } 210 tellContext(nid, args->verbosity>=1); 211 } 212 else 213 nid = args->nid; 214 215 if (args->do_migrate && !args->do_migrateself) 216 Evc_net_migrate(nid); 217 218 doExternalSync(ext_sync_fd, args->sync_msg); 219 doSyncStage1(p, args->do_disconnect); 220 DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid()); 221 execvp (argv[optind],argv+optind); 222 doSyncStage2(p, args->do_disconnect); 223 224 PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]); 225 exit(wrapper_exit_code); 226 } 227 228 assert(args->do_disconnect); 229 230 waitOnSync(pid, p, args->nid!=VC_DYNAMIC_XID && args->do_migrate); 231 return EXIT_SUCCESS; 232 } 233 234 int main (int argc, char *argv[]) 235 { 236 struct Arguments args = { 237 .nid = VC_DYNAMIC_XID, 238 .do_create = false, 239 .do_migrate = false, 240 .do_migrateself = false, 241 .do_disconnect = false, 242 .is_silentexist = false, 243 .verbosity = 1, 244 .sync_msg = "ok", 245 }; 246 247 while (1) { 248 int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0); 249 if (c==-1) break; 250 251 switch (c) { 252 case CMD_HELP : showHelp(1, argv[0], 0); 253 case CMD_VERSION : showVersion(); 254 case CMD_CREATE : args.do_create = true; break; 255 case CMD_MIGRATE : args.do_migrate = true; break; 256 case CMD_DISCONNECT : args.do_disconnect = true; break; 257 case CMD_SILENTEXIST : args.is_silentexist = true; break; 258 case CMD_SYNCSOCK : args.sync_sock = optarg; break; 259 case CMD_SYNCMSG : args.sync_msg = optarg; break; 260 case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break; 261 case CMD_SILENT : --args.verbosity; break; 262 case CMD_MIGRATESELF : 263 args.do_migrate = true; 264 args.do_migrateself = true; 265 break; 266 267 default : 268 WRITE_MSG(2, "Try '"); 269 WRITE_STR(2, argv[0]); 270 WRITE_MSG(2, " --help' for more information.\n"); 271 return wrapper_exit_code; 272 break; 273 } 274 } 275 276 signal(SIGCHLD, SIG_DFL); 277 278 if (args.do_migrateself) 279 args.nid = Evc_get_task_nid(0); 280 281 if (!args.do_create && !args.do_migrate) 282 WRITE_MSG(2, "Neither '--create' nor '--migrate' specified; try '--help' for more information\n"); 283 else if (args.do_create && args.do_migrate) 284 WRITE_MSG(2, "Can not specify '--create' and '--migrate' at the same time; try '--help' for more information\n"); 285 else if (!args.do_create && args.nid==VC_DYNAMIC_XID) 286 WRITE_MSG(2, "Can not migrate to an unknown context\n"); 287 else if (optind>=argc) 288 WRITE_MSG(2, "No command given; use '--help' for more information.\n"); 289 else 290 return doit(&args, argv); 291 292 return wrapper_exit_code; 293 }