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