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