rumpuser.c revision 1.61 1 /* $NetBSD: rumpuser.c,v 1.61 2014/07/10 08:17:43 justin Exp $ */
2
3 /*
4 * Copyright (c) 2007-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 "rumpuser_port.h"
29
30 #if !defined(lint)
31 __RCSID("$NetBSD: rumpuser.c,v 1.61 2014/07/10 08:17:43 justin Exp $");
32 #endif /* !lint */
33
34 #include <sys/stat.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37
38 #include <assert.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <signal.h>
43 #include <stdarg.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <unistd.h>
50
51 #include <rump/rumpuser.h>
52
53 #include "rumpuser_int.h"
54
55 struct rumpuser_hyperup rumpuser__hyp;
56
57 int
58 rumpuser_init(int version, const struct rumpuser_hyperup *hyp)
59 {
60
61 if (version != RUMPUSER_VERSION) {
62 fprintf(stderr, "rumpuser mismatch, kern: %d, hypervisor %d\n",
63 version, RUMPUSER_VERSION);
64 return 1;
65 }
66
67 #ifdef RUMPUSER_USE_DEVRANDOM
68 uint32_t rv;
69 int fd;
70
71 if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
72 srandom(time(NULL));
73 } else {
74 if (read(fd, &rv, sizeof(rv)) != sizeof(rv))
75 srandom(time(NULL));
76 else
77 srandom(rv);
78 close(fd);
79 }
80 #endif
81
82 rumpuser__thrinit();
83 rumpuser__hyp = *hyp;
84
85 return 0;
86 }
87
88 int
89 rumpuser_clock_gettime(int enum_rumpclock, int64_t *sec, long *nsec)
90 {
91 enum rumpclock rclk = enum_rumpclock;
92 struct timespec ts;
93 clockid_t clk;
94 int rv;
95
96 switch (rclk) {
97 case RUMPUSER_CLOCK_RELWALL:
98 clk = CLOCK_REALTIME;
99 break;
100 case RUMPUSER_CLOCK_ABSMONO:
101 #ifdef HAVE_CLOCK_NANOSLEEP
102 clk = CLOCK_MONOTONIC;
103 #else
104 clk = CLOCK_REALTIME;
105 #endif
106 break;
107 default:
108 abort();
109 }
110
111 if (clock_gettime(clk, &ts) == -1) {
112 rv = errno;
113 } else {
114 *sec = ts.tv_sec;
115 *nsec = ts.tv_nsec;
116 rv = 0;
117 }
118
119 ET(rv);
120 }
121
122 int
123 rumpuser_clock_sleep(int enum_rumpclock, int64_t sec, long nsec)
124 {
125 enum rumpclock rclk = enum_rumpclock;
126 struct timespec rqt, rmt;
127 int nlocks;
128 int rv;
129
130 rumpkern_unsched(&nlocks, NULL);
131
132 /*LINTED*/
133 rqt.tv_sec = sec;
134 /*LINTED*/
135 rqt.tv_nsec = nsec;
136
137 switch (rclk) {
138 case RUMPUSER_CLOCK_RELWALL:
139 do {
140 rv = nanosleep(&rqt, &rmt);
141 rqt = rmt;
142 } while (rv == -1 && errno == EINTR);
143 if (rv == -1) {
144 rv = errno;
145 }
146 break;
147 case RUMPUSER_CLOCK_ABSMONO:
148 do {
149 #ifdef HAVE_CLOCK_NANOSLEEP
150 rv = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
151 &rqt, NULL);
152 #else
153 /* le/la/der/die/das sigh. timevalspec tailspin */
154 struct timespec ts, tsr;
155 clock_gettime(CLOCK_REALTIME, &ts);
156 if (ts.tv_sec == rqt.tv_sec ?
157 ts.tv_nsec > rqt.tv_nsec : ts.tv_sec > rqt.tv_sec) {
158 rv = 0;
159 } else {
160 tsr.tv_sec = rqt.tv_sec - ts.tv_sec;
161 tsr.tv_nsec = rqt.tv_nsec - ts.tv_nsec;
162 if (tsr.tv_nsec < 0) {
163 tsr.tv_sec--;
164 tsr.tv_nsec += 1000*1000*1000;
165 }
166 rv = nanosleep(&tsr, NULL);
167 }
168 #endif
169 } while (rv == -1 && errno == EINTR);
170 if (rv == -1) {
171 rv = errno;
172 }
173 break;
174 default:
175 abort();
176 }
177
178 rumpkern_sched(nlocks, NULL);
179
180 ET(rv);
181 }
182
183 static int
184 gethostncpu(void)
185 {
186 int ncpu = 1; /* unknown, really */
187
188 #ifdef _SC_NPROCESSORS_ONLN
189 ncpu = sysconf(_SC_NPROCESSORS_ONLN);
190 #endif
191
192 return ncpu;
193 }
194
195 int
196 rumpuser_getparam(const char *name, void *buf, size_t blen)
197 {
198 int rv;
199
200 if (strcmp(name, RUMPUSER_PARAM_NCPU) == 0) {
201 int ncpu;
202
203 if (getenv_r("RUMP_NCPU", buf, blen) == -1) {
204 sprintf(buf, "2"); /* default */
205 } else if (strcmp(buf, "host") == 0) {
206 ncpu = gethostncpu();
207 snprintf(buf, blen, "%d", ncpu);
208 }
209 rv = 0;
210 } else if (strcmp(name, RUMPUSER_PARAM_HOSTNAME) == 0) {
211 char tmp[MAXHOSTNAMELEN];
212
213 if (gethostname(tmp, sizeof(tmp)) == -1) {
214 snprintf(buf, blen, "rump-%05d", (int)getpid());
215 } else {
216 snprintf(buf, blen, "rump-%05d.%s",
217 (int)getpid(), tmp);
218 }
219 rv = 0;
220 } else if (*name == '_') {
221 rv = EINVAL;
222 } else {
223 if (getenv_r(name, buf, blen) == -1)
224 rv = errno;
225 else
226 rv = 0;
227 }
228
229 ET(rv);
230 }
231
232 void
233 rumpuser_putchar(int c)
234 {
235
236 putchar(c);
237 }
238
239 __dead void
240 rumpuser_exit(int rv)
241 {
242
243 if (rv == RUMPUSER_PANIC)
244 abort();
245 else
246 exit(rv);
247 }
248
249 void
250 rumpuser_seterrno(int error)
251 {
252
253 errno = error;
254 }
255
256 /*
257 * This is meant for safe debugging prints from the kernel.
258 */
259 void
260 rumpuser_dprintf(const char *format, ...)
261 {
262 va_list ap;
263
264 va_start(ap, format);
265 vfprintf(stderr, format, ap);
266 va_end(ap);
267 }
268
269 int
270 rumpuser_kill(int64_t pid, int rumpsig)
271 {
272 int sig;
273
274 sig = rumpuser__sig_rump2host(rumpsig);
275 if (sig > 0)
276 raise(sig);
277 return 0;
278 }
279
280 int
281 rumpuser_getrandom(void *buf, size_t buflen, int flags, size_t *retp)
282 {
283 size_t origlen = buflen;
284 uint32_t *p = buf;
285 uint32_t tmp;
286 int chunk;
287
288 do {
289 chunk = buflen < 4 ? buflen : 4; /* portable MIN ... */
290 tmp = RUMPUSER_RANDOM();
291 memcpy(p, &tmp, chunk);
292 p++;
293 buflen -= chunk;
294 } while (chunk);
295
296 *retp = origlen;
297 ET(0);
298 }
299