Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afsd / afsd_fuse.c
CommitLineData
805e021f
CE
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 */
56static struct fuse_args afsd_args = FUSE_ARGS_INIT(0, NULL);
57
58/* command-line arguments to pass to FUSE */
59static struct fuse_args fuse_args = FUSE_ARGS_INIT(0, NULL);
60
61/* used for command-line parsing in fuafsd_fuse_opt below */
62static int fuafsd_cmd_accept = 0;
63static int nullfd;
64static 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 */
74static char *
75afs_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
86static void *
87fuafsd_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
98static int
99fuafsd_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
117static int
118fuafsd_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
139static int
140fuafsd_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
159static int
160fuafsd_releasedir(const char *path, struct fuse_file_info * fi)
161{
162 return uafs_closedir((usr_DIR *)(uintptr_t)fi->fh);
163}
164
165static int
166fuafsd_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
187static int
188fuafsd_open(const char *path, struct fuse_file_info * fi)
189{
190 return fuafsd_create(path, 0, fi);
191}
192
193static int
194fuafsd_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
209static int
210fuafsd_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
231static int
232fuafsd_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
250static int
251fuafsd_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
269static int
270fuafsd_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
288static int
289fuafsd_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
312static int
313fuafsd_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
336static int
337fuafsd_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
360static int
361fuafsd_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
379static int
380fuafsd_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
398static int
399fuafsd_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
419static int
420fuafsd_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
434static int
435fuafsd_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
448static void
449fuafsd_destroy(void * private_data)
450{
451 uafs_Shutdown();
452}
453
454static 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 */
483static int
484fuafsd_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 */
500static void
501split_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 */
577int
578main(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}