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