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