2 * Copyright (c) 2008-2010 Sine Nomine Associates
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 * afsd_fuse.c - Driver for afsd.fuse, and glue between FUSE and libuafs
37 #include <afsconfig.h>
38 #include <afs/param.h>
40 #include <sysincludes.h>
41 #include <afs/afsutil.h>
42 #include <afs_usrops.h>
44 #include <afs/afs_args.h>
52 #define FUSE_USE_VERSION 27
55 /* command-line arguments to pass to afsd and the cmd_ library */
56 static struct fuse_args afsd_args
= FUSE_ARGS_INIT(0, NULL
);
58 /* command-line arguments to pass to FUSE */
59 static struct fuse_args fuse_args
= FUSE_ARGS_INIT(0, NULL
);
61 /* used for command-line parsing in fuafsd_fuse_opt below */
62 static int fuafsd_cmd_accept
= 0;
64 static int stderr_save
;
67 * Turn FUSE-y paths into libuafs-y paths.
69 * @param[in] apath a path in the form of /localcell/foo/bar
71 * @return a path (non-const) in the form /afs/localcell/foo/bar to be freed
75 afs_path(const char *apath
)
77 static const char prefix
[] = "/afs/";
80 if (asprintf(&path
, "%s%s", prefix
, apath
) < 0)
87 fuafsd_init(struct fuse_conn_info
*conn
)
91 uafs_setMountDir("/afs");
96 /* Wrappers around libuafs calls for FUSE */
99 fuafsd_getattr(const char *apath
, struct stat
*stbuf
)
102 char *path
= afs_path(apath
);
107 code
= uafs_lstat(path
, stbuf
);
118 fuafsd_opendir(const char *apath
, struct fuse_file_info
* fi
)
121 char *path
= afs_path(apath
);
126 dirp
= uafs_opendir(path
);
134 fi
->fh
= (uintptr_t)dirp
;
140 fuafsd_readdir(const char *path
, void * buf
, fuse_fill_dir_t filler
,
141 off_t offset
, struct fuse_file_info
* fi
)
144 struct usr_dirent
* direntP
;
146 dirp
= (usr_DIR
*)(uintptr_t)fi
->fh
;
149 while ((direntP
= uafs_readdir(dirp
))) {
150 if (filler(buf
, direntP
->d_name
, NULL
, 0)) {
160 fuafsd_releasedir(const char *path
, struct fuse_file_info
* fi
)
162 return uafs_closedir((usr_DIR
*)(uintptr_t)fi
->fh
);
166 fuafsd_create(const char *apath
, mode_t mode
, struct fuse_file_info
* fi
)
169 char *path
= afs_path(apath
);
174 fd
= uafs_open(path
, fi
->flags
, mode
);
188 fuafsd_open(const char *path
, struct fuse_file_info
* fi
)
190 return fuafsd_create(path
, 0, fi
);
194 fuafsd_read(const char *path
, char * buf
, size_t len
, off_t offset
,
195 struct fuse_file_info
* fi
)
201 code
= uafs_pread(fd
, buf
, len
, offset
);
210 fuafsd_readlink(const char *apath
, char * buf
, size_t len
)
213 char *path
= afs_path(apath
);
218 code
= uafs_readlink(path
, buf
, len
);
232 fuafsd_mkdir(const char *apath
, mode_t mode
)
235 char *path
= afs_path(apath
);
240 code
= uafs_mkdir(path
, mode
);
251 fuafsd_unlink(const char *apath
)
254 char *path
= afs_path(apath
);
259 code
= uafs_unlink(path
);
270 fuafsd_rmdir(const char *apath
)
273 char *path
= afs_path(apath
);
278 code
= uafs_rmdir(path
);
289 fuafsd_symlink(const char *atarget
, const char *asource
)
292 char *target
= afs_path(atarget
);
293 char *source
= afs_path(asource
);
295 if (target
== NULL
|| source
== NULL
) {
296 if (target
) free(target
);
297 if (source
) free(source
);
301 code
= uafs_symlink(target
, source
);
313 fuafsd_rename(const char *aold
, const char *anew
)
316 char *old
= afs_path(aold
);
317 char *new = afs_path(anew
);
319 if (old
== NULL
|| new == NULL
) {
325 code
= uafs_rename(old
, new);
337 fuafsd_link(const char *aexisting
, const char *anew
)
340 char *existing
= afs_path(aexisting
);
341 char *new = afs_path(anew
);
343 if (existing
== NULL
|| new == NULL
) {
344 if (existing
) free(existing
);
349 code
= uafs_link(existing
, new);
361 fuafsd_chmod(const char *apath
, mode_t mode
)
364 char *path
= afs_path(apath
);
369 code
= uafs_chmod(path
, mode
);
380 fuafsd_truncate(const char *apath
, off_t length
)
383 char *path
= afs_path(apath
);
388 code
= uafs_truncate(path
, length
);
399 fuafsd_write(const char *path
, const char *abuf
, size_t len
, off_t offset
,
400 struct fuse_file_info
* fi
)
403 char *buf
= malloc(len
);
406 memcpy(buf
, abuf
, len
);
408 code
= uafs_pwrite(fd
, buf
, len
, offset
);
420 fuafsd_statvfs(const char * path
, struct statvfs
* buf
)
422 if (uafs_statvfs(buf
) < 0) {
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.
430 buf
->f_bsize
= buf
->f_frsize
;
435 fuafsd_release(const char *path
, struct fuse_file_info
* fi
)
441 if (uafs_close(fd
) < 0) {
449 fuafsd_destroy(void * private_data
)
454 static struct fuse_operations fuafsd_oper
= {
456 .getattr
= fuafsd_getattr
,
457 .opendir
= fuafsd_opendir
,
458 .readdir
= fuafsd_readdir
,
459 .releasedir
= fuafsd_releasedir
,
461 .create
= fuafsd_create
,
463 .readlink
= fuafsd_readlink
,
464 .mkdir
= fuafsd_mkdir
,
465 .rmdir
= fuafsd_rmdir
,
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
478 /* Command line argument processing */
481 * See fuafsd_fuse_opt below.
484 fuafsd_cmd_check(struct cmd_syndesc
* ts
, void *beforeRock
)
486 fuafsd_cmd_accept
= 1;
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
501 split_args(const struct fuse_args
*args
)
505 cmd_SetBeforeProc(fuafsd_cmd_check
, NULL
);
507 nullfd
= open("/dev/null", O_WRONLY
);
508 stderr_save
= dup(2);
509 if (nullfd
< 0 || stderr_save
< 0) {
514 for (i
= 0; args
->argv
[i
]; ++i
) {
516 char *arg
= args
->argv
[i
];
517 char *argv
[3] = {args
->argv
[0], arg
, NULL
};
519 if (fuafsd_cmd_accept
) {
520 fuse_opt_add_arg(&afsd_args
, arg
);
521 fuafsd_cmd_accept
= 0;
525 /* redirect stderr to null, so libcmd doesn't print out
526 * an error message for unknown options */
527 if (dup2(nullfd
, 2) < 0) {
532 code
= cmd_Dispatch(2, argv
);
534 if (dup2(stderr_save
, 2) < 0) {
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 */
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
);
550 if (code
== CMD_TOOFEW
) {
551 /* flag takes another argument; get the next one, too */
552 fuafsd_cmd_accept
= 1;
554 fuafsd_cmd_accept
= 0;
558 /* libcmd doesn't recognize the argument; give it to FUSE */
559 fuse_opt_add_arg(&fuse_args
, arg
);
563 if (close(nullfd
) < 0) {
566 if (close(stderr_save
) < 0) {
570 cmd_SetBeforeProc(NULL
, NULL
);
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.
578 main(int argc
, char **argv
)
581 struct fuse_args args
= FUSE_ARGS_INIT(argc
-1, &argv
[1]);
582 fuse_opt_add_arg(&afsd_args
, argv
[0]);
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");
589 fuse_opt_add_arg(&fuse_args
, argv
[0]);
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");
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");
602 code
= uafs_Setup("/afs");
611 code
= uafs_ParseArgs(afsd_args
.argc
, afsd_args
.argv
);
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.
619 "afsd.fuse: Could not parse command line options; code %d\n",
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
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
, "--");
633 fuse_opt_add_arg(&fuse_args
, uafs_MountDir());
635 return fuse_main(fuse_args
.argc
, fuse_args
.argv
, &fuafsd_oper
, NULL
);