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