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)
78 static const char prefix[] = "/afs/";
81 len = strlen(apath) + sizeof(prefix);
85 sprintf(path, "%s%s", prefix, apath);
91 fuafsd_init(struct fuse_conn_info *conn)
95 uafs_setMountDir("/afs");
100 /* Wrappers around libuafs calls for FUSE */
103 fuafsd_getattr(const char *apath, struct stat *stbuf)
106 char *path = afs_path(apath);
108 code = uafs_lstat(path, stbuf);
119 fuafsd_opendir(const char *apath, struct fuse_file_info * fi)
122 char *path = afs_path(apath);
124 dirp = uafs_opendir(path);
132 fi->fh = (uintptr_t)dirp;
138 fuafsd_readdir(const char *path, void * buf, fuse_fill_dir_t filler,
139 off_t offset, struct fuse_file_info * fi)
142 struct usr_dirent * direntP;
144 dirp = (usr_DIR *)(uintptr_t)fi->fh;
147 while ((direntP = uafs_readdir(dirp))) {
148 if (filler(buf, direntP->d_name, NULL, 0)) {
158 fuafsd_releasedir(const char *path, struct fuse_file_info * fi)
160 return uafs_closedir((usr_DIR *)(uintptr_t)fi->fh);
164 fuafsd_create(const char *apath, mode_t mode, struct fuse_file_info * fi)
167 char *path = afs_path(apath);
169 fd = uafs_open(path, fi->flags, mode);
183 fuafsd_open(const char *path, struct fuse_file_info * fi)
185 return fuafsd_create(path, 0, fi);
189 fuafsd_read(const char *path, char * buf, size_t len, off_t offset,
190 struct fuse_file_info * fi)
196 code = uafs_pread(fd, buf, len, offset);
205 fuafsd_readlink(const char *apath, char * buf, size_t len)
208 char *path = afs_path(apath);
210 code = uafs_readlink(path, buf, len);
224 fuafsd_mkdir(const char *apath, mode_t mode)
227 char *path = afs_path(apath);
229 code = uafs_mkdir(path, mode);
240 fuafsd_unlink(const char *apath)
243 char *path = afs_path(apath);
245 code = uafs_unlink(path);
256 fuafsd_rmdir(const char *apath)
259 char *path = afs_path(apath);
261 code = uafs_rmdir(path);
272 fuafsd_symlink(const char *atarget, const char *asource)
275 char *target = afs_path(atarget);
276 char *source = afs_path(asource);
278 code = uafs_symlink(target, source);
290 fuafsd_rename(const char *aold, const char *anew)
293 char *old = afs_path(aold);
294 char *new = afs_path(anew);
296 code = uafs_rename(old, new);
308 fuafsd_link(const char *aexisting, const char *anew)
311 char *existing = afs_path(aexisting);
312 char *new = afs_path(anew);
314 code = uafs_link(existing, new);
326 fuafsd_chmod(const char *apath, mode_t mode)
329 char *path = afs_path(apath);
331 code = uafs_chmod(path, mode);
342 fuafsd_truncate(const char *apath, off_t length)
345 char *path = afs_path(apath);
347 code = uafs_truncate(path, length);
358 fuafsd_write(const char *path, const char *abuf, size_t len, off_t offset,
359 struct fuse_file_info * fi)
362 char *buf = malloc(len);
365 memcpy(buf, abuf, len);
367 code = uafs_pwrite(fd, buf, len, offset);
379 fuafsd_statvfs(const char * path, struct statvfs * buf)
381 if (uafs_statvfs(buf) < 0) {
386 * FUSE ignores frsize, and uses bsize for displaying e.g. available
387 * space. Just set bsize to frsize so we get a consistent `df` output.
389 buf->f_bsize = buf->f_frsize;
394 fuafsd_release(const char *path, struct fuse_file_info * fi)
400 if (uafs_close(fd) < 0) {
408 fuafsd_destroy(void * private_data)
413 static struct fuse_operations fuafsd_oper = {
415 .getattr = fuafsd_getattr,
416 .opendir = fuafsd_opendir,
417 .readdir = fuafsd_readdir,
418 .releasedir = fuafsd_releasedir,
420 .create = fuafsd_create,
422 .readlink = fuafsd_readlink,
423 .mkdir = fuafsd_mkdir,
424 .rmdir = fuafsd_rmdir,
426 .unlink = fuafsd_unlink,
427 .symlink = fuafsd_symlink,
428 .rename = fuafsd_rename,
429 .chmod = fuafsd_chmod,
430 .truncate = fuafsd_truncate,
431 .write = fuafsd_write,
432 .statfs = fuafsd_statvfs,
433 .release = fuafsd_release,
434 .destroy = fuafsd_destroy
437 /* Command line argument processing */
440 * See fuafsd_fuse_opt below.
443 fuafsd_cmd_check(struct cmd_syndesc * ts, void *beforeRock)
445 fuafsd_cmd_accept = 1;
450 * Split arguments into FUSE and afsd/libcmd arguments. To determine whether an
451 * argument is meant for FUSE or for the cmd interface, we pass the given
452 * argument to cmd_Dispatch, and see if our beforeProc is run (which we set to
453 * fuafsd_cmd_check). If it was run, the argument is acceptable to cmd; if it
454 * was not run, cmd doesn't know what to do with the argument, so we assume the
455 * argument is meant for FUSE. We can tell if fuafsd_cmd_check was run by the
456 * global fuafsd_cmd_accept bool, which is set to true when fuafsd_cmd_check is
460 split_args(const struct fuse_args *args)
464 cmd_SetBeforeProc(fuafsd_cmd_check, NULL);
466 nullfd = open("/dev/null", O_WRONLY);
467 stderr_save = dup(2);
468 if (nullfd < 0 || stderr_save < 0) {
473 for (i = 0; args->argv[i]; ++i) {
475 char *arg = args->argv[i];
476 char *argv[3] = {args->argv[0], arg, NULL};
478 if (fuafsd_cmd_accept) {
479 fuse_opt_add_arg(&afsd_args, arg);
480 fuafsd_cmd_accept = 0;
484 /* redirect stderr to null, so libcmd doesn't print out
485 * an error message for unknown options */
486 if (dup2(nullfd, 2) < 0) {
491 code = cmd_Dispatch(2, argv);
493 if (dup2(stderr_save, 2) < 0) {
498 /* fuafsd_cmd_check should prevent the dispatch from succeeding;
499 * the only way we should be able to succeed is if -help was
500 * specified, so just exit */
505 if (fuafsd_cmd_accept || code == CMD_TOOFEW) {
506 /* libcmd accepted the argument; must go to afsd */
507 fuse_opt_add_arg(&afsd_args, arg);
509 if (code == CMD_TOOFEW) {
510 /* flag takes another argument; get the next one, too */
511 fuafsd_cmd_accept = 1;
513 fuafsd_cmd_accept = 0;
517 /* libcmd doesn't recognize the argument; give it to FUSE */
518 fuse_opt_add_arg(&fuse_args, arg);
522 if (close(nullfd) < 0) {
525 if (close(stderr_save) < 0) {
529 cmd_SetBeforeProc(NULL, NULL);
533 * First we divide the given arguments into FUSE and cmd arguments, pass the
534 * FUSE arguments to FUSE, and call cmd_Dispatch in the FUSE init function.
537 main(int argc, char **argv)
540 struct fuse_args args = FUSE_ARGS_INIT(argc-1, &argv[1]);
541 fuse_opt_add_arg(&afsd_args, argv[0]);
542 fuse_opt_add_arg(&fuse_args, argv[0]);
544 /* let us determine file inode numbers, not FUSE. also make "AFS" appear
545 * in df/mount/mnttab/etc output. */
546 fuse_opt_add_arg(&fuse_args, "-ouse_ino,fsname=AFS");
549 /* allow other users to access the mountpoint. only do this for
550 * root, since non-root may or may not be able to do this */
551 fuse_opt_add_arg(&fuse_args, "-oallow_other");
554 code = uafs_Setup("/afs");
563 uafs_ParseArgs(afsd_args.argc, afsd_args.argv);
565 /* pass "-- /mount/dir" to fuse to specify dir to mount; "--" is
566 * just to make sure fuse doesn't interpret the mount dir as a flag
568 fuse_opt_add_arg(&fuse_args, "--");
569 fuse_opt_add_arg(&fuse_args, uafs_MountDir());
571 return fuse_main(fuse_args.argc, fuse_args.argv, &fuafsd_oper, NULL);