3 // Copyright (C) 2004-2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // Copyright (C) 2006 Daniel Hokka Zakrisson <daniel@hozac.com>
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.
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.
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.
25 #include "lib/internal.h"
26 #include "lib_internal/util.h"
27 #include "lib_internal/jail.h"
33 #include <sys/socket.h>
37 #include <sys/types.h>
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
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
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 },
85 char const * sync_sock;
86 char const * sync_msg;
89 int wrapper_exit_code = 255;
92 showHelp(int fd, char const *cmd, int res)
94 WRITE_MSG(fd, "Usage:\n ");
97 " --create [--nid <nid>] <opts>* [--] <program> <args>*\n ");
100 " [(--migrate --nid <nid>)|--migrate-self] <opts>* [--] <program> <args>*\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"
115 "'ncontext --create' exits with code 254 iff the context exists already.\n"
117 "Please report bugs to " PACKAGE_BUGREPORT "\n");
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);
134 #include "context-sync.hc"
136 static inline ALWAYSINLINE void
137 tellContext(nid_t nid, bool do_it)
139 char buf[sizeof(nid_t)*3+2];
144 l = utilvserver_fmt_long(buf,nid);
146 WRITE_MSG(1, "New network context is ");
152 connectExternalSync(char const *filename)
155 struct sockaddr_un addr;
157 if (filename==0) return -1;
159 ENSC_INIT_UNIX_SOCK(addr, filename);
161 fd = Esocket(PF_UNIX, SOCK_STREAM, 0);
162 Econnect(fd, &addr, sizeof(addr));
168 doExternalSync(int fd, char const *msg)
174 if (msg) EsendAll(fd, msg, strlen(msg));
175 Eshutdown(fd, SHUT_WR);
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);
185 static inline ALWAYSINLINE int
186 doit(struct Arguments const *args, char *argv[])
189 pid_t pid = initSync(p, args->do_disconnect);
193 int ext_sync_fd = connectExternalSync(args->sync_sock);
195 doSyncStage0(p, args->do_disconnect);
197 if (args->do_create) {
198 nid = vc_net_create(args->nid);
202 if (!args->is_silentexist)
203 perror(ENSC_WRAPPERS_PREFIX "vc_net_create()");
206 perror(ENSC_WRAPPERS_PREFIX "vc_net_create()");
207 return wrapper_exit_code;
210 tellContext(nid, args->verbosity>=1);
215 if (args->do_migrate && !args->do_migrateself)
216 Evc_net_migrate(nid);
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);
224 PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]);
225 exit(wrapper_exit_code);
228 assert(args->do_disconnect);
230 waitOnSync(pid, p, args->nid!=VC_DYNAMIC_XID && args->do_migrate);
234 int main (int argc, char *argv[])
236 struct Arguments args = {
237 .nid = VC_DYNAMIC_XID,
240 .do_migrateself = false,
241 .do_disconnect = false,
242 .is_silentexist = false,
248 int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
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;
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;
276 signal(SIGCHLD, SIG_DFL);
278 if (args.do_migrateself)
279 args.nid = Evc_get_task_nid(0);
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");
290 return doit(&args, argv);
292 return wrapper_exit_code;