]> CyberLeo.Net >> Repos - SourceForge/afuse.git/blob - src/afuse.c
Tidying up for release 0.2.
[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 // !!FIXME!! allow escaping of %'s
284 // Note: this method strips out quotes and applies them itself as should be appropriate
285 char *expand_template(const char *template, const char *mount_point, const char *root_name)
286 {
287         int len = 0;
288         int i;
289         char *expanded_name;
290         char *expanded_name_start;
291
292         // calculate length
293         for(i = 0; template[i]; i++)
294                 if(template[i] == '%') {
295                         switch(template[i + 1])
296                         {
297                                 case 'm':
298                                         len += strlen(mount_point) + 2;
299                                         i++;
300                                         break;
301                                 case 'r':
302                                         len += strlen(root_name) + 2;
303                                         i++;
304                                         break;
305                         }
306                 } else if(template[i] != '"')
307                         len++;
308
309         expanded_name_start = expanded_name = my_malloc(len + 1);
310
311         for(i = 0; template[i]; i++)
312                 if(template[i] == '%') {
313                         int j = 0;
314                         switch(template[i + 1])
315                         {
316                                 case 'm':
317                                         *expanded_name++ = '"';
318                                         while(mount_point[j])
319                                                 *expanded_name++ = mount_point[j++];
320                                         *expanded_name++ = '"';
321                                         i++;
322                                         break;
323                                 case 'r':
324                                         *expanded_name++ = '"';
325                                         while(root_name[j])
326                                                 *expanded_name++ = root_name[j++];
327                                         *expanded_name++ = '"';
328                                         i++;
329                                         break;
330                         }
331                 } else if(template[i] != '"')
332                         *expanded_name++ = template[i];
333
334         *expanded_name = '\0';
335
336         return expanded_name_start;
337 }
338
339 mount_list_t *do_mount(const char *root_name)
340 {
341         char *mount_point;
342         char *mount_command;
343         mount_list_t *mount;
344         int sysret;
345
346         fprintf(stderr, "Mounting: %s\n", root_name);
347
348         if( !(mount_point = make_mount_point(root_name)) ) {
349                 fprintf(stderr, "Failed to create mount point directory: %s/%s\n",
350                         mount_point_directory, root_name);
351                 return NULL;
352         }
353
354         mount_command = expand_template(user_options.mount_command_template,
355                                         mount_point, root_name);
356         sysret = system(mount_command);
357
358         fprintf(stderr, "sysret: %.8x\n", sysret);
359
360         if(sysret) {
361                 fprintf(stderr, "Failed to invoke mount command: '%s' (%s)\n",
362                         mount_command, sysret != -1 ?
363                                 "Error executing mount" :
364                                 strerror(errno));
365
366                 // remove the now unused directory
367                 if( rmdir(mount_point) == -1 )
368                         fprintf(stderr, "Failed to remove mount point dir: %s (%s)",
369                                 mount_point, strerror(errno));
370
371                 free(mount_command);
372                 free(mount_point);
373                 return NULL;
374         }
375
376         mount = add_mount(root_name, mount_point);
377
378         free(mount_command);
379         return mount;
380 }
381
382 int do_umount(mount_list_t *mount)
383 {
384         char *unmount_command;
385         int sysret;
386
387         fprintf(stderr, "Unmounting: %s\n", mount->root_name);
388
389         unmount_command = expand_template(user_options.unmount_command_template,
390                                           mount->mount_point, mount->root_name);
391         sysret = system(unmount_command);
392         if(sysret) {
393                 fprintf(stderr, "Failed to invoke unmount command: '%s' (%s)\n",
394                         unmount_command, sysret != -1 ?
395                                        "Error executing mount" :
396                                        strerror(errno));
397                 /* Still unmount anyway */
398         }
399
400         if( rmdir(mount->mount_point) == -1 )
401                 fprintf(stderr, "Failed to remove mount point dir: %s (%s)",
402                                 mount->mount_point, strerror(errno));
403         remove_mount(mount);
404         free(unmount_command);
405         return 1;
406 }
407
408 void unmount_all(void)
409 {
410         fprintf(stderr, "Attempting to unmount all filesystems:\n");
411
412         while(mount_list) {
413                 fprintf(stderr, "\tUnmounting: %s\n", mount_list->root_name);
414
415                 do_umount(mount_list);
416         }
417
418         fprintf(stderr, "done.\n");
419 }
420
421 void shutdown(void)
422 {
423         BLOCK_SIGALRM;
424
425         unmount_all();
426
427         UNBLOCK_SIGALRM;
428
429         if(rmdir(mount_point_directory) == -1)
430                 fprintf(stderr, "Failed to remove temporary mount point directory: %s (%s)\n",
431                         mount_point_directory, strerror(errno));
432 }
433
434 int max_path_out_len(const char *path_in)
435 {
436         return strlen(mount_point_directory) + strlen(path_in) + 2;
437 }
438
439 // returns true if path is the a child directory of a root node
440 // e.g. /a/b is a child, /a is not.
441 int extract_root_name(const char *path, char *root_name)
442 {
443         int i;
444         int is_child;
445
446         for(i = 1; path[i] && path[i] != '/'; i++)
447                 root_name[i - 1] = path[i];
448         root_name[i - 1] = '\0';
449
450         return strlen(&path[i]);
451 }
452
453 typedef enum {PROC_PATH_FAILED, PROC_PATH_ROOT_DIR, PROC_PATH_PROXY_DIR} proc_result_t;
454
455 proc_result_t process_path(const char *path_in, char *path_out, char *root_name,
456                            int attempt_mount, mount_list_t **out_mount)
457 {
458         int i;
459         char *path_out_base;
460         int is_child;
461         int len;
462         mount_list_t *mount = NULL;
463
464         *out_mount = NULL;
465
466         fprintf(stderr, "Path in: %s\n", path_in);
467         is_child = extract_root_name(path_in, root_name);
468         fprintf(stderr, "root_name is: %s\n", root_name);
469
470         // Mount filesystem if necessary
471         // the combination of is_child and attempt_mount prevent inappropriate
472         // mounting of a filesystem for example if the user tries to mknod
473         // in the afuse root this should cause an error not a mount.
474         // !!FIXME!! this is broken on FUSE < 2.5 (?) because a getattr
475         // on the root node seems to occur with every single access.
476         if( /*(is_child || attempt_mount ) &&  */
477            strlen(root_name) > 0            &&
478            !(mount = find_mount(root_name)) &&
479            !(mount = do_mount(root_name)))
480                 return PROC_PATH_FAILED;
481
482         if (mount && !check_mount(mount))
483         {
484                 do_umount(mount);
485                 mount = do_mount(root_name);
486                 if (!mount)
487                         return PROC_PATH_FAILED;
488         }
489
490         // construct path_out (mount_point_directory + '/' + path_in + '\0')
491         path_out_base = path_out;
492         len = strlen(mount_point_directory);
493         memcpy(path_out, mount_point_directory, len);
494         path_out += len;
495         *path_out++ = '/';
496         len = strlen(path_in) - 1;
497         memcpy(path_out, path_in + 1, len);
498         path_out += len;
499         *path_out = '\0';
500         fprintf(stderr, "Path out: %s\n", path_out_base);
501
502         *out_mount = mount;
503
504         return strlen(root_name) ? PROC_PATH_PROXY_DIR : PROC_PATH_ROOT_DIR;
505 }
506
507 static int afuse_getattr(const char *path, struct stat *stbuf)
508 {
509         int res;
510         char *root_name = alloca( strlen(path) );
511         char *real_path = alloca( max_path_out_len(path) );
512         int retval;
513         mount_list_t *mount;
514         BLOCK_SIGALRM;
515
516         fprintf(stderr, "> GetAttr\n");
517
518         switch( process_path(path, real_path, root_name, 0, &mount) )
519         {
520                 case PROC_PATH_FAILED:
521                         retval = -ENXIO;
522                         break;
523
524                 case PROC_PATH_ROOT_DIR:
525                         fprintf(stderr, "Getattr on: (%s) - %s\n", path, root_name);
526                         if(mount || strlen(root_name) == 0) {
527                                 stbuf->st_mode    = S_IFDIR | 0700;
528                                 stbuf->st_nlink   = 1;
529                                 stbuf->st_uid     = getuid();
530                                 stbuf->st_gid     = getgid();
531                                 stbuf->st_size    = 0;
532                                 stbuf->st_blksize = 0;
533                                 stbuf->st_blocks  = 0;
534                                 stbuf->st_atime   = 0;
535                                 stbuf->st_mtime   = 0;
536                                 stbuf->st_ctime   = 0;
537                                 retval = 0;
538                         } else
539                                 retval = -ENOENT;
540                         break;
541
542                 case PROC_PATH_PROXY_DIR:
543                         retval = get_retval(lstat(real_path, stbuf));
544                         break;
545         }
546         if (mount)
547                 update_auto_unmount(mount);
548         UNBLOCK_SIGALRM;
549         return retval;
550 }
551
552 static int afuse_readlink(const char *path, char *buf, size_t size)
553 {
554         int res;
555         char *root_name = alloca( strlen(path) );
556         char *real_path = alloca( max_path_out_len(path) );
557         int retval;
558         mount_list_t *mount;
559         BLOCK_SIGALRM;
560
561         switch( process_path(path, real_path, root_name, 1, &mount) )
562         {
563                 case PROC_PATH_FAILED:
564                         retval = -ENXIO;
565                         break;
566                 case PROC_PATH_ROOT_DIR:
567                         retval = -ENOENT;
568                         break;
569                 case PROC_PATH_PROXY_DIR:
570                         res = readlink(real_path, buf, size - 1);
571                         if (res == -1)
572                         {
573                                 retval = -errno;
574                                 break;
575                         }
576                         buf[res] = '\0';
577                         retval = 0;
578                         break;
579         }
580         if (mount)
581                 update_auto_unmount(mount);
582         UNBLOCK_SIGALRM;
583         return retval;
584 }
585
586 static int afuse_opendir(const char *path, struct fuse_file_info *fi)
587 {
588         DIR *dp;
589         char *root_name = alloca( strlen(path) );
590         mount_list_t *mount;
591         char *real_path = alloca( max_path_out_len(path) );
592         int retval;
593         BLOCK_SIGALRM;
594
595         switch( process_path(path, real_path, root_name, 1, &mount) )
596         {
597                 case PROC_PATH_FAILED:
598                         retval = -ENXIO;
599                         break;
600                 case PROC_PATH_ROOT_DIR:
601                         retval = 0;
602                         break;
603                 case PROC_PATH_PROXY_DIR:
604                         dp = opendir(real_path);
605                         if (dp == NULL) {
606                                 retval = -errno;
607                                 break;
608                         }
609                         fi->fh = (unsigned long) dp;
610                         if(mount)
611                                 dir_list_add(&mount->dir_list, dp);
612                         retval = 0;
613                         break;
614         }
615         if (mount)
616                 update_auto_unmount(mount);
617         UNBLOCK_SIGALRM;
618         return retval;
619 }
620
621 static inline DIR *get_dirp(struct fuse_file_info *fi)
622 {
623         return (DIR *) (uintptr_t) fi->fh;
624 }
625
626 static int afuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
627                        off_t offset, struct fuse_file_info *fi)
628 {
629         DIR *dp = get_dirp(fi);
630         struct dirent *de;
631         char *root_name = alloca( strlen(path) );
632         char *real_path = alloca( max_path_out_len(path) );
633         mount_list_t *mount, *next;
634         int retval;
635         BLOCK_SIGALRM;
636
637         switch( process_path(path, real_path, root_name, 1, &mount) )
638         {
639                 case PROC_PATH_FAILED:
640                         retval = -ENXIO;
641                         break;
642
643                 case PROC_PATH_ROOT_DIR:
644                         filler(buf, ".", NULL, 0);
645                         filler(buf, "..", NULL, 0);
646                         for(mount = mount_list; mount; mount = next)
647                         {
648                                 next = mount->next;
649                                 /* Check for dead mounts. */
650                                 if (!check_mount(mount))
651                                         do_umount(mount);
652                                 else
653                                         filler(buf, mount->root_name, NULL, 0);
654                         }
655                         mount = NULL;
656                         retval = 0;
657                         break;
658
659                 case PROC_PATH_PROXY_DIR:
660                         seekdir(dp, offset);
661                         while ((de = readdir(dp)) != NULL) {
662                                 struct stat st;
663                                 memset(&st, 0, sizeof(st));
664                                 st.st_ino = de->d_ino;
665                                 st.st_mode = de->d_type << 12;
666                                 if (filler(buf, de->d_name, &st, telldir(dp)))
667                                         break;
668                         }
669                         retval = 0;
670                         break;
671         }
672         if (mount)
673                 update_auto_unmount(mount);
674         UNBLOCK_SIGALRM;
675         return retval;
676 }
677
678 static int afuse_releasedir(const char *path, struct fuse_file_info *fi)
679 {
680         DIR *dp = get_dirp(fi);
681         mount_list_t *mount;
682         char *root_name = alloca( strlen(path) );
683         char *real_path = alloca( max_path_out_len(path) );
684         int retval;
685
686         BLOCK_SIGALRM;
687
688         switch( process_path(path, real_path, root_name, 1, &mount) )
689         {
690                 case PROC_PATH_FAILED:
691                         retval = -ENXIO;
692                         break;
693
694                 case PROC_PATH_ROOT_DIR:
695                         retval = 0;
696                         break;
697
698                 case PROC_PATH_PROXY_DIR:
699                         if (mount)
700                                 dir_list_remove(&mount->dir_list, dp);
701                         closedir(dp);
702                         retval = 0;
703         }
704         if (mount)
705                 update_auto_unmount(mount);
706         UNBLOCK_SIGALRM;
707         return retval;
708 }
709
710 static int afuse_mknod(const char *path, mode_t mode, dev_t rdev)
711 {
712         char *root_name = alloca( strlen(path) );
713         char *real_path = alloca( max_path_out_len(path) );
714         mount_list_t *mount;
715         int retval;
716         BLOCK_SIGALRM;
717         fprintf(stderr, "> Mknod\n");
718
719         switch( process_path(path, real_path, root_name, 0, &mount) )
720         {
721                 case PROC_PATH_FAILED:
722                         retval = -ENXIO;
723                         break;
724
725                 case PROC_PATH_ROOT_DIR:
726                         retval = -ENOTSUP;
727                         break;
728
729                 case PROC_PATH_PROXY_DIR:
730                         if (S_ISFIFO(mode))
731                                 retval = get_retval(mkfifo(real_path, mode));
732                         else
733                                 retval = get_retval(mknod(real_path, mode, rdev));
734                         break;
735         }
736         if (mount)
737                 update_auto_unmount(mount);
738         UNBLOCK_SIGALRM;
739         return retval;
740 }
741
742 static int afuse_mkdir(const char *path, mode_t mode)
743 {
744         char *root_name = alloca( strlen(path) );
745         char *real_path = alloca( max_path_out_len(path) );
746         int retval;
747         mount_list_t *mount;
748         BLOCK_SIGALRM;
749
750         switch( process_path(path, real_path, root_name, 0, &mount) )
751         {
752                 case PROC_PATH_FAILED:
753                         retval = -ENXIO;
754                         break;
755                 case PROC_PATH_ROOT_DIR:
756                         retval = -ENOTSUP;
757                         break;
758                 case PROC_PATH_PROXY_DIR:
759                         retval = get_retval(mkdir(real_path, mode));
760                         break;
761         }
762         if (mount)
763                 update_auto_unmount(mount);
764         UNBLOCK_SIGALRM;
765         return retval;
766 }
767
768 static int afuse_unlink(const char *path)
769 {
770         char *root_name = alloca( strlen(path) );
771         char *real_path = alloca( max_path_out_len(path) );
772         mount_list_t *mount;
773         int retval;
774         BLOCK_SIGALRM;
775
776         switch( process_path(path, real_path, root_name, 0, &mount) )
777         {
778                 case PROC_PATH_FAILED:
779                         retval = -ENXIO;
780                         break;
781                 case PROC_PATH_ROOT_DIR:
782                         retval = -ENOTSUP;
783                         break;
784                 case PROC_PATH_PROXY_DIR:
785                         retval = get_retval(unlink(real_path));
786                         break;
787         }
788         if (mount)
789                 update_auto_unmount(mount);
790         UNBLOCK_SIGALRM;
791         return retval;
792 }
793
794 static int afuse_rmdir(const char *path)
795 {
796         char *root_name = alloca( strlen(path) );
797         char *real_path = alloca( max_path_out_len(path) );
798         mount_list_t *mount;
799         int retval;
800         BLOCK_SIGALRM;
801
802         switch( process_path(path, real_path, root_name, 0, &mount) )
803         {
804                 case PROC_PATH_FAILED:
805                         retval = -ENXIO;
806                         break;
807                 case PROC_PATH_ROOT_DIR:
808                         retval = -ENOTSUP;
809                         break;
810                 case PROC_PATH_PROXY_DIR:
811                         if (!extract_root_name(path, root_name))
812                         {
813                                 /* Unmount */
814                                 if (mount->dir_list || mount->fd_list)
815                                         retval = -EBUSY;
816                                 else
817                                 {
818                                         do_umount(mount);
819                                         mount = NULL;
820                                         retval = 0;
821                                 }
822                         } else
823                                 retval = get_retval(rmdir(real_path));
824                         break;
825         }
826         if (mount)
827                 update_auto_unmount(mount);
828         UNBLOCK_SIGALRM;
829         return retval;
830 }
831
832 static int afuse_symlink(const char *from, const char *to)
833 {
834         char *root_name_to = alloca( strlen(to) );
835         char *real_to_path = alloca( max_path_out_len(to) );
836         mount_list_t *mount;
837         int retval;
838         BLOCK_SIGALRM;
839
840         switch( process_path(to, real_to_path, root_name_to, 0, &mount) )
841         {
842                 case PROC_PATH_FAILED:
843                         retval = -ENXIO;
844                         break;
845                 case PROC_PATH_ROOT_DIR:
846                         retval = -ENOTSUP;
847                         break;
848                 case PROC_PATH_PROXY_DIR:
849                         retval = get_retval(symlink(from, real_to_path));
850                         break;
851         }
852         if (mount)
853                 update_auto_unmount(mount);
854         UNBLOCK_SIGALRM;
855         return retval;
856 }
857
858 static int afuse_rename(const char *from, const char *to)
859 {
860         char *root_name_from = alloca( strlen(from) );
861         char *root_name_to = alloca( strlen(to) );
862         char *real_from_path = alloca( max_path_out_len(from) );
863         char *real_to_path = alloca( max_path_out_len(to) );
864         mount_list_t *mount_from, *mount_to = NULL;
865         int retval;
866         BLOCK_SIGALRM;
867
868         switch( process_path(from, real_from_path, root_name_from, 0, &mount_from) )
869         {
870                 case PROC_PATH_FAILED:
871                         retval = -ENXIO;
872                         break;
873
874                 case PROC_PATH_ROOT_DIR:
875                         retval = -ENOTSUP;
876                         break;
877
878                 case PROC_PATH_PROXY_DIR:
879                         switch( process_path(to, real_to_path, root_name_to, 0, &mount_to) )
880                         {
881                                 case PROC_PATH_FAILED:
882                                         retval = -ENXIO;
883                                         break;
884
885                                 case PROC_PATH_ROOT_DIR:
886                                         retval = -ENOTSUP;
887                                         break;
888
889                                 case PROC_PATH_PROXY_DIR:
890                                         retval = get_retval(rename(real_from_path, real_to_path));
891                                         break;
892                         }
893                         break;
894         }
895         if (mount_to)
896                 update_auto_unmount(mount_to);
897         if (mount_from && mount_from != mount_to)
898                 update_auto_unmount(mount_from);
899         UNBLOCK_SIGALRM;
900         return retval;
901 }
902
903 static int afuse_link(const char *from, const char *to)
904 {
905         char *root_name_from = alloca( strlen(from) );
906         char *root_name_to = alloca( strlen(to) );
907         char *real_from_path = alloca( max_path_out_len(from) );
908         char *real_to_path = alloca( max_path_out_len(to) );
909         mount_list_t *mount_to = NULL, *mount_from;
910         int retval;
911         BLOCK_SIGALRM;
912
913         switch( process_path(from, real_from_path, root_name_from, 0, &mount_from) )
914         {
915                 case PROC_PATH_FAILED:
916                         retval = -ENXIO;
917                         break;
918                 case PROC_PATH_ROOT_DIR:
919                         retval = -ENOTSUP;
920                         break;
921                 case PROC_PATH_PROXY_DIR:
922                         switch( process_path(to, real_to_path, root_name_to, 0, &mount_to) )
923                         {
924                                 case PROC_PATH_FAILED:
925                                         retval = -ENXIO;
926                                         break;
927                                 case PROC_PATH_ROOT_DIR:
928                                         retval = -ENOTSUP;
929                                         break;
930                                 case PROC_PATH_PROXY_DIR:
931                                         retval = get_retval(link(real_from_path, real_to_path));
932                                         break;
933                         }
934                         break;
935         }
936         if (mount_to)
937                 update_auto_unmount(mount_to);
938         if (mount_from && mount_from != mount_to)
939                 update_auto_unmount(mount_from);
940         UNBLOCK_SIGALRM;
941         return retval;
942 }
943
944 static int afuse_chmod(const char *path, mode_t mode)
945 {
946         char *root_name = alloca( strlen(path) );
947         char *real_path = alloca( max_path_out_len(path) );
948         mount_list_t *mount;
949         int retval;
950         BLOCK_SIGALRM;
951
952         switch( process_path(path, real_path, root_name, 0, &mount) )
953         {
954                 case PROC_PATH_FAILED:
955                         retval = -ENXIO;
956                         break;
957                 case PROC_PATH_ROOT_DIR:
958                         retval = -ENOTSUP;
959                         break;
960                 case PROC_PATH_PROXY_DIR:
961                         retval = get_retval(chmod(real_path, mode));
962                         break;
963         }
964         if (mount)
965                 update_auto_unmount(mount);
966         UNBLOCK_SIGALRM;
967         return retval;
968 }
969
970 static int afuse_chown(const char *path, uid_t uid, gid_t gid)
971 {
972         char *root_name = alloca( strlen(path) );
973         char *real_path = alloca( max_path_out_len(path) );
974         mount_list_t *mount;
975         int retval;
976         BLOCK_SIGALRM;
977
978         switch( process_path(path, real_path, root_name, 0, &mount) )
979         {
980                 case PROC_PATH_FAILED:
981                         retval = -ENXIO;
982                         break;
983                 case PROC_PATH_ROOT_DIR:
984                         retval = -ENOTSUP;
985                         break;
986                 case PROC_PATH_PROXY_DIR:
987                         retval = get_retval(lchown(real_path, uid, gid));
988                         break;
989         }
990         if (mount)
991                 update_auto_unmount(mount);
992         UNBLOCK_SIGALRM;
993         return retval;
994 }
995
996 static int afuse_truncate(const char *path, off_t size)
997 {
998         char *root_name = alloca( strlen(path) );
999         char *real_path = alloca( max_path_out_len(path) );
1000         mount_list_t *mount;
1001         int retval;
1002         BLOCK_SIGALRM;
1003
1004         switch( process_path(path, real_path, root_name, 0, &mount) )
1005         {
1006                 case PROC_PATH_FAILED:
1007                         retval = -ENXIO;
1008                         break;
1009                 case PROC_PATH_ROOT_DIR:
1010                         retval = -ENOTSUP;
1011                         break;
1012                 case PROC_PATH_PROXY_DIR:
1013                         retval = get_retval(truncate(real_path, size));
1014                         break;
1015         }
1016         if (mount)
1017                 update_auto_unmount(mount);
1018         UNBLOCK_SIGALRM;
1019         return retval;
1020 }
1021
1022
1023 static int afuse_utime(const char *path, struct utimbuf *buf)
1024 {
1025         int res;
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(utime(real_path, buf));
1042                         break;
1043         }
1044         if (mount)
1045                 update_auto_unmount(mount);
1046         UNBLOCK_SIGALRM;
1047         return retval;
1048 }
1049
1050
1051 static int afuse_open(const char *path, struct fuse_file_info *fi)
1052 {
1053         int fd;
1054         char *root_name = alloca( strlen(path) );
1055         mount_list_t *mount;
1056         char *real_path = alloca( max_path_out_len(path) );
1057         int retval;
1058         BLOCK_SIGALRM;
1059
1060         switch( process_path(path, real_path, root_name, 1, &mount) )
1061         {
1062                 case PROC_PATH_FAILED:
1063                         retval = -ENXIO;
1064                         break;
1065                 case PROC_PATH_ROOT_DIR:
1066                         retval = -ENOENT;
1067                         break;
1068                 case PROC_PATH_PROXY_DIR:
1069                         fd = open(real_path, fi->flags);
1070                         if (fd == -1) {
1071                                 retval = -errno;
1072                                 break;
1073                         }
1074
1075                         fi->fh = fd;
1076                         if(mount)
1077                                 fd_list_add(&mount->fd_list, fd);
1078                         retval = 0;
1079                         break;
1080         }
1081         if (mount)
1082                 update_auto_unmount(mount);
1083         UNBLOCK_SIGALRM;
1084         return retval;
1085 }
1086
1087 static int afuse_read(const char *path, char *buf, size_t size, off_t offset,
1088                       struct fuse_file_info *fi)
1089 {
1090         int res;
1091
1092         (void)path;
1093         res = pread(fi->fh, buf, size, offset);
1094         if (res == -1)
1095                 res = -errno;
1096
1097         return res;
1098 }
1099
1100 static int afuse_write(const char *path, const char *buf, size_t size,
1101                        off_t offset, struct fuse_file_info *fi)
1102 {
1103         int res;
1104
1105         (void) path;
1106         res = pwrite(fi->fh, buf, size, offset);
1107         if (res == -1)
1108                 res = -errno;
1109
1110         if(user_options.flush_writes)
1111                 fsync(fi->fh);
1112
1113         return res;
1114 }
1115
1116
1117 static int afuse_release(const char *path, struct fuse_file_info *fi)
1118 {
1119         char *root_name = alloca( strlen(path) );
1120         mount_list_t *mount;
1121         int retval;
1122         BLOCK_SIGALRM;
1123
1124         extract_root_name(path, root_name);
1125         mount = find_mount(root_name);
1126         retval = get_retval(close(fi->fh));
1127
1128         if(mount)
1129         {
1130                 fd_list_remove(&mount->fd_list, fi->fh);
1131                 update_auto_unmount(mount);
1132         }
1133
1134         UNBLOCK_SIGALRM;
1135         return retval;
1136 }
1137
1138 static int afuse_fsync(const char *path, int isdatasync,
1139                        struct fuse_file_info *fi)
1140 {
1141         int res;
1142         (void) path;
1143
1144         #ifndef HAVE_FDATASYNC
1145         (void) isdatasync;
1146         #else
1147         if (isdatasync)
1148                 res = fdatasync(fi->fh);
1149         else
1150         #endif
1151                 res = fsync(fi->fh);
1152         return get_retval(res);
1153 }
1154
1155 #if FUSE_VERSION >= 25
1156 static int afuse_access(const char *path, int mask)
1157 {
1158         char *root_name = alloca( strlen(path) );
1159         char *real_path = alloca( max_path_out_len(path) );
1160         mount_list_t *mount;
1161         int retval;
1162         BLOCK_SIGALRM;
1163
1164         switch( process_path(path, real_path, root_name, 1, &mount) )
1165         {
1166                 case PROC_PATH_FAILED:
1167                         retval = -ENXIO;
1168                         break;
1169                 case PROC_PATH_ROOT_DIR:
1170                 case PROC_PATH_PROXY_DIR:
1171                         retval = get_retval(access(real_path, mask));
1172                         break;
1173         }
1174         if (mount)
1175                 update_auto_unmount(mount);
1176         UNBLOCK_SIGALRM;
1177         return retval;
1178 }
1179
1180 static int afuse_ftruncate(const char *path, off_t size,
1181                            struct fuse_file_info *fi)
1182 {
1183         (void) path;
1184         return get_retval(ftruncate(fi->fh, size));
1185 }
1186
1187 static int afuse_create(const char *path, mode_t mode, struct fuse_file_info *fi)
1188 {
1189         int fd;
1190         char *root_name = alloca( strlen(path) );
1191         char *real_path = alloca( max_path_out_len(path) );
1192         mount_list_t *mount;
1193         int retval;
1194         BLOCK_SIGALRM;
1195
1196         switch( process_path(path, real_path, root_name, 0, &mount) )
1197         {
1198                 case PROC_PATH_FAILED:
1199                         retval = -ENXIO;
1200                         break;
1201                 case PROC_PATH_ROOT_DIR:
1202                         retval = -ENOTSUP;
1203                         break;
1204                 case PROC_PATH_PROXY_DIR:
1205                         fd = open(real_path, fi->flags, mode);
1206                         if (fd == -1)
1207                         {
1208                                 retval = -errno;
1209                                 break;
1210                         }
1211                         fi->fh = fd;
1212                         retval = 0;
1213                         break;
1214         }
1215         if (mount)
1216                 update_auto_unmount(mount);
1217         UNBLOCK_SIGALRM;
1218         return retval;
1219 }
1220
1221 static int afuse_fgetattr(const char *path, struct stat *stbuf,
1222                           struct fuse_file_info *fi)
1223 {
1224         (void) path;
1225
1226         return get_retval(fstat(fi->fh, stbuf));
1227 }
1228 #endif
1229
1230
1231 #if FUSE_VERSION >= 25
1232 static int afuse_statfs(const char *path, struct statvfs *stbuf)
1233 #else
1234 static int afuse_statfs(const char *path, struct statfs *stbuf)
1235 #endif
1236 {
1237         char *root_name = alloca( strlen(path) );
1238         char *real_path = alloca( max_path_out_len(path) );
1239         mount_list_t *mount;
1240         int retval;
1241         BLOCK_SIGALRM;
1242
1243         switch( process_path(path, real_path, root_name, 1, &mount) )
1244         {
1245                 case PROC_PATH_FAILED:
1246                         retval = -ENXIO;
1247                         break;
1248
1249                 case PROC_PATH_ROOT_DIR:
1250 #if FUSE_VERSION >= 25
1251                         stbuf->f_namemax = 0x7fffffff;
1252                         stbuf->f_frsize  = 512;
1253 #else
1254                         stbuf->f_namelen = 0x7fffffff;
1255 #endif
1256                         stbuf->f_bsize   = 1024;
1257                         stbuf->f_blocks  = 0;
1258                         stbuf->f_bfree   = 0;
1259                         stbuf->f_bavail  = 0;
1260                         stbuf->f_files   = 0;
1261                         stbuf->f_ffree   = 0;
1262                         retval = 0;
1263                         break;
1264
1265                 case PROC_PATH_PROXY_DIR:
1266                         retval = get_retval(statvfs(real_path, stbuf));
1267                         break;
1268         }
1269         if (mount)
1270                 update_auto_unmount(mount);
1271         UNBLOCK_SIGALRM;
1272         return retval;
1273 }
1274
1275 void afuse_destroy(void *p)
1276 {
1277         shutdown();
1278 }
1279
1280 #ifdef HAVE_SETXATTR
1281 /* xattr operations are optional and can safely be left unimplemented */
1282 static int afuse_setxattr(const char *path, const char *name, const char *value,
1283                           size_t size, int flags)
1284 {
1285         char *root_name = alloca( strlen(path) );
1286         char *real_path = alloca( max_path_out_len(path) );
1287         mount_list_t *mount;
1288         int retval;
1289         BLOCK_SIGALRM;
1290
1291         switch( process_path(path, real_path, root_name, 0, &mount) )
1292         {
1293                 case PROC_PATH_FAILED:
1294                         retval = -ENXIO;
1295                         break;
1296                 case PROC_PATH_ROOT_DIR:
1297                         retval = -ENOENT;
1298                         break;
1299                 case PROC_PATH_PROXY_DIR:
1300                         retval = get_retval(lsetxattr(real_path, name, value, size, flags));
1301                         break;
1302         }
1303         if (mount)
1304                 update_auto_unmount(mount);
1305         UNBLOCK_SIGALRM;
1306         return retval;
1307 }
1308
1309 static int afuse_getxattr(const char *path, const char *name, char *value,
1310                                                   size_t size)
1311 {
1312         char *root_name = alloca( strlen(path) );
1313         char *real_path = alloca( max_path_out_len(path) );
1314         mount_list_t *mount;
1315         int retval;
1316         BLOCK_SIGALRM;
1317
1318         switch( process_path(path, real_path, root_name, 1, &mount) )
1319         {
1320                 case PROC_PATH_FAILED:
1321                         retval = -ENXIO;
1322                         break;
1323                 case PROC_PATH_ROOT_DIR:
1324                         retval = -ENOTSUP;
1325                         break;
1326                 case PROC_PATH_PROXY_DIR:
1327                         retval = get_retval(lgetxattr(real_path, name, value, size));
1328                         break;
1329         }
1330         if (mount)
1331                 update_auto_unmount(mount);
1332         UNBLOCK_SIGALRM;
1333         return retval;
1334 }
1335
1336 static int afuse_listxattr(const char *path, char *list, size_t size)
1337 {
1338         char *root_name = alloca( strlen(path) );
1339         char *real_path = alloca( max_path_out_len(path) );
1340         mount_list_t *mount;
1341         int retval;
1342         BLOCK_SIGALRM;
1343
1344         switch( process_path(path, real_path, root_name, 1, &mount) )
1345         {
1346                 case PROC_PATH_FAILED:
1347                         retval = -ENXIO;
1348                         break;
1349                 case PROC_PATH_ROOT_DIR:
1350                         retval = -ENOTSUP;
1351                         break;
1352                 case PROC_PATH_PROXY_DIR:
1353                         retval = get_retval(llistxattr(real_path, list, size));
1354                         break;
1355         }
1356         if (mount)
1357                 update_auto_unmount(mount);
1358         UNBLOCK_SIGALRM;
1359         return retval;
1360 }
1361
1362 static int afuse_removexattr(const char *path, const char *name)
1363 {
1364         char *root_name = alloca( strlen(path) );
1365         char *real_path = alloca( max_path_out_len(path) );
1366         mount_list_t *mount;
1367         int retval;
1368         BLOCK_SIGALRM;
1369
1370         switch( process_path(path, real_path, root_name, 0, &mount) )
1371         {
1372                 case PROC_PATH_FAILED:
1373                         retval = -ENXIO;
1374                         break;
1375                 case PROC_PATH_ROOT_DIR:
1376                         retval = -ENOTSUP;
1377                         break;
1378                 case PROC_PATH_PROXY_DIR:
1379                         retval = get_retval(lremovexattr(real_path, name));
1380                         break;
1381         }
1382         if (mount)
1383                 update_auto_unmount(mount);
1384         UNBLOCK_SIGALRM;
1385         return retval;
1386 }
1387 #endif /* HAVE_SETXATTR */
1388
1389 static struct fuse_operations afuse_oper = {
1390         .getattr     = afuse_getattr,
1391         .readlink    = afuse_readlink,
1392         .opendir     = afuse_opendir,
1393         .readdir     = afuse_readdir,
1394         .releasedir  = afuse_releasedir,
1395         .mknod       = afuse_mknod,
1396         .mkdir       = afuse_mkdir,
1397         .symlink     = afuse_symlink,
1398         .unlink      = afuse_unlink,
1399         .rmdir       = afuse_rmdir,
1400         .rename      = afuse_rename,
1401         .link        = afuse_link,
1402         .chmod       = afuse_chmod,
1403         .chown       = afuse_chown,
1404         .truncate    = afuse_truncate,
1405         .utime       = afuse_utime,
1406         .open        = afuse_open,
1407         .read        = afuse_read,
1408         .write       = afuse_write,
1409         .release     = afuse_release,
1410         .fsync       = afuse_fsync,
1411         .statfs      = afuse_statfs,
1412 #if FUSE_VERSION >= 25
1413         .access      = afuse_access,
1414         .create      = afuse_create,
1415         .ftruncate   = afuse_ftruncate,
1416         .fgetattr    = afuse_fgetattr,
1417 #endif
1418         .destroy     = afuse_destroy,
1419 #ifdef HAVE_SETXATTR
1420         .setxattr    = afuse_setxattr,
1421         .getxattr    = afuse_getxattr,
1422         .listxattr   = afuse_listxattr,
1423         .removexattr = afuse_removexattr,
1424 #endif
1425 };
1426
1427
1428 enum {
1429         KEY_HELP,
1430         KEY_FLUSHWRITES
1431 };
1432
1433 #define AFUSE_OPT(t, p, v) { t, offsetof(struct user_options_t, p), v }
1434
1435 static struct fuse_opt afuse_opts[] = {
1436         AFUSE_OPT("mount_template=%s", mount_command_template, 0),
1437         AFUSE_OPT("unmount_template=%s", unmount_command_template, 0),
1438
1439         AFUSE_OPT("timeout=%Lu", auto_unmount_delay, 0),
1440
1441         FUSE_OPT_KEY("flushwrites",     KEY_FLUSHWRITES),
1442         FUSE_OPT_KEY("-h",     KEY_HELP),
1443         FUSE_OPT_KEY("--help", KEY_HELP),
1444
1445         FUSE_OPT_END
1446 };
1447
1448 static void usage(const char *progname)
1449 {
1450         fprintf(stderr,
1451 "Usage: %s mountpoint [options]\n"
1452 "\n"
1453 "    -o opt,[opt...]        mount options\n"
1454 "    -h   --help            print help\n"
1455 "    -V   --version         print FUSE version information\n"
1456 "\n"
1457 "afuse options:\n"
1458 "    -o mount_template=CMD    template for CMD to execute to mount (*)\n"
1459 "    -o unmount_template=CMD  template for CMD to execute to unmount (*) (**)\n"
1460 "    -o timeout=TIMEOUT       automatically unmount after TIMEOUT seconds\n"
1461 "    -o flushwrites           flushes data to disk for all file writes\n"
1462 "\n\n"
1463 " (*) - When executed, %%r and %%m are expanded in templates to the root\n"
1464 "       directory name for the new mount point, and the actual directory to\n"
1465 "       mount onto respectively to mount onto. Both templates are REQUIRED.\n"
1466 "\n"
1467 " (**) - The unmount command must perform a lazy unmount operation. E.g. the\n"
1468 "        -u -z options to fusermount, or -l for regular mount.\n"
1469 "\n", progname);
1470 }
1471
1472 static int afuse_opt_proc(void *data, const char *arg, int key,
1473                           struct fuse_args *outargs)
1474 {
1475         (void) arg;
1476
1477         switch(key)
1478         {
1479                 case KEY_HELP:
1480                         usage(outargs->argv[0]);
1481                         fuse_opt_add_arg(outargs, "-ho");
1482                         fuse_main(outargs->argc, outargs->argv, &afuse_oper);
1483                         exit(1);
1484
1485                 case KEY_FLUSHWRITES:
1486                         user_options.flush_writes = true;
1487                         return 0;
1488
1489                 default:
1490                         return 1;
1491         }
1492 }
1493
1494 int main(int argc, char *argv[])
1495 {
1496         struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1497         char *temp_dir_name = my_malloc(strlen(TMP_DIR_TEMPLATE));
1498         strcpy(temp_dir_name, TMP_DIR_TEMPLATE);
1499
1500         if(fuse_opt_parse(&args, &user_options, afuse_opts, afuse_opt_proc) == -1)
1501                 return 1;
1502
1503         // !!FIXME!! force single-threading for now as data structures are not locked
1504         fuse_opt_add_arg(&args, "-s");
1505
1506         // Adjust user specified timeout from seconds to microseconds as required
1507         user_options.auto_unmount_delay *= 1000000;
1508
1509         auto_unmount_ph_init(&auto_unmount_ph);
1510
1511         /**
1512          * Install the SIGALRM signal handler.
1513          */
1514         {
1515                 struct sigaction act;
1516                 act.sa_handler = &handle_auto_unmount_timer;
1517                 sigemptyset(&act.sa_mask);
1518                 act.sa_flags = 0;
1519                 while (sigaction(SIGALRM, &act, NULL) == -1 && errno == EINTR)
1520                         continue;
1521         }
1522
1523         // Check for required parameters
1524         if(!user_options.mount_command_template || !user_options.unmount_command_template) {
1525                 fprintf(stderr, "(Un)Mount command templates missing.\n\n");
1526                 usage(argv[0]);
1527                 fuse_opt_add_arg(&args, "-ho");
1528                 fuse_main(args.argc, args.argv, &afuse_oper);
1529
1530                 return 1;
1531         }
1532
1533         if( !(mount_point_directory = mkdtemp(temp_dir_name)) ) {
1534                 fprintf(stderr, "Failed to create temporary mount point dir.\n");
1535                 return 1;
1536         }
1537
1538         {
1539                 struct stat buf;
1540                 if (lstat(mount_point_directory, &buf) == -1) {
1541                         fprintf(stderr, "Failed to stat temporary mount point dir.\n");
1542                         return 1;
1543                 }
1544                 mount_point_dev = buf.st_dev;
1545         }
1546
1547         umask(0);
1548
1549
1550         // !!FIXME!! death by signal doesn't unmount fs
1551         return fuse_main(args.argc, args.argv, &afuse_oper);
1552 }
1553
1554 /*
1555   Local Variables:
1556   c-basic-offset: 4
1557   indent-tabs-mode: t
1558   End:
1559  */