/* $NetBSD: rump_allserver.c,v 1.39 2015/04/16 10:05:43 pooka Exp $ */ /*- * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __RCSID("$NetBSD: rump_allserver.c,v 1.39 2015/04/16 10:05:43 pooka Exp $"); #endif /* !lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include __dead static void usage(void) { #ifndef HAVE_GETPROGNAME #define getprogname() "rump_server" #endif fprintf(stderr, "usage: %s [-s] [-c ncpu] [-d drivespec] [-l libs] " "[-m modules] bindurl\n", getprogname()); exit(1); } __dead static void diedie(int sflag, const char *reason, int error, const char *errstr) { if (reason != NULL) fputs(reason, stderr); if (errstr) { fprintf(stderr, ": %s", errstr); } fputc('\n', stderr); if (!sflag) rump_daemonize_done(error); exit(1); } __dead static void die(int sflag, int error, const char *reason) { diedie(sflag, reason, error, error == 0 ? NULL : strerror(error)); } __dead static void die_rumperr(int sflag, int error, const char *reason) { diedie(sflag, reason, error, error == 0 ? NULL : rump_strerror(error)); } static sem_t sigsem; static void sigreboot(int sig) { sem_post(&sigsem); } static const char *const disktokens[] = { #define DKEY 0 "key", #define DFILE 1 "hostpath", #define DSIZE 2 #define DSIZE_E -1 "size", #define DOFFSET 3 "offset", #define DLABEL 4 "disklabel", #define DTYPE 5 "type", NULL }; struct etfsreg { const char *key; const char *hostpath; off_t flen; off_t foffset; char partition; enum rump_etfs_type type; }; struct etfstype { const char *name; enum rump_etfs_type type; } etfstypes[] = { { "blk", RUMP_ETFS_BLK }, { "chr", RUMP_ETFS_CHR }, { "reg", RUMP_ETFS_REG }, }; static void processlabel(int, int, int, off_t *, off_t *); #define ALLOCCHUNK 32 int main(int argc, char *argv[]) { const char *serverurl; struct etfsreg *etfs = NULL; unsigned netfs = 0, curetfs = 0; int error; int ch, sflag, onthepath; unsigned i; char **modarray = NULL, **libarray = NULL; unsigned nmods = 0, curmod = 0, nlibs = 0, curlib = 0, libidx; unsigned liblast = -1; /* XXXgcc */ setprogname(argv[0]); sflag = 0; while ((ch = getopt(argc, argv, "c:d:l:m:r:sv")) != -1) { switch (ch) { case 'c': setenv("RUMP_NCPU", optarg, 1); break; case 'd': { char *options, *value; char *key, *hostpath; long long flen, foffset; char partition; int ftype; flen = foffset = 0; partition = 0; key = hostpath = NULL; ftype = -1; options = optarg; while (*options) { switch (getsubopt(&options, __UNCONST(disktokens), &value)) { case DKEY: if (key != NULL) { fprintf(stderr, "key already given\n"); usage(); } key = value; break; case DFILE: if (hostpath != NULL) { fprintf(stderr, "hostpath already given\n"); usage(); } hostpath = value; break; case DSIZE: if (flen != 0) { fprintf(stderr, "size already given\n"); usage(); } if (strcmp(value, "host") == 0) { if (foffset != 0) { fprintf(stderr, "cannot specify " "offset with " "size=host\n"); usage(); } flen = DSIZE_E; } else { #ifdef HAVE_STRSUFTOLL /* XXX: off_t max? */ flen = strsuftoll("-d size", value, 0, LLONG_MAX); #else flen = strtoull(value, NULL, 10); #endif } break; case DOFFSET: if (foffset != 0) { fprintf(stderr, "offset already given\n"); usage(); } if (flen == DSIZE_E) { fprintf(stderr, "cannot " "specify offset with " "size=host\n"); usage(); } #ifdef HAVE_STRSUFTOLL /* XXX: off_t max? */ foffset = strsuftoll("-d offset", value, 0, LLONG_MAX); #else foffset = strtoull(value, NULL, 10); #endif break; case DLABEL: if (foffset != 0 || flen != 0) { fprintf(stderr, "disklabel needs to be " "used alone\n"); usage(); } if (strlen(value) != 1 || *value < 'a' || *value > 'z') { fprintf(stderr, "invalid label part\n"); usage(); } partition = *value; break; case DTYPE: if (ftype != -1) { fprintf(stderr, "type already specified\n"); usage(); } for (i = 0; i < __arraycount(etfstypes); i++) { if (strcmp(etfstypes[i].name, value) == 0) break; } if (i == __arraycount(etfstypes)) { fprintf(stderr, "invalid type %s\n", value); usage(); } ftype = etfstypes[i].type; break; default: fprintf(stderr, "invalid dtoken\n"); usage(); break; } } if (key == NULL || hostpath == NULL || (flen == 0 && partition == 0 && ftype != RUMP_ETFS_REG)) { fprintf(stderr, "incomplete drivespec\n"); usage(); } if (ftype == -1) ftype = RUMP_ETFS_BLK; if (netfs - curetfs == 0) { etfs = realloc(etfs, (netfs+ALLOCCHUNK)*sizeof(*etfs)); if (etfs == NULL) die(1, errno, "realloc etfs"); netfs += ALLOCCHUNK; } etfs[curetfs].key = key; etfs[curetfs].hostpath = hostpath; etfs[curetfs].flen = flen; etfs[curetfs].foffset = foffset; etfs[curetfs].partition = partition; etfs[curetfs].type = ftype; curetfs++; break; } case 'l': if (nlibs - curlib == 0) { libarray = realloc(libarray, (nlibs+ALLOCCHUNK) * sizeof(char *)); if (libarray == NULL) die(1, errno, "realloc"); nlibs += ALLOCCHUNK; } libarray[curlib++] = optarg; break; case 'm': if (nmods - curmod == 0) { modarray = realloc(modarray, (nmods+ALLOCCHUNK) * sizeof(char *)); if (modarray == NULL) die(1, errno, "realloc"); nmods += ALLOCCHUNK; } modarray[curmod++] = optarg; break; case 'r': setenv("RUMP_MEMLIMIT", optarg, 1); break; case 's': sflag = 1; break; case 'v': setenv("RUMP_VERBOSE", "1", 1); break; default: usage(); /*NOTREACHED*/ } } argc -= optind; argv += optind; if (argc != 1) usage(); /* * Automatically "resolve" component dependencies, i.e. * try to load libs in a loop until all are loaded or a * full loop completes with no loads (latter case is an error). */ for (onthepath = 1, nlibs = curlib; onthepath && nlibs > 0;) { onthepath = 0; for (libidx = 0; libidx < curlib; libidx++) { /* loaded already? */ if (libarray[libidx] == NULL) continue; /* try to load */ liblast = libidx; if (dlopen(libarray[libidx], RTLD_LAZY|RTLD_GLOBAL) == NULL) { char pb[MAXPATHLEN]; /* try to mimic linker -l syntax */ snprintf(pb, sizeof(pb), "lib%s.so", libarray[libidx]); if (dlopen(pb, RTLD_LAZY|RTLD_GLOBAL) == NULL) continue; } /* managed to load that one */ libarray[libidx] = NULL; nlibs--; onthepath = 1; } } if (nlibs > 0) { fprintf(stderr, "failed to load -libraries, last error from \"%s\":\n", libarray[liblast]); fprintf(stderr, " %s", dlerror()); die(1, 0, NULL); } free(libarray); serverurl = argv[0]; if (!sflag) { error = rump_daemonize_begin(); if (error) die_rumperr(1, error, "rump daemonize"); } error = rump_init(); if (error) die_rumperr(sflag, error, "rump init failed"); /* load modules */ for (i = 0; i < curmod; i++) { struct rump_modctl_load ml; #define ETFSKEY "/module.mod" if ((error = rump_pub_etfs_register(ETFSKEY, modarray[0], RUMP_ETFS_REG)) != 0) die_rumperr(sflag, error, "module etfs register failed"); memset(&ml, 0, sizeof(ml)); ml.ml_filename = ETFSKEY; /* * XXX: since this is a syscall, error namespace depends * on loaded emulations. revisit and fix. */ if (rump_sys_modctl(RUMP_MODCTL_LOAD, &ml) == -1) die(sflag, errno, "module load failed"); rump_pub_etfs_remove(ETFSKEY); #undef ETFSKEY } free(modarray); /* register host drives */ for (i = 0; i < curetfs; i++) { struct stat sb; off_t foffset, flen, fendoff; int fd, oflags; oflags = etfs[i].flen == DSIZE_E ? 0 : O_CREAT; fd = open(etfs[i].hostpath, O_RDWR | oflags, 0644); if (fd == -1) die(sflag, errno, "etfs hostpath open"); if (etfs[i].partition) { processlabel(sflag, fd, etfs[i].partition - 'a', &foffset, &flen); } else { foffset = etfs[i].foffset; flen = etfs[i].flen; } if (fstat(fd, &sb) == -1) die(sflag, errno, "fstat etfs hostpath"); if (flen == DSIZE_E) { if (sb.st_size == 0) die(sflag, EINVAL, "size=host, but cannot " "query non-zero size"); flen = sb.st_size; } fendoff = foffset + flen; if (S_ISREG(sb.st_mode) && sb.st_size < fendoff) { if (ftruncate(fd, fendoff) == -1) die(sflag, errno, "truncate"); } close(fd); if ((error = rump_pub_etfs_register_withsize(etfs[i].key, etfs[i].hostpath, etfs[i].type, foffset, flen)) != 0) die_rumperr(sflag, error, "etfs register"); } error = rump_init_server(serverurl); if (error) die_rumperr(sflag, error, "rump server init failed"); if (!sflag) rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS); sem_init(&sigsem, 0, 0); signal(SIGTERM, sigreboot); signal(SIGINT, sigreboot); sem_wait(&sigsem); rump_sys_reboot(0, NULL); /*NOTREACHED*/ return 0; } /* * Copyright (c) 1987, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)disklabel.h 8.2 (Berkeley) 7/10/94 */ #define RUMPSERVER_MAXPARTITIONS 22 #define RUMPSERVER_DISKMAGIC ((uint32_t)0x82564557) /* magic */ #define RUMPSERVER_DEVSHIFT 9 struct rumpserver_disklabel { uint32_t d_magic; /* the magic number */ uint16_t d_type; /* drive type */ uint16_t d_subtype; /* controller/d_type specific */ char d_typename[16]; /* type name, e.g. "eagle" */ /* * d_packname contains the pack identifier and is returned when * the disklabel is read off the disk or in-core copy. * d_boot0 and d_boot1 are the (optional) names of the * primary (block 0) and secondary (block 1-15) bootstraps * as found in /usr/mdec. These are returned when using * getdiskbyname(3) to retrieve the values from /etc/disktab. */ union { char un_d_packname[16]; /* pack identifier */ struct { char *un_d_boot0; /* primary bootstrap name */ char *un_d_boot1; /* secondary bootstrap name */ } un_b; } d_un; #define d_packname d_un.un_d_packname #define d_boot0 d_un.un_b.un_d_boot0 #define d_boot1 d_un.un_b.un_d_boot1 /* disk geometry: */ uint32_t d_secsize; /* # of bytes per sector */ uint32_t d_nsectors; /* # of data sectors per track */ uint32_t d_ntracks; /* # of tracks per cylinder */ uint32_t d_ncylinders; /* # of data cylinders per unit */ uint32_t d_secpercyl; /* # of data sectors per cylinder */ uint32_t d_secperunit; /* # of data sectors per unit */ /* * Spares (bad sector replacements) below are not counted in * d_nsectors or d_secpercyl. Spare sectors are assumed to * be physical sectors which occupy space at the end of each * track and/or cylinder. */ uint16_t d_sparespertrack; /* # of spare sectors per track */ uint16_t d_sparespercyl; /* # of spare sectors per cylinder */ /* * Alternative cylinders include maintenance, replacement, * configuration description areas, etc. */ uint32_t d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* * d_interleave, d_trackskew and d_cylskew describe perturbations * in the media format used to compensate for a slow controller. * Interleave is physical sector interleave, set up by the * formatter or controller when formatting. When interleaving is * in use, logically adjacent sectors are not physically * contiguous, but instead are separated by some number of * sectors. It is specified as the ratio of physical sectors * traversed per logical sector. Thus an interleave of 1:1 * implies contiguous layout, while 2:1 implies that logical * sector 0 is separated by one sector from logical sector 1. * d_trackskew is the offset of sector 0 on track N relative to * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew * is the offset of sector 0 on cylinder N relative to sector 0 * on cylinder N-1. */ uint16_t d_rpm; /* rotational speed */ uint16_t d_interleave; /* hardware sector interleave */ uint16_t d_trackskew; /* sector 0 skew, per track */ uint16_t d_cylskew; /* sector 0 skew, per cylinder */ uint32_t d_headswitch; /* head switch time, usec */ uint32_t d_trkseek; /* track-to-track seek, usec */ uint32_t d_flags; /* generic flags */ #define NDDATA 5 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 uint32_t d_spare[NSPARE]; /* reserved for future use */ uint32_t d_magic2; /* the magic number (again) */ uint16_t d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ uint16_t d_npartitions; /* number of partitions in following */ uint32_t d_bbsize; /* size of boot area at sn0, bytes */ uint32_t d_sbsize; /* max size of fs superblock, bytes */ struct rumpserver_partition { /* the partition table */ uint32_t p_size; /* number of sectors in partition */ uint32_t p_offset; /* starting sector */ union { uint32_t fsize; /* FFS, ADOS: filesystem basic fragment size */ uint32_t cdsession; /* ISO9660: session offset */ } __partition_u2; #define p_fsize __partition_u2.fsize #define p_cdsession __partition_u2.cdsession uint8_t p_fstype; /* filesystem type, see below */ uint8_t p_frag; /* filesystem fragments per block */ union { uint16_t cpg; /* UFS: FS cylinders per group */ uint16_t sgs; /* LFS: FS segment shift */ } __partition_u1; #define p_cpg __partition_u1.cpg #define p_sgs __partition_u1.sgs } d_partitions[RUMPSERVER_MAXPARTITIONS]; /* actually may be more */ }; /* for swapping disklabel, so don't care about perf, just portability */ #define bs32(x) \ ((((x) & 0xff000000) >> 24)| \ (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | \ (((x) & 0x000000ff) << 24)) #define bs16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) /* * From: * $NetBSD: disklabel_dkcksum.c,v 1.4 2005/05/15 21:01:34 thorpej Exp */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static uint16_t rs_dl_dkcksum(struct rumpserver_disklabel *lp, int imswapped) { uint16_t *start, *end; uint16_t sum; uint16_t npart; if (imswapped) npart = bs16(lp->d_npartitions); else npart = lp->d_npartitions; sum = 0; start = (uint16_t *)(void *)lp; end = (uint16_t *)(void *)&lp->d_partitions[npart]; while (start < end) { if (imswapped) sum ^= bs16(*start); else sum ^= *start; start++; } return (sum); } /* * From: * NetBSD: disklabel_scan.c,v 1.3 2009/01/18 12:13:03 lukem Exp */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Roland C. Dowdeswell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static int rs_dl_scan(struct rumpserver_disklabel *lp, int *isswapped, char *buf, size_t buflen) { size_t i; int imswapped; uint16_t npart; /* scan for the correct magic numbers. */ for (i=0; i <= buflen - sizeof(*lp); i += 4) { memcpy(lp, buf + i, sizeof(*lp)); if (lp->d_magic == RUMPSERVER_DISKMAGIC && lp->d_magic2 == RUMPSERVER_DISKMAGIC) { imswapped = 0; goto sanity; } if (lp->d_magic == bs32(RUMPSERVER_DISKMAGIC) && lp->d_magic2 == bs32(RUMPSERVER_DISKMAGIC)) { imswapped = 1; goto sanity; } } return 1; sanity: if (imswapped) npart = bs16(lp->d_npartitions); else npart = lp->d_npartitions; /* we've found something, let's sanity check it */ if (npart > RUMPSERVER_MAXPARTITIONS || rs_dl_dkcksum(lp, imswapped)) return 1; *isswapped = imswapped; return 0; } static void processlabel(int sflag, int fd, int partition, off_t *foffp, off_t *flenp) { struct rumpserver_disklabel dl; char buf[1<<16]; uint32_t foffset, flen; int imswapped; if (pread(fd, buf, sizeof(buf), 0) == -1) die(sflag, errno, "could not read disk device"); if (rs_dl_scan(&dl, &imswapped, buf, sizeof(buf))) die(sflag, ENOENT, "disklabel not found"); if (partition >= dl.d_npartitions) die(sflag, ENOENT, "partition not available"); foffset = dl.d_partitions[partition].p_offset << RUMPSERVER_DEVSHIFT; flen = dl.d_partitions[partition].p_size << RUMPSERVER_DEVSHIFT; if (imswapped) { foffset = bs32(foffset); flen = bs32(flen); } *foffp = (off_t)foffset; *flenp = (off_t)flen; }