1 1.60 rillig /* $NetBSD: ukfs.c,v 1.60 2022/04/19 20:32:17 rillig Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.38 pooka * Copyright (c) 2007, 2008, 2009 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Development of this software was supported by the 7 1.1 pooka * Finnish Cultural Foundation. 8 1.1 pooka * 9 1.1 pooka * Redistribution and use in source and binary forms, with or without 10 1.1 pooka * modification, are permitted provided that the following conditions 11 1.1 pooka * are met: 12 1.1 pooka * 1. Redistributions of source code must retain the above copyright 13 1.1 pooka * notice, this list of conditions and the following disclaimer. 14 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 pooka * notice, this list of conditions and the following disclaimer in the 16 1.1 pooka * documentation and/or other materials provided with the distribution. 17 1.1 pooka * 18 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 pooka * SUCH DAMAGE. 29 1.1 pooka */ 30 1.1 pooka 31 1.1 pooka /* 32 1.1 pooka * This library enables access to files systems directly without 33 1.1 pooka * involving system calls. 34 1.1 pooka */ 35 1.1 pooka 36 1.1 pooka #ifdef __linux__ 37 1.1 pooka #define _XOPEN_SOURCE 500 38 1.1 pooka #define _BSD_SOURCE 39 1.1 pooka #define _FILE_OFFSET_BITS 64 40 1.1 pooka #endif 41 1.1 pooka 42 1.3 pooka #include <sys/param.h> 43 1.3 pooka #include <sys/queue.h> 44 1.1 pooka #include <sys/stat.h> 45 1.4 pooka #include <sys/sysctl.h> 46 1.4 pooka #include <sys/mount.h> 47 1.1 pooka 48 1.1 pooka #include <assert.h> 49 1.3 pooka #include <dirent.h> 50 1.3 pooka #include <dlfcn.h> 51 1.1 pooka #include <err.h> 52 1.1 pooka #include <errno.h> 53 1.11 pooka #include <fcntl.h> 54 1.1 pooka #include <pthread.h> 55 1.1 pooka #include <stdio.h> 56 1.1 pooka #include <stdlib.h> 57 1.1 pooka #include <string.h> 58 1.1 pooka #include <unistd.h> 59 1.1 pooka #include <stdint.h> 60 1.1 pooka 61 1.1 pooka #include <rump/ukfs.h> 62 1.1 pooka 63 1.1 pooka #include <rump/rump.h> 64 1.59 pooka #include <rump/rumpvnode_if.h> 65 1.1 pooka #include <rump/rump_syscalls.h> 66 1.1 pooka 67 1.38 pooka #include "ukfs_int_disklabel.h" 68 1.38 pooka 69 1.1 pooka #define UKFS_MODE_DEFAULT 0555 70 1.1 pooka 71 1.1 pooka struct ukfs { 72 1.54 pooka pthread_spinlock_t ukfs_spin; 73 1.54 pooka 74 1.1 pooka struct mount *ukfs_mp; 75 1.54 pooka struct lwp *ukfs_lwp; 76 1.37 pooka void *ukfs_specific; 77 1.1 pooka 78 1.11 pooka int ukfs_devfd; 79 1.54 pooka 80 1.30 pooka char *ukfs_devpath; 81 1.30 pooka char *ukfs_mountpath; 82 1.54 pooka char *ukfs_cwd; 83 1.54 pooka 84 1.45 pooka struct ukfs_part *ukfs_part; 85 1.1 pooka }; 86 1.1 pooka 87 1.30 pooka static int builddirs(const char *, mode_t, 88 1.30 pooka int (*mkdirfn)(struct ukfs *, const char *, mode_t), struct ukfs *); 89 1.30 pooka 90 1.1 pooka struct mount * 91 1.1 pooka ukfs_getmp(struct ukfs *ukfs) 92 1.1 pooka { 93 1.1 pooka 94 1.1 pooka return ukfs->ukfs_mp; 95 1.1 pooka } 96 1.1 pooka 97 1.37 pooka void 98 1.37 pooka ukfs_setspecific(struct ukfs *ukfs, void *priv) 99 1.37 pooka { 100 1.37 pooka 101 1.37 pooka ukfs->ukfs_specific = priv; 102 1.37 pooka } 103 1.37 pooka 104 1.37 pooka void * 105 1.37 pooka ukfs_getspecific(struct ukfs *ukfs) 106 1.37 pooka { 107 1.37 pooka 108 1.37 pooka return ukfs->ukfs_specific; 109 1.37 pooka } 110 1.37 pooka 111 1.20 pooka #ifdef DONT_WANT_PTHREAD_LINKAGE 112 1.20 pooka #define pthread_spin_lock(a) 113 1.20 pooka #define pthread_spin_unlock(a) 114 1.20 pooka #define pthread_spin_init(a,b) 115 1.20 pooka #define pthread_spin_destroy(a) 116 1.20 pooka #endif 117 1.20 pooka 118 1.54 pooka static int 119 1.54 pooka precall(struct ukfs *ukfs, struct lwp **curlwp) 120 1.1 pooka { 121 1.1 pooka 122 1.54 pooka /* save previous. ensure start from pristine context */ 123 1.54 pooka *curlwp = rump_pub_lwproc_curlwp(); 124 1.54 pooka if (*curlwp) 125 1.54 pooka rump_pub_lwproc_switch(ukfs->ukfs_lwp); 126 1.56 pooka rump_pub_lwproc_rfork(RUMP_RFCFDG); 127 1.54 pooka 128 1.54 pooka if (rump_sys_chroot(ukfs->ukfs_mountpath) == -1) 129 1.54 pooka return errno; 130 1.54 pooka if (rump_sys_chdir(ukfs->ukfs_cwd) == -1) 131 1.54 pooka return errno; 132 1.54 pooka 133 1.54 pooka return 0; 134 1.1 pooka } 135 1.1 pooka 136 1.1 pooka static void 137 1.54 pooka postcall(struct lwp *curlwp) 138 1.1 pooka { 139 1.53 pooka 140 1.53 pooka rump_pub_lwproc_releaselwp(); 141 1.54 pooka if (curlwp) 142 1.54 pooka rump_pub_lwproc_switch(curlwp); 143 1.1 pooka } 144 1.1 pooka 145 1.54 pooka #define PRECALL() \ 146 1.54 pooka struct lwp *ukfs_curlwp; \ 147 1.54 pooka do { \ 148 1.54 pooka int ukfs_rv; \ 149 1.54 pooka if ((ukfs_rv = precall(ukfs, &ukfs_curlwp)) != 0) { \ 150 1.54 pooka errno = ukfs_rv; \ 151 1.54 pooka return -1; \ 152 1.54 pooka } \ 153 1.60 rillig } while (0) 154 1.54 pooka 155 1.54 pooka #define POSTCALL() postcall(ukfs_curlwp); 156 1.54 pooka 157 1.43 pooka struct ukfs_part { 158 1.47 pooka pthread_spinlock_t part_lck; 159 1.47 pooka int part_refcount; 160 1.47 pooka 161 1.43 pooka int part_type; 162 1.43 pooka char part_labelchar; 163 1.43 pooka off_t part_devoff; 164 1.43 pooka off_t part_devsize; 165 1.43 pooka }; 166 1.43 pooka 167 1.43 pooka enum ukfs_parttype { UKFS_PART_NONE, UKFS_PART_DISKLABEL, UKFS_PART_OFFSET }; 168 1.43 pooka 169 1.43 pooka static struct ukfs_part ukfs__part_none = { 170 1.43 pooka .part_type = UKFS_PART_NONE, 171 1.43 pooka .part_devoff = 0, 172 1.43 pooka .part_devsize = RUMP_ETFS_SIZE_ENDOFF, 173 1.43 pooka }; 174 1.43 pooka static struct ukfs_part ukfs__part_na; 175 1.44 pooka struct ukfs_part *ukfs_part_none = &ukfs__part_none; 176 1.44 pooka struct ukfs_part *ukfs_part_na = &ukfs__part_na; 177 1.43 pooka 178 1.45 pooka #define PART2LOCKSIZE(len) ((len) == RUMP_ETFS_SIZE_ENDOFF ? 0 : (len)) 179 1.45 pooka 180 1.1 pooka int 181 1.10 pooka _ukfs_init(int version) 182 1.1 pooka { 183 1.10 pooka int rv; 184 1.10 pooka 185 1.10 pooka if (version != UKFS_VERSION) { 186 1.58 christos errno = EPROGMISMATCH; 187 1.58 christos warn("incompatible ukfs version, %d vs. %d", 188 1.10 pooka version, UKFS_VERSION); 189 1.10 pooka return -1; 190 1.10 pooka } 191 1.1 pooka 192 1.10 pooka if ((rv = rump_init()) != 0) { 193 1.10 pooka errno = rv; 194 1.10 pooka return -1; 195 1.10 pooka } 196 1.1 pooka 197 1.1 pooka return 0; 198 1.1 pooka } 199 1.1 pooka 200 1.31 pooka /*ARGSUSED*/ 201 1.30 pooka static int 202 1.30 pooka rumpmkdir(struct ukfs *dummy, const char *path, mode_t mode) 203 1.30 pooka { 204 1.30 pooka 205 1.30 pooka return rump_sys_mkdir(path, mode); 206 1.30 pooka } 207 1.30 pooka 208 1.38 pooka int 209 1.43 pooka ukfs_part_probe(char *devpath, struct ukfs_part **partp) 210 1.38 pooka { 211 1.43 pooka struct ukfs_part *part; 212 1.38 pooka char *p; 213 1.43 pooka int error = 0; 214 1.43 pooka int devfd = -1; 215 1.43 pooka 216 1.43 pooka if ((p = strstr(devpath, UKFS_PARTITION_SCANMAGIC)) != NULL) { 217 1.58 christos warnx("ukfs: %%PART is deprecated. use " 218 1.58 christos "%%DISKLABEL instead"); 219 1.43 pooka errno = ENODEV; 220 1.43 pooka return -1; 221 1.43 pooka } 222 1.43 pooka 223 1.43 pooka part = malloc(sizeof(*part)); 224 1.43 pooka if (part == NULL) { 225 1.43 pooka errno = ENOMEM; 226 1.43 pooka return -1; 227 1.43 pooka } 228 1.47 pooka if (pthread_spin_init(&part->part_lck, PTHREAD_PROCESS_PRIVATE) == -1) { 229 1.47 pooka error = errno; 230 1.47 pooka free(part); 231 1.47 pooka errno = error; 232 1.47 pooka return -1; 233 1.47 pooka } 234 1.43 pooka part->part_type = UKFS_PART_NONE; 235 1.47 pooka part->part_refcount = 1; 236 1.38 pooka 237 1.38 pooka /* 238 1.43 pooka * Check for magic in pathname: 239 1.43 pooka * disklabel: /regularpath%DISKLABEL:labelchar%\0 240 1.43 pooka * offsets: /regularpath%OFFSET:start,end%\0 241 1.38 pooka */ 242 1.43 pooka #define MAGICADJ_DISKLABEL(p, n) (p+sizeof(UKFS_DISKLABEL_SCANMAGIC)-1+n) 243 1.43 pooka if ((p = strstr(devpath, UKFS_DISKLABEL_SCANMAGIC)) != NULL 244 1.43 pooka && strlen(p) == UKFS_DISKLABEL_MAGICLEN 245 1.43 pooka && *(MAGICADJ_DISKLABEL(p,1)) == '%') { 246 1.43 pooka if (*(MAGICADJ_DISKLABEL(p,0)) >= 'a' && 247 1.43 pooka *(MAGICADJ_DISKLABEL(p,0)) < 'a' + UKFS_MAXPARTITIONS) { 248 1.43 pooka struct ukfs__disklabel dl; 249 1.43 pooka struct ukfs__partition *pp; 250 1.57 pooka int imswapped; 251 1.43 pooka char buf[65536]; 252 1.43 pooka char labelchar = *(MAGICADJ_DISKLABEL(p,0)); 253 1.43 pooka int partition = labelchar - 'a'; 254 1.57 pooka uint32_t poffset, psize; 255 1.43 pooka 256 1.38 pooka *p = '\0'; 257 1.43 pooka devfd = open(devpath, O_RDONLY); 258 1.43 pooka if (devfd == -1) { 259 1.43 pooka error = errno; 260 1.43 pooka goto out; 261 1.43 pooka } 262 1.43 pooka 263 1.43 pooka /* Locate the disklabel and find the partition. */ 264 1.43 pooka if (pread(devfd, buf, sizeof(buf), 0) == -1) { 265 1.43 pooka error = errno; 266 1.43 pooka goto out; 267 1.43 pooka } 268 1.43 pooka 269 1.57 pooka if (ukfs__disklabel_scan(&dl, &imswapped, 270 1.57 pooka buf, sizeof(buf)) != 0) { 271 1.43 pooka error = ENOENT; 272 1.43 pooka goto out; 273 1.43 pooka } 274 1.43 pooka 275 1.43 pooka if (dl.d_npartitions < partition) { 276 1.43 pooka error = ENOENT; 277 1.43 pooka goto out; 278 1.43 pooka } 279 1.43 pooka 280 1.43 pooka pp = &dl.d_partitions[partition]; 281 1.43 pooka part->part_type = UKFS_PART_DISKLABEL; 282 1.43 pooka part->part_labelchar = labelchar; 283 1.57 pooka if (imswapped) { 284 1.57 pooka poffset = bswap32(pp->p_offset); 285 1.57 pooka psize = bswap32(pp->p_size); 286 1.57 pooka } else { 287 1.57 pooka poffset = pp->p_offset; 288 1.57 pooka psize = pp->p_size; 289 1.57 pooka } 290 1.57 pooka part->part_devoff = poffset << DEV_BSHIFT; 291 1.57 pooka part->part_devsize = psize << DEV_BSHIFT; 292 1.38 pooka } else { 293 1.43 pooka error = EINVAL; 294 1.43 pooka } 295 1.43 pooka #define MAGICADJ_OFFSET(p, n) (p+sizeof(UKFS_OFFSET_SCANMAGIC)-1+n) 296 1.43 pooka } else if (((p = strstr(devpath, UKFS_OFFSET_SCANMAGIC)) != NULL) 297 1.43 pooka && (strlen(p) >= UKFS_OFFSET_MINLEN)) { 298 1.43 pooka char *comma, *pers, *ep, *nptr; 299 1.43 pooka u_quad_t val; 300 1.43 pooka 301 1.43 pooka comma = strchr(p, ','); 302 1.43 pooka if (comma == NULL) { 303 1.43 pooka error = EINVAL; 304 1.43 pooka goto out; 305 1.43 pooka } 306 1.43 pooka pers = strchr(comma, '%'); 307 1.43 pooka if (pers == NULL) { 308 1.43 pooka error = EINVAL; 309 1.43 pooka goto out; 310 1.43 pooka } 311 1.43 pooka *comma = '\0'; 312 1.43 pooka *pers = '\0'; 313 1.43 pooka *p = '\0'; 314 1.43 pooka 315 1.43 pooka nptr = MAGICADJ_OFFSET(p,0); 316 1.43 pooka /* check if string is negative */ 317 1.43 pooka if (*nptr == '-') { 318 1.43 pooka error = ERANGE; 319 1.43 pooka goto out; 320 1.43 pooka } 321 1.43 pooka val = strtouq(nptr, &ep, 10); 322 1.43 pooka if (val == UQUAD_MAX) { 323 1.43 pooka error = ERANGE; 324 1.43 pooka goto out; 325 1.43 pooka } 326 1.43 pooka if (*ep != '\0') { 327 1.43 pooka error = EADDRNOTAVAIL; /* creative ;) */ 328 1.43 pooka goto out; 329 1.43 pooka } 330 1.43 pooka part->part_devoff = val; 331 1.43 pooka 332 1.43 pooka /* omstart */ 333 1.43 pooka 334 1.43 pooka nptr = comma+1; 335 1.43 pooka /* check if string is negative */ 336 1.43 pooka if (*nptr == '-') { 337 1.43 pooka error = ERANGE; 338 1.43 pooka goto out; 339 1.43 pooka } 340 1.43 pooka val = strtouq(nptr, &ep, 10); 341 1.43 pooka if (val == UQUAD_MAX) { 342 1.43 pooka error = ERANGE; 343 1.43 pooka goto out; 344 1.43 pooka } 345 1.43 pooka if (*ep != '\0') { 346 1.43 pooka error = EADDRNOTAVAIL; /* creative ;) */ 347 1.43 pooka goto out; 348 1.38 pooka } 349 1.43 pooka part->part_devsize = val; 350 1.43 pooka part->part_type = UKFS_PART_OFFSET; 351 1.38 pooka } else { 352 1.47 pooka ukfs_part_release(part); 353 1.43 pooka part = ukfs_part_none; 354 1.43 pooka } 355 1.43 pooka 356 1.43 pooka out: 357 1.43 pooka if (devfd != -1) 358 1.43 pooka close(devfd); 359 1.43 pooka if (error) { 360 1.43 pooka free(part); 361 1.43 pooka errno = error; 362 1.43 pooka } else { 363 1.43 pooka *partp = part; 364 1.43 pooka } 365 1.43 pooka 366 1.43 pooka return error ? -1 : 0; 367 1.43 pooka } 368 1.43 pooka 369 1.43 pooka int 370 1.43 pooka ukfs_part_tostring(struct ukfs_part *part, char *str, size_t strsize) 371 1.43 pooka { 372 1.43 pooka int rv; 373 1.43 pooka 374 1.43 pooka *str = '\0'; 375 1.43 pooka /* "pseudo" values */ 376 1.43 pooka if (part == ukfs_part_na) { 377 1.43 pooka errno = EINVAL; 378 1.43 pooka return -1; 379 1.43 pooka } 380 1.43 pooka if (part == ukfs_part_none) 381 1.43 pooka return 0; 382 1.43 pooka 383 1.43 pooka rv = 0; 384 1.43 pooka switch (part->part_type) { 385 1.43 pooka case UKFS_PART_NONE: 386 1.43 pooka break; 387 1.43 pooka 388 1.43 pooka case UKFS_PART_DISKLABEL: 389 1.43 pooka snprintf(str, strsize, "%%DISKLABEL:%c%%",part->part_labelchar); 390 1.43 pooka rv = 1; 391 1.43 pooka break; 392 1.43 pooka 393 1.43 pooka case UKFS_PART_OFFSET: 394 1.43 pooka snprintf(str, strsize, "[%llu,%llu]", 395 1.43 pooka (unsigned long long)part->part_devoff, 396 1.43 pooka (unsigned long long)(part->part_devoff+part->part_devsize)); 397 1.43 pooka rv = 1; 398 1.43 pooka break; 399 1.38 pooka } 400 1.38 pooka 401 1.38 pooka return rv; 402 1.38 pooka } 403 1.38 pooka 404 1.45 pooka static void 405 1.45 pooka unlockdev(int fd, struct ukfs_part *part) 406 1.45 pooka { 407 1.45 pooka struct flock flarg; 408 1.45 pooka 409 1.47 pooka if (part == ukfs_part_na) 410 1.47 pooka return; 411 1.47 pooka 412 1.45 pooka memset(&flarg, 0, sizeof(flarg)); 413 1.45 pooka flarg.l_type = F_UNLCK; 414 1.45 pooka flarg.l_whence = SEEK_SET; 415 1.45 pooka flarg.l_start = part->part_devoff; 416 1.45 pooka flarg.l_len = PART2LOCKSIZE(part->part_devsize); 417 1.45 pooka if (fcntl(fd, F_SETLK, &flarg) == -1) 418 1.45 pooka warn("ukfs: cannot unlock device file"); 419 1.45 pooka } 420 1.45 pooka 421 1.38 pooka /* 422 1.38 pooka * Open the disk file and flock it. Also, if we are operation on 423 1.38 pooka * an embedded partition, find the partition offset and size from 424 1.38 pooka * the disklabel. 425 1.38 pooka * 426 1.38 pooka * We hard-fail only in two cases: 427 1.38 pooka * 1) we failed to get the partition info out (don't know what offset 428 1.38 pooka * to mount from) 429 1.45 pooka * 2) we failed to flock the source device (i.e. fcntl() fails, 430 1.38 pooka * not e.g. open() before it) 431 1.38 pooka * 432 1.38 pooka * Otherwise we let the code proceed to mount and let the file system 433 1.38 pooka * throw the proper error. The only questionable bit is that if we 434 1.45 pooka * soft-fail before flock and mount does succeed... 435 1.38 pooka * 436 1.38 pooka * Returns: -1 error (errno reports error code) 437 1.38 pooka * 0 success 438 1.38 pooka * 439 1.38 pooka * dfdp: -1 device is not open 440 1.38 pooka * n device is open 441 1.38 pooka */ 442 1.38 pooka static int 443 1.43 pooka process_diskdevice(const char *devpath, struct ukfs_part *part, int rdonly, 444 1.43 pooka int *dfdp) 445 1.1 pooka { 446 1.22 pooka struct stat sb; 447 1.38 pooka int rv = 0, devfd; 448 1.38 pooka 449 1.38 pooka /* defaults */ 450 1.38 pooka *dfdp = -1; 451 1.38 pooka 452 1.38 pooka devfd = open(devpath, rdonly ? O_RDONLY : O_RDWR); 453 1.38 pooka if (devfd == -1) { 454 1.43 pooka rv = errno; 455 1.38 pooka goto out; 456 1.38 pooka } 457 1.38 pooka 458 1.38 pooka if (fstat(devfd, &sb) == -1) { 459 1.38 pooka rv = errno; 460 1.38 pooka goto out; 461 1.38 pooka } 462 1.1 pooka 463 1.11 pooka /* 464 1.38 pooka * We do this only for non-block device since the 465 1.38 pooka * (NetBSD) kernel allows block device open only once. 466 1.38 pooka * We also need to close the device for fairly obvious reasons. 467 1.11 pooka */ 468 1.38 pooka if (!S_ISBLK(sb.st_mode)) { 469 1.45 pooka struct flock flarg; 470 1.45 pooka 471 1.45 pooka memset(&flarg, 0, sizeof(flarg)); 472 1.45 pooka flarg.l_type = rdonly ? F_RDLCK : F_WRLCK; 473 1.45 pooka flarg.l_whence = SEEK_SET; 474 1.45 pooka flarg.l_start = part->part_devoff; 475 1.45 pooka flarg.l_len = PART2LOCKSIZE(part->part_devsize); 476 1.45 pooka if (fcntl(devfd, F_SETLK, &flarg) == -1) { 477 1.45 pooka pid_t holder; 478 1.45 pooka int sverrno; 479 1.45 pooka 480 1.45 pooka sverrno = errno; 481 1.45 pooka if (fcntl(devfd, F_GETLK, &flarg) != 1) 482 1.45 pooka holder = flarg.l_pid; 483 1.45 pooka else 484 1.45 pooka holder = -1; 485 1.45 pooka warnx("ukfs_mount: cannot lock device. held by pid %d", 486 1.45 pooka holder); 487 1.45 pooka rv = sverrno; 488 1.11 pooka goto out; 489 1.11 pooka } 490 1.38 pooka } else { 491 1.38 pooka close(devfd); 492 1.38 pooka devfd = -1; 493 1.38 pooka } 494 1.38 pooka *dfdp = devfd; 495 1.22 pooka 496 1.38 pooka out: 497 1.38 pooka if (rv) { 498 1.38 pooka if (devfd != -1) 499 1.22 pooka close(devfd); 500 1.11 pooka } 501 1.1 pooka 502 1.38 pooka return rv; 503 1.38 pooka } 504 1.38 pooka 505 1.49 pooka struct mountinfo { 506 1.49 pooka const char *mi_vfsname; 507 1.49 pooka const char *mi_mountpath; 508 1.49 pooka int mi_mntflags; 509 1.49 pooka void *mi_arg; 510 1.49 pooka size_t mi_alen; 511 1.49 pooka int *mi_error; 512 1.49 pooka }; 513 1.49 pooka static void * 514 1.49 pooka mfs_mounter(void *arg) 515 1.49 pooka { 516 1.49 pooka struct mountinfo *mi = arg; 517 1.49 pooka int rv; 518 1.49 pooka 519 1.49 pooka rv = rump_sys_mount(mi->mi_vfsname, mi->mi_mountpath, mi->mi_mntflags, 520 1.49 pooka mi->mi_arg, mi->mi_alen); 521 1.49 pooka if (rv) { 522 1.49 pooka warn("mfs mount failed. fix me."); 523 1.49 pooka abort(); /* XXX */ 524 1.49 pooka } 525 1.49 pooka 526 1.49 pooka return NULL; 527 1.49 pooka } 528 1.49 pooka 529 1.38 pooka static struct ukfs * 530 1.43 pooka doukfsmount(const char *vfsname, const char *devpath, struct ukfs_part *part, 531 1.38 pooka const char *mountpath, int mntflags, void *arg, size_t alen) 532 1.38 pooka { 533 1.38 pooka struct ukfs *fs = NULL; 534 1.54 pooka struct lwp *curlwp; 535 1.39 pooka int rv = 0, devfd = -1; 536 1.38 pooka int mounted = 0; 537 1.38 pooka int regged = 0; 538 1.38 pooka 539 1.47 pooka pthread_spin_lock(&part->part_lck); 540 1.47 pooka part->part_refcount++; 541 1.47 pooka pthread_spin_unlock(&part->part_lck); 542 1.43 pooka if (part != ukfs_part_na) { 543 1.43 pooka if ((rv = process_diskdevice(devpath, part, 544 1.43 pooka mntflags & MNT_RDONLY, &devfd)) != 0) 545 1.43 pooka goto out; 546 1.43 pooka } 547 1.38 pooka 548 1.1 pooka fs = malloc(sizeof(struct ukfs)); 549 1.1 pooka if (fs == NULL) { 550 1.1 pooka rv = ENOMEM; 551 1.1 pooka goto out; 552 1.1 pooka } 553 1.1 pooka memset(fs, 0, sizeof(struct ukfs)); 554 1.30 pooka 555 1.30 pooka /* create our mountpoint. this is never removed. */ 556 1.30 pooka if (builddirs(mountpath, 0777, rumpmkdir, NULL) == -1) { 557 1.30 pooka if (errno != EEXIST) { 558 1.30 pooka rv = errno; 559 1.30 pooka goto out; 560 1.30 pooka } 561 1.30 pooka } 562 1.1 pooka 563 1.43 pooka if (part != ukfs_part_na) { 564 1.43 pooka /* LINTED */ 565 1.40 pooka rv = rump_pub_etfs_register_withsize(devpath, devpath, 566 1.43 pooka RUMP_ETFS_BLK, part->part_devoff, part->part_devsize); 567 1.33 pooka if (rv) { 568 1.33 pooka goto out; 569 1.33 pooka } 570 1.33 pooka regged = 1; 571 1.33 pooka } 572 1.38 pooka 573 1.49 pooka /* 574 1.49 pooka * MFS is special since mount(2) doesn't return. Hence, we 575 1.49 pooka * create a thread here. Could fix mfs to return, but there's 576 1.49 pooka * too much history for me to bother. 577 1.49 pooka */ 578 1.49 pooka if (strcmp(vfsname, MOUNT_MFS) == 0) { 579 1.49 pooka pthread_t pt; 580 1.49 pooka struct mountinfo mi; 581 1.49 pooka int i; 582 1.49 pooka 583 1.49 pooka mi.mi_vfsname = vfsname; 584 1.49 pooka mi.mi_mountpath = mountpath; 585 1.49 pooka mi.mi_mntflags = mntflags; 586 1.49 pooka mi.mi_arg = arg; 587 1.49 pooka mi.mi_alen = alen; 588 1.49 pooka 589 1.49 pooka if (pthread_create(&pt, NULL, mfs_mounter, &mi) == -1) { 590 1.49 pooka rv = errno; 591 1.49 pooka goto out; 592 1.49 pooka } 593 1.49 pooka 594 1.49 pooka for (i = 0;i < 100000; i++) { 595 1.49 pooka struct statvfs svfsb; 596 1.49 pooka 597 1.49 pooka rv = rump_sys_statvfs1(mountpath, &svfsb, ST_WAIT); 598 1.49 pooka if (rv == -1) { 599 1.49 pooka rv = errno; 600 1.49 pooka goto out; 601 1.49 pooka } 602 1.49 pooka 603 1.49 pooka if (strcmp(svfsb.f_mntonname, mountpath) == 0 && 604 1.49 pooka strcmp(svfsb.f_fstypename, MOUNT_MFS) == 0) { 605 1.49 pooka break; 606 1.49 pooka } 607 1.49 pooka usleep(1); 608 1.49 pooka } 609 1.49 pooka } else { 610 1.49 pooka rv = rump_sys_mount(vfsname, mountpath, mntflags, arg, alen); 611 1.49 pooka if (rv) { 612 1.49 pooka rv = errno; 613 1.49 pooka goto out; 614 1.49 pooka } 615 1.1 pooka } 616 1.49 pooka 617 1.30 pooka mounted = 1; 618 1.40 pooka rv = rump_pub_vfs_getmp(mountpath, &fs->ukfs_mp); 619 1.11 pooka if (rv) { 620 1.11 pooka goto out; 621 1.11 pooka } 622 1.30 pooka 623 1.33 pooka if (regged) { 624 1.33 pooka fs->ukfs_devpath = strdup(devpath); 625 1.33 pooka } 626 1.30 pooka fs->ukfs_mountpath = strdup(mountpath); 627 1.11 pooka pthread_spin_init(&fs->ukfs_spin, PTHREAD_PROCESS_SHARED); 628 1.11 pooka fs->ukfs_devfd = devfd; 629 1.45 pooka fs->ukfs_part = part; 630 1.11 pooka assert(rv == 0); 631 1.1 pooka 632 1.54 pooka curlwp = rump_pub_lwproc_curlwp(); 633 1.54 pooka rump_pub_lwproc_newlwp(0); 634 1.54 pooka fs->ukfs_lwp = rump_pub_lwproc_curlwp(); 635 1.54 pooka fs->ukfs_cwd = strdup("/"); 636 1.54 pooka rump_pub_lwproc_switch(curlwp); 637 1.54 pooka 638 1.1 pooka out: 639 1.1 pooka if (rv) { 640 1.30 pooka if (fs) { 641 1.1 pooka free(fs); 642 1.30 pooka fs = NULL; 643 1.30 pooka } 644 1.30 pooka if (mounted) 645 1.30 pooka rump_sys_unmount(mountpath, MNT_FORCE); 646 1.33 pooka if (regged) 647 1.40 pooka rump_pub_etfs_remove(devpath); 648 1.11 pooka if (devfd != -1) { 649 1.46 pooka unlockdev(devfd, part); 650 1.11 pooka close(devfd); 651 1.11 pooka } 652 1.45 pooka ukfs_part_release(part); 653 1.34 pooka errno = rv; 654 1.1 pooka } 655 1.1 pooka 656 1.1 pooka return fs; 657 1.1 pooka } 658 1.1 pooka 659 1.38 pooka struct ukfs * 660 1.38 pooka ukfs_mount(const char *vfsname, const char *devpath, 661 1.38 pooka const char *mountpath, int mntflags, void *arg, size_t alen) 662 1.38 pooka { 663 1.38 pooka 664 1.43 pooka return doukfsmount(vfsname, devpath, ukfs_part_na, 665 1.38 pooka mountpath, mntflags, arg, alen); 666 1.38 pooka } 667 1.38 pooka 668 1.38 pooka struct ukfs * 669 1.43 pooka ukfs_mount_disk(const char *vfsname, const char *devpath, 670 1.43 pooka struct ukfs_part *part, const char *mountpath, int mntflags, 671 1.43 pooka void *arg, size_t alen) 672 1.38 pooka { 673 1.38 pooka 674 1.43 pooka return doukfsmount(vfsname, devpath, part, 675 1.38 pooka mountpath, mntflags, arg, alen); 676 1.38 pooka } 677 1.38 pooka 678 1.30 pooka int 679 1.1 pooka ukfs_release(struct ukfs *fs, int flags) 680 1.1 pooka { 681 1.54 pooka struct lwp *curlwp = rump_pub_lwproc_curlwp(); 682 1.54 pooka 683 1.54 pooka /* get root lwp */ 684 1.54 pooka rump_pub_lwproc_switch(fs->ukfs_lwp); 685 1.56 pooka rump_pub_lwproc_rfork(RUMP_RFCFDG); 686 1.1 pooka 687 1.1 pooka if ((flags & UKFS_RELFLAG_NOUNMOUNT) == 0) { 688 1.37 pooka int rv, mntflag, error; 689 1.9 pooka 690 1.30 pooka mntflag = 0; 691 1.30 pooka if (flags & UKFS_RELFLAG_FORCE) 692 1.30 pooka mntflag = MNT_FORCE; 693 1.54 pooka 694 1.30 pooka rv = rump_sys_unmount(fs->ukfs_mountpath, mntflag); 695 1.37 pooka if (rv == -1) { 696 1.37 pooka error = errno; 697 1.53 pooka rump_pub_lwproc_releaselwp(); 698 1.54 pooka if (curlwp) 699 1.54 pooka rump_pub_lwproc_switch(curlwp); 700 1.37 pooka errno = error; 701 1.30 pooka return -1; 702 1.30 pooka } 703 1.1 pooka } 704 1.1 pooka 705 1.33 pooka if (fs->ukfs_devpath) { 706 1.40 pooka rump_pub_etfs_remove(fs->ukfs_devpath); 707 1.33 pooka free(fs->ukfs_devpath); 708 1.33 pooka } 709 1.30 pooka free(fs->ukfs_mountpath); 710 1.54 pooka free(fs->ukfs_cwd); 711 1.54 pooka 712 1.54 pooka /* release this routine's lwp and ukfs base lwp */ 713 1.54 pooka rump_pub_lwproc_releaselwp(); 714 1.54 pooka rump_pub_lwproc_switch(fs->ukfs_lwp); 715 1.54 pooka rump_pub_lwproc_releaselwp(); 716 1.1 pooka 717 1.1 pooka pthread_spin_destroy(&fs->ukfs_spin); 718 1.16 stacktic if (fs->ukfs_devfd != -1) { 719 1.45 pooka unlockdev(fs->ukfs_devfd, fs->ukfs_part); 720 1.16 stacktic close(fs->ukfs_devfd); 721 1.16 stacktic } 722 1.47 pooka ukfs_part_release(fs->ukfs_part); 723 1.1 pooka free(fs); 724 1.30 pooka 725 1.54 pooka if (curlwp) 726 1.54 pooka rump_pub_lwproc_switch(curlwp); 727 1.54 pooka 728 1.30 pooka return 0; 729 1.1 pooka } 730 1.1 pooka 731 1.43 pooka void 732 1.43 pooka ukfs_part_release(struct ukfs_part *part) 733 1.43 pooka { 734 1.47 pooka int release; 735 1.43 pooka 736 1.47 pooka if (part != ukfs_part_none && part != ukfs_part_na) { 737 1.47 pooka pthread_spin_lock(&part->part_lck); 738 1.47 pooka release = --part->part_refcount == 0; 739 1.47 pooka pthread_spin_unlock(&part->part_lck); 740 1.47 pooka if (release) { 741 1.47 pooka pthread_spin_destroy(&part->part_lck); 742 1.47 pooka free(part); 743 1.47 pooka } 744 1.47 pooka } 745 1.43 pooka } 746 1.43 pooka 747 1.1 pooka #define STDCALL(ukfs, thecall) \ 748 1.1 pooka int rv = 0; \ 749 1.1 pooka \ 750 1.54 pooka PRECALL(); \ 751 1.21 pooka rv = thecall; \ 752 1.54 pooka POSTCALL(); \ 753 1.21 pooka return rv; 754 1.1 pooka 755 1.1 pooka int 756 1.24 pooka ukfs_opendir(struct ukfs *ukfs, const char *dirname, struct ukfs_dircookie **c) 757 1.1 pooka { 758 1.1 pooka struct vnode *vp; 759 1.24 pooka int rv; 760 1.1 pooka 761 1.54 pooka PRECALL(); 762 1.40 pooka rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, RUMP_NAMEI_LOCKLEAF, dirname, 763 1.1 pooka NULL, &vp, NULL); 764 1.54 pooka POSTCALL(); 765 1.24 pooka 766 1.24 pooka if (rv == 0) { 767 1.51 hannken RUMP_VOP_UNLOCK(vp); 768 1.24 pooka } else { 769 1.24 pooka errno = rv; 770 1.24 pooka rv = -1; 771 1.24 pooka } 772 1.24 pooka 773 1.24 pooka /*LINTED*/ 774 1.24 pooka *c = (struct ukfs_dircookie *)vp; 775 1.24 pooka return rv; 776 1.24 pooka } 777 1.24 pooka 778 1.24 pooka static int 779 1.24 pooka getmydents(struct vnode *vp, off_t *off, uint8_t *buf, size_t bufsize) 780 1.24 pooka { 781 1.24 pooka struct uio *uio; 782 1.24 pooka size_t resid; 783 1.24 pooka int rv, eofflag; 784 1.50 pooka struct kauth_cred *cred; 785 1.24 pooka 786 1.40 pooka uio = rump_pub_uio_setup(buf, bufsize, *off, RUMPUIO_READ); 787 1.53 pooka cred = rump_pub_cred_create(0, 0, 0, NULL); 788 1.9 pooka rv = RUMP_VOP_READDIR(vp, uio, cred, &eofflag, NULL, NULL); 789 1.40 pooka rump_pub_cred_put(cred); 790 1.51 hannken RUMP_VOP_UNLOCK(vp); 791 1.40 pooka *off = rump_pub_uio_getoff(uio); 792 1.40 pooka resid = rump_pub_uio_free(uio); 793 1.1 pooka 794 1.1 pooka if (rv) { 795 1.1 pooka errno = rv; 796 1.1 pooka return -1; 797 1.1 pooka } 798 1.1 pooka 799 1.1 pooka /* LINTED: not totally correct return type, but follows syscall */ 800 1.1 pooka return bufsize - resid; 801 1.1 pooka } 802 1.1 pooka 803 1.24 pooka /*ARGSUSED*/ 804 1.24 pooka int 805 1.24 pooka ukfs_getdents_cookie(struct ukfs *ukfs, struct ukfs_dircookie *c, off_t *off, 806 1.24 pooka uint8_t *buf, size_t bufsize) 807 1.24 pooka { 808 1.24 pooka /*LINTED*/ 809 1.24 pooka struct vnode *vp = (struct vnode *)c; 810 1.24 pooka 811 1.24 pooka RUMP_VOP_LOCK(vp, RUMP_LK_SHARED); 812 1.24 pooka return getmydents(vp, off, buf, bufsize); 813 1.24 pooka } 814 1.24 pooka 815 1.24 pooka int 816 1.24 pooka ukfs_getdents(struct ukfs *ukfs, const char *dirname, off_t *off, 817 1.24 pooka uint8_t *buf, size_t bufsize) 818 1.24 pooka { 819 1.24 pooka struct vnode *vp; 820 1.24 pooka int rv; 821 1.24 pooka 822 1.54 pooka PRECALL(); 823 1.40 pooka rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, RUMP_NAMEI_LOCKLEAF, dirname, 824 1.24 pooka NULL, &vp, NULL); 825 1.24 pooka if (rv) { 826 1.54 pooka POSTCALL(); 827 1.24 pooka errno = rv; 828 1.24 pooka return -1; 829 1.24 pooka } 830 1.24 pooka 831 1.24 pooka rv = getmydents(vp, off, buf, bufsize); 832 1.40 pooka rump_pub_vp_rele(vp); 833 1.54 pooka POSTCALL(); 834 1.24 pooka return rv; 835 1.24 pooka } 836 1.24 pooka 837 1.24 pooka /*ARGSUSED*/ 838 1.24 pooka int 839 1.24 pooka ukfs_closedir(struct ukfs *ukfs, struct ukfs_dircookie *c) 840 1.24 pooka { 841 1.24 pooka 842 1.24 pooka /*LINTED*/ 843 1.40 pooka rump_pub_vp_rele((struct vnode *)c); 844 1.24 pooka return 0; 845 1.24 pooka } 846 1.24 pooka 847 1.24 pooka int 848 1.24 pooka ukfs_open(struct ukfs *ukfs, const char *filename, int flags) 849 1.24 pooka { 850 1.24 pooka int fd; 851 1.24 pooka 852 1.54 pooka PRECALL(); 853 1.24 pooka fd = rump_sys_open(filename, flags, 0); 854 1.54 pooka POSTCALL(); 855 1.24 pooka if (fd == -1) 856 1.24 pooka return -1; 857 1.24 pooka 858 1.24 pooka return fd; 859 1.24 pooka } 860 1.24 pooka 861 1.1 pooka ssize_t 862 1.1 pooka ukfs_read(struct ukfs *ukfs, const char *filename, off_t off, 863 1.1 pooka uint8_t *buf, size_t bufsize) 864 1.1 pooka { 865 1.21 pooka int fd; 866 1.1 pooka ssize_t xfer = -1; /* XXXgcc */ 867 1.1 pooka 868 1.54 pooka PRECALL(); 869 1.21 pooka fd = rump_sys_open(filename, RUMP_O_RDONLY, 0); 870 1.21 pooka if (fd == -1) 871 1.1 pooka goto out; 872 1.1 pooka 873 1.27 pooka xfer = rump_sys_pread(fd, buf, bufsize, off); 874 1.21 pooka rump_sys_close(fd); 875 1.1 pooka 876 1.1 pooka out: 877 1.54 pooka POSTCALL(); 878 1.21 pooka if (fd == -1) { 879 1.1 pooka return -1; 880 1.1 pooka } 881 1.1 pooka return xfer; 882 1.1 pooka } 883 1.1 pooka 884 1.24 pooka /*ARGSUSED*/ 885 1.24 pooka ssize_t 886 1.24 pooka ukfs_read_fd(struct ukfs *ukfs, int fd, off_t off, uint8_t *buf, size_t buflen) 887 1.24 pooka { 888 1.24 pooka 889 1.27 pooka return rump_sys_pread(fd, buf, buflen, off); 890 1.24 pooka } 891 1.24 pooka 892 1.1 pooka ssize_t 893 1.1 pooka ukfs_write(struct ukfs *ukfs, const char *filename, off_t off, 894 1.1 pooka uint8_t *buf, size_t bufsize) 895 1.1 pooka { 896 1.21 pooka int fd; 897 1.1 pooka ssize_t xfer = -1; /* XXXgcc */ 898 1.1 pooka 899 1.54 pooka PRECALL(); 900 1.21 pooka fd = rump_sys_open(filename, RUMP_O_WRONLY, 0); 901 1.21 pooka if (fd == -1) 902 1.1 pooka goto out; 903 1.1 pooka 904 1.1 pooka /* write and commit */ 905 1.27 pooka xfer = rump_sys_pwrite(fd, buf, bufsize, off); 906 1.21 pooka if (xfer > 0) 907 1.21 pooka rump_sys_fsync(fd); 908 1.1 pooka 909 1.21 pooka rump_sys_close(fd); 910 1.1 pooka 911 1.1 pooka out: 912 1.54 pooka POSTCALL(); 913 1.21 pooka if (fd == -1) { 914 1.1 pooka return -1; 915 1.1 pooka } 916 1.1 pooka return xfer; 917 1.1 pooka } 918 1.1 pooka 919 1.24 pooka /*ARGSUSED*/ 920 1.24 pooka ssize_t 921 1.24 pooka ukfs_write_fd(struct ukfs *ukfs, int fd, off_t off, uint8_t *buf, size_t buflen, 922 1.24 pooka int dosync) 923 1.24 pooka { 924 1.24 pooka ssize_t xfer; 925 1.24 pooka 926 1.27 pooka xfer = rump_sys_pwrite(fd, buf, buflen, off); 927 1.24 pooka if (xfer > 0 && dosync) 928 1.24 pooka rump_sys_fsync(fd); 929 1.24 pooka 930 1.24 pooka return xfer; 931 1.24 pooka } 932 1.24 pooka 933 1.24 pooka /*ARGSUSED*/ 934 1.24 pooka int 935 1.24 pooka ukfs_close(struct ukfs *ukfs, int fd) 936 1.24 pooka { 937 1.24 pooka 938 1.24 pooka rump_sys_close(fd); 939 1.24 pooka return 0; 940 1.24 pooka } 941 1.24 pooka 942 1.1 pooka int 943 1.1 pooka ukfs_create(struct ukfs *ukfs, const char *filename, mode_t mode) 944 1.1 pooka { 945 1.21 pooka int fd; 946 1.1 pooka 947 1.54 pooka PRECALL(); 948 1.21 pooka fd = rump_sys_open(filename, RUMP_O_WRONLY | RUMP_O_CREAT, mode); 949 1.21 pooka if (fd == -1) 950 1.21 pooka return -1; 951 1.21 pooka rump_sys_close(fd); 952 1.1 pooka 953 1.54 pooka POSTCALL(); 954 1.1 pooka return 0; 955 1.1 pooka } 956 1.1 pooka 957 1.1 pooka int 958 1.1 pooka ukfs_mknod(struct ukfs *ukfs, const char *path, mode_t mode, dev_t dev) 959 1.1 pooka { 960 1.1 pooka 961 1.21 pooka STDCALL(ukfs, rump_sys_mknod(path, mode, dev)); 962 1.1 pooka } 963 1.1 pooka 964 1.1 pooka int 965 1.1 pooka ukfs_mkfifo(struct ukfs *ukfs, const char *path, mode_t mode) 966 1.1 pooka { 967 1.1 pooka 968 1.21 pooka STDCALL(ukfs, rump_sys_mkfifo(path, mode)); 969 1.1 pooka } 970 1.1 pooka 971 1.1 pooka int 972 1.1 pooka ukfs_mkdir(struct ukfs *ukfs, const char *filename, mode_t mode) 973 1.1 pooka { 974 1.1 pooka 975 1.21 pooka STDCALL(ukfs, rump_sys_mkdir(filename, mode)); 976 1.1 pooka } 977 1.1 pooka 978 1.1 pooka int 979 1.1 pooka ukfs_remove(struct ukfs *ukfs, const char *filename) 980 1.1 pooka { 981 1.1 pooka 982 1.21 pooka STDCALL(ukfs, rump_sys_unlink(filename)); 983 1.1 pooka } 984 1.1 pooka 985 1.1 pooka int 986 1.1 pooka ukfs_rmdir(struct ukfs *ukfs, const char *filename) 987 1.1 pooka { 988 1.1 pooka 989 1.21 pooka STDCALL(ukfs, rump_sys_rmdir(filename)); 990 1.1 pooka } 991 1.1 pooka 992 1.1 pooka int 993 1.1 pooka ukfs_link(struct ukfs *ukfs, const char *filename, const char *f_create) 994 1.1 pooka { 995 1.1 pooka 996 1.21 pooka STDCALL(ukfs, rump_sys_link(filename, f_create)); 997 1.1 pooka } 998 1.1 pooka 999 1.1 pooka int 1000 1.1 pooka ukfs_symlink(struct ukfs *ukfs, const char *filename, const char *linkname) 1001 1.1 pooka { 1002 1.1 pooka 1003 1.21 pooka STDCALL(ukfs, rump_sys_symlink(filename, linkname)); 1004 1.1 pooka } 1005 1.1 pooka 1006 1.1 pooka ssize_t 1007 1.1 pooka ukfs_readlink(struct ukfs *ukfs, const char *filename, 1008 1.1 pooka char *linkbuf, size_t buflen) 1009 1.1 pooka { 1010 1.1 pooka ssize_t rv; 1011 1.1 pooka 1012 1.54 pooka PRECALL(); 1013 1.21 pooka rv = rump_sys_readlink(filename, linkbuf, buflen); 1014 1.54 pooka POSTCALL(); 1015 1.1 pooka return rv; 1016 1.1 pooka } 1017 1.1 pooka 1018 1.1 pooka int 1019 1.1 pooka ukfs_rename(struct ukfs *ukfs, const char *from, const char *to) 1020 1.1 pooka { 1021 1.1 pooka 1022 1.21 pooka STDCALL(ukfs, rump_sys_rename(from, to)); 1023 1.1 pooka } 1024 1.1 pooka 1025 1.1 pooka int 1026 1.1 pooka ukfs_chdir(struct ukfs *ukfs, const char *path) 1027 1.1 pooka { 1028 1.54 pooka char *newpath, *oldpath; 1029 1.1 pooka int rv; 1030 1.1 pooka 1031 1.54 pooka PRECALL(); 1032 1.21 pooka rv = rump_sys_chdir(path); 1033 1.21 pooka if (rv == -1) 1034 1.1 pooka goto out; 1035 1.1 pooka 1036 1.54 pooka newpath = malloc(MAXPATHLEN); 1037 1.54 pooka if (rump_sys___getcwd(newpath, MAXPATHLEN) == -1) { 1038 1.54 pooka goto out; 1039 1.54 pooka } 1040 1.54 pooka 1041 1.1 pooka pthread_spin_lock(&ukfs->ukfs_spin); 1042 1.54 pooka oldpath = ukfs->ukfs_cwd; 1043 1.54 pooka ukfs->ukfs_cwd = newpath; 1044 1.1 pooka pthread_spin_unlock(&ukfs->ukfs_spin); 1045 1.54 pooka free(oldpath); 1046 1.1 pooka 1047 1.1 pooka out: 1048 1.54 pooka POSTCALL(); 1049 1.21 pooka return rv; 1050 1.1 pooka } 1051 1.1 pooka 1052 1.1 pooka int 1053 1.1 pooka ukfs_stat(struct ukfs *ukfs, const char *filename, struct stat *file_stat) 1054 1.1 pooka { 1055 1.28 pooka int rv; 1056 1.1 pooka 1057 1.54 pooka PRECALL(); 1058 1.52 pooka rv = rump_sys_stat(filename, file_stat); 1059 1.54 pooka POSTCALL(); 1060 1.28 pooka 1061 1.28 pooka return rv; 1062 1.1 pooka } 1063 1.1 pooka 1064 1.1 pooka int 1065 1.1 pooka ukfs_lstat(struct ukfs *ukfs, const char *filename, struct stat *file_stat) 1066 1.1 pooka { 1067 1.28 pooka int rv; 1068 1.1 pooka 1069 1.54 pooka PRECALL(); 1070 1.52 pooka rv = rump_sys_lstat(filename, file_stat); 1071 1.54 pooka POSTCALL(); 1072 1.28 pooka 1073 1.28 pooka return rv; 1074 1.1 pooka } 1075 1.1 pooka 1076 1.1 pooka int 1077 1.1 pooka ukfs_chmod(struct ukfs *ukfs, const char *filename, mode_t mode) 1078 1.1 pooka { 1079 1.1 pooka 1080 1.21 pooka STDCALL(ukfs, rump_sys_chmod(filename, mode)); 1081 1.1 pooka } 1082 1.1 pooka 1083 1.1 pooka int 1084 1.1 pooka ukfs_lchmod(struct ukfs *ukfs, const char *filename, mode_t mode) 1085 1.1 pooka { 1086 1.1 pooka 1087 1.21 pooka STDCALL(ukfs, rump_sys_lchmod(filename, mode)); 1088 1.1 pooka } 1089 1.1 pooka 1090 1.1 pooka int 1091 1.1 pooka ukfs_chown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid) 1092 1.1 pooka { 1093 1.1 pooka 1094 1.21 pooka STDCALL(ukfs, rump_sys_chown(filename, uid, gid)); 1095 1.1 pooka } 1096 1.1 pooka 1097 1.1 pooka int 1098 1.1 pooka ukfs_lchown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid) 1099 1.1 pooka { 1100 1.1 pooka 1101 1.21 pooka STDCALL(ukfs, rump_sys_lchown(filename, uid, gid)); 1102 1.1 pooka } 1103 1.1 pooka 1104 1.1 pooka int 1105 1.1 pooka ukfs_chflags(struct ukfs *ukfs, const char *filename, u_long flags) 1106 1.1 pooka { 1107 1.1 pooka 1108 1.21 pooka STDCALL(ukfs, rump_sys_chflags(filename, flags)); 1109 1.1 pooka } 1110 1.1 pooka 1111 1.1 pooka int 1112 1.1 pooka ukfs_lchflags(struct ukfs *ukfs, const char *filename, u_long flags) 1113 1.1 pooka { 1114 1.1 pooka 1115 1.21 pooka STDCALL(ukfs, rump_sys_lchflags(filename, flags)); 1116 1.1 pooka } 1117 1.1 pooka 1118 1.1 pooka int 1119 1.1 pooka ukfs_utimes(struct ukfs *ukfs, const char *filename, const struct timeval *tptr) 1120 1.1 pooka { 1121 1.1 pooka 1122 1.21 pooka STDCALL(ukfs, rump_sys_utimes(filename, tptr)); 1123 1.1 pooka } 1124 1.1 pooka 1125 1.1 pooka int 1126 1.1 pooka ukfs_lutimes(struct ukfs *ukfs, const char *filename, 1127 1.1 pooka const struct timeval *tptr) 1128 1.1 pooka { 1129 1.1 pooka 1130 1.21 pooka STDCALL(ukfs, rump_sys_lutimes(filename, tptr)); 1131 1.1 pooka } 1132 1.1 pooka 1133 1.3 pooka /* 1134 1.3 pooka * Dynamic module support 1135 1.3 pooka */ 1136 1.3 pooka 1137 1.3 pooka /* load one library */ 1138 1.3 pooka 1139 1.3 pooka /* 1140 1.3 pooka * XXX: the dlerror stuff isn't really threadsafe, but then again I 1141 1.3 pooka * can't protect against other threads calling dl*() outside of ukfs, 1142 1.3 pooka * so just live with it being flimsy 1143 1.3 pooka */ 1144 1.3 pooka int 1145 1.3 pooka ukfs_modload(const char *fname) 1146 1.3 pooka { 1147 1.26 pooka void *handle; 1148 1.48 pooka const struct modinfo *const *mi_start, *const *mi_end; 1149 1.3 pooka int error; 1150 1.3 pooka 1151 1.42 njoly handle = dlopen(fname, RTLD_LAZY|RTLD_GLOBAL); 1152 1.3 pooka if (handle == NULL) { 1153 1.13 pooka const char *dlmsg = dlerror(); 1154 1.13 pooka if (strstr(dlmsg, "Undefined symbol")) 1155 1.3 pooka return 0; 1156 1.58 christos warnx("dlopen %s failed: %s", fname, dlmsg); 1157 1.3 pooka /* XXXerrno */ 1158 1.3 pooka return -1; 1159 1.3 pooka } 1160 1.3 pooka 1161 1.48 pooka mi_start = dlsym(handle, "__start_link_set_modules"); 1162 1.48 pooka mi_end = dlsym(handle, "__stop_link_set_modules"); 1163 1.48 pooka if (mi_start && mi_end) { 1164 1.48 pooka error = rump_pub_module_init(mi_start, 1165 1.48 pooka (size_t)(mi_end-mi_start)); 1166 1.3 pooka if (error) 1167 1.3 pooka goto errclose; 1168 1.3 pooka return 1; 1169 1.3 pooka } 1170 1.3 pooka error = EINVAL; 1171 1.3 pooka 1172 1.3 pooka errclose: 1173 1.3 pooka dlclose(handle); 1174 1.3 pooka errno = error; 1175 1.3 pooka return -1; 1176 1.3 pooka } 1177 1.3 pooka 1178 1.3 pooka struct loadfail { 1179 1.3 pooka char *pname; 1180 1.3 pooka 1181 1.3 pooka LIST_ENTRY(loadfail) entries; 1182 1.3 pooka }; 1183 1.3 pooka 1184 1.3 pooka #define RUMPFSMOD_PREFIX "librumpfs_" 1185 1.3 pooka #define RUMPFSMOD_SUFFIX ".so" 1186 1.3 pooka 1187 1.3 pooka int 1188 1.3 pooka ukfs_modload_dir(const char *dir) 1189 1.3 pooka { 1190 1.3 pooka char nbuf[MAXPATHLEN+1], *p; 1191 1.3 pooka struct dirent entry, *result; 1192 1.3 pooka DIR *libdir; 1193 1.3 pooka struct loadfail *lf, *nlf; 1194 1.3 pooka int error, nloaded = 0, redo; 1195 1.3 pooka LIST_HEAD(, loadfail) lfs; 1196 1.3 pooka 1197 1.3 pooka libdir = opendir(dir); 1198 1.3 pooka if (libdir == NULL) 1199 1.3 pooka return -1; 1200 1.3 pooka 1201 1.3 pooka LIST_INIT(&lfs); 1202 1.3 pooka for (;;) { 1203 1.3 pooka if ((error = readdir_r(libdir, &entry, &result)) != 0) 1204 1.3 pooka break; 1205 1.3 pooka if (!result) 1206 1.3 pooka break; 1207 1.3 pooka if (strncmp(result->d_name, RUMPFSMOD_PREFIX, 1208 1.3 pooka strlen(RUMPFSMOD_PREFIX)) != 0) 1209 1.3 pooka continue; 1210 1.3 pooka if (((p = strstr(result->d_name, RUMPFSMOD_SUFFIX)) == NULL) 1211 1.3 pooka || strlen(p) != strlen(RUMPFSMOD_SUFFIX)) 1212 1.3 pooka continue; 1213 1.3 pooka strlcpy(nbuf, dir, sizeof(nbuf)); 1214 1.3 pooka strlcat(nbuf, "/", sizeof(nbuf)); 1215 1.3 pooka strlcat(nbuf, result->d_name, sizeof(nbuf)); 1216 1.3 pooka switch (ukfs_modload(nbuf)) { 1217 1.3 pooka case 0: 1218 1.3 pooka lf = malloc(sizeof(*lf)); 1219 1.3 pooka if (lf == NULL) { 1220 1.3 pooka error = ENOMEM; 1221 1.3 pooka break; 1222 1.3 pooka } 1223 1.3 pooka lf->pname = strdup(nbuf); 1224 1.3 pooka if (lf->pname == NULL) { 1225 1.3 pooka free(lf); 1226 1.3 pooka error = ENOMEM; 1227 1.3 pooka break; 1228 1.3 pooka } 1229 1.3 pooka LIST_INSERT_HEAD(&lfs, lf, entries); 1230 1.3 pooka break; 1231 1.3 pooka case 1: 1232 1.3 pooka nloaded++; 1233 1.3 pooka break; 1234 1.3 pooka default: 1235 1.3 pooka /* ignore errors */ 1236 1.3 pooka break; 1237 1.3 pooka } 1238 1.3 pooka } 1239 1.3 pooka closedir(libdir); 1240 1.3 pooka if (error && nloaded != 0) 1241 1.3 pooka error = 0; 1242 1.3 pooka 1243 1.3 pooka /* 1244 1.3 pooka * El-cheapo dependency calculator. Just try to load the 1245 1.3 pooka * modules n times in a loop 1246 1.3 pooka */ 1247 1.3 pooka for (redo = 1; redo;) { 1248 1.3 pooka redo = 0; 1249 1.3 pooka nlf = LIST_FIRST(&lfs); 1250 1.3 pooka while ((lf = nlf) != NULL) { 1251 1.3 pooka nlf = LIST_NEXT(lf, entries); 1252 1.3 pooka if (ukfs_modload(lf->pname) == 1) { 1253 1.3 pooka nloaded++; 1254 1.3 pooka redo = 1; 1255 1.3 pooka LIST_REMOVE(lf, entries); 1256 1.3 pooka free(lf->pname); 1257 1.3 pooka free(lf); 1258 1.3 pooka } 1259 1.3 pooka } 1260 1.3 pooka } 1261 1.3 pooka 1262 1.3 pooka while ((lf = LIST_FIRST(&lfs)) != NULL) { 1263 1.3 pooka LIST_REMOVE(lf, entries); 1264 1.3 pooka free(lf->pname); 1265 1.3 pooka free(lf); 1266 1.3 pooka } 1267 1.3 pooka 1268 1.3 pooka if (error && nloaded == 0) { 1269 1.3 pooka errno = error; 1270 1.3 pooka return -1; 1271 1.3 pooka } 1272 1.3 pooka 1273 1.3 pooka return nloaded; 1274 1.3 pooka } 1275 1.3 pooka 1276 1.4 pooka /* XXX: this code uses definitions from NetBSD, needs rumpdefs */ 1277 1.4 pooka ssize_t 1278 1.4 pooka ukfs_vfstypes(char *buf, size_t buflen) 1279 1.4 pooka { 1280 1.4 pooka int mib[3]; 1281 1.4 pooka struct sysctlnode q, ans[128]; 1282 1.4 pooka size_t alen; 1283 1.21 pooka int i; 1284 1.4 pooka 1285 1.4 pooka mib[0] = CTL_VFS; 1286 1.4 pooka mib[1] = VFS_GENERIC; 1287 1.4 pooka mib[2] = CTL_QUERY; 1288 1.4 pooka alen = sizeof(ans); 1289 1.4 pooka 1290 1.4 pooka memset(&q, 0, sizeof(q)); 1291 1.4 pooka q.sysctl_flags = SYSCTL_VERSION; 1292 1.4 pooka 1293 1.21 pooka if (rump_sys___sysctl(mib, 3, ans, &alen, &q, sizeof(q)) == -1) { 1294 1.4 pooka return -1; 1295 1.4 pooka } 1296 1.4 pooka 1297 1.4 pooka for (i = 0; i < alen/sizeof(ans[0]); i++) 1298 1.4 pooka if (strcmp("fstypes", ans[i].sysctl_name) == 0) 1299 1.4 pooka break; 1300 1.4 pooka if (i == alen/sizeof(ans[0])) { 1301 1.4 pooka errno = ENXIO; 1302 1.4 pooka return -1; 1303 1.4 pooka } 1304 1.4 pooka 1305 1.4 pooka mib[0] = CTL_VFS; 1306 1.4 pooka mib[1] = VFS_GENERIC; 1307 1.4 pooka mib[2] = ans[i].sysctl_num; 1308 1.4 pooka 1309 1.21 pooka if (rump_sys___sysctl(mib, 3, buf, &buflen, NULL, 0) == -1) { 1310 1.4 pooka return -1; 1311 1.4 pooka } 1312 1.4 pooka 1313 1.4 pooka return buflen; 1314 1.4 pooka } 1315 1.3 pooka 1316 1.3 pooka /* 1317 1.3 pooka * Utilities 1318 1.3 pooka */ 1319 1.30 pooka static int 1320 1.30 pooka builddirs(const char *pathname, mode_t mode, 1321 1.30 pooka int (*mkdirfn)(struct ukfs *, const char *, mode_t), struct ukfs *fs) 1322 1.1 pooka { 1323 1.1 pooka char *f1, *f2; 1324 1.1 pooka int rv; 1325 1.1 pooka mode_t mask; 1326 1.1 pooka bool end; 1327 1.1 pooka 1328 1.1 pooka /*ukfs_umask((mask = ukfs_umask(0)));*/ 1329 1.1 pooka umask((mask = umask(0))); 1330 1.1 pooka 1331 1.1 pooka f1 = f2 = strdup(pathname); 1332 1.1 pooka if (f1 == NULL) { 1333 1.1 pooka errno = ENOMEM; 1334 1.1 pooka return -1; 1335 1.1 pooka } 1336 1.1 pooka 1337 1.1 pooka end = false; 1338 1.1 pooka for (;;) { 1339 1.1 pooka /* find next component */ 1340 1.1 pooka f2 += strspn(f2, "/"); 1341 1.1 pooka f2 += strcspn(f2, "/"); 1342 1.1 pooka if (*f2 == '\0') 1343 1.1 pooka end = true; 1344 1.1 pooka else 1345 1.1 pooka *f2 = '\0'; 1346 1.1 pooka 1347 1.30 pooka rv = mkdirfn(fs, f1, mode & ~mask); 1348 1.1 pooka if (errno == EEXIST) 1349 1.1 pooka rv = 0; 1350 1.1 pooka 1351 1.1 pooka if (rv == -1 || *f2 != '\0' || end) 1352 1.1 pooka break; 1353 1.1 pooka 1354 1.1 pooka *f2 = '/'; 1355 1.1 pooka } 1356 1.1 pooka 1357 1.1 pooka free(f1); 1358 1.1 pooka 1359 1.1 pooka return rv; 1360 1.1 pooka } 1361 1.30 pooka 1362 1.30 pooka int 1363 1.30 pooka ukfs_util_builddirs(struct ukfs *ukfs, const char *pathname, mode_t mode) 1364 1.30 pooka { 1365 1.30 pooka 1366 1.30 pooka return builddirs(pathname, mode, ukfs_mkdir, ukfs); 1367 1.30 pooka } 1368