rump_allserver.c revision 1.27 1 /* $NetBSD: rump_allserver.c,v 1.27 2013/11/13 16:43:38 pooka Exp $ */
2
3 /*-
4 * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <rump/rumpuser_port.h>
29
30 #ifndef lint
31 __RCSID("$NetBSD: rump_allserver.c,v 1.27 2013/11/13 16:43:38 pooka Exp $");
32 #endif /* !lint */
33
34 #include <sys/types.h>
35 #include <sys/signal.h>
36 #include <sys/stat.h>
37
38 #ifdef PLATFORM_HAS_DISKLABEL
39 #include <sys/disklabel.h>
40 #include <util.h>
41 #endif
42
43 #include <dlfcn.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <semaphore.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdint.h>
50 #include <string.h>
51 #include <unistd.h>
52
53 #include <rump/rump.h>
54 #include <rump/rump_syscalls.h>
55 #include <rump/rumpdefs.h>
56
57 __dead static void
58 usage(void)
59 {
60
61 #ifndef PLATFORM_HAS_SETGETPROGNAME
62 #define getprogname() "rump_server"
63 #endif
64 fprintf(stderr, "usage: %s [-s] [-c ncpu] [-d drivespec] [-l libs] "
65 "[-m modules] bindurl\n", getprogname());
66 exit(1);
67 }
68
69 __dead static void
70 die(int sflag, int error, const char *reason)
71 {
72
73 fprintf(stderr, "%s: %s", reason, strerror(error));
74 if (!sflag)
75 rump_daemonize_done(error);
76 exit(1);
77 }
78
79 static sem_t sigsem;
80 static void
81 sigreboot(int sig)
82 {
83
84 sem_post(&sigsem);
85 }
86
87 static const char *const disktokens[] = {
88 #define DKEY 0
89 "key",
90 #define DFILE 1
91 "hostpath",
92 #define DSIZE 2
93 #define DSIZE_E -1
94 "size",
95 #define DOFFSET 3
96 "offset",
97 #define DLABEL 4
98 "disklabel",
99 #define DTYPE 5
100 "type",
101 NULL
102 };
103
104 struct etfsreg {
105 const char *key;
106 const char *hostpath;
107 off_t flen;
108 off_t foffset;
109 char partition;
110 enum rump_etfs_type type;
111 };
112
113 struct etfstype {
114 const char *name;
115 enum rump_etfs_type type;
116 } etfstypes[] = {
117 { "blk", RUMP_ETFS_BLK },
118 { "chr", RUMP_ETFS_CHR },
119 { "reg", RUMP_ETFS_REG },
120 };
121
122 int
123 main(int argc, char *argv[])
124 {
125 const char *serverurl;
126 struct etfsreg *etfs = NULL;
127 unsigned netfs = 0, curetfs = 0;
128 int error;
129 int ch, sflag;
130 unsigned i;
131 char **modarray = NULL;
132 unsigned nmods = 0, curmod = 0;
133
134 #ifdef PLATFORM_HAS_SETGETPROGNAME
135 setprogname(argv[0]);
136 #endif
137
138 sflag = 0;
139 while ((ch = getopt(argc, argv, "c:d:l:m:r:sv")) != -1) {
140 switch (ch) {
141 case 'c':
142 setenv("RUMP_NCPU", optarg, 1);
143 break;
144 case 'd': {
145 char *options, *value;
146 char *key, *hostpath;
147 long long flen, foffset;
148 char partition;
149 int ftype;
150
151 flen = foffset = 0;
152 partition = 0;
153 key = hostpath = NULL;
154 ftype = -1;
155 options = optarg;
156 while (*options) {
157 switch (getsubopt(&options,
158 __UNCONST(disktokens), &value)) {
159 case DKEY:
160 if (key != NULL) {
161 fprintf(stderr,
162 "key already given\n");
163 usage();
164 }
165 key = value;
166 break;
167
168 case DFILE:
169 if (hostpath != NULL) {
170 fprintf(stderr,
171 "hostpath already given\n");
172 usage();
173 }
174 hostpath = value;
175 break;
176
177 case DSIZE:
178 if (flen != 0) {
179 fprintf(stderr,
180 "size already given\n");
181 usage();
182 }
183 if (strcmp(value, "host") == 0) {
184 if (foffset != 0) {
185 fprintf(stderr,
186 "cannot specify "
187 "offset with "
188 "size=host\n");
189 usage();
190 }
191 flen = DSIZE_E;
192 } else {
193 #ifdef PLATFORM_HAS_STRSUFTOLL
194 /* XXX: off_t max? */
195 flen = strsuftoll("-d size",
196 value, 0, LLONG_MAX);
197 #else
198 flen = strtoull(value,
199 NULL, 10);
200 #endif
201 }
202 break;
203 case DOFFSET:
204 if (foffset != 0) {
205 fprintf(stderr,
206 "offset already given\n");
207 usage();
208 }
209 if (flen == DSIZE_E) {
210 fprintf(stderr, "cannot "
211 "specify offset with "
212 "size=host\n");
213 usage();
214 }
215 #ifdef PLATFORM_HAS_STRSUFTOLL
216 /* XXX: off_t max? */
217 foffset = strsuftoll("-d offset", value,
218 0, LLONG_MAX);
219 #else
220 foffset = strtoull(value, NULL, 10);
221 #endif
222 break;
223
224 case DLABEL:
225 if (foffset != 0 || flen != 0) {
226 fprintf(stderr,
227 "disklabel needs to be "
228 "used alone\n");
229 usage();
230 }
231 if (strlen(value) != 1 ||
232 *value < 'a' || *value > 'z') {
233 fprintf(stderr,
234 "invalid label part\n");
235 usage();
236 }
237 partition = *value;
238 break;
239
240 case DTYPE:
241 if (ftype != -1) {
242 fprintf(stderr,
243 "type already specified\n");
244 usage();
245 }
246
247 for (i = 0;
248 i < __arraycount(etfstypes);
249 i++) {
250 if (strcmp(etfstypes[i].name,
251 value) == 0)
252 break;
253 }
254 if (i == __arraycount(etfstypes)) {
255 fprintf(stderr,
256 "invalid type %s\n", value);
257 usage();
258 }
259 ftype = etfstypes[i].type;
260 break;
261
262 default:
263 fprintf(stderr, "invalid dtoken\n");
264 usage();
265 break;
266 }
267 }
268
269 if (key == NULL || hostpath == NULL ||
270 (flen == 0 && partition == 0)) {
271 fprintf(stderr, "incomplete drivespec\n");
272 usage();
273 }
274 if (ftype == -1)
275 ftype = RUMP_ETFS_BLK;
276
277 if (netfs - curetfs == 0) {
278 etfs = realloc(etfs, (netfs+16)*sizeof(*etfs));
279 if (etfs == NULL)
280 die(1, errno, "realloc etfs");
281 netfs += 16;
282 }
283
284 etfs[curetfs].key = key;
285 etfs[curetfs].hostpath = hostpath;
286 etfs[curetfs].flen = flen;
287 etfs[curetfs].foffset = foffset;
288 etfs[curetfs].partition = partition;
289 etfs[curetfs].type = ftype;
290 curetfs++;
291
292 break;
293 }
294 case 'l':
295 if (dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
296 char pb[MAXPATHLEN];
297 /* try to mimic linker -l syntax */
298
299 snprintf(pb, sizeof(pb), "lib%s.so", optarg);
300 if (dlopen(pb, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
301 die(1, 0, "dlopen lib");
302 }
303 }
304 break;
305 case 'm': {
306
307 if (nmods - curmod == 0) {
308 modarray = realloc(modarray,
309 (nmods+16) * sizeof(char *));
310 if (modarray == NULL)
311 die(1, errno, "realloc");
312 nmods += 16;
313 }
314 modarray[curmod++] = optarg;
315 break; }
316 case 'r':
317 setenv("RUMP_MEMLIMIT", optarg, 1);
318 break;
319 case 's':
320 sflag = 1;
321 break;
322 case 'v':
323 setenv("RUMP_VERBOSE", "1", 1);
324 break;
325 default:
326 usage();
327 /*NOTREACHED*/
328 }
329 }
330
331 argc -= optind;
332 argv += optind;
333
334 if (argc != 1)
335 usage();
336
337 serverurl = argv[0];
338
339 if (!sflag) {
340 error = rump_daemonize_begin();
341 if (error)
342 die(1, error, "rump daemonize");
343 }
344
345 error = rump_init();
346 if (error)
347 die(sflag, error, "rump init failed");
348
349 /* load modules */
350 for (i = 0; i < curmod; i++) {
351 struct rump_modctl_load ml;
352
353 #define ETFSKEY "/module.mod"
354 if ((error = rump_pub_etfs_register(ETFSKEY,
355 modarray[0], RUMP_ETFS_REG)) != 0)
356 die(sflag, error, "module etfs register failed");
357 memset(&ml, 0, sizeof(ml));
358 ml.ml_filename = ETFSKEY;
359 if (rump_sys_modctl(RUMP_MODCTL_LOAD, &ml) == -1)
360 die(sflag, errno, "module load failed");
361 rump_pub_etfs_remove(ETFSKEY);
362 #undef ETFSKEY
363 }
364
365 /* register host drives */
366 for (i = 0; i < curetfs; i++) {
367 struct stat sb;
368 off_t foffset, flen, fendoff;
369 int fd, oflags;
370
371 oflags = etfs[i].flen == DSIZE_E ? 0 : O_CREAT;
372 fd = open(etfs[i].hostpath, O_RDWR | oflags, 0644);
373 if (fd == -1)
374 die(sflag, errno, "etfs hostpath open");
375
376 #ifdef PLATFORM_HAS_DISKLABEL
377 if (etfs[i].partition) {
378 struct disklabel dl;
379 char buf[1<<16];
380 int partition = etfs[i].partition - 'a';
381
382 pread(fd, buf, sizeof(buf), 0);
383 if (disklabel_scan(&dl, buf, sizeof(buf)))
384 die(sflag, ENOENT, "disklabel not found");
385
386 if (partition >= dl.d_npartitions)
387 die(sflag, ENOENT, "partition not available");
388
389 foffset = dl.d_partitions[partition].p_offset
390 << DEV_BSHIFT;
391 flen = dl.d_partitions[partition].p_size
392 << DEV_BSHIFT;
393 } else {
394 #else
395 {
396 #endif
397 foffset = etfs[i].foffset;
398 flen = etfs[i].flen;
399 }
400
401 if (fstat(fd, &sb) == -1)
402 die(sflag, errno, "fstat etfs hostpath");
403 if (flen == DSIZE_E) {
404 if (sb.st_size == 0)
405 die(sflag, EINVAL, "size=host, but cannot "
406 "query non-zero size");
407 flen = sb.st_size;
408 }
409 fendoff = foffset + flen;
410 if (S_ISREG(sb.st_mode) && sb.st_size < fendoff) {
411 if (ftruncate(fd, fendoff) == -1)
412 die(sflag, errno, "truncate");
413 }
414 close(fd);
415
416 if ((error = rump_pub_etfs_register_withsize(etfs[i].key,
417 etfs[i].hostpath, etfs[i].type, foffset, flen)) != 0)
418 die(sflag, error, "etfs register");
419 }
420
421 error = rump_init_server(serverurl);
422 if (error)
423 die(sflag, error, "rump server init failed");
424
425 if (!sflag)
426 rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS);
427
428 sem_init(&sigsem, 0, 0);
429 signal(SIGTERM, sigreboot);
430 signal(SIGINT, sigreboot);
431 sem_wait(&sigsem);
432
433 rump_sys_reboot(0, NULL);
434 /*NOTREACHED*/
435
436 return 0;
437 }
438