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