xref: /netbsd-src/usr.bin/rump_allserver/rump_allserver.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: rump_allserver.c,v 1.13 2011/01/03 12:18:25 wiz 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.13 2011/01/03 12:18:25 wiz 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 	NULL
85 };
86 
87 struct etfsreg {
88 	const char *key;
89 	const char *hostpath;
90 	off_t flen;
91 	enum rump_etfs_type type;
92 };
93 
94 int
95 main(int argc, char *argv[])
96 {
97 	const char *serverurl;
98 	char **modarray = NULL;
99 	unsigned nmods = 0, curmod = 0, i;
100 	struct etfsreg *etfs = NULL;
101 	unsigned netfs = 0, curetfs = 0;
102 	int error;
103 	int ch, sflag;
104 	int ncpu;
105 
106 	setprogname(argv[0]);
107 
108 	sflag = 0;
109 	while ((ch = getopt(argc, argv, "c:d:l:m:s")) != -1) {
110 		switch (ch) {
111 		case 'c':
112 			ncpu = atoi(optarg);
113 			/* XXX: MAXCPUS is from host, not from kernel */
114 			if (ncpu < 1 || ncpu > MAXCPUS)
115 				err(1, "CPU count needs to be between "
116 				    "1 and %d\n", MAXCPUS);
117 			setenv("RUMP_NCPU", optarg, 1);
118 			break;
119 		case 'd': {
120 			char *options, *value;
121 			char *key, *hostpath;
122 			long long flen;
123 
124 			flen = 0;
125 			key = hostpath = NULL;
126 			options = optarg;
127 			while (*options) {
128 				switch (getsubopt(&options,
129 				    __UNCONST(disktokens), &value)) {
130 				case DKEY:
131 					if (key != NULL) {
132 						fprintf(stderr,
133 						    "key already given\n");
134 						usage();
135 					}
136 					key = value;
137 					break;
138 				case DFILE:
139 					if (hostpath != NULL) {
140 						fprintf(stderr,
141 						    "hostpath already given\n");
142 						usage();
143 					}
144 					hostpath = value;
145 					break;
146 				case DSIZE:
147 					if (flen != 0) {
148 						fprintf(stderr,
149 						    "size already given\n");
150 						usage();
151 					}
152 					/* XXX: off_t max? */
153 					flen = strsuftoll("-d size", value,
154 					    0, LLONG_MAX);
155 					break;
156 				default:
157 					fprintf(stderr, "invalid dtoken\n");
158 					usage();
159 					break;
160 				}
161 			}
162 
163 			if (key == NULL || hostpath == NULL || flen == 0) {
164 				fprintf(stderr, "incomplete drivespec\n");
165 				usage();
166 			}
167 
168 			if (netfs - curetfs == 0) {
169 				etfs = realloc(etfs, (netfs+16)*sizeof(*etfs));
170 				if (etfs == NULL)
171 					err(1, "realloc etfs");
172 				netfs += 16;
173 			}
174 
175 			etfs[curetfs].key = key;
176 			etfs[curetfs].hostpath = hostpath;
177 			etfs[curetfs].flen = flen;
178 			etfs[curetfs].type = RUMP_ETFS_BLK;
179 			curetfs++;
180 
181 			break;
182 		}
183 		case 'l':
184 			if (dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
185 				char pb[MAXPATHLEN];
186 				/* try to mimic linker -l syntax */
187 
188 				snprintf(pb, sizeof(pb), "lib%s.so", optarg);
189 				if (dlopen(pb, RTLD_LAZY|RTLD_GLOBAL) == NULL) {
190 					errx(1, "dlopen %s failed: %s",
191 					    pb, dlerror());
192 				}
193 			}
194 			break;
195 		case 'm':
196 			if (nmods - curmod == 0) {
197 				modarray = realloc(modarray,
198 				    (nmods+16) * sizeof(char *));
199 				if (modarray == NULL)
200 					err(1, "realloc");
201 				nmods += 16;
202 			}
203 			modarray[curmod++] = optarg;
204 			break;
205 		case 's':
206 			sflag = 1;
207 			break;
208 		default:
209 			usage();
210 			/*NOTREACHED*/
211 		}
212 	}
213 
214 	argc -= optind;
215 	argv += optind;
216 
217 	if (argc != 1)
218 		usage();
219 
220 	serverurl = argv[0];
221 
222 	if (!sflag) {
223 		error = rump_daemonize_begin();
224 		if (error)
225 			errx(1, "rump daemonize: %s", strerror(error));
226 	}
227 
228 	error = rump_init();
229 	if (error)
230 		die(sflag, error, "rump init failed");
231 
232 	/* load modules */
233 	for (i = 0; i < curmod; i++) {
234 		struct modctl_load ml;
235 
236 #define ETFSKEY "/module.mod"
237 		if ((error = rump_pub_etfs_register(ETFSKEY,
238 		    modarray[0], RUMP_ETFS_REG)) != 0)
239 			die(sflag, error, "module etfs register failed");
240 		memset(&ml, 0, sizeof(ml));
241 		ml.ml_filename = ETFSKEY;
242 		if (rump_sys_modctl(MODCTL_LOAD, &ml) == -1)
243 			die(sflag, errno, "module load failed");
244 		rump_pub_etfs_remove(ETFSKEY);
245 #undef ETFSKEY
246 	}
247 
248 	/* register host drives */
249 	for (i = 0; i < curetfs; i++) {
250 		int fd;
251 
252 		fd = open(etfs[i].hostpath, O_RDWR | O_CREAT, 0755);
253 		if (fd == -1)
254 			die(sflag, error, "etfs hostpath create");
255 		if (ftruncate(fd, etfs[i].flen) == -1)
256 			die(sflag, error, "truncate");
257 		close(fd);
258 
259 		if ((error = rump_pub_etfs_register(etfs[i].key,
260 		    etfs[i].hostpath, etfs[i].type)) != 0)
261 			die(sflag, error, "etfs register");
262 	}
263 
264 	error = rump_init_server(serverurl);
265 	if (error)
266 		die(sflag, error, "rump server init failed");
267 
268 	if (!sflag)
269 		rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS);
270 
271 	sem_init(&sigsem, 0, 0);
272 	signal(SIGTERM, sigreboot);
273 	signal(SIGINT, sigreboot);
274 	sem_wait(&sigsem);
275 
276 	rump_sys_reboot(0, NULL);
277 	/*NOTREACHED*/
278 
279 	return 0;
280 }
281