rump_allserver.c revision 1.13.2.1 1 /* $NetBSD: rump_allserver.c,v 1.13.2.1 2011/02/08 16:20:12 bouyer 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.13.2.1 2011/02/08 16:20:12 bouyer 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 "size",
86 #define DOFFSET 3
87 "offset",
88 #define DLABEL 4
89 "disklabel",
90 NULL
91 };
92
93 struct etfsreg {
94 const char *key;
95 const char *hostpath;
96 off_t flen;
97 off_t foffset;
98 char partition;
99 enum rump_etfs_type type;
100 };
101
102 int
103 main(int argc, char *argv[])
104 {
105 const char *serverurl;
106 char **modarray = NULL;
107 unsigned nmods = 0, curmod = 0, i;
108 struct etfsreg *etfs = NULL;
109 unsigned netfs = 0, curetfs = 0;
110 int error;
111 int ch, sflag;
112 int ncpu;
113
114 setprogname(argv[0]);
115
116 sflag = 0;
117 while ((ch = getopt(argc, argv, "c:d:l:m:s")) != -1) {
118 switch (ch) {
119 case 'c':
120 ncpu = atoi(optarg);
121 /* XXX: MAXCPUS is from host, not from kernel */
122 if (ncpu < 1 || ncpu > MAXCPUS)
123 err(1, "CPU count needs to be between "
124 "1 and %d\n", MAXCPUS);
125 setenv("RUMP_NCPU", optarg, 1);
126 break;
127 case 'd': {
128 char *options, *value;
129 char *key, *hostpath;
130 long long flen, foffset;
131 char partition;
132
133 flen = foffset = 0;
134 partition = 0;
135 key = hostpath = NULL;
136 options = optarg;
137 while (*options) {
138 switch (getsubopt(&options,
139 __UNCONST(disktokens), &value)) {
140 case DKEY:
141 if (key != NULL) {
142 fprintf(stderr,
143 "key already given\n");
144 usage();
145 }
146 key = value;
147 break;
148
149 case DFILE:
150 if (hostpath != NULL) {
151 fprintf(stderr,
152 "hostpath already given\n");
153 usage();
154 }
155 hostpath = value;
156 break;
157
158 case DSIZE:
159 if (flen != 0) {
160 fprintf(stderr,
161 "size already given\n");
162 usage();
163 }
164 /* XXX: off_t max? */
165 flen = strsuftoll("-d size", value,
166 0, LLONG_MAX);
167 break;
168 case DOFFSET:
169 if (foffset != 0) {
170 fprintf(stderr,
171 "offset already given\n");
172 usage();
173 }
174 /* XXX: off_t max? */
175 foffset = strsuftoll("-d offset", value,
176 0, LLONG_MAX);
177 break;
178
179 case DLABEL:
180 if (foffset != 0 || flen != 0) {
181 fprintf(stderr,
182 "disklabel needs to be "
183 "used alone\n");
184 usage();
185 }
186 if (strlen(value) != 1 ||
187 *value < 'a' || *value > 'z') {
188 fprintf(stderr,
189 "invalid label part\n");
190 usage();
191 }
192 partition = *value;
193 break;
194
195 default:
196 fprintf(stderr, "invalid dtoken\n");
197 usage();
198 break;
199 }
200 }
201
202 if (key == NULL || hostpath == NULL ||
203 (flen == 0 && partition == 0)) {
204 fprintf(stderr, "incomplete drivespec\n");
205 usage();
206 }
207
208 if (netfs - curetfs == 0) {
209 etfs = realloc(etfs, (netfs+16)*sizeof(*etfs));
210 if (etfs == NULL)
211 err(1, "realloc etfs");
212 netfs += 16;
213 }
214
215 etfs[curetfs].key = key;
216 etfs[curetfs].hostpath = hostpath;
217 etfs[curetfs].flen = flen;
218 etfs[curetfs].foffset = foffset;
219 etfs[curetfs].partition = partition;
220 etfs[curetfs].type = RUMP_ETFS_BLK;
221 curetfs++;
222
223 break;
224 }
225 case 'l':
226 if (dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
227 char pb[MAXPATHLEN];
228 /* try to mimic linker -l syntax */
229
230 snprintf(pb, sizeof(pb), "lib%s.so", optarg);
231 if (dlopen(pb, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
232 errx(1, "dlopen %s failed: %s",
233 pb, dlerror());
234 }
235 }
236 break;
237 case 'm':
238 if (nmods - curmod == 0) {
239 modarray = realloc(modarray,
240 (nmods+16) * sizeof(char *));
241 if (modarray == NULL)
242 err(1, "realloc");
243 nmods += 16;
244 }
245 modarray[curmod++] = optarg;
246 break;
247 case 's':
248 sflag = 1;
249 break;
250 default:
251 usage();
252 /*NOTREACHED*/
253 }
254 }
255
256 argc -= optind;
257 argv += optind;
258
259 if (argc != 1)
260 usage();
261
262 serverurl = argv[0];
263
264 if (!sflag) {
265 error = rump_daemonize_begin();
266 if (error)
267 errx(1, "rump daemonize: %s", strerror(error));
268 }
269
270 error = rump_init();
271 if (error)
272 die(sflag, error, "rump init failed");
273
274 /* load modules */
275 for (i = 0; i < curmod; i++) {
276 struct modctl_load ml;
277
278 #define ETFSKEY "/module.mod"
279 if ((error = rump_pub_etfs_register(ETFSKEY,
280 modarray[0], RUMP_ETFS_REG)) != 0)
281 die(sflag, error, "module etfs register failed");
282 memset(&ml, 0, sizeof(ml));
283 ml.ml_filename = ETFSKEY;
284 if (rump_sys_modctl(MODCTL_LOAD, &ml) == -1)
285 die(sflag, errno, "module load failed");
286 rump_pub_etfs_remove(ETFSKEY);
287 #undef ETFSKEY
288 }
289
290 /* register host drives */
291 for (i = 0; i < curetfs; i++) {
292 char buf[1<<16];
293 struct disklabel dl;
294 struct stat sb;
295 off_t foffset, flen, fendoff;
296 int fd;
297
298 fd = open(etfs[i].hostpath, O_RDWR | O_CREAT, 0644);
299 if (fd == -1)
300 die(sflag, errno, "etfs hostpath create");
301
302 if (etfs[i].partition) {
303 int partition = etfs[i].partition - 'a';
304
305 pread(fd, buf, sizeof(buf), 0);
306 if (disklabel_scan(&dl, buf, sizeof(buf)))
307 die(sflag, ENOENT, "disklabel not found");
308
309 if (partition >= dl.d_npartitions)
310 die(sflag, ENOENT, "partition not available");
311
312 foffset = dl.d_partitions[partition].p_offset
313 << DEV_BSHIFT;
314 flen = dl.d_partitions[partition].p_size
315 << DEV_BSHIFT;
316 } else {
317 foffset = etfs[i].foffset;
318 flen = etfs[i].flen;
319 }
320 fendoff = foffset + flen;
321
322 if (fstat(fd, &sb) == -1)
323 die(sflag, errno, "fstat etfs hostpath");
324 if (S_ISREG(sb.st_mode) && sb.st_size < fendoff) {
325 if (ftruncate(fd, fendoff) == -1)
326 die(sflag, errno, "truncate");
327 }
328 close(fd);
329
330 if ((error = rump_pub_etfs_register_withsize(etfs[i].key,
331 etfs[i].hostpath, etfs[i].type, foffset, flen)) != 0)
332 die(sflag, error, "etfs register");
333 }
334
335 error = rump_init_server(serverurl);
336 if (error)
337 die(sflag, error, "rump server init failed");
338
339 if (!sflag)
340 rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS);
341
342 sem_init(&sigsem, 0, 0);
343 signal(SIGTERM, sigreboot);
344 signal(SIGINT, sigreboot);
345 sem_wait(&sigsem);
346
347 rump_sys_reboot(0, NULL);
348 /*NOTREACHED*/
349
350 return 0;
351 }
352