File: ncontext.c

package info (click to toggle)
util-vserver 0.30.216-pre2864-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 13,576 kB
  • ctags: 4,462
  • sloc: ansic: 23,615; sh: 15,550; xml: 1,893; makefile: 402; python: 301; perl: 85; awk: 4
file content (293 lines) | stat: -rw-r--r-- 8,426 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// $Id: ncontext.c 2414 2006-12-08 13:20:10Z dhozac $    --*- c -*--

// Copyright (C) 2004-2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
// Copyright (C) 2006 Daniel Hokka Zakrisson <daniel@hozac.com>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "util.h"
#include "lib/internal.h"
#include "lib_internal/util.h"
#include "lib_internal/jail.h"

#include <vserver.h>
#include <getopt.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>


#define ENSC_WRAPPERS_PREFIX	"ncontext: "
#define ENSC_WRAPPERS_UNISTD	1
#define ENSC_WRAPPERS_VSERVER	1
#define ENSC_WRAPPERS_FCNTL	1
#define ENSC_WRAPPERS_SOCKET	1
#define ENSC_WRAPPERS_IOSOCK	1
#include <wrappers.h>

#define CMD_HELP		0x1000
#define CMD_VERSION		0x1001
#define CMD_NID			0x4000
#define CMD_CREATE		0x4001
#define CMD_MIGRATE		0x4002
#define CMD_DISCONNECT		0x4003
#define CMD_SILENT		0x4004
#define CMD_SYNCSOCK		0x4005
#define CMD_SYNCMSG		0x4006
#define CMD_MIGRATESELF		0x4007
#define CMD_SILENTEXIST		0x4008


struct option const
CMDLINE_OPTIONS[] = {
  { "help",       no_argument,       0, CMD_HELP },
  { "version",    no_argument,       0, CMD_VERSION },
  { "nid",        required_argument, 0, CMD_NID },
  { "create",     no_argument,       0, CMD_CREATE },
  { "migrate",    no_argument,       0, CMD_MIGRATE },
  { "migrate-self", no_argument,       	0, CMD_MIGRATESELF },
  { "disconnect",   no_argument,	0, CMD_DISCONNECT },
  { "silent",       no_argument,       	0, CMD_SILENT },
  { "silentexist",  no_argument,       	0, CMD_SILENTEXIST },
  { "syncsock",     required_argument, 	0, CMD_SYNCSOCK },
  { "syncmsg",      required_argument, 	0, CMD_SYNCMSG },
  { 0,0,0,0 },
};

struct Arguments {
    bool		do_create;
    bool		do_migrate;
    bool		do_migrateself;
    bool		do_disconnect;
    bool		is_silentexist;
    int			verbosity;
    nid_t		nid;
    char const *	sync_sock;
    char const *	sync_msg;
};

int		wrapper_exit_code = 255;

static void
showHelp(int fd, char const *cmd, int res)
{
  WRITE_MSG(fd, "Usage:\n    ");
  WRITE_STR(fd, cmd);
  WRITE_MSG(fd,
	    " --create [--nid <nid>] <opts>* [--] <program> <args>*\n    ");
  WRITE_STR(fd, cmd);
  WRITE_MSG(fd,
	    " [(--migrate --nid <nid>)|--migrate-self]  <opts>* [--] <program> <args>*\n"
	    "\n"
	    "<opts> can be:\n"
	    "    --disconnect    ...  start program in background\n"
	    "    --silent        ...  be silent\n"
	    "    --silentexist   ...  be silent when context exists already; useful\n"
	    "                         for '--create' only\n"
	    "    --syncsock <filename>\n"
	    "                    ...  before executing the program, send a message\n"
	    "                         to the socket and wait until it closes.\n"
	    "                         <filename> must be a SOCK_STREAM unix socket\n"
	    "    --syncmsg <message>\n"
	    "                    ...  use <message> as synchronization message; by\n"
	    "                         default, 'ok' will be used\n"
	    "\n"
	    "'ncontext --create' exits with code 254 iff the context exists already.\n"
	    "\n"
	    "Please report bugs to " PACKAGE_BUGREPORT "\n");

  exit(res);
}

static void
showVersion()
{
  WRITE_MSG(1,
	    "ncontext " VERSION " -- manages the creation of network contexts\n"
	    "This program is part of " PACKAGE_STRING "\n\n"
	    "Copyright (C) 2004-2006 Enrico Scholz\n"
	    "Copyright (C) 2006 Daniel Hokka Zakrisson\n"
	    VERSION_COPYRIGHT_DISCLAIMER);
  exit(0);
}

#include "context-sync.hc"

static inline ALWAYSINLINE void
tellContext(nid_t nid, bool do_it)
{
  char		buf[sizeof(nid_t)*3+2];
  size_t	l;

  if (!do_it) return;

  l = utilvserver_fmt_long(buf,nid);

  WRITE_MSG(1, "New network context is ");
  Vwrite   (1, buf, l);
  WRITE_MSG(1, "\n");
}

static int
connectExternalSync(char const *filename)
{
  int			fd;
  struct sockaddr_un	addr;
  
  if (filename==0) return -1;

  ENSC_INIT_UNIX_SOCK(addr, filename);

  fd = Esocket(PF_UNIX, SOCK_STREAM, 0);
  Econnect(fd, &addr, sizeof(addr));

  return fd;
}

static void
doExternalSync(int fd, char const *msg)
{
  char		c;
  
  if (fd==-1) return;

  if (msg) EsendAll(fd, msg, strlen(msg));
  Eshutdown(fd, SHUT_WR);

  if (TEMP_FAILURE_RETRY(recv(fd, &c, 1, MSG_NOSIGNAL))!=0) {
    WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unexpected external synchronization event\n");
    exit(wrapper_exit_code);
  }

  Eclose(fd);
}

static inline ALWAYSINLINE int
doit(struct Arguments const *args, char *argv[])
{
  int			p[2][2];
  pid_t			pid = initSync(p, args->do_disconnect);
  
  if (pid==0) {
    nid_t			nid;
    int				ext_sync_fd = connectExternalSync(args->sync_sock);

    doSyncStage0(p, args->do_disconnect);  
    
    if (args->do_create) {
      nid = vc_net_create(args->nid);
      if (nid==VC_NOCTX) {
	switch (errno) {
	  case EEXIST	:
	    if (!args->is_silentexist)
	      perror(ENSC_WRAPPERS_PREFIX "vc_net_create()");
	    return 254;
	  default	:
	    perror(ENSC_WRAPPERS_PREFIX "vc_net_create()");
	    return wrapper_exit_code;
	}
      }
      tellContext(nid, args->verbosity>=1);
    }
    else
      nid = args->nid;

    if (args->do_migrate && !args->do_migrateself)
      Evc_net_migrate(nid);

    doExternalSync(ext_sync_fd, args->sync_msg);
    doSyncStage1(p, args->do_disconnect);
    DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid());
    execvp (argv[optind],argv+optind);
    doSyncStage2(p, args->do_disconnect);

    PERROR_Q(ENSC_WRAPPERS_PREFIX "execvp", argv[optind]);
    exit(wrapper_exit_code);
  }

  assert(args->do_disconnect);
    
  waitOnSync(pid, p, args->nid!=VC_DYNAMIC_XID && args->do_migrate);
  return EXIT_SUCCESS;
}

int main (int argc, char *argv[])
{
  struct Arguments		args = {
    .nid               = VC_DYNAMIC_XID,
    .do_create         = false,
    .do_migrate        = false,
    .do_migrateself    = false,
    .do_disconnect     = false,
    .is_silentexist    = false,
    .verbosity         = 1,
    .sync_msg          = "ok",
  };
  
  while (1) {
    int		c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
    if (c==-1) break;
    
    switch (c) {
      case CMD_HELP		:  showHelp(1, argv[0], 0);
      case CMD_VERSION		:  showVersion();
      case CMD_CREATE		:  args.do_create      = true;   break;
      case CMD_MIGRATE		:  args.do_migrate     = true;   break;
      case CMD_DISCONNECT	:  args.do_disconnect  = true;   break;
      case CMD_SILENTEXIST	:  args.is_silentexist = true;   break;
      case CMD_SYNCSOCK		:  args.sync_sock      = optarg; break;
      case CMD_SYNCMSG		:  args.sync_msg       = optarg; break;
      case CMD_NID		:  args.nid = Evc_nidopt2nid(optarg,true); break;
      case CMD_SILENT		:  --args.verbosity; break;
      case CMD_MIGRATESELF	:
	args.do_migrate     = true;
	args.do_migrateself = true;
	break;

      default		:
	WRITE_MSG(2, "Try '");
	WRITE_STR(2, argv[0]);
	WRITE_MSG(2, " --help' for more information.\n");
	return wrapper_exit_code;
	break;
    }
  }

  signal(SIGCHLD, SIG_DFL);
  
  if (args.do_migrateself)
    args.nid = Evc_get_task_nid(0);
  
  if (!args.do_create && !args.do_migrate)
    WRITE_MSG(2, "Neither '--create' nor '--migrate' specified; try '--help' for more information\n");
  else if (args.do_create && args.do_migrate)
    WRITE_MSG(2, "Can not specify '--create' and '--migrate' at the same time; try '--help' for more information\n");
  else if (!args.do_create && args.nid==VC_DYNAMIC_XID)
    WRITE_MSG(2, "Can not migrate to an unknown context\n");
  else if (optind>=argc)
    WRITE_MSG(2, "No command given; use '--help' for more information.\n");
  else
    return doit(&args, argv);

  return wrapper_exit_code;
}