rump_allserver.c revision 1.14 1 /* $NetBSD: rump_allserver.c,v 1.14 2011/02/03 11:21:16 pooka Exp $ */
2
3 /*-
4 * Copyright (c) 2010 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.14 2011/02/03 11:21:16 pooka Exp $");
31 #endif /* !lint */
32
33 #include <sys/types.h>
34 #include <sys/signal.h>
35 #include <sys/module.h>
36
37 #include <rump/rump.h>
38 #include <rump/rump_syscalls.h>
39
40 #include <dlfcn.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <semaphore.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 static void
51 usage(void)
52 {
53
54 fprintf(stderr, "usage: %s [-s] [-c ncpu] [-d drivespec] [-l libs] "
55 "[-m modules] bindurl\n", getprogname());
56 exit(1);
57 }
58
59 static void
60 die(int sflag, int error, const char *reason)
61 {
62
63 warnx("%s: %s", reason, strerror(error));
64 if (!sflag)
65 rump_daemonize_done(error);
66 exit(1);
67 }
68
69 static sem_t sigsem;
70 static void
71 sigreboot(int sig)
72 {
73
74 sem_post(&sigsem);
75 }
76
77 static const char *const disktokens[] = {
78 #define DKEY 0
79 "key",
80 #define DFILE 1
81 "hostpath",
82 #define DSIZE 2
83 "size",
84 #define DOFFSET 3
85 "offset",
86 NULL
87 };
88
89 struct etfsreg {
90 const char *key;
91 const char *hostpath;
92 off_t flen;
93 off_t foffset;
94 enum rump_etfs_type type;
95 };
96
97 int
98 main(int argc, char *argv[])
99 {
100 const char *serverurl;
101 char **modarray = NULL;
102 unsigned nmods = 0, curmod = 0, i;
103 struct etfsreg *etfs = NULL;
104 unsigned netfs = 0, curetfs = 0;
105 int error;
106 int ch, sflag;
107 int ncpu;
108
109 setprogname(argv[0]);
110
111 sflag = 0;
112 while ((ch = getopt(argc, argv, "c:d:l:m:s")) != -1) {
113 switch (ch) {
114 case 'c':
115 ncpu = atoi(optarg);
116 /* XXX: MAXCPUS is from host, not from kernel */
117 if (ncpu < 1 || ncpu > MAXCPUS)
118 err(1, "CPU count needs to be between "
119 "1 and %d\n", MAXCPUS);
120 setenv("RUMP_NCPU", optarg, 1);
121 break;
122 case 'd': {
123 char *options, *value;
124 char *key, *hostpath;
125 long long flen, foffset;
126
127 flen = foffset = 0;
128 key = hostpath = NULL;
129 options = optarg;
130 while (*options) {
131 switch (getsubopt(&options,
132 __UNCONST(disktokens), &value)) {
133 case DKEY:
134 if (key != NULL) {
135 fprintf(stderr,
136 "key already given\n");
137 usage();
138 }
139 key = value;
140 break;
141 case DFILE:
142 if (hostpath != NULL) {
143 fprintf(stderr,
144 "hostpath already given\n");
145 usage();
146 }
147 hostpath = value;
148 break;
149 case DSIZE:
150 if (flen != 0) {
151 fprintf(stderr,
152 "size already given\n");
153 usage();
154 }
155 /* XXX: off_t max? */
156 flen = strsuftoll("-d size", value,
157 0, LLONG_MAX);
158 break;
159 case DOFFSET:
160 if (foffset != 0) {
161 fprintf(stderr,
162 "offset already given\n");
163 usage();
164 }
165 /* XXX: off_t max? */
166 foffset = strsuftoll("-d offset", value,
167 0, LLONG_MAX);
168 break;
169 default:
170 fprintf(stderr, "invalid dtoken\n");
171 usage();
172 break;
173 }
174 }
175
176 if (key == NULL || hostpath == NULL || flen == 0) {
177 fprintf(stderr, "incomplete drivespec\n");
178 usage();
179 }
180
181 if (netfs - curetfs == 0) {
182 etfs = realloc(etfs, (netfs+16)*sizeof(*etfs));
183 if (etfs == NULL)
184 err(1, "realloc etfs");
185 netfs += 16;
186 }
187
188 etfs[curetfs].key = key;
189 etfs[curetfs].hostpath = hostpath;
190 etfs[curetfs].flen = flen;
191 etfs[curetfs].foffset = foffset;
192 etfs[curetfs].type = RUMP_ETFS_BLK;
193 curetfs++;
194
195 break;
196 }
197 case 'l':
198 if (dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
199 char pb[MAXPATHLEN];
200 /* try to mimic linker -l syntax */
201
202 snprintf(pb, sizeof(pb), "lib%s.so", optarg);
203 if (dlopen(pb, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
204 errx(1, "dlopen %s failed: %s",
205 pb, dlerror());
206 }
207 }
208 break;
209 case 'm':
210 if (nmods - curmod == 0) {
211 modarray = realloc(modarray,
212 (nmods+16) * sizeof(char *));
213 if (modarray == NULL)
214 err(1, "realloc");
215 nmods += 16;
216 }
217 modarray[curmod++] = optarg;
218 break;
219 case 's':
220 sflag = 1;
221 break;
222 default:
223 usage();
224 /*NOTREACHED*/
225 }
226 }
227
228 argc -= optind;
229 argv += optind;
230
231 if (argc != 1)
232 usage();
233
234 serverurl = argv[0];
235
236 if (!sflag) {
237 error = rump_daemonize_begin();
238 if (error)
239 errx(1, "rump daemonize: %s", strerror(error));
240 }
241
242 error = rump_init();
243 if (error)
244 die(sflag, error, "rump init failed");
245
246 /* load modules */
247 for (i = 0; i < curmod; i++) {
248 struct modctl_load ml;
249
250 #define ETFSKEY "/module.mod"
251 if ((error = rump_pub_etfs_register(ETFSKEY,
252 modarray[0], RUMP_ETFS_REG)) != 0)
253 die(sflag, error, "module etfs register failed");
254 memset(&ml, 0, sizeof(ml));
255 ml.ml_filename = ETFSKEY;
256 if (rump_sys_modctl(MODCTL_LOAD, &ml) == -1)
257 die(sflag, errno, "module load failed");
258 rump_pub_etfs_remove(ETFSKEY);
259 #undef ETFSKEY
260 }
261
262 /* register host drives */
263 for (i = 0; i < curetfs; i++) {
264 struct stat sb;
265 off_t fsize;
266 int fd;
267
268 fsize = etfs[i].foffset + etfs[i].flen;
269 fd = open(etfs[i].hostpath, O_RDWR | O_CREAT, 0755);
270 if (fd == -1)
271 die(sflag, errno, "etfs hostpath create");
272 if (fstat(fd, &sb) == -1)
273 die(sflag, errno, "fstat etfs hostpath");
274 if (S_ISREG(sb.st_mode) && sb.st_size < fsize) {
275 if (ftruncate(fd, fsize) == -1)
276 die(sflag, errno, "truncate");
277 }
278 close(fd);
279
280 if ((error = rump_pub_etfs_register_withsize(etfs[i].key,
281 etfs[i].hostpath, etfs[i].type,
282 etfs[i].foffset, etfs[i].flen)) != 0)
283 die(sflag, error, "etfs register");
284 }
285
286 error = rump_init_server(serverurl);
287 if (error)
288 die(sflag, error, "rump server init failed");
289
290 if (!sflag)
291 rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS);
292
293 sem_init(&sigsem, 0, 0);
294 signal(SIGTERM, sigreboot);
295 signal(SIGINT, sigreboot);
296 sem_wait(&sigsem);
297
298 rump_sys_reboot(0, NULL);
299 /*NOTREACHED*/
300
301 return 0;
302 }
303