venus: Remove dedebug
[openafs.git] / src / afsd / afsd_fuse.c
1 /*
2  * Copyright (c) 2008-2010 Sine Nomine Associates
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of Sine Nomine Associates nor the names of its
17  *    contributors may be used to endorse or promote products derived from
18  *    this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
21  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /*
34  * afsd_fuse.c - Driver for afsd.fuse, and glue between FUSE and libuafs
35  */
36
37 #include <afsconfig.h>
38 #include <afs/param.h>
39
40 #include <sysincludes.h>
41 #include <afs/afsutil.h>
42 #include <afs_usrops.h>
43 #include <afs/cmd.h>
44 #include <afs/afs_args.h>
45
46 #include "afsd.h"
47
48 #include <errno.h>
49 #include <stddef.h>
50 #include <stdio.h>
51
52 #define FUSE_USE_VERSION 27
53 #include <fuse.h>
54
55 /* command-line arguments to pass to afsd and the cmd_ library */
56 static struct fuse_args afsd_args = FUSE_ARGS_INIT(0, NULL);
57
58 /* command-line arguments to pass to FUSE */
59 static struct fuse_args fuse_args = FUSE_ARGS_INIT(0, NULL);
60
61 /* used for command-line parsing in fuafsd_fuse_opt below */
62 static int fuafsd_cmd_accept = 0;
63 static int nullfd;
64 static int stderr_save;
65
66 /**
67  * Turn FUSE-y paths into libuafs-y paths.
68  *
69  * @param[in] apath  a path in the form of /localcell/foo/bar
70  *
71  * @return a path (non-const) in the form /afs/localcell/foo/bar to be freed
72  *         by the caller
73  */
74 static char *
75 afs_path(const char *apath)
76 {
77     static const char prefix[] = "/afs/";
78     char *path;
79
80     if (asprintf(&path, "%s%s", prefix, apath) < 0)
81         path = NULL;
82
83     return path;
84 }
85
86 static void *
87 fuafsd_init(struct fuse_conn_info *conn)
88 {
89     uafs_Run();
90
91     uafs_setMountDir("/afs");
92
93     return NULL;
94 }
95
96 /* Wrappers around libuafs calls for FUSE */
97
98 static int
99 fuafsd_getattr(const char *apath, struct stat *stbuf)
100 {
101         int code;
102         char *path = afs_path(apath);
103
104         if (path == NULL)
105             return -ENOMEM;
106
107         code = uafs_lstat(path, stbuf);
108
109         free(path);
110
111         if (code < 0) {
112                 return -errno;
113         }
114         return 0;
115 }
116
117 static int
118 fuafsd_opendir(const char *apath, struct fuse_file_info * fi)
119 {
120         usr_DIR * dirp;
121         char *path = afs_path(apath);
122
123         if (path == NULL)
124             return -ENOMEM;
125
126         dirp = uafs_opendir(path);
127
128         free(path);
129
130         if (!dirp) {
131                 return -errno;
132         }
133
134         fi->fh = (uintptr_t)dirp;
135
136         return 0;
137 }
138
139 static int
140 fuafsd_readdir(const char *path, void * buf, fuse_fill_dir_t filler,
141                off_t offset, struct fuse_file_info * fi)
142 {
143         usr_DIR * dirp;
144         struct usr_dirent * direntP;
145
146         dirp = (usr_DIR *)(uintptr_t)fi->fh;
147
148         errno = 0;
149         while ((direntP = uafs_readdir(dirp))) {
150                 if (filler(buf, direntP->d_name, NULL, 0)) {
151                         /* buffer is full */
152                         return 0;
153                 }
154         }
155
156         return -errno;
157 }
158
159 static int
160 fuafsd_releasedir(const char *path, struct fuse_file_info * fi)
161 {
162         return uafs_closedir((usr_DIR *)(uintptr_t)fi->fh);
163 }
164
165 static int
166 fuafsd_create(const char *apath, mode_t mode, struct fuse_file_info * fi)
167 {
168         int fd;
169         char *path = afs_path(apath);
170
171         if (path == NULL)
172             return -ENOMEM;
173
174         fd = uafs_open(path, fi->flags, mode);
175
176         free(path);
177
178         if (fd < 0) {
179                 return -errno;
180         }
181
182         fi->fh = fd;
183
184         return 0;
185 }
186
187 static int
188 fuafsd_open(const char *path, struct fuse_file_info * fi)
189 {
190         return fuafsd_create(path, 0, fi);
191 }
192
193 static int
194 fuafsd_read(const char *path, char * buf, size_t len, off_t offset,
195         struct fuse_file_info * fi)
196 {
197         int fd, code;
198
199         fd = fi->fh;
200
201         code = uafs_pread(fd, buf, len, offset);
202         if (code < 0) {
203                 return -errno;
204         }
205
206         return code;
207 }
208
209 static int
210 fuafsd_readlink(const char *apath, char * buf, size_t len)
211 {
212         int code;
213         char *path = afs_path(apath);
214
215         if (path == NULL)
216             return -ENOMEM;
217
218         code = uafs_readlink(path, buf, len);
219
220         free(path);
221
222         if (code < 0) {
223                 return -errno;
224         }
225
226         buf[code] = '\0';
227
228         return 0;
229 }
230
231 static int
232 fuafsd_mkdir(const char *apath, mode_t mode)
233 {
234         int code;
235         char *path = afs_path(apath);
236
237         if (path == NULL)
238             return -ENOMEM;
239
240         code = uafs_mkdir(path, mode);
241
242         free(path);
243
244         if (code < 0) {
245                 return -errno;
246         }
247         return 0;
248 }
249
250 static int
251 fuafsd_unlink(const char *apath)
252 {
253         int code;
254         char *path = afs_path(apath);
255
256         if (path == NULL)
257             return -ENOMEM;
258
259         code = uafs_unlink(path);
260
261         free(path);
262
263         if (code < 0) {
264                 return -errno;
265         }
266         return 0;
267 }
268
269 static int
270 fuafsd_rmdir(const char *apath)
271 {
272         int code;
273         char *path = afs_path(apath);
274
275         if (path == NULL)
276             return -ENOMEM;
277
278         code = uafs_rmdir(path);
279
280         free(path);
281
282         if (code < 0) {
283                 return -errno;
284         }
285         return 0;
286 }
287
288 static int
289 fuafsd_symlink(const char *atarget, const char *asource)
290 {
291         int code;
292         char *target = afs_path(atarget);
293         char *source = afs_path(asource);
294
295         if (target == NULL || source == NULL) {
296             if (target) free(target);
297             if (source) free(source);
298             return -ENOMEM;
299         }
300
301         code = uafs_symlink(target, source);
302
303         free(target);
304         free(source);
305
306         if (code < 0) {
307                 return -errno;
308         }
309         return 0;
310 }
311
312 static int
313 fuafsd_rename(const char *aold, const char *anew)
314 {
315         int code;
316         char *old = afs_path(aold);
317         char *new = afs_path(anew);
318
319         if (old == NULL || new == NULL) {
320             if (old) free(old);
321             if (new) free(new);
322             return -ENOMEM;
323         }
324
325         code = uafs_rename(old, new);
326
327         free(old);
328         free(new);
329
330         if (code < 0) {
331                 return -errno;
332         }
333         return 0;
334 }
335
336 static int
337 fuafsd_link(const char *aexisting, const char *anew)
338 {
339         int code;
340         char *existing = afs_path(aexisting);
341         char *new = afs_path(anew);
342
343         if (existing == NULL || new == NULL) {
344             if (existing) free(existing);
345             if (new) free(new);
346             return -ENOMEM;
347         }
348
349         code = uafs_link(existing, new);
350
351         free(existing);
352         free(new);
353
354         if (code < 0) {
355                 return -errno;
356         }
357         return 0;
358 }
359
360 static int
361 fuafsd_chmod(const char *apath, mode_t mode)
362 {
363         int code;
364         char *path = afs_path(apath);
365
366         if (path == NULL)
367             return -ENOMEM;
368
369         code = uafs_chmod(path, mode);
370
371         free(path);
372
373         if (code < 0) {
374                 return -errno;
375         }
376         return 0;
377 }
378
379 static int
380 fuafsd_truncate(const char *apath, off_t length)
381 {
382         int code;
383         char *path = afs_path(apath);
384
385         if (path == NULL)
386             return -ENOMEM;
387
388         code = uafs_truncate(path, length);
389
390         free(path);
391
392         if (code < 0) {
393                 return -errno;
394         }
395         return 0;
396 }
397
398 static int
399 fuafsd_write(const char *path, const char *abuf, size_t len, off_t offset,
400              struct fuse_file_info * fi)
401 {
402         int fd, code;
403         char *buf = malloc(len);
404
405         fd = fi->fh;
406         memcpy(buf, abuf, len);
407
408         code = uafs_pwrite(fd, buf, len, offset);
409
410         free(buf);
411
412         if (code < 0) {
413                 return -errno;
414         }
415
416         return code;
417 }
418
419 static int
420 fuafsd_statvfs(const char * path, struct statvfs * buf)
421 {
422         if (uafs_statvfs(buf) < 0) {
423                 return -errno;
424         }
425
426         /*
427          * FUSE ignores frsize, and uses bsize for displaying e.g. available
428          * space. Just set bsize to frsize so we get a consistent `df` output.
429          */
430         buf->f_bsize = buf->f_frsize;
431         return 0;
432 }
433
434 static int
435 fuafsd_release(const char *path, struct fuse_file_info * fi)
436 {
437         int fd;
438
439         fd = fi->fh;
440
441         if (uafs_close(fd) < 0) {
442                 return -errno;
443         }
444
445         return 0;
446 }
447
448 static void
449 fuafsd_destroy(void * private_data)
450 {
451         uafs_Shutdown();
452 }
453
454 static struct fuse_operations fuafsd_oper = {
455         .init       = fuafsd_init,
456         .getattr    = fuafsd_getattr,
457         .opendir    = fuafsd_opendir,
458         .readdir    = fuafsd_readdir,
459         .releasedir = fuafsd_releasedir,
460         .open       = fuafsd_open,
461         .create     = fuafsd_create,
462         .read       = fuafsd_read,
463         .readlink   = fuafsd_readlink,
464         .mkdir      = fuafsd_mkdir,
465         .rmdir      = fuafsd_rmdir,
466         .link       = fuafsd_link,
467         .unlink     = fuafsd_unlink,
468         .symlink    = fuafsd_symlink,
469         .rename     = fuafsd_rename,
470         .chmod      = fuafsd_chmod,
471         .truncate   = fuafsd_truncate,
472         .write      = fuafsd_write,
473         .statfs     = fuafsd_statvfs,
474         .release    = fuafsd_release,
475         .destroy    = fuafsd_destroy
476 };
477
478 /* Command line argument processing */
479
480 /*
481  * See fuafsd_fuse_opt below.
482  */
483 static int
484 fuafsd_cmd_check(struct cmd_syndesc * ts, void *beforeRock)
485 {
486         fuafsd_cmd_accept = 1;
487         return 1;
488 }
489
490 /*
491  * Split arguments into FUSE and afsd/libcmd arguments. To determine whether an
492  * argument is meant for FUSE or for the cmd interface, we pass the given
493  * argument to cmd_Dispatch, and see if our beforeProc is run (which we set to
494  * fuafsd_cmd_check). If it was run, the argument is acceptable to cmd; if it
495  * was not run, cmd doesn't know what to do with the argument, so we assume the
496  * argument is meant for FUSE. We can tell if fuafsd_cmd_check was run by the
497  * global fuafsd_cmd_accept bool, which is set to true when fuafsd_cmd_check is
498  * run.
499  */
500 static void
501 split_args(const struct fuse_args *args)
502 {
503         int i;
504
505         cmd_SetBeforeProc(fuafsd_cmd_check, NULL);
506
507         nullfd = open("/dev/null", O_WRONLY);
508         stderr_save = dup(2);
509         if (nullfd < 0 || stderr_save < 0) {
510                 perror("open/dup");
511                 exit(1);
512         }
513
514         for (i = 0; args->argv[i]; ++i) {
515                 int code;
516                 char *arg = args->argv[i];
517                 char *argv[3] = {args->argv[0], arg, NULL};
518
519                 if (fuafsd_cmd_accept) {
520                         fuse_opt_add_arg(&afsd_args, arg);
521                         fuafsd_cmd_accept = 0;
522                         continue;
523                 }
524
525                 /* redirect stderr to null, so libcmd doesn't print out
526                  * an error message for unknown options */
527                 if (dup2(nullfd, 2) < 0) {
528                         perror("dup2");
529                         exit(1);
530                 }
531
532                 code = cmd_Dispatch(2, argv);
533
534                 if (dup2(stderr_save, 2) < 0) {
535                         perror("dup2");
536                         exit(1);
537                 }
538
539                 /* fuafsd_cmd_check should prevent the dispatch from succeeding;
540                  * the only way we should be able to succeed is if -help was
541                  * specified, so just exit */
542                 if (code == 0) {
543                         exit(1);
544                 }
545
546                 if (fuafsd_cmd_accept || code == CMD_TOOFEW) {
547                         /* libcmd accepted the argument; must go to afsd */
548                         fuse_opt_add_arg(&afsd_args, arg);
549
550                         if (code == CMD_TOOFEW) {
551                                 /* flag takes another argument; get the next one, too */
552                                 fuafsd_cmd_accept = 1;
553                         } else {
554                                 fuafsd_cmd_accept = 0;
555                         }
556
557                 } else {
558                         /* libcmd doesn't recognize the argument; give it to FUSE */
559                         fuse_opt_add_arg(&fuse_args, arg);
560                 }
561         }
562
563         if (close(nullfd) < 0) {
564                 perror("close");
565         }
566         if (close(stderr_save) < 0) {
567                 perror("close");
568         }
569
570         cmd_SetBeforeProc(NULL, NULL);
571 }
572
573 /*
574  * First we divide the given arguments into FUSE and cmd arguments, pass the
575  * FUSE arguments to FUSE, and call cmd_Dispatch in the FUSE init function.
576  */
577 int
578 main(int argc, char **argv)
579 {
580         int code;
581         struct fuse_args args = FUSE_ARGS_INIT(argc-1, &argv[1]);
582         fuse_opt_add_arg(&afsd_args, argv[0]);
583
584 #ifdef AFS_SUN511_ENV
585         /* for some reason, Solaris 11 FUSE takes the filesystem name from
586          * argv[0], and ignores the -ofsname option */
587         fuse_opt_add_arg(&fuse_args, "AFS");
588 #else
589         fuse_opt_add_arg(&fuse_args, argv[0]);
590 #endif
591
592         /* let us determine file inode numbers, not FUSE. also make "AFS" appear
593          * in df/mount/mnttab/etc output. */
594         fuse_opt_add_arg(&fuse_args, "-ouse_ino,fsname=AFS");
595
596         if (getuid() == 0) {
597             /* allow other users to access the mountpoint. only do this for
598              * root, since non-root may or may not be able to do this */
599             fuse_opt_add_arg(&fuse_args, "-oallow_other");
600         }
601
602         code = uafs_Setup("/afs");
603         if (code) {
604                 errno = code;
605                 perror("libuafs");
606                 return 1;
607         }
608
609         split_args(&args);
610
611         code = uafs_ParseArgs(afsd_args.argc, afsd_args.argv);
612         if (code != 0) {
613             /*
614              * split_args() failed to populate afds_args correctly.
615              * We do not not bother to check for CMD_HELP here, since
616              * split_args() exits when -help is given.
617              */
618             fprintf(stderr,
619                     "afsd.fuse: Could not parse command line options; code %d\n",
620                     code);
621             return 1;
622         }
623
624         /* pass "-- /mount/dir" to fuse to specify dir to mount; "--" is
625          * just to make sure fuse doesn't interpret the mount dir as a flag
626          */
627 #ifndef AFS_SUN511_ENV
628         /* This seems to screw up option parsing on Solaris 11 FUSE, so just
629          * don't do it. This makes it slightly more annoying to mount on a dir
630          * called -foo or something, but oh well. */
631         fuse_opt_add_arg(&fuse_args, "--");
632 #endif
633         fuse_opt_add_arg(&fuse_args, uafs_MountDir());
634
635         return fuse_main(fuse_args.argc, fuse_args.argv, &fuafsd_oper, NULL);
636 }