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 asprintf(&path, "%s%s", prefix, apath);
86 fuafsd_init(struct fuse_conn_info *conn)
90 uafs_setMountDir("/afs");
95 /* Wrappers around libuafs calls for FUSE */
98 fuafsd_getattr(const char *apath, struct stat *stbuf)
101 char *path = afs_path(apath);
103 code = uafs_lstat(path, stbuf);
114 fuafsd_opendir(const char *apath, struct fuse_file_info * fi)
117 char *path = afs_path(apath);
119 dirp = uafs_opendir(path);
127 fi->fh = (uintptr_t)dirp;
133 fuafsd_readdir(const char *path, void * buf, fuse_fill_dir_t filler,
134 off_t offset, struct fuse_file_info * fi)
137 struct usr_dirent * direntP;
139 dirp = (usr_DIR *)(uintptr_t)fi->fh;
142 while ((direntP = uafs_readdir(dirp))) {
143 if (filler(buf, direntP->d_name, NULL, 0)) {
153 fuafsd_releasedir(const char *path, struct fuse_file_info * fi)
155 return uafs_closedir((usr_DIR *)(uintptr_t)fi->fh);
159 fuafsd_create(const char *apath, mode_t mode, struct fuse_file_info * fi)
162 char *path = afs_path(apath);
164 fd = uafs_open(path, fi->flags, mode);
178 fuafsd_open(const char *path, struct fuse_file_info * fi)
180 return fuafsd_create(path, 0, fi);
184 fuafsd_read(const char *path, char * buf, size_t len, off_t offset,
185 struct fuse_file_info * fi)
191 code = uafs_pread(fd, buf, len, offset);
200 fuafsd_readlink(const char *apath, char * buf, size_t len)
203 char *path = afs_path(apath);
205 code = uafs_readlink(path, buf, len);
219 fuafsd_mkdir(const char *apath, mode_t mode)
222 char *path = afs_path(apath);
224 code = uafs_mkdir(path, mode);
235 fuafsd_unlink(const char *apath)
238 char *path = afs_path(apath);
240 code = uafs_unlink(path);
251 fuafsd_rmdir(const char *apath)
254 char *path = afs_path(apath);
256 code = uafs_rmdir(path);
267 fuafsd_symlink(const char *atarget, const char *asource)
270 char *target = afs_path(atarget);
271 char *source = afs_path(asource);
273 code = uafs_symlink(target, source);
285 fuafsd_rename(const char *aold, const char *anew)
288 char *old = afs_path(aold);
289 char *new = afs_path(anew);
291 code = uafs_rename(old, new);
303 fuafsd_link(const char *aexisting, const char *anew)
306 char *existing = afs_path(aexisting);
307 char *new = afs_path(anew);
309 code = uafs_link(existing, new);
321 fuafsd_chmod(const char *apath, mode_t mode)
324 char *path = afs_path(apath);
326 code = uafs_chmod(path, mode);
337 fuafsd_truncate(const char *apath, off_t length)
340 char *path = afs_path(apath);
342 code = uafs_truncate(path, length);
353 fuafsd_write(const char *path, const char *abuf, size_t len, off_t offset,
354 struct fuse_file_info * fi)
357 char *buf = malloc(len);
360 memcpy(buf, abuf, len);
362 code = uafs_pwrite(fd, buf, len, offset);
374 fuafsd_statvfs(const char * path, struct statvfs * buf)
376 if (uafs_statvfs(buf) < 0) {
381 * FUSE ignores frsize, and uses bsize for displaying e.g. available
382 * space. Just set bsize to frsize so we get a consistent `df` output.
384 buf->f_bsize = buf->f_frsize;
389 fuafsd_release(const char *path, struct fuse_file_info * fi)
395 if (uafs_close(fd) < 0) {
403 fuafsd_destroy(void * private_data)
408 static struct fuse_operations fuafsd_oper = {
410 .getattr = fuafsd_getattr,
411 .opendir = fuafsd_opendir,
412 .readdir = fuafsd_readdir,
413 .releasedir = fuafsd_releasedir,
415 .create = fuafsd_create,
417 .readlink = fuafsd_readlink,
418 .mkdir = fuafsd_mkdir,
419 .rmdir = fuafsd_rmdir,
421 .unlink = fuafsd_unlink,
422 .symlink = fuafsd_symlink,
423 .rename = fuafsd_rename,
424 .chmod = fuafsd_chmod,
425 .truncate = fuafsd_truncate,
426 .write = fuafsd_write,
427 .statfs = fuafsd_statvfs,
428 .release = fuafsd_release,
429 .destroy = fuafsd_destroy
432 /* Command line argument processing */
435 * See fuafsd_fuse_opt below.
438 fuafsd_cmd_check(struct cmd_syndesc * ts, void *beforeRock)
440 fuafsd_cmd_accept = 1;
445 * Split arguments into FUSE and afsd/libcmd arguments. To determine whether an
446 * argument is meant for FUSE or for the cmd interface, we pass the given
447 * argument to cmd_Dispatch, and see if our beforeProc is run (which we set to
448 * fuafsd_cmd_check). If it was run, the argument is acceptable to cmd; if it
449 * was not run, cmd doesn't know what to do with the argument, so we assume the
450 * argument is meant for FUSE. We can tell if fuafsd_cmd_check was run by the
451 * global fuafsd_cmd_accept bool, which is set to true when fuafsd_cmd_check is
455 split_args(const struct fuse_args *args)
459 cmd_SetBeforeProc(fuafsd_cmd_check, NULL);
461 nullfd = open("/dev/null", O_WRONLY);
462 stderr_save = dup(2);
463 if (nullfd < 0 || stderr_save < 0) {
468 for (i = 0; args->argv[i]; ++i) {
470 char *arg = args->argv[i];
471 char *argv[3] = {args->argv[0], arg, NULL};
473 if (fuafsd_cmd_accept) {
474 fuse_opt_add_arg(&afsd_args, arg);
475 fuafsd_cmd_accept = 0;
479 /* redirect stderr to null, so libcmd doesn't print out
480 * an error message for unknown options */
481 if (dup2(nullfd, 2) < 0) {
486 code = cmd_Dispatch(2, argv);
488 if (dup2(stderr_save, 2) < 0) {
493 /* fuafsd_cmd_check should prevent the dispatch from succeeding;
494 * the only way we should be able to succeed is if -help was
495 * specified, so just exit */
500 if (fuafsd_cmd_accept || code == CMD_TOOFEW) {
501 /* libcmd accepted the argument; must go to afsd */
502 fuse_opt_add_arg(&afsd_args, arg);
504 if (code == CMD_TOOFEW) {
505 /* flag takes another argument; get the next one, too */
506 fuafsd_cmd_accept = 1;
508 fuafsd_cmd_accept = 0;
512 /* libcmd doesn't recognize the argument; give it to FUSE */
513 fuse_opt_add_arg(&fuse_args, arg);
517 if (close(nullfd) < 0) {
520 if (close(stderr_save) < 0) {
524 cmd_SetBeforeProc(NULL, NULL);
528 * First we divide the given arguments into FUSE and cmd arguments, pass the
529 * FUSE arguments to FUSE, and call cmd_Dispatch in the FUSE init function.
532 main(int argc, char **argv)
535 struct fuse_args args = FUSE_ARGS_INIT(argc-1, &argv[1]);
536 fuse_opt_add_arg(&afsd_args, argv[0]);
538 #ifdef AFS_SUN511_ENV
539 /* for some reason, Solaris 11 FUSE takes the filesystem name from
540 * argv[0], and ignores the -ofsname option */
541 fuse_opt_add_arg(&fuse_args, "AFS");
543 fuse_opt_add_arg(&fuse_args, argv[0]);
546 /* let us determine file inode numbers, not FUSE. also make "AFS" appear
547 * in df/mount/mnttab/etc output. */
548 fuse_opt_add_arg(&fuse_args, "-ouse_ino,fsname=AFS");
551 /* allow other users to access the mountpoint. only do this for
552 * root, since non-root may or may not be able to do this */
553 fuse_opt_add_arg(&fuse_args, "-oallow_other");
556 code = uafs_Setup("/afs");
565 uafs_ParseArgs(afsd_args.argc, afsd_args.argv);
567 /* pass "-- /mount/dir" to fuse to specify dir to mount; "--" is
568 * just to make sure fuse doesn't interpret the mount dir as a flag
570 #ifndef AFS_SUN511_ENV
571 /* This seems to screw up option parsing on Solaris 11 FUSE, so just
572 * don't do it. This makes it slightly more annoying to mount on a dir
573 * called -foo or something, but oh well. */
574 fuse_opt_add_arg(&fuse_args, "--");
576 fuse_opt_add_arg(&fuse_args, uafs_MountDir());
578 return fuse_main(fuse_args.argc, fuse_args.argv, &fuafsd_oper, NULL);