1 /* 2 afuse - An automounter using FUSE 3 Copyright (C) 2008-2013 Jacob Bower <jacob.bower@gmail.com> 4 5 Portions of this program derive from examples provided with 6 FUSE-2.5.2. 7 8 This program can be distributed under the terms of the GNU GPL. 9 See the file COPYING. 10 */ 11 12 #include <config.h> 13 14 #ifdef linux 15 // For pread()/pwrite() 16 #define _XOPEN_SOURCE 500 17 // For getline() 18 #define _GNU_SOURCE 19 #endif 20 21 #include <fuse.h> 22 #include <fuse_opt.h> 23 #ifndef __USE_BSD 24 // for mkdtemp 25 #define __USE_BSD 26 #endif 27 #include <stdlib.h> 28 #include <stdio.h> 29 #include <string.h> 30 #include <stddef.h> 31 #include <unistd.h> 32 //#include <alloca.h> 33 #include <fcntl.h> 34 #include <dirent.h> 35 #include <errno.h> 36 #include <sys/wait.h> 37 #include <sys/types.h> 38 #include <sys/time.h> 39 #include <unistd.h> 40 #include <stdint.h> 41 #include <signal.h> 42 #include <fnmatch.h> 43 #ifdef HAVE_SETXATTR 44 #include <sys/xattr.h> 45 46 #if !HAVE_GETLINE && !HAVE_FGETLN 47 #error Need getline or fgetln 48 #endif 49 50 #ifdef XATTR_NOFOLLOW 51 #define lgetxattr(p, n, v, s) \ 52 getxattr(p, n, v, s, 0, XATTR_NOFOLLOW) 53 #define lsetxattr(p, n, v, s, f) \ 54 setxattr(p, n, v, s, 0, f | XATTR_NOFOLLOW) 55 #define llistxattr(p, list, s) \ 56 listxattr(p, list, s, XATTR_NOFOLLOW) 57 #define lremovexattr(p, n) \ 58 removexattr(p, n, XATTR_NOFOLLOW) 59 #endif /* XATTR_NOFOLLOW */ 60 #endif /* HAVE_SETXATTR */ 61 62 #include "fd_list.h" 63 #include "dir_list.h" 64 #include "string_sorted_list.h" 65 #include "utils.h" 66 67 #include "variable_pairing_heap.h" custom_drawing_get_drawable(CustomDrawing * cd)68 69 #define TMP_DIR_TEMPLATE "/tmp/afuse-XXXXXX" 70 static char *mount_point_directory; 71 static dev_t mount_point_dev; 72 73 // Data structure filled in when parsing command line args 74 struct user_options_t { 75 char *mount_command_template; 76 char *unmount_command_template; custom_drawing_get_gdk_drawable(CustomDrawing * cd)77 char *populate_root_command; 78 char *filter_file; 79 bool flush_writes; 80 bool exact_getattr; 81 uint64_t auto_unmount_delay; 82 } user_options = { 83 NULL, NULL, NULL, NULL, false, false, UINT64_MAX}; 84 85 typedef struct _mount_list_t { 86 struct _mount_list_t *next; 87 struct _mount_list_t *prev; 88 89 char *root_name; 90 char *mount_point; 91 fd_list_t *fd_list; 92 dir_list_t *dir_list; 93 94 PH_NEW_LINK(struct _mount_list_t) auto_unmount_ph_node; 95 /* This is the sort key for the auto_unmount_ph heap. It will 96 equal UINT64_MAX if this node is not in the heap. */ 97 int64_t auto_unmount_time; 98 } mount_list_t; 99 100 typedef struct _mount_filter_list_t { 101 struct _mount_filter_list_t *next; 102 103 char *pattern; 104 } mount_filter_list_t; 105 106 PH_DECLARE_TYPE(auto_unmount_ph, mount_list_t) 107 PH_DEFINE_TYPE(auto_unmount_ph, mount_list_t, auto_unmount_ph_node, 108 auto_unmount_time) 109 110 static mount_filter_list_t *mount_filter_list = NULL; 111 112 #define BLOCK_SIGALRM \ 113 sigset_t block_sigalrm_oldset, block_sigalrm_set; \ 114 sigemptyset(&block_sigalrm_set); \ 115 sigaddset(&block_sigalrm_set, SIGALRM); \ 116 sigprocmask(SIG_BLOCK, &block_sigalrm_set, &block_sigalrm_oldset) 117 118 #define UNBLOCK_SIGALRM \ 119 sigprocmask(SIG_SETMASK, &block_sigalrm_oldset, NULL) 120 121 #define DEFAULT_CASE_INVALID_ENUM \ 122 fprintf(stderr, "Unexpected switch value in %s:%s:%d\n", \ 123 __FILE__, __func__, __LINE__); \ 124 exit(1); 125 126 static auto_unmount_ph_t auto_unmount_ph; 127 static int64_t auto_unmount_next_timeout = INT64_MAX; 128 129 static void add_mount_filter(const char *glob) 130 { 131 mount_filter_list_t *new_entry; 132 133 new_entry = my_malloc(sizeof(mount_filter_list_t)); 134 new_entry->pattern = my_strdup(glob); 135 new_entry->next = mount_filter_list; 136 137 mount_filter_list = new_entry; 138 } 139 140 static int is_mount_filtered(const char *mount_point) 141 { 142 mount_filter_list_t *current_filter; 143 144 current_filter = mount_filter_list; 145 146 while (current_filter) { 147 if (!fnmatch(current_filter->pattern, mount_point, 0)) 148 return 1; 149 150 current_filter = current_filter->next; 151 } 152 153 return 0; 154 } 155 156 static void load_mount_filter_file(const char *filename) 157 { 158 FILE *filter_file; 159 if ((filter_file = fopen(filename, "r")) == NULL) { 160 fprintf(stderr, "Failed to open filter file '%s'\n", filename); 161 exit(1); 162 } 163 164 char *line = NULL; 165 ssize_t llen; 166 size_t lsize; 167 #ifdef HAVE_GETLINE 168 while ((llen = getline(&line, &lsize, filter_file)) != -1) 169 #else // HAVE_FGETLN 170 while (line = fgetln(filter_file, &llen)) 171 #endif 172 { 173 if (llen >= 1) { 174 if (line[0] == '#') 175 continue; 176 177 if (line[llen - 1] == '\n') { 178 line[llen - 1] = '\0'; 179 llen--; 180 } 181 } 182 183 if (llen > 0) 184 add_mount_filter(line); 185 } 186 187 free(line); 188 189 fclose(filter_file); 190 } 191 192 static int64_t from_timeval(const struct timeval *tv) 193 { 194 return (int64_t) tv->tv_sec * 1000000 + ((int64_t) tv->tv_usec); 195 } 196 197 static void to_timeval(struct timeval *tv, int64_t usec) 198 { 199 tv->tv_sec = usec / 1000000; 200 tv->tv_usec = usec % 1000000; 201 } 202 203 static int get_retval(int res) 204 { 205 if (res == -1) 206 return -errno; 207 return 0; 208 } 209 210 static int check_mount(mount_list_t * mount) 211 { 212 struct stat buf; 213 214 if (lstat(mount->mount_point, &buf) == -1) 215 return 0; 216 if (buf.st_dev == mount_point_dev) 217 return 0; 218 return 1; 219 } 220 221 static void update_auto_unmount(mount_list_t * mount) 222 { 223 if (user_options.auto_unmount_delay == UINT64_MAX) 224 return; 225 226 /* Get the current time */ 227 struct timeval tv; 228 mount_list_t *min_mount; 229 int64_t cur_time, next_time; 230 gettimeofday(&tv, NULL); 231 cur_time = from_timeval(&tv); 232 233 if (mount) { 234 /* Always remove first */ 235 if (mount->auto_unmount_time != INT64_MAX) 236 auto_unmount_ph_remove(&auto_unmount_ph, mount); 237 238 if (!mount->fd_list && !mount->dir_list) { 239 mount->auto_unmount_time = 240 cur_time + user_options.auto_unmount_delay; 241 auto_unmount_ph_insert(&auto_unmount_ph, mount); 242 } else { 243 mount->auto_unmount_time = INT64_MAX; 244 } 245 } 246 min_mount = auto_unmount_ph_min(&auto_unmount_ph); 247 next_time = min_mount ? min_mount->auto_unmount_time : INT64_MAX; 248 249 if (next_time != auto_unmount_next_timeout) { 250 struct itimerval itv; 251 auto_unmount_next_timeout = next_time; 252 253 if (next_time != INT64_MAX) { 254 if (next_time > cur_time) 255 to_timeval(&itv.it_value, next_time - cur_time); 256 else /* Timer is set to expire immediately --- set it to 1 instead */ 257 to_timeval(&itv.it_value, 1); 258 } else { 259 /* Disable the timer */ 260 to_timeval(&itv.it_value, 0); 261 } 262 to_timeval(&itv.it_interval, 0); 263 if (setitimer(ITIMER_REAL, &itv, NULL) != 0) { 264 perror("Error setting timer"); 265 } 266 } 267 } 268 269 int do_umount(mount_list_t * mount); 270 271 static void handle_auto_unmount_timer(int x) 272 { 273 (void)x; /* Ignored */ 274 /* Get the current time */ 275 struct timeval tv; 276 int64_t cur_time; 277 mount_list_t *mount; 278 gettimeofday(&tv, NULL); 279 cur_time = from_timeval(&tv); 280 281 while ((mount = auto_unmount_ph_min(&auto_unmount_ph)) != NULL && 282 mount->auto_unmount_time <= cur_time) { 283 do_umount(mount); 284 } 285 286 update_auto_unmount(NULL); 287 } 288 289 mount_list_t *mount_list = NULL; 290 291 mount_list_t *find_mount(const char *root_name) 292 { 293 mount_list_t *current_mount = mount_list; 294 295 while (current_mount) { 296 if (strcmp(root_name, current_mount->root_name) == 0) 297 return current_mount; 298 299 current_mount = current_mount->next; 300 } 301 302 return NULL; 303 } 304 305 int is_mount(const char *root_name) 306 { 307 return find_mount(root_name) ? 1 : 0; 308 } 309 310 mount_list_t *add_mount(const char *root_name, char *mount_point) 311 { 312 mount_list_t *new_mount; 313 314 new_mount = (mount_list_t *) my_malloc(sizeof(mount_list_t)); 315 new_mount->root_name = my_strdup(root_name); 316 new_mount->mount_point = mount_point; 317 318 new_mount->next = mount_list; 319 new_mount->prev = NULL; 320 new_mount->fd_list = NULL; 321 new_mount->dir_list = NULL; 322 new_mount->auto_unmount_time = INT64_MAX; 323 if (mount_list) 324 mount_list->prev = new_mount; 325 326 mount_list = new_mount; 327 328 update_auto_unmount(new_mount); 329 330 return new_mount; 331 } 332 333 void remove_mount(mount_list_t * current_mount) 334 { 335 if (current_mount->auto_unmount_time != INT64_MAX) 336 auto_unmount_ph_remove(&auto_unmount_ph, current_mount); 337 338 free(current_mount->root_name); 339 free(current_mount->mount_point); 340 if (current_mount->prev) 341 current_mount->prev->next = current_mount->next; 342 else 343 mount_list = current_mount->next; 344 if (current_mount->next) 345 current_mount->next->prev = current_mount->prev; 346 free(current_mount); 347 update_auto_unmount(NULL); 348 } 349 350 char *make_mount_point(const char *root_name) 351 { 352 char *dir_tmp; 353 354 // Create the mount point 355 dir_tmp = 356 my_malloc(strlen(mount_point_directory) + 2 + strlen(root_name)); 357 strcpy(dir_tmp, mount_point_directory); 358 strcat(dir_tmp, "/"); 359 strcat(dir_tmp, root_name); 360 361 if (mkdir(dir_tmp, 0700) == -1 && errno != EEXIST) { 362 fprintf(stderr, "Cannot create directory: %s (%s)\n", 363 dir_tmp, strerror(errno)); 364 free(dir_tmp); 365 return NULL; 366 } 367 return dir_tmp; 368 } 369 370 // Note: this method strips out quotes and applies them itself as should be appropriate 371 bool run_template(const char *template, const char *mount_point, 372 const char *root_name) 373 { 374 int len = 0; 375 int nargs = 1; 376 int i; 377 char *buf; 378 char *p; 379 char **args; 380 char **arg; 381 bool quote = false; 382 pid_t pid; 383 int status; 384 385 // calculate length 386 for (i = 0; template[i]; i++) 387 if (template[i] == '%') { 388 switch (template[i + 1]) { 389 case 'm': 390 len += strlen(mount_point); 391 i++; 392 break; 393 case 'r': 394 len += strlen(root_name); 395 i++; 396 break; 397 case '%': 398 len++; 399 i++; 400 break; 401 } 402 } else if (template[i] == ' ' && !quote) { 403 len++; 404 nargs++; 405 } else if (template[i] == '"') 406 quote = !quote; 407 else if (template[i] == '\\' && template[i + 1]) 408 len++, i++; 409 else 410 len++; 411 412 buf = my_malloc(len + 1); 413 args = my_malloc((nargs + 1) * sizeof(*args)); 414 415 p = buf; 416 arg = args; 417 *arg++ = p; 418 419 for (i = 0; template[i]; i++) 420 if (template[i] == '%') { 421 switch (template[i + 1]) { 422 case 'm': 423 strcpy(p, mount_point); 424 p += strlen(mount_point); 425 i++; 426 break; 427 case 'r': 428 strcpy(p, root_name); 429 p += strlen(root_name); 430 i++; 431 break; 432 case '%': 433 *p++ = '%'; 434 i++; 435 break; 436 } 437 } else if (template[i] == ' ' && !quote) { 438 *p++ = '\0'; 439 *arg++ = p; 440 } else if (template[i] == '"') 441 quote = !quote; 442 else if (template[i] == '\\' && template[i + 1]) 443 *p++ = template[++i]; 444 else 445 *p++ = template[i]; 446 447 *p = '\0'; 448 *arg = NULL; 449 450 pid = fork(); 451 if (pid == -1) { 452 fprintf(stderr, "Failed to fork (%s)\n", strerror(errno)); 453 free(args); 454 free(buf); 455 return false; 456 } 457 if (pid == 0) { 458 execvp(args[0], args); 459 abort(); 460 } 461 pid = waitpid(pid, &status, 0); 462 if (pid == -1) { 463 fprintf(stderr, "Failed to waitpid (%s)\n", strerror(errno)); 464 free(args); 465 free(buf); 466 return false; 467 } 468 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 469 fprintf(stderr, "Failed to invoke command: %s\n", args[0]); 470 free(args); 471 free(buf); 472 return false; 473 } 474 free(args); 475 free(buf); 476 return true; 477 } 478 479 mount_list_t *do_mount(const char *root_name) 480 { 481 char *mount_point; 482 mount_list_t *mount; 483 484 fprintf(stderr, "Mounting: %s\n", root_name); 485 486 if (!(mount_point = make_mount_point(root_name))) { 487 fprintf(stderr, 488 "Failed to create mount point directory: %s/%s\n", 489 mount_point_directory, root_name); 490 return NULL; 491 } 492 493 if (!run_template(user_options.mount_command_template, 494 mount_point, root_name)) { 495 // remove the now unused directory 496 if (rmdir(mount_point) == -1) 497 fprintf(stderr, 498 "Failed to remove mount point dir: %s (%s)", 499 mount_point, strerror(errno)); 500 501 free(mount_point); 502 return NULL; 503 } 504 505 mount = add_mount(root_name, mount_point); 506 return mount; 507 } 508 509 int do_umount(mount_list_t * mount) 510 { 511 fprintf(stderr, "Unmounting: %s\n", mount->root_name); 512 513 run_template(user_options.unmount_command_template, 514 mount->mount_point, mount->root_name); 515 /* Still unmount anyway */ 516 517 if (rmdir(mount->mount_point) == -1) 518 fprintf(stderr, "Failed to remove mount point dir: %s (%s)", 519 mount->mount_point, strerror(errno)); 520 remove_mount(mount); 521 return 1; 522 } 523 524 void unmount_all(void) 525 { 526 fprintf(stderr, "Attempting to unmount all filesystems:\n"); 527 528 while (mount_list) { 529 fprintf(stderr, "\tUnmounting: %s\n", mount_list->root_name); 530 531 do_umount(mount_list); 532 } 533 534 fprintf(stderr, "done.\n"); 535 } 536 537 void shutdown(void) 538 { 539 BLOCK_SIGALRM; 540 541 unmount_all(); 542 543 UNBLOCK_SIGALRM; 544 545 if (rmdir(mount_point_directory) == -1) 546 fprintf(stderr, 547 "Failed to remove temporary mount point directory: %s (%s)\n", 548 mount_point_directory, strerror(errno)); 549 } 550 551 int max_path_out_len(const char *path_in) 552 { 553 return strlen(mount_point_directory) + strlen(path_in) + 2; 554 } 555 556 // returns true if path is a child directory of a root node 557 // e.g. /a/b is a child, /a is not. 558 int extract_root_name(const char *path, char *root_name) 559 { 560 int i; 561 562 for (i = 1; path[i] && path[i] != '/'; i++) 563 root_name[i - 1] = path[i]; 564 root_name[i - 1] = '\0'; 565 566 return strlen(&path[i]); 567 } 568 569 typedef enum { 570 PROC_PATH_FAILED, 571 PROC_PATH_ROOT_DIR, 572 PROC_PATH_ROOT_SUBDIR, 573 PROC_PATH_PROXY_DIR 574 } proc_result_t; 575 576 proc_result_t process_path(const char *path_in, char *path_out, char *root_name, 577 int attempt_mount, mount_list_t ** out_mount) 578 { 579 char *path_out_base; 580 int is_child; 581 int len; 582 mount_list_t *mount = NULL; 583 584 *out_mount = NULL; 585 586 fprintf(stderr, "Path in: %s\n", path_in); 587 is_child = extract_root_name(path_in, root_name); 588 fprintf(stderr, "root_name is: %s\n", root_name); 589 590 if (is_mount_filtered(root_name)) 591 return PROC_PATH_FAILED; 592 593 // Mount filesystem if necessary 594 // the combination of is_child and attempt_mount prevent inappropriate 595 // mounting of a filesystem for example if the user tries to mknod 596 // in the afuse root this should cause an error not a mount. 597 // !!FIXME!! this is broken on FUSE < 2.5 (?) because a getattr 598 // on the root node seems to occur with every single access. 599 if ((is_child || attempt_mount) && 600 strlen(root_name) > 0 && 601 !(mount = find_mount(root_name)) && !(mount = do_mount(root_name))) 602 return PROC_PATH_FAILED; 603 604 if (mount && !check_mount(mount)) { 605 do_umount(mount); 606 mount = do_mount(root_name); 607 if (!mount) 608 return PROC_PATH_FAILED; 609 } 610 // construct path_out (mount_point_directory + '/' + path_in + '\0') 611 path_out_base = path_out; 612 len = strlen(mount_point_directory); 613 memcpy(path_out, mount_point_directory, len); 614 path_out += len; 615 *path_out++ = '/'; 616 len = strlen(path_in) - 1; 617 memcpy(path_out, path_in + 1, len); 618 path_out += len; 619 *path_out = '\0'; 620 fprintf(stderr, "Path out: %s\n", path_out_base); 621 622 *out_mount = mount; 623 624 if (is_child) 625 return PROC_PATH_PROXY_DIR; 626 else if (strlen(root_name)) 627 return PROC_PATH_ROOT_SUBDIR; 628 else 629 return PROC_PATH_ROOT_DIR; 630 } 631 632 static int afuse_getattr(const char *path, struct stat *stbuf) 633 { 634 char *root_name = alloca(strlen(path)); 635 char *real_path = alloca(max_path_out_len(path)); 636 int retval; 637 mount_list_t *mount; 638 BLOCK_SIGALRM; 639 640 fprintf(stderr, "> GetAttr\n"); 641 642 switch (process_path(path, real_path, root_name, 0, &mount)) { 643 case PROC_PATH_FAILED: 644 retval = -ENXIO; 645 break; 646 647 case PROC_PATH_ROOT_DIR: 648 fprintf(stderr, "Getattr on: (%s) - %s\n", path, root_name); 649 stbuf->st_mode = S_IFDIR | 0700; 650 stbuf->st_nlink = 1; 651 stbuf->st_uid = getuid(); 652 stbuf->st_gid = getgid(); 653 stbuf->st_size = 0; 654 stbuf->st_blksize = 0; 655 stbuf->st_blocks = 0; 656 stbuf->st_atime = 0; 657 stbuf->st_mtime = 0; 658 stbuf->st_ctime = 0; 659 retval = 0; 660 break; 661 case PROC_PATH_ROOT_SUBDIR: 662 if (user_options.exact_getattr) 663 /* try to mount it */ 664 process_path(path, real_path, root_name, 1, &mount); 665 if (!mount) { 666 stbuf->st_mode = S_IFDIR | 0000; 667 if (!user_options.exact_getattr) 668 stbuf->st_mode = S_IFDIR | 0750; 669 stbuf->st_nlink = 1; 670 stbuf->st_uid = getuid(); 671 stbuf->st_gid = getgid(); 672 stbuf->st_size = 0; 673 stbuf->st_blksize = 0; 674 stbuf->st_blocks = 0; 675 stbuf->st_atime = 0; 676 stbuf->st_mtime = 0; 677 stbuf->st_ctime = 0; 678 retval = 0; 679 break; 680 } 681 682 case PROC_PATH_PROXY_DIR: 683 retval = get_retval(lstat(real_path, stbuf)); 684 break; 685 686 default: 687 DEFAULT_CASE_INVALID_ENUM; 688 } 689 if (mount) 690 update_auto_unmount(mount); 691 UNBLOCK_SIGALRM; 692 return retval; 693 } 694 695 static int afuse_readlink(const char *path, char *buf, size_t size) 696 { 697 int res; 698 char *root_name = alloca(strlen(path)); 699 char *real_path = alloca(max_path_out_len(path)); 700 int retval; 701 mount_list_t *mount; 702 BLOCK_SIGALRM; 703 704 switch (process_path(path, real_path, root_name, 1, &mount)) { 705 case PROC_PATH_FAILED: 706 retval = -ENXIO; 707 break; 708 case PROC_PATH_ROOT_DIR: 709 retval = -ENOENT; 710 break; 711 case PROC_PATH_ROOT_SUBDIR: 712 if (!mount) { 713 retval = -ENOENT; 714 break; 715 } 716 case PROC_PATH_PROXY_DIR: 717 res = readlink(real_path, buf, size - 1); 718 if (res == -1) { 719 retval = -errno; 720 break; 721 } 722 buf[res] = '\0'; 723 retval = 0; 724 break; 725 726 default: 727 DEFAULT_CASE_INVALID_ENUM; 728 } 729 if (mount) 730 update_auto_unmount(mount); 731 UNBLOCK_SIGALRM; 732 return retval; 733 } 734 735 static int afuse_opendir(const char *path, struct fuse_file_info *fi) 736 { 737 DIR *dp; 738 char *root_name = alloca(strlen(path)); 739 mount_list_t *mount; 740 char *real_path = alloca(max_path_out_len(path)); 741 int retval; 742 BLOCK_SIGALRM; 743 744 switch (process_path(path, real_path, root_name, 1, &mount)) { 745 case PROC_PATH_FAILED: 746 retval = -ENXIO; 747 break; 748 case PROC_PATH_ROOT_DIR: 749 retval = 0; 750 break; 751 case PROC_PATH_ROOT_SUBDIR: 752 if (!mount) { 753 retval = -EACCES; 754 fi->fh = 0lu; 755 break; 756 } 757 case PROC_PATH_PROXY_DIR: 758 dp = opendir(real_path); 759 if (dp == NULL) { 760 retval = -errno; 761 break; 762 } 763 fi->fh = (unsigned long)dp; 764 if (mount) 765 dir_list_add(&mount->dir_list, dp); 766 retval = 0; 767 break; 768 769 default: 770 DEFAULT_CASE_INVALID_ENUM; 771 } 772 if (mount) 773 update_auto_unmount(mount); 774 UNBLOCK_SIGALRM; 775 return retval; 776 } 777 778 static inline DIR *get_dirp(struct fuse_file_info *fi) 779 { 780 return (DIR *) (uintptr_t) fi->fh; 781 } 782 783 int populate_root_dir(char *pop_cmd, struct list_t **dir_entry_listptr, 784 fuse_fill_dir_t filler, void *buf) 785 { 786 FILE *browser; 787 size_t hsize = 0; 788 ssize_t hlen; 789 char *dir_entry = NULL; 790 791 if (!pop_cmd) 792 return -1; 793 794 if ((browser = popen(pop_cmd, "r")) == NULL) { 795 fprintf(stderr, "Failed to execute populate_root_command=%s\n", 796 pop_cmd); 797 return -errno; 798 } 799 800 int loop_error = 0; 801 #ifdef HAVE_GETLINE 802 while ((hlen = getline(&dir_entry, &hsize, browser)) != -1) 803 #else // HAVE_FGETLN 804 while (dir_entry = fgetln(browser, &hsize)) 805 #endif 806 { 807 if (hlen >= 1 && dir_entry[hlen - 1] == '\n') 808 dir_entry[hlen - 1] = '\0'; 809 810 fprintf(stderr, "Got entry \"%s\"\n", dir_entry); 811 812 int insert_err = 813 insert_sorted_if_unique(dir_entry_listptr, dir_entry); 814 if (insert_err == 1) // already in list 815 continue; 816 else if (insert_err) { 817 fprintf(stderr, 818 "populate_root_command: failed on inserting new entry into sorted list.\n"); 819 loop_error = 1; 820 } 821 822 if (strlen(dir_entry) != 0) 823 filler(buf, dir_entry, NULL, 0); 824 } 825 826 free(dir_entry); 827 828 int pclose_err = pclose(browser); 829 if (pclose_err) { 830 int pclose_errno = errno; 831 fprintf(stderr, 832 "populate_root_command: pclose failed, ret %d, status %d, errno %d (%s)\n", 833 pclose_errno, WEXITSTATUS(pclose_errno), pclose_errno, 834 strerror(pclose_errno)); 835 } 836 837 return loop_error || pclose_err; 838 } 839 840 static int afuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 841 off_t offset, struct fuse_file_info *fi) 842 { 843 DIR *dp = get_dirp(fi); 844 struct dirent *de; 845 char *root_name = alloca(strlen(path)); 846 char *real_path = alloca(max_path_out_len(path)); 847 struct list_t *dir_entry_list = NULL; 848 mount_list_t *mount, *next; 849 int retval; 850 BLOCK_SIGALRM; 851 852 switch (process_path(path, real_path, root_name, 1, &mount)) { 853 case PROC_PATH_FAILED: 854 retval = -ENXIO; 855 break; 856 857 case PROC_PATH_ROOT_DIR: 858 filler(buf, ".", NULL, 0); 859 filler(buf, "..", NULL, 0); 860 insert_sorted_if_unique(&dir_entry_list, "."); 861 insert_sorted_if_unique(&dir_entry_list, ".."); 862 for (mount = mount_list; mount; mount = next) { 863 next = mount->next; 864 /* Check for dead mounts. */ 865 if (!check_mount(mount)) { 866 do_umount(mount); 867 } else { 868 if (insert_sorted_if_unique 869 (&dir_entry_list, mount->root_name)) 870 retval = -1; 871 filler(buf, mount->root_name, NULL, 0); 872 } 873 } 874 populate_root_dir(user_options.populate_root_command, 875 &dir_entry_list, filler, buf); 876 destroy_list(&dir_entry_list); 877 mount = NULL; 878 retval = 0; 879 break; 880 881 case PROC_PATH_ROOT_SUBDIR: 882 if (!mount) { 883 retval = (!dp) ? -EBADF : -EACCES; 884 break; 885 } 886 case PROC_PATH_PROXY_DIR: 887 seekdir(dp, offset); 888 while ((de = readdir(dp)) != NULL) { 889 struct stat st; 890 memset(&st, 0, sizeof(st)); 891 st.st_ino = de->d_ino; 892 st.st_mode = de->d_type << 12; 893 if (filler(buf, de->d_name, &st, telldir(dp))) 894 break; 895 } 896 retval = 0; 897 break; 898 899 default: 900 DEFAULT_CASE_INVALID_ENUM; 901 } 902 if (mount) 903 update_auto_unmount(mount); 904 UNBLOCK_SIGALRM; 905 return retval; 906 } 907 908 static int afuse_releasedir(const char *path, struct fuse_file_info *fi) 909 { 910 DIR *dp = get_dirp(fi); 911 mount_list_t *mount; 912 char *root_name = alloca(strlen(path)); 913 char *real_path = alloca(max_path_out_len(path)); 914 int retval; 915 916 BLOCK_SIGALRM; 917 918 switch (process_path(path, real_path, root_name, 1, &mount)) { 919 case PROC_PATH_FAILED: 920 retval = -ENXIO; 921 break; 922 923 case PROC_PATH_ROOT_DIR: 924 retval = 0; 925 break; 926 927 case PROC_PATH_ROOT_SUBDIR: 928 case PROC_PATH_PROXY_DIR: 929 if (mount) 930 dir_list_remove(&mount->dir_list, dp); 931 if (dp) 932 closedir(dp); 933 retval = 0; 934 break; 935 936 default: 937 DEFAULT_CASE_INVALID_ENUM; 938 } 939 if (mount) 940 update_auto_unmount(mount); 941 UNBLOCK_SIGALRM; 942 return retval; 943 } 944 945 static int afuse_mknod(const char *path, mode_t mode, dev_t rdev) 946 { 947 char *root_name = alloca(strlen(path)); 948 char *real_path = alloca(max_path_out_len(path)); 949 mount_list_t *mount; 950 int retval; 951 BLOCK_SIGALRM; 952 fprintf(stderr, "> Mknod\n"); 953 954 switch (process_path(path, real_path, root_name, 0, &mount)) { 955 case PROC_PATH_FAILED: 956 retval = -ENXIO; 957 break; 958 959 case PROC_PATH_ROOT_DIR: 960 case PROC_PATH_ROOT_SUBDIR: 961 retval = -ENOTSUP; 962 break; 963 964 case PROC_PATH_PROXY_DIR: 965 if (S_ISFIFO(mode)) 966 retval = get_retval(mkfifo(real_path, mode)); 967 else 968 retval = get_retval(mknod(real_path, mode, rdev)); 969 break; 970 971 default: 972 DEFAULT_CASE_INVALID_ENUM; 973 } 974 if (mount) 975 update_auto_unmount(mount); 976 UNBLOCK_SIGALRM; 977 return retval; 978 } 979 980 static int afuse_mkdir(const char *path, mode_t mode) 981 { 982 char *root_name = alloca(strlen(path)); 983 char *real_path = alloca(max_path_out_len(path)); 984 int retval; 985 mount_list_t *mount; 986 BLOCK_SIGALRM; 987 988 switch (process_path(path, real_path, root_name, 0, &mount)) { 989 case PROC_PATH_FAILED: 990 retval = -ENXIO; 991 break; 992 case PROC_PATH_ROOT_DIR: 993 case PROC_PATH_ROOT_SUBDIR: 994 retval = -ENOTSUP; 995 break; 996 case PROC_PATH_PROXY_DIR: 997 retval = get_retval(mkdir(real_path, mode)); 998 break; 999 1000 default: 1001 DEFAULT_CASE_INVALID_ENUM; 1002 } 1003 if (mount) 1004 update_auto_unmount(mount); 1005 UNBLOCK_SIGALRM; 1006 return retval; 1007 } 1008 1009 static int afuse_unlink(const char *path) 1010 { 1011 char *root_name = alloca(strlen(path)); 1012 char *real_path = alloca(max_path_out_len(path)); 1013 mount_list_t *mount; 1014 int retval; 1015 BLOCK_SIGALRM; 1016 1017 switch (process_path(path, real_path, root_name, 0, &mount)) { 1018 case PROC_PATH_FAILED: 1019 retval = -ENXIO; 1020 break; 1021 case PROC_PATH_ROOT_DIR: 1022 case PROC_PATH_ROOT_SUBDIR: 1023 retval = -ENOTSUP; 1024 break; 1025 case PROC_PATH_PROXY_DIR: 1026 retval = get_retval(unlink(real_path)); 1027 break; 1028 1029 default: 1030 DEFAULT_CASE_INVALID_ENUM; 1031 } 1032 if (mount) 1033 update_auto_unmount(mount); 1034 UNBLOCK_SIGALRM; 1035 return retval; 1036 } 1037 1038 static int afuse_rmdir(const char *path) 1039 { 1040 char *root_name = alloca(strlen(path)); 1041 char *real_path = alloca(max_path_out_len(path)); 1042 mount_list_t *mount; 1043 int retval; 1044 BLOCK_SIGALRM; 1045 1046 switch (process_path(path, real_path, root_name, 0, &mount)) { 1047 case PROC_PATH_FAILED: 1048 retval = -ENXIO; 1049 break; 1050 case PROC_PATH_ROOT_DIR: 1051 retval = -ENOTSUP; 1052 break; 1053 case PROC_PATH_ROOT_SUBDIR: 1054 if (mount) { 1055 /* Unmount */ 1056 if (mount->dir_list || mount->fd_list) 1057 retval = -EBUSY; 1058 else { 1059 do_umount(mount); 1060 mount = NULL; 1061 retval = 0; 1062 } 1063 } else 1064 retval = -ENOTSUP; 1065 break; 1066 case PROC_PATH_PROXY_DIR: 1067 retval = get_retval(rmdir(real_path)); 1068 break; 1069 1070 default: 1071 DEFAULT_CASE_INVALID_ENUM; 1072 } 1073 if (mount) 1074 update_auto_unmount(mount); 1075 UNBLOCK_SIGALRM; 1076 return retval; 1077 } 1078 1079 static int afuse_symlink(const char *from, const char *to) 1080 { 1081 char *root_name_to = alloca(strlen(to)); 1082 char *real_to_path = alloca(max_path_out_len(to)); 1083 mount_list_t *mount; 1084 int retval; 1085 BLOCK_SIGALRM; 1086 1087 switch (process_path(to, real_to_path, root_name_to, 0, &mount)) { 1088 case PROC_PATH_FAILED: 1089 retval = -ENXIO; 1090 break; 1091 case PROC_PATH_ROOT_DIR: 1092 case PROC_PATH_ROOT_SUBDIR: 1093 retval = -ENOTSUP; 1094 break; 1095 case PROC_PATH_PROXY_DIR: 1096 retval = get_retval(symlink(from, real_to_path)); 1097 break; 1098 1099 default: 1100 DEFAULT_CASE_INVALID_ENUM; 1101 } 1102 if (mount) 1103 update_auto_unmount(mount); 1104 UNBLOCK_SIGALRM; 1105 return retval; 1106 } 1107 1108 static int afuse_rename(const char *from, const char *to) 1109 { 1110 char *root_name_from = alloca(strlen(from)); 1111 char *root_name_to = alloca(strlen(to)); 1112 char *real_from_path = alloca(max_path_out_len(from)); 1113 char *real_to_path = alloca(max_path_out_len(to)); 1114 mount_list_t *mount_from, *mount_to = NULL; 1115 int retval; 1116 BLOCK_SIGALRM; 1117 1118 switch (process_path 1119 (from, real_from_path, root_name_from, 0, &mount_from)) { 1120 1121 case PROC_PATH_FAILED: 1122 retval = -ENXIO; 1123 break; 1124 1125 case PROC_PATH_ROOT_DIR: 1126 case PROC_PATH_ROOT_SUBDIR: 1127 retval = -ENOTSUP; 1128 break; 1129 1130 case PROC_PATH_PROXY_DIR: 1131 switch (process_path 1132 (to, real_to_path, root_name_to, 0, &mount_to)) { 1133 1134 case PROC_PATH_FAILED: 1135 retval = -ENXIO; 1136 break; 1137 1138 case PROC_PATH_ROOT_DIR: 1139 case PROC_PATH_ROOT_SUBDIR: 1140 retval = -ENOTSUP; 1141 break; 1142 1143 case PROC_PATH_PROXY_DIR: 1144 retval = 1145 get_retval(rename(real_from_path, real_to_path)); 1146 break; 1147 1148 default: 1149 DEFAULT_CASE_INVALID_ENUM; 1150 } 1151 break; 1152 1153 default: 1154 DEFAULT_CASE_INVALID_ENUM; 1155 } 1156 if (mount_to) 1157 update_auto_unmount(mount_to); 1158 if (mount_from && mount_from != mount_to) 1159 update_auto_unmount(mount_from); 1160 UNBLOCK_SIGALRM; 1161 return retval; 1162 } 1163 1164 static int afuse_link(const char *from, const char *to) 1165 { 1166 char *root_name_from = alloca(strlen(from)); 1167 char *root_name_to = alloca(strlen(to)); 1168 char *real_from_path = alloca(max_path_out_len(from)); 1169 char *real_to_path = alloca(max_path_out_len(to)); 1170 mount_list_t *mount_to = NULL, *mount_from; 1171 int retval; 1172 BLOCK_SIGALRM; 1173 1174 switch (process_path 1175 (from, real_from_path, root_name_from, 0, &mount_from)) { 1176 1177 case PROC_PATH_FAILED: 1178 retval = -ENXIO; 1179 break; 1180 case PROC_PATH_ROOT_DIR: 1181 case PROC_PATH_ROOT_SUBDIR: 1182 retval = -ENOTSUP; 1183 break; 1184 case PROC_PATH_PROXY_DIR: 1185 switch (process_path 1186 (to, real_to_path, root_name_to, 0, &mount_to)) { 1187 1188 case PROC_PATH_FAILED: 1189 retval = -ENXIO; 1190 break; 1191 case PROC_PATH_ROOT_DIR: 1192 case PROC_PATH_ROOT_SUBDIR: 1193 retval = -ENOTSUP; 1194 break; 1195 case PROC_PATH_PROXY_DIR: 1196 retval = get_retval(link(real_from_path, real_to_path)); 1197 break; 1198 1199 default: 1200 DEFAULT_CASE_INVALID_ENUM; 1201 } 1202 break; 1203 1204 default: 1205 DEFAULT_CASE_INVALID_ENUM; 1206 } 1207 if (mount_to) 1208 update_auto_unmount(mount_to); 1209 if (mount_from && mount_from != mount_to) 1210 update_auto_unmount(mount_from); 1211 UNBLOCK_SIGALRM; 1212 return retval; 1213 } 1214 1215 static int afuse_chmod(const char *path, mode_t mode) 1216 { 1217 char *root_name = alloca(strlen(path)); 1218 char *real_path = alloca(max_path_out_len(path)); 1219 mount_list_t *mount; 1220 int retval; 1221 BLOCK_SIGALRM; 1222 1223 switch (process_path(path, real_path, root_name, 0, &mount)) { 1224 case PROC_PATH_FAILED: 1225 retval = -ENXIO; 1226 break; 1227 case PROC_PATH_ROOT_DIR: 1228 case PROC_PATH_ROOT_SUBDIR: 1229 retval = -ENOTSUP; 1230 break; 1231 case PROC_PATH_PROXY_DIR: 1232 retval = get_retval(chmod(real_path, mode)); 1233 break; 1234 1235 default: 1236 DEFAULT_CASE_INVALID_ENUM; 1237 } 1238 if (mount) 1239 update_auto_unmount(mount); 1240 UNBLOCK_SIGALRM; 1241 return retval; 1242 } 1243 1244 static int afuse_chown(const char *path, uid_t uid, gid_t gid) 1245 { 1246 char *root_name = alloca(strlen(path)); 1247 char *real_path = alloca(max_path_out_len(path)); 1248 mount_list_t *mount; 1249 int retval; 1250 BLOCK_SIGALRM; 1251 1252 switch (process_path(path, real_path, root_name, 0, &mount)) { 1253 case PROC_PATH_FAILED: 1254 retval = -ENXIO; 1255 break; 1256 case PROC_PATH_ROOT_DIR: 1257 case PROC_PATH_ROOT_SUBDIR: 1258 retval = -ENOTSUP; 1259 break; 1260 case PROC_PATH_PROXY_DIR: 1261 retval = get_retval(lchown(real_path, uid, gid)); 1262 break; 1263 1264 default: 1265 DEFAULT_CASE_INVALID_ENUM; 1266 } 1267 if (mount) 1268 update_auto_unmount(mount); 1269 UNBLOCK_SIGALRM; 1270 return retval; 1271 } 1272 1273 static int afuse_truncate(const char *path, off_t size) 1274 { 1275 char *root_name = alloca(strlen(path)); 1276 char *real_path = alloca(max_path_out_len(path)); 1277 mount_list_t *mount; 1278 int retval; 1279 BLOCK_SIGALRM; 1280 1281 switch (process_path(path, real_path, root_name, 0, &mount)) { 1282 case PROC_PATH_FAILED: 1283 retval = -ENXIO; 1284 break; 1285 case PROC_PATH_ROOT_DIR: 1286 case PROC_PATH_ROOT_SUBDIR: 1287 retval = -ENOTSUP; 1288 break; 1289 case PROC_PATH_PROXY_DIR: 1290 retval = get_retval(truncate(real_path, size)); 1291 break; 1292 1293 default: 1294 DEFAULT_CASE_INVALID_ENUM; 1295 } 1296 if (mount) 1297 update_auto_unmount(mount); 1298 UNBLOCK_SIGALRM; 1299 return retval; 1300 } 1301 1302 static int afuse_utime(const char *path, struct utimbuf *buf) 1303 { 1304 char *root_name = alloca(strlen(path)); 1305 char *real_path = alloca(max_path_out_len(path)); 1306 mount_list_t *mount; 1307 int retval; 1308 BLOCK_SIGALRM; 1309 1310 switch (process_path(path, real_path, root_name, 0, &mount)) { 1311 case PROC_PATH_FAILED: 1312 retval = -ENXIO; 1313 break; 1314 case PROC_PATH_ROOT_DIR: 1315 retval = -ENOTSUP; 1316 break; 1317 case PROC_PATH_ROOT_SUBDIR: 1318 if (!mount) { 1319 retval = -ENOTSUP; 1320 break; 1321 } 1322 case PROC_PATH_PROXY_DIR: 1323 retval = get_retval(utime(real_path, buf)); 1324 break; 1325 1326 default: 1327 DEFAULT_CASE_INVALID_ENUM; 1328 } 1329 if (mount) 1330 update_auto_unmount(mount); 1331 UNBLOCK_SIGALRM; 1332 return retval; 1333 } 1334 1335 static int afuse_open(const char *path, struct fuse_file_info *fi) 1336 { 1337 int fd; 1338 char *root_name = alloca(strlen(path)); 1339 mount_list_t *mount; 1340 char *real_path = alloca(max_path_out_len(path)); 1341 int retval; 1342 BLOCK_SIGALRM; 1343 1344 switch (process_path(path, real_path, root_name, 1, &mount)) { 1345 case PROC_PATH_FAILED: 1346 retval = -ENXIO; 1347 break; 1348 case PROC_PATH_ROOT_DIR: 1349 case PROC_PATH_ROOT_SUBDIR: 1350 retval = -ENOENT; 1351 break; 1352 case PROC_PATH_PROXY_DIR: 1353 fd = open(real_path, fi->flags); 1354 if (fd == -1) { 1355 retval = -errno; 1356 break; 1357 } 1358 1359 fi->fh = fd; 1360 if (mount) 1361 fd_list_add(&mount->fd_list, fd); 1362 retval = 0; 1363 break; 1364 1365 default: 1366 DEFAULT_CASE_INVALID_ENUM; 1367 } 1368 if (mount) 1369 update_auto_unmount(mount); 1370 UNBLOCK_SIGALRM; 1371 return retval; 1372 } 1373 1374 static int afuse_read(const char *path, char *buf, size_t size, off_t offset, 1375 struct fuse_file_info *fi) 1376 { 1377 int res; 1378 1379 (void)path; 1380 res = pread(fi->fh, buf, size, offset); 1381 if (res == -1) 1382 res = -errno; 1383 1384 return res; 1385 } 1386 1387 static int afuse_write(const char *path, const char *buf, size_t size, 1388 off_t offset, struct fuse_file_info *fi) 1389 { 1390 int res; 1391 1392 (void)path; 1393 res = pwrite(fi->fh, buf, size, offset); 1394 if (res == -1) 1395 res = -errno; 1396 1397 if (user_options.flush_writes) 1398 fsync(fi->fh); 1399 1400 return res; 1401 } 1402 1403 static int afuse_release(const char *path, struct fuse_file_info *fi) 1404 { 1405 char *root_name = alloca(strlen(path)); 1406 mount_list_t *mount; 1407 int retval; 1408 BLOCK_SIGALRM; 1409 1410 extract_root_name(path, root_name); 1411 mount = find_mount(root_name); 1412 retval = get_retval(close(fi->fh)); 1413 1414 if (mount) { 1415 fd_list_remove(&mount->fd_list, fi->fh); 1416 update_auto_unmount(mount); 1417 } 1418 1419 UNBLOCK_SIGALRM; 1420 return retval; 1421 } 1422 1423 static int afuse_fsync(const char *path, int isdatasync, 1424 struct fuse_file_info *fi) 1425 { 1426 int res; 1427 (void)path; 1428 1429 #ifndef HAVE_FDATASYNC 1430 (void)isdatasync; 1431 #else 1432 if (isdatasync) 1433 res = fdatasync(fi->fh); 1434 else 1435 #endif 1436 res = fsync(fi->fh); 1437 return get_retval(res); 1438 } 1439 1440 #if FUSE_VERSION >= 25 1441 static int afuse_access(const char *path, int mask) 1442 { 1443 char *root_name = alloca(strlen(path)); 1444 char *real_path = alloca(max_path_out_len(path)); 1445 mount_list_t *mount; 1446 int retval; 1447 BLOCK_SIGALRM; 1448 1449 switch (process_path(path, real_path, root_name, 1, &mount)) { 1450 case PROC_PATH_FAILED: 1451 retval = -ENXIO; 1452 break; 1453 case PROC_PATH_ROOT_DIR: 1454 case PROC_PATH_PROXY_DIR: 1455 retval = get_retval(access(real_path, mask)); 1456 break; 1457 case PROC_PATH_ROOT_SUBDIR: 1458 if (mount) 1459 retval = get_retval(access(real_path, mask)); 1460 else 1461 retval = -EACCES; 1462 break; 1463 1464 default: 1465 DEFAULT_CASE_INVALID_ENUM; 1466 } 1467 if (mount) 1468 update_auto_unmount(mount); 1469 UNBLOCK_SIGALRM; 1470 return retval; 1471 } 1472 1473 static int afuse_ftruncate(const char *path, off_t size, 1474 struct fuse_file_info *fi) 1475 { 1476 (void)path; 1477 return get_retval(ftruncate(fi->fh, size)); 1478 } 1479 1480 static int afuse_create(const char *path, mode_t mode, 1481 struct fuse_file_info *fi) 1482 { 1483 int fd; 1484 char *root_name = alloca(strlen(path)); 1485 char *real_path = alloca(max_path_out_len(path)); 1486 mount_list_t *mount; 1487 int retval; 1488 BLOCK_SIGALRM; 1489 1490 switch (process_path(path, real_path, root_name, 0, &mount)) { 1491 case PROC_PATH_FAILED: 1492 retval = -ENXIO; 1493 break; 1494 case PROC_PATH_ROOT_DIR: 1495 case PROC_PATH_ROOT_SUBDIR: 1496 retval = -ENOTSUP; 1497 break; 1498 case PROC_PATH_PROXY_DIR: 1499 fd = open(real_path, fi->flags, mode); 1500 if (fd == -1) { 1501 retval = -errno; 1502 break; 1503 } 1504 fi->fh = fd; 1505 retval = 0; 1506 break; 1507 1508 default: 1509 DEFAULT_CASE_INVALID_ENUM; 1510 } 1511 if (mount) 1512 update_auto_unmount(mount); 1513 UNBLOCK_SIGALRM; 1514 return retval; 1515 } 1516 1517 static int afuse_fgetattr(const char *path, struct stat *stbuf, 1518 struct fuse_file_info *fi) 1519 { 1520 (void)path; 1521 1522 return get_retval(fstat(fi->fh, stbuf)); 1523 } 1524 #endif 1525 1526 #if FUSE_VERSION >= 25 1527 static int afuse_statfs(const char *path, struct statvfs *stbuf) 1528 #else 1529 static int afuse_statfs(const char *path, struct statfs *stbuf) 1530 #endif 1531 { 1532 char *root_name = alloca(strlen(path)); 1533 char *real_path = alloca(max_path_out_len(path)); 1534 mount_list_t *mount; 1535 int retval; 1536 BLOCK_SIGALRM; 1537 1538 switch (process_path(path, real_path, root_name, 1, &mount)) { 1539 case PROC_PATH_FAILED: 1540 retval = -ENXIO; 1541 break; 1542 1543 case PROC_PATH_ROOT_DIR: 1544 #if FUSE_VERSION >= 25 1545 stbuf->f_namemax = 0x7fffffff; 1546 stbuf->f_frsize = 512; 1547 #else 1548 stbuf->f_namelen = 0x7fffffff; 1549 #endif 1550 stbuf->f_bsize = 1024; 1551 stbuf->f_blocks = 0; 1552 stbuf->f_bfree = 0; 1553 stbuf->f_bavail = 0; 1554 stbuf->f_files = 0; 1555 stbuf->f_ffree = 0; 1556 retval = 0; 1557 break; 1558 1559 case PROC_PATH_ROOT_SUBDIR: 1560 if (!mount) { 1561 retval = -EACCES; 1562 break; 1563 } 1564 case PROC_PATH_PROXY_DIR: 1565 retval = get_retval(statvfs(real_path, stbuf)); 1566 break; 1567 1568 default: 1569 DEFAULT_CASE_INVALID_ENUM; 1570 } 1571 if (mount) 1572 update_auto_unmount(mount); 1573 UNBLOCK_SIGALRM; 1574 return retval; 1575 } 1576 1577 void afuse_destroy(void *p) 1578 { 1579 (void)p; /* Unused */ 1580 shutdown(); 1581 } 1582 1583 #ifdef HAVE_SETXATTR 1584 /* xattr operations are optional and can safely be left unimplemented */ 1585 static int afuse_setxattr(const char *path, const char *name, const char *value, 1586 size_t size, int flags) 1587 { 1588 char *root_name = alloca(strlen(path)); 1589 char *real_path = alloca(max_path_out_len(path)); 1590 mount_list_t *mount; 1591 int retval; 1592 BLOCK_SIGALRM; 1593 1594 switch (process_path(path, real_path, root_name, 0, &mount)) { 1595 case PROC_PATH_FAILED: 1596 retval = -ENXIO; 1597 break; 1598 case PROC_PATH_ROOT_DIR: 1599 retval = -ENOENT; 1600 break; 1601 case PROC_PATH_ROOT_SUBDIR: 1602 if (!mount) { 1603 retval = -ENOTSUP; 1604 break; 1605 } 1606 case PROC_PATH_PROXY_DIR: 1607 retval = 1608 get_retval(lsetxattr(real_path, name, value, size, flags)); 1609 break; 1610 1611 default: 1612 DEFAULT_CASE_INVALID_ENUM; 1613 } 1614 if (mount) 1615 update_auto_unmount(mount); 1616 UNBLOCK_SIGALRM; 1617 return retval; 1618 } 1619 1620 static int afuse_getxattr(const char *path, const char *name, char *value, 1621 size_t size) 1622 { 1623 char *root_name = alloca(strlen(path)); 1624 char *real_path = alloca(max_path_out_len(path)); 1625 mount_list_t *mount; 1626 int retval; 1627 BLOCK_SIGALRM; 1628 1629 switch (process_path(path, real_path, root_name, 1, &mount)) { 1630 case PROC_PATH_FAILED: 1631 retval = -ENXIO; 1632 break; 1633 case PROC_PATH_ROOT_DIR: 1634 retval = -ENOTSUP; 1635 break; 1636 case PROC_PATH_ROOT_SUBDIR: 1637 if (!mount) { 1638 retval = -ENOTSUP; 1639 break; 1640 } 1641 case PROC_PATH_PROXY_DIR: 1642 retval = get_retval(lgetxattr(real_path, name, value, size)); 1643 break; 1644 1645 default: 1646 DEFAULT_CASE_INVALID_ENUM; 1647 } 1648 if (mount) 1649 update_auto_unmount(mount); 1650 UNBLOCK_SIGALRM; 1651 return retval; 1652 } 1653 1654 static int afuse_listxattr(const char *path, char *list, size_t size) 1655 { 1656 char *root_name = alloca(strlen(path)); 1657 char *real_path = alloca(max_path_out_len(path)); 1658 mount_list_t *mount; 1659 int retval; 1660 BLOCK_SIGALRM; 1661 1662 switch (process_path(path, real_path, root_name, 1, &mount)) { 1663 case PROC_PATH_FAILED: 1664 retval = -ENXIO; 1665 break; 1666 case PROC_PATH_ROOT_DIR: 1667 retval = -ENOTSUP; 1668 break; 1669 case PROC_PATH_ROOT_SUBDIR: 1670 if (!mount) { 1671 retval = -ENOTSUP; 1672 break; 1673 } 1674 case PROC_PATH_PROXY_DIR: 1675 retval = get_retval(llistxattr(real_path, list, size)); 1676 break; 1677 1678 default: 1679 DEFAULT_CASE_INVALID_ENUM; 1680 } 1681 if (mount) 1682 update_auto_unmount(mount); 1683 UNBLOCK_SIGALRM; 1684 return retval; 1685 } 1686 1687 static int afuse_removexattr(const char *path, const char *name) 1688 { 1689 char *root_name = alloca(strlen(path)); 1690 char *real_path = alloca(max_path_out_len(path)); 1691 mount_list_t *mount; 1692 int retval; 1693 BLOCK_SIGALRM; 1694 1695 switch (process_path(path, real_path, root_name, 0, &mount)) { 1696 case PROC_PATH_FAILED: 1697 retval = -ENXIO; 1698 break; 1699 case PROC_PATH_ROOT_DIR: 1700 retval = -ENOTSUP; 1701 break; 1702 case PROC_PATH_ROOT_SUBDIR: 1703 if (!mount) { 1704 retval = -ENOTSUP; 1705 break; 1706 } 1707 case PROC_PATH_PROXY_DIR: 1708 retval = get_retval(lremovexattr(real_path, name)); 1709 break; 1710 1711 default: 1712 DEFAULT_CASE_INVALID_ENUM; 1713 } 1714 if (mount) 1715 update_auto_unmount(mount); 1716 UNBLOCK_SIGALRM; 1717 return retval; 1718 } 1719 #endif /* HAVE_SETXATTR */ 1720 1721 static struct fuse_operations afuse_oper = { 1722 .getattr = afuse_getattr, 1723 .readlink = afuse_readlink, 1724 .opendir = afuse_opendir, 1725 .readdir = afuse_readdir, 1726 .releasedir = afuse_releasedir, 1727 .mknod = afuse_mknod, 1728 .mkdir = afuse_mkdir, 1729 .symlink = afuse_symlink, 1730 .unlink = afuse_unlink, 1731 .rmdir = afuse_rmdir, 1732 .rename = afuse_rename, 1733 .link = afuse_link, 1734 .chmod = afuse_chmod, 1735 .chown = afuse_chown, 1736 .truncate = afuse_truncate, 1737 .utime = afuse_utime, 1738 .open = afuse_open, 1739 .read = afuse_read, 1740 .write = afuse_write, 1741 .release = afuse_release, 1742 .fsync = afuse_fsync, 1743 .statfs = afuse_statfs, 1744 #if FUSE_VERSION >= 25 1745 .access = afuse_access, 1746 .create = afuse_create, 1747 .ftruncate = afuse_ftruncate, 1748 .fgetattr = afuse_fgetattr, 1749 #endif 1750 .destroy = afuse_destroy, 1751 #ifdef HAVE_SETXATTR 1752 .setxattr = afuse_setxattr, 1753 .getxattr = afuse_getxattr, 1754 .listxattr = afuse_listxattr, 1755 .removexattr = afuse_removexattr, 1756 #endif 1757 }; 1758 1759 enum { 1760 KEY_HELP, 1761 KEY_FLUSHWRITES, 1762 KEY_EXACT_GETATTR 1763 }; 1764 1765 #define AFUSE_OPT(t, p, v) { t, offsetof(struct user_options_t, p), v } 1766 1767 static struct fuse_opt afuse_opts[] = { 1768 AFUSE_OPT("mount_template=%s", mount_command_template, 0), 1769 AFUSE_OPT("unmount_template=%s", unmount_command_template, 0), 1770 AFUSE_OPT("populate_root_command=%s", populate_root_command, 0), 1771 AFUSE_OPT("filter_file=%s", filter_file, 0), 1772 1773 AFUSE_OPT("timeout=%llu", auto_unmount_delay, 0), 1774 1775 FUSE_OPT_KEY("exact_getattr", KEY_EXACT_GETATTR), 1776 FUSE_OPT_KEY("flushwrites", KEY_FLUSHWRITES), 1777 FUSE_OPT_KEY("-h", KEY_HELP), 1778 FUSE_OPT_KEY("--help", KEY_HELP), 1779 1780 FUSE_OPT_END 1781 }; 1782 1783 static void usage(const char *progname) 1784 { 1785 fprintf(stderr, 1786 "Usage: %s mountpoint [options]\n" 1787 "\n" 1788 " -o opt,[opt...] mount options\n" 1789 " -h --help print help\n" 1790 " -V --version print FUSE version information\n" 1791 "\n" 1792 "afuse options:\n" 1793 " -o mount_template=CMD template for CMD to execute to mount (1)\n" 1794 " -o unmount_template=CMD template for CMD to execute to unmount (1) (2)\n" 1795 " -o populate_root_command=CMD CMD to execute providing root directory list (3)\n" 1796 " -o filter_file=FILE FILE listing ignore filters for mount points (4)\n" 1797 " -o timeout=TIMEOUT automatically unmount after TIMEOUT seconds\n" 1798 " -o flushwrites flushes data to disk for all file writes\n" 1799 " -o exact_getattr allows getattr calls to cause a mount\n" 1800 "\n\n" 1801 " (1) - When executed, %%r and %%m are expanded in templates to the root\n" 1802 " directory name for the new mount point, and the actual directory to\n" 1803 " mount onto respectively to mount onto. Both templates are REQUIRED.\n" 1804 "\n" 1805 " (2) - The unmount command must perform a lazy unmount operation. E.g. the\n" 1806 " -u -z options to fusermount, or -l for regular mount.\n" 1807 "\n" 1808 " (3) - The populate_root command should output one dir entry per line,\n" 1809 " and return immediately. It is run for each directory listing request.\n" 1810 "\n" 1811 " (4) - Each line of the filter file is a shell wildcard filter (glob). A '#'\n" 1812 " as the first character on a line ignores a filter.\n" 1813 "\n" 1814 " The following filter patterns are hard-coded:" 1815 "\n", progname); 1816 1817 mount_filter_list_t *cur = mount_filter_list; 1818 while (cur) { 1819 fprintf(stderr, " %s\n", cur->pattern); 1820 cur = cur->next; 1821 } 1822 1823 fprintf(stderr, "\n"); 1824 } 1825 1826 static int afuse_opt_proc(void *data, const char *arg, int key, 1827 struct fuse_args *outargs) 1828 { 1829 /* Unused */ 1830 (void)arg; 1831 (void)data; 1832 1833 switch (key) { 1834 case KEY_HELP: 1835 usage(outargs->argv[0]); 1836 fuse_opt_add_arg(outargs, "-ho"); 1837 fuse_main(outargs->argc, outargs->argv, &afuse_oper); 1838 exit(1); 1839 1840 case KEY_FLUSHWRITES: 1841 user_options.flush_writes = true; 1842 return 0; 1843 1844 case KEY_EXACT_GETATTR: 1845 user_options.exact_getattr = true; 1846 return 0; 1847 1848 default: 1849 return 1; 1850 } 1851 } 1852 1853 int main(int argc, char *argv[]) 1854 { 1855 struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 1856 char *temp_dir_name = my_malloc(strlen(TMP_DIR_TEMPLATE)); 1857 strcpy(temp_dir_name, TMP_DIR_TEMPLATE); 1858 1859 if (fuse_opt_parse(&args, &user_options, afuse_opts, afuse_opt_proc) == 1860 -1) 1861 return 1; 1862 1863 // !!FIXME!! force single-threading for now as data structures are not locked 1864 fuse_opt_add_arg(&args, "-s"); 1865 1866 // Adjust user specified timeout from seconds to microseconds as required 1867 if (user_options.auto_unmount_delay != UINT64_MAX) 1868 user_options.auto_unmount_delay *= 1000000; 1869 1870 auto_unmount_ph_init(&auto_unmount_ph); 1871 1872 /** 1873 * Install the SIGALRM signal handler. 1874 */ 1875 { 1876 struct sigaction act; 1877 act.sa_handler = &handle_auto_unmount_timer; 1878 sigemptyset(&act.sa_mask); 1879 act.sa_flags = 0; 1880 while (sigaction(SIGALRM, &act, NULL) == -1 && errno == EINTR) 1881 continue; 1882 } 1883 1884 // Check for required parameters 1885 if (!user_options.mount_command_template 1886 || !user_options.unmount_command_template) { 1887 fprintf(stderr, "(Un)Mount command templates missing.\n\n"); 1888 usage(argv[0]); 1889 fuse_opt_add_arg(&args, "-ho"); 1890 fuse_main(args.argc, args.argv, &afuse_oper); 1891 1892 return 1; 1893 } 1894 1895 if (user_options.filter_file) 1896 load_mount_filter_file(user_options.filter_file); 1897 1898 if (!(mount_point_directory = mkdtemp(temp_dir_name))) { 1899 fprintf(stderr, 1900 "Failed to create temporary mount point dir.\n"); 1901 return 1; 1902 } 1903 1904 { 1905 struct stat buf; 1906 if (lstat(mount_point_directory, &buf) == -1) { 1907 fprintf(stderr, 1908 "Failed to stat temporary mount point dir.\n"); 1909 return 1; 1910 } 1911 mount_point_dev = buf.st_dev; 1912 } 1913 1914 umask(0); 1915 1916 // !!FIXME!! death by signal doesn't unmount fs 1917 return fuse_main(args.argc, args.argv, &afuse_oper); 1918 } 1919