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