Home | History | Annotate | Line # | Download | only in rump_allserver
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