1 /* 2 * Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 /* NOTE this code will move to a new driver in the next hypercall revision */ 27 28 #include "rumpuser_port.h" 29 30 #if !defined(lint) 31 __RCSID("$NetBSD: rumpuser_file.c,v 1.1 2014/07/09 23:41:40 justin Exp $"); 32 #endif /* !lint */ 33 34 #include <sys/ioctl.h> 35 #include <sys/mman.h> 36 #include <sys/uio.h> 37 #include <sys/stat.h> 38 #include <sys/time.h> 39 #include <sys/types.h> 40 41 #ifdef __NetBSD__ 42 #include <sys/disk.h> 43 #include <sys/disklabel.h> 44 #include <sys/dkio.h> 45 #endif 46 47 #if defined(__NetBSD__) || defined(__FreeBSD__) || \ 48 defined(__DragonFly__) || defined(__APPLE__) 49 #define __BSD__ 50 #endif 51 52 #if defined(__BSD__) 53 #include <sys/sysctl.h> 54 #endif 55 56 #include <assert.h> 57 #include <errno.h> 58 #include <fcntl.h> 59 #include <netdb.h> 60 #include <stdarg.h> 61 #include <stdint.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include <rump/rumpuser.h> 68 69 #include "rumpuser_int.h" 70 71 int 72 rumpuser_getfileinfo(const char *path, uint64_t *sizep, int *ftp) 73 { 74 struct stat sb; 75 uint64_t size = 0; 76 int needsdev = 0, rv = 0, ft = 0; 77 int fd = -1; 78 79 if (stat(path, &sb) == -1) { 80 rv = errno; 81 goto out; 82 } 83 84 switch (sb.st_mode & S_IFMT) { 85 case S_IFDIR: 86 ft = RUMPUSER_FT_DIR; 87 break; 88 case S_IFREG: 89 ft = RUMPUSER_FT_REG; 90 break; 91 case S_IFBLK: 92 ft = RUMPUSER_FT_BLK; 93 needsdev = 1; 94 break; 95 case S_IFCHR: 96 ft = RUMPUSER_FT_CHR; 97 needsdev = 1; 98 break; 99 default: 100 ft = RUMPUSER_FT_OTHER; 101 break; 102 } 103 104 if (!needsdev) { 105 size = sb.st_size; 106 } else if (sizep) { 107 /* 108 * Welcome to the jungle. Of course querying the kernel 109 * for a device partition size is supposed to be far from 110 * trivial. On NetBSD we use ioctl. On $other platform 111 * we have a problem. We try "the lseek trick" and just 112 * fail if that fails. Platform specific code can later 113 * be written here if appropriate. 114 * 115 * On NetBSD we hope and pray that for block devices nobody 116 * else is holding them open, because otherwise the kernel 117 * will not permit us to open it. Thankfully, this is 118 * usually called only in bootstrap and then we can 119 * forget about it. 120 */ 121 #ifndef __NetBSD__ 122 off_t off; 123 124 fd = open(path, O_RDONLY); 125 if (fd == -1) { 126 rv = errno; 127 goto out; 128 } 129 130 off = lseek(fd, 0, SEEK_END); 131 if (off != 0) { 132 size = off; 133 goto out; 134 } 135 fprintf(stderr, "error: device size query not implemented on " 136 "this platform\n"); 137 rv = EOPNOTSUPP; 138 goto out; 139 #else 140 struct disklabel lab; 141 struct partition *parta; 142 struct dkwedge_info dkw; 143 144 fd = open(path, O_RDONLY); 145 if (fd == -1) { 146 rv = errno; 147 goto out; 148 } 149 150 if (ioctl(fd, DIOCGDINFO, &lab) == 0) { 151 parta = &lab.d_partitions[DISKPART(sb.st_rdev)]; 152 size = (uint64_t)lab.d_secsize * parta->p_size; 153 goto out; 154 } 155 156 if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) { 157 /* 158 * XXX: should use DIOCGDISKINFO to query 159 * sector size, but that requires proplib, 160 * so just don't bother for now. it's nice 161 * that something as difficult as figuring out 162 * a partition's size has been made so easy. 163 */ 164 size = dkw.dkw_size << DEV_BSHIFT; 165 goto out; 166 } 167 168 rv = errno; 169 #endif /* __NetBSD__ */ 170 } 171 172 out: 173 if (rv == 0 && sizep) 174 *sizep = size; 175 if (rv == 0 && ftp) 176 *ftp = ft; 177 if (fd != -1) 178 close(fd); 179 180 ET(rv); 181 } 182 183 int 184 rumpuser_open(const char *path, int ruflags, int *fdp) 185 { 186 int fd, flags, rv; 187 188 switch (ruflags & RUMPUSER_OPEN_ACCMODE) { 189 case RUMPUSER_OPEN_RDONLY: 190 flags = O_RDONLY; 191 break; 192 case RUMPUSER_OPEN_WRONLY: 193 flags = O_WRONLY; 194 break; 195 case RUMPUSER_OPEN_RDWR: 196 flags = O_RDWR; 197 break; 198 default: 199 rv = EINVAL; 200 goto out; 201 } 202 203 #define TESTSET(_ru_, _h_) if (ruflags & _ru_) flags |= _h_; 204 TESTSET(RUMPUSER_OPEN_CREATE, O_CREAT); 205 TESTSET(RUMPUSER_OPEN_EXCL, O_EXCL); 206 #undef TESTSET 207 208 KLOCK_WRAP(fd = open(path, flags, 0644)); 209 if (fd == -1) { 210 rv = errno; 211 } else { 212 *fdp = fd; 213 rv = 0; 214 } 215 216 out: 217 ET(rv); 218 } 219 220 int 221 rumpuser_close(int fd) 222 { 223 int nlocks; 224 225 rumpkern_unsched(&nlocks, NULL); 226 fsync(fd); 227 close(fd); 228 rumpkern_sched(nlocks, NULL); 229 230 ET(0); 231 } 232 233 /* 234 * Assume "struct rumpuser_iovec" and "struct iovec" are the same. 235 * If you encounter POSIX platforms where they aren't, add some 236 * translation for iovlen > 1. 237 */ 238 int 239 rumpuser_iovread(int fd, struct rumpuser_iovec *ruiov, size_t iovlen, 240 int64_t roff, size_t *retp) 241 { 242 struct iovec *iov = (struct iovec *)ruiov; 243 off_t off = (off_t)roff; 244 ssize_t nn; 245 int rv; 246 247 if (off == RUMPUSER_IOV_NOSEEK) { 248 KLOCK_WRAP(nn = readv(fd, iov, iovlen)); 249 } else { 250 int nlocks; 251 252 rumpkern_unsched(&nlocks, NULL); 253 if (lseek(fd, off, SEEK_SET) == off) { 254 nn = readv(fd, iov, iovlen); 255 } else { 256 nn = -1; 257 } 258 rumpkern_sched(nlocks, NULL); 259 } 260 261 if (nn == -1) { 262 rv = errno; 263 } else { 264 *retp = (size_t)nn; 265 rv = 0; 266 } 267 268 ET(rv); 269 } 270 271 int 272 rumpuser_iovwrite(int fd, const struct rumpuser_iovec *ruiov, size_t iovlen, 273 int64_t roff, size_t *retp) 274 { 275 const struct iovec *iov = (const struct iovec *)ruiov; 276 off_t off = (off_t)roff; 277 ssize_t nn; 278 int rv; 279 280 if (off == RUMPUSER_IOV_NOSEEK) { 281 KLOCK_WRAP(nn = writev(fd, iov, iovlen)); 282 } else { 283 int nlocks; 284 285 rumpkern_unsched(&nlocks, NULL); 286 if (lseek(fd, off, SEEK_SET) == off) { 287 nn = writev(fd, iov, iovlen); 288 } else { 289 nn = -1; 290 } 291 rumpkern_sched(nlocks, NULL); 292 } 293 294 if (nn == -1) { 295 rv = errno; 296 } else { 297 *retp = (size_t)nn; 298 rv = 0; 299 } 300 301 ET(rv); 302 } 303 304 int 305 rumpuser_syncfd(int fd, int flags, uint64_t start, uint64_t len) 306 { 307 int rv = 0; 308 309 /* 310 * For now, assume fd is regular file and does not care 311 * about read syncing 312 */ 313 if ((flags & RUMPUSER_SYNCFD_BOTH) == 0) { 314 rv = EINVAL; 315 goto out; 316 } 317 if ((flags & RUMPUSER_SYNCFD_WRITE) == 0) { 318 rv = 0; 319 goto out; 320 } 321 322 #ifdef __NetBSD__ 323 { 324 int fsflags = FDATASYNC; 325 326 if (fsflags & RUMPUSER_SYNCFD_SYNC) 327 fsflags |= FDISKSYNC; 328 if (fsync_range(fd, fsflags, start, len) == -1) 329 rv = errno; 330 } 331 #else 332 /* el-simplo */ 333 if (fsync(fd) == -1) 334 rv = errno; 335 #endif 336 337 out: 338 ET(rv); 339 } 340