1 /* $NetBSD: rumpuser.c,v 1.46 2009/11/19 13:42:29 pooka Exp $ */
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by Google Summer of Code
7 * and the Finnish Cultural Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: rumpuser.c,v 1.46 2009/11/19 13:42:29 pooka Exp $");
36 /* thank the maker for this */
38 #define _XOPEN_SOURCE 500
40 #define _FILE_OFFSET_BITS 64
44 #include <sys/param.h>
45 #include <sys/event.h>
46 #include <sys/ioctl.h>
51 #include <sys/disklabel.h>
67 #include <rump/rumpuser.h>
69 #include "rumpuser_int.h"
72 rumpuser_getfileinfo(const char *path
, uint64_t *size
, int *ft
, int *error
)
77 if (stat(path
, &sb
) == -1) {
82 switch (sb
.st_mode
& S_IFMT
) {
84 *ft
= RUMPUSER_FT_DIR
;
87 *ft
= RUMPUSER_FT_REG
;
90 *ft
= RUMPUSER_FT_BLK
;
94 *ft
= RUMPUSER_FT_CHR
;
98 *ft
= RUMPUSER_FT_OTHER
;
106 * Welcome to the jungle. Of course querying the kernel
107 * for a device partition size is supposed to be far from
108 * trivial. On NetBSD we use ioctl. On $other platform
109 * we have a problem. We try "the lseek trick" and just
110 * fail if that fails. Platform specific code can later
111 * be written here if appropriate.
113 * On NetBSD we hope and pray that for block devices nobody
114 * else is holding them open, because otherwise the kernel
115 * will not permit us to open it. Thankfully, this is
116 * usually called only in bootstrap and then we can
123 fd
= open(path
, O_RDONLY
);
129 off
= lseek(fd
, 0, SEEK_END
);
135 fprintf(stderr
, "error: device size query not implemented on "
140 struct disklabel lab
;
141 struct partition
*parta
;
144 fd
= open(path
, O_RDONLY
);
150 if (ioctl(fd
, DIOCGDINFO
, &lab
) == -1) {
156 parta
= &lab
.d_partitions
[DISKPART(sb
.st_rdev
)];
157 *size
= (uint64_t)lab
.d_secsize
* parta
->p_size
;
158 #endif /* __NetBSD__ */
165 rumpuser_nanosleep(uint64_t *sec
, uint64_t *nsec
, int *error
)
167 struct timespec rqt
, rmt
;
175 KLOCK_WRAP(rv
= nanosleep(&rqt
, &rmt
));
186 rumpuser__malloc(size_t howmuch
, int canfail
, const char *func
, int line
)
190 rv
= malloc(howmuch
);
191 if (rv
== NULL
&& canfail
== 0) {
192 warn("malloc failed %s (%d)", func
, line
);
200 rumpuser__realloc(void *ptr
, size_t howmuch
, int canfail
,
201 const char *func
, int line
)
205 rv
= realloc(ptr
, howmuch
);
206 if (rv
== NULL
&& canfail
== 0) {
207 warn("realloc failed %s (%d)", func
, line
);
215 rumpuser_free(void *ptr
)
222 rumpuser_anonmmap(size_t size
, int alignbit
, int exec
, int *error
)
227 prot
= PROT_READ
|PROT_WRITE
;
230 /* XXX: MAP_ALIGNED() is not portable */
231 rv
= mmap(NULL
, size
, prot
, MAP_ANON
| MAP_ALIGNED(alignbit
), -1, 0);
232 if (rv
== MAP_FAILED
) {
240 rumpuser_unmap(void *addr
, size_t len
)
244 rv
= munmap(addr
, len
);
249 rumpuser_filemmap(int fd
, off_t offset
, size_t len
, int flags
, int *error
)
254 if (flags
& RUMPUSER_FILEMMAP_TRUNCATE
)
255 ftruncate(fd
, offset
+ len
);
258 if (flags
& RUMPUSER_FILEMMAP_SHARED
)
259 mmflags
|= MAP_SHARED
;
261 mmflags
|= MAP_PRIVATE
;
264 if (flags
& RUMPUSER_FILEMMAP_READ
)
266 if (flags
& RUMPUSER_FILEMMAP_WRITE
)
269 rv
= mmap(NULL
, len
, PROT_READ
|PROT_WRITE
, mmflags
, fd
, offset
);
270 if (rv
== MAP_FAILED
) {
280 rumpuser_memsync(void *addr
, size_t len
, int *error
)
283 DOCALL_KLOCK(int, (msync(addr
, len
, MS_SYNC
)));
287 rumpuser_open(const char *path
, int flags
, int *error
)
290 DOCALL(int, (open(path
, flags
, 0644)));
294 rumpuser_ioctl(int fd
, u_long cmd
, void *data
, int *error
)
297 DOCALL_KLOCK(int, (ioctl(fd
, cmd
, data
)));
301 rumpuser_close(int fd
, int *error
)
304 DOCALL(int, close(fd
));
308 rumpuser_fsync(int fd
, int *error
)
311 DOCALL_KLOCK(int, fsync(fd
));
315 rumpuser_read(int fd
, void *data
, size_t size
, int *error
)
319 KLOCK_WRAP(rv
= read(fd
, data
, size
));
327 rumpuser_pread(int fd
, void *data
, size_t size
, off_t offset
, int *error
)
331 KLOCK_WRAP(rv
= pread(fd
, data
, size
, offset
));
339 rumpuser_read_bio(int fd
, void *data
, size_t size
, off_t offset
,
340 rump_biodone_fn biodone
, void *biodonecookie
)
345 rv
= rumpuser_pread(fd
, data
, size
, offset
, &error
);
346 /* check against <0 instead of ==-1 to get typing below right */
350 /* LINTED: see above */
351 biodone(biodonecookie
, rv
, error
);
355 rumpuser_write(int fd
, const void *data
, size_t size
, int *error
)
359 KLOCK_WRAP(rv
= write(fd
, data
, size
));
367 rumpuser_pwrite(int fd
, const void *data
, size_t size
, off_t offset
, int *error
)
371 KLOCK_WRAP(rv
= pwrite(fd
, data
, size
, offset
));
379 rumpuser_write_bio(int fd
, const void *data
, size_t size
, off_t offset
,
380 rump_biodone_fn biodone
, void *biodonecookie
)
385 rv
= rumpuser_pwrite(fd
, data
, size
, offset
, &error
);
386 /* check against <0 instead of ==-1 to get typing below right */
390 /* LINTED: see above */
391 biodone(biodonecookie
, rv
, error
);
395 rumpuser_readv(int fd
, const struct rumpuser_iovec
*riov
, int iovcnt
,
402 iovp
= malloc(iovcnt
* sizeof(struct iovec
));
407 for (i
= 0; i
< iovcnt
; i
++) {
408 iovp
[i
].iov_base
= riov
[i
].iov_base
;
410 iovp
[i
].iov_len
= riov
[i
].iov_len
;
413 KLOCK_WRAP(rv
= readv(fd
, iovp
, iovcnt
));
422 rumpuser_writev(int fd
, const struct rumpuser_iovec
*riov
, int iovcnt
,
429 iovp
= malloc(iovcnt
* sizeof(struct iovec
));
434 for (i
= 0; i
< iovcnt
; i
++) {
435 iovp
[i
].iov_base
= riov
[i
].iov_base
;
437 iovp
[i
].iov_len
= riov
[i
].iov_len
;
440 KLOCK_WRAP(rv
= writev(fd
, iovp
, iovcnt
));
449 rumpuser_gettime(uint64_t *sec
, uint64_t *nsec
, int *error
)
454 rv
= gettimeofday(&tv
, NULL
);
461 *nsec
= tv
.tv_usec
* 1000;
467 rumpuser_getenv(const char *name
, char *buf
, size_t blen
, int *error
)
470 DOCALL(int, getenv_r(name
, buf
, blen
));
474 rumpuser_gethostname(char *name
, size_t namelen
, int *error
)
477 DOCALL(int, (gethostname(name
, namelen
)));
481 rumpuser_poll(struct pollfd
*fds
, int nfds
, int timeout
, int *error
)
484 DOCALL_KLOCK(int, (poll(fds
, (nfds_t
)nfds
, timeout
)));
488 rumpuser_putchar(int c
, int *error
)
491 DOCALL(int, (putchar(c
)));
495 rumpuser_exit(int rv
)
498 if (rv
== RUMPUSER_PANIC
)
505 rumpuser_seterrno(int error
)
512 rumpuser_writewatchfile_setup(int kq
, int fd
, intptr_t opaque
, int *error
)
524 EV_SET(&kev
, fd
, EVFILT_VNODE
, EV_ADD
|EV_ENABLE
|EV_CLEAR
,
525 NOTE_WRITE
, 0, opaque
);
526 if (kevent(kq
, &kev
, 1, NULL
, 0, NULL
) == -1) {
535 rumpuser_writewatchfile_wait(int kq
, intptr_t *opaque
, int *error
)
540 KLOCK_WRAP(rv
= kevent(kq
, NULL
, 0, &kev
, 1, NULL
));
552 * This is meant for safe debugging prints from the kernel.
555 rumpuser_dprintf(const char *format
, ...)
560 va_start(ap
, format
);
561 rv
= vprintf(format
, ap
);