libfuse/lib/helper.c

456 lines
14 KiB
C
Raw Normal View History

2001-11-21 18:03:39 +08:00
/*
FUSE: Filesystem in Userspace
2005-01-10 20:29:28 +08:00
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
2001-11-21 18:03:39 +08:00
2002-10-25 20:41:16 +08:00
This program can be distributed under the terms of the GNU LGPL.
See the file COPYING.LIB.
2001-11-21 18:03:39 +08:00
*/
2005-08-15 21:19:07 +08:00
#include "fuse_i.h"
2005-01-04 20:45:54 +08:00
#include "fuse_compat.h"
2001-11-21 18:03:39 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
2002-12-05 22:23:01 +08:00
#include <string.h>
2001-11-21 18:03:39 +08:00
#include <limits.h>
#include <signal.h>
2004-10-22 00:33:17 +08:00
static struct fuse *fuse_instance;
2001-11-21 18:03:39 +08:00
2004-10-21 17:35:10 +08:00
static void usage(const char *progname)
2001-11-21 18:03:39 +08:00
{
2004-12-05 05:20:05 +08:00
if (progname)
fprintf(stderr,
"usage: %s mountpoint [FUSE options]\n\n", progname);
2005-02-02 19:14:04 +08:00
fprintf(stderr,
2004-12-05 05:20:05 +08:00
"FUSE options:\n"
2005-02-09 23:47:51 +08:00
" -d enable debug output (implies -f)\n"
" -f foreground operation\n"
2005-10-11 18:12:08 +08:00
" -s disable multi-threaded operation\n"
2005-02-09 23:47:51 +08:00
" -r mount read only (equivalent to '-o ro')\n"
" -o opt,[opt...] mount options\n"
" -h print help\n"
2004-01-26 19:28:44 +08:00
"\n"
2004-07-24 01:16:29 +08:00
"Mount options:\n"
" default_permissions enable permission checking\n"
" allow_other allow access to other users\n"
2005-01-10 04:05:27 +08:00
" allow_root allow access to root\n"
2004-07-24 01:16:29 +08:00
" kernel_cache cache files in kernel\n"
" large_read issue large read requests (2.4 only)\n"
" direct_io use direct I/O\n"
" max_read=N set maximum size of read requests\n"
" hard_remove immediate removal (don't hide files)\n"
" debug enable debug output\n"
2005-02-11 03:39:34 +08:00
" fsname=NAME set filesystem name in mtab\n"
2005-05-27 17:12:43 +08:00
" use_ino let filesystem set inode numbers\n"
" readdir_ino try to fill in d_ino in readdir\n"
2005-07-06 18:07:52 +08:00
" nonempty allow mounts over non-empty file/dir\n"
2005-07-06 21:34:02 +08:00
" umask=M set file permissions (octal)\n"
" uid=N set file owner\n"
" gid=N set file group\n"
2005-05-27 17:12:43 +08:00
);
2001-11-21 18:03:39 +08:00
}
2004-10-21 17:35:10 +08:00
static void invalid_option(const char *argv[], int argctr)
2004-01-26 19:28:44 +08:00
{
2004-10-21 17:35:10 +08:00
fprintf(stderr, "fuse: invalid option: %s\n\n", argv[argctr]);
2004-12-07 18:04:24 +08:00
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
2004-01-26 19:28:44 +08:00
}
2005-08-03 17:11:06 +08:00
static void exit_handler(int sig)
2001-11-21 18:03:39 +08:00
{
2005-08-03 17:11:06 +08:00
(void) sig;
2004-10-22 00:33:17 +08:00
if (fuse_instance != NULL)
fuse_exit(fuse_instance);
2001-11-21 18:03:39 +08:00
}
2005-08-03 17:11:06 +08:00
static int set_one_signal_handler(int sig, void (*handler)(int))
2001-11-21 18:03:39 +08:00
{
struct sigaction sa;
2004-07-03 00:20:45 +08:00
struct sigaction old_sa;
2001-11-21 18:03:39 +08:00
2004-07-17 02:27:50 +08:00
memset(&sa, 0, sizeof(struct sigaction));
2004-07-03 00:20:45 +08:00
sa.sa_handler = handler;
2001-11-21 18:03:39 +08:00
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
2005-08-03 17:11:06 +08:00
if (sigaction(sig, NULL, &old_sa) == -1) {
2004-07-03 00:20:45 +08:00
perror("FUSE: cannot get old signal handler");
2004-10-21 17:35:10 +08:00
return -1;
2001-11-21 18:03:39 +08:00
}
2005-02-02 19:14:04 +08:00
2004-07-03 00:20:45 +08:00
if (old_sa.sa_handler == SIG_DFL &&
2005-08-03 17:11:06 +08:00
sigaction(sig, &sa, NULL) == -1) {
2004-07-03 00:20:45 +08:00
perror("Cannot set signal handler");
2004-10-21 17:35:10 +08:00
return -1;
2001-11-21 18:03:39 +08:00
}
2004-10-21 17:35:10 +08:00
return 0;
2001-11-21 18:03:39 +08:00
}
2005-08-03 17:11:06 +08:00
static int set_signal_handlers(void)
{
2004-10-21 17:35:10 +08:00
if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
set_one_signal_handler(SIGINT, exit_handler) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
return -1;
2004-09-16 16:43:24 +08:00
return 0;
}
2005-01-04 20:45:54 +08:00
static int opt_member(const char *opts, const char *opt)
{
const char *e, *s = opts;
int optlen = strlen(opt);
for (s = opts; s; s = e + 1) {
if(!(e = strchr(s, ',')))
break;
if (e - s == optlen && strncmp(s, opt, optlen) == 0)
return 1;
}
return (s && strcmp(s, opt) == 0);
}
2004-09-16 16:42:40 +08:00
static int add_option_to(const char *opt, char **optp)
2004-07-24 01:16:29 +08:00
{
unsigned len = strlen(opt);
if (*optp) {
unsigned oldlen = strlen(*optp);
2005-08-03 17:11:06 +08:00
*optp = (char *) realloc(*optp, oldlen + 1 + len + 1);
2004-09-16 16:42:40 +08:00
if (*optp == NULL)
return -1;
2004-07-24 01:16:29 +08:00
(*optp)[oldlen] = ',';
strcpy(*optp + oldlen + 1, opt);
} else {
2005-08-03 17:11:06 +08:00
*optp = (char *) malloc(len + 1);
2004-09-16 16:42:40 +08:00
if (*optp == NULL)
return -1;
2004-07-24 01:16:29 +08:00
strcpy(*optp, opt);
}
2004-09-16 16:42:40 +08:00
return 0;
2004-07-24 01:16:29 +08:00
}
2004-10-21 17:35:10 +08:00
static int add_options(char **lib_optp, char **kernel_optp, const char *opts)
2004-07-24 01:16:29 +08:00
{
char *xopts = strdup(opts);
char *s = xopts;
char *opt;
2005-07-07 20:35:37 +08:00
int has_allow_other = 0;
int has_allow_root = 0;
2004-09-16 16:42:40 +08:00
if (xopts == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
2004-10-21 17:35:10 +08:00
return -1;
2004-09-16 16:42:40 +08:00
}
2004-07-24 01:16:29 +08:00
while((opt = strsep(&s, ",")) != NULL) {
2004-09-16 16:42:40 +08:00
int res;
2005-04-22 20:04:55 +08:00
if (fuse_is_lib_option(opt)) {
2004-09-16 16:42:40 +08:00
res = add_option_to(opt, lib_optp);
2005-04-22 20:04:55 +08:00
/* Compatibility hack */
2005-07-07 20:35:37 +08:00
if (strcmp(opt, "allow_root") == 0 && res != -1) {
has_allow_root = 1;
2005-04-22 20:04:55 +08:00
res = add_option_to("allow_other", kernel_optp);
2005-07-07 20:35:37 +08:00
}
2005-04-22 20:04:55 +08:00
}
2005-07-07 20:35:37 +08:00
else {
2004-09-16 16:42:40 +08:00
res = add_option_to(opt, kernel_optp);
2005-07-07 20:35:37 +08:00
if (strcmp(opt, "allow_other") == 0)
has_allow_other = 1;
}
2004-09-16 16:42:40 +08:00
if (res == -1) {
fprintf(stderr, "fuse: memory allocation failed\n");
2004-10-21 17:35:10 +08:00
return -1;
2004-09-16 16:42:40 +08:00
}
2004-07-24 01:16:29 +08:00
}
2005-07-07 20:35:37 +08:00
if (has_allow_other && has_allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
return -1;
}
2004-07-24 01:16:29 +08:00
free(xopts);
2004-10-21 17:35:10 +08:00
return 0;
2004-07-24 01:16:29 +08:00
}
2004-10-21 17:35:10 +08:00
static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts,
char **lib_opts, char **mountpoint,
int *multithreaded, int *background)
2001-11-21 18:03:39 +08:00
{
2004-10-21 17:35:10 +08:00
int res;
2004-02-25 16:39:42 +08:00
int argctr;
2004-10-21 17:35:10 +08:00
const char *basename;
2004-07-24 01:16:29 +08:00
char *fsname_opt;
2005-02-02 19:14:04 +08:00
2004-10-21 17:35:10 +08:00
*kernel_opts = NULL;
*lib_opts = NULL;
*mountpoint = NULL;
*multithreaded = 1;
*background = 1;
2004-07-24 01:16:29 +08:00
basename = strrchr(argv[0], '/');
if (basename == NULL)
basename = argv[0];
else if (basename[1] != '\0')
basename++;
2005-08-03 17:11:06 +08:00
fsname_opt = (char *) malloc(strlen(basename) + 64);
2004-09-16 16:42:40 +08:00
if (fsname_opt == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
2004-10-21 17:35:10 +08:00
return -1;
2004-09-16 16:42:40 +08:00
}
2004-07-24 01:16:29 +08:00
sprintf(fsname_opt, "fsname=%s", basename);
2004-10-21 17:35:10 +08:00
res = add_options(lib_opts, kernel_opts, fsname_opt);
2004-07-24 01:16:29 +08:00
free(fsname_opt);
2004-10-21 17:35:10 +08:00
if (res == -1)
goto err;
2005-02-02 19:14:04 +08:00
2004-07-24 01:16:29 +08:00
for (argctr = 1; argctr < argc; argctr ++) {
if (argv[argctr][0] == '-') {
if (strlen(argv[argctr]) == 2)
switch (argv[argctr][1]) {
2004-07-24 01:16:29 +08:00
case 'o':
if (argctr + 1 == argc || argv[argctr+1][0] == '-') {
2004-12-05 05:20:05 +08:00
fprintf(stderr, "missing option after -o\n");
2004-12-07 18:04:24 +08:00
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
2004-10-21 17:35:10 +08:00
goto err;
2004-07-24 01:16:29 +08:00
}
argctr ++;
2004-10-21 17:35:10 +08:00
res = add_options(lib_opts, kernel_opts, argv[argctr]);
if (res == -1)
goto err;
2004-07-24 01:16:29 +08:00
break;
2005-02-02 19:14:04 +08:00
2004-02-25 16:39:42 +08:00
case 'd':
2004-10-21 17:35:10 +08:00
res = add_options(lib_opts, kernel_opts, "debug");
if (res == -1)
goto err;
2004-02-25 16:39:42 +08:00
break;
2005-02-02 19:14:04 +08:00
2004-11-30 08:00:02 +08:00
case 'r':
res = add_options(lib_opts, kernel_opts, "ro");
if (res == -1)
goto err;
break;
case 'f':
2004-10-21 17:35:10 +08:00
*background = 0;
break;
2004-02-25 16:39:42 +08:00
case 's':
2004-10-21 17:35:10 +08:00
*multithreaded = 0;
2004-02-25 16:39:42 +08:00
break;
2005-02-02 19:14:04 +08:00
2004-02-25 16:39:42 +08:00
case 'h':
usage(argv[0]);
2004-10-21 17:35:10 +08:00
goto err;
2005-02-02 19:14:04 +08:00
2004-02-25 16:39:42 +08:00
default:
invalid_option(argv, argctr);
2004-10-21 17:35:10 +08:00
goto err;
2004-02-25 16:39:42 +08:00
}
2004-07-24 01:16:29 +08:00
else {
2004-10-21 17:35:10 +08:00
if (argv[argctr][1] == 'o') {
res = add_options(lib_opts, kernel_opts, &argv[argctr][2]);
if (res == -1)
goto err;
2004-12-05 05:20:05 +08:00
} else if(strcmp(argv[argctr], "-ho") == 0) {
usage(NULL);
goto err;
} else {
2004-07-24 01:16:29 +08:00
invalid_option(argv, argctr);
2004-10-21 17:35:10 +08:00
goto err;
}
2004-07-24 01:16:29 +08:00
}
2004-10-21 17:35:10 +08:00
} else if (*mountpoint == NULL) {
*mountpoint = strdup(argv[argctr]);
if (*mountpoint == NULL) {
2004-09-16 16:42:40 +08:00
fprintf(stderr, "fuse: memory allocation failed\n");
2004-10-21 17:35:10 +08:00
goto err;
2004-09-16 16:42:40 +08:00
}
}
2004-10-21 17:35:10 +08:00
else {
2004-01-26 19:28:44 +08:00
invalid_option(argv, argctr);
2004-10-21 17:35:10 +08:00
goto err;
}
2004-01-26 19:28:44 +08:00
}
2004-10-21 17:35:10 +08:00
return 0;
err:
free(*kernel_opts);
free(*lib_opts);
free(*mountpoint);
return -1;
}
2004-12-04 08:40:50 +08:00
static struct fuse *fuse_setup_common(int argc, char *argv[],
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *multithreaded,
int *fd,
int compat)
2004-10-21 17:35:10 +08:00
{
struct fuse *fuse;
int background;
char *kernel_opts;
char *lib_opts;
int res;
2004-12-04 08:40:50 +08:00
2004-10-22 00:33:17 +08:00
if (fuse_instance != NULL) {
2004-12-08 00:46:42 +08:00
fprintf(stderr, "fuse: fuse_setup() called twice\n");
2004-10-22 00:33:17 +08:00
return NULL;
}
2004-10-21 17:35:10 +08:00
res = fuse_parse_cmdline(argc, (const char **) argv, &kernel_opts,
&lib_opts, mountpoint, multithreaded,
&background);
if (res == -1)
return NULL;
*fd = fuse_mount(*mountpoint, kernel_opts);
if (*fd == -1)
goto err_free;
2004-12-04 08:40:50 +08:00
fuse = fuse_new_common(*fd, lib_opts, op, op_size, compat);
2004-10-21 17:35:10 +08:00
if (fuse == NULL)
goto err_unmount;
2005-01-04 20:45:54 +08:00
if (background && !opt_member(lib_opts, "debug")) {
2004-10-21 17:35:10 +08:00
res = daemon(0, 0);
if (res == -1) {
perror("fuse: failed to daemonize program\n");
goto err_destroy;
}
}
2004-10-22 00:33:17 +08:00
2004-10-21 17:35:10 +08:00
res = set_signal_handlers();
if (res == -1)
goto err_destroy;
2004-10-22 00:39:09 +08:00
fuse_instance = fuse;
2004-10-21 17:35:10 +08:00
free(kernel_opts);
free(lib_opts);
return fuse;
err_destroy:
fuse_destroy(fuse);
err_unmount:
fuse_unmount(*mountpoint);
err_free:
free(kernel_opts);
free(lib_opts);
free(*mountpoint);
return NULL;
}
2004-12-08 00:46:42 +08:00
struct fuse *fuse_setup(int argc, char *argv[],
2004-12-04 08:40:50 +08:00
const struct fuse_operations *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
{
return fuse_setup_common(argc, argv, op, op_size, mountpoint,
multithreaded, fd, 0);
}
2005-11-12 05:32:42 +08:00
struct fuse *fuse_setup_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, 22);
}
2004-12-08 00:46:42 +08:00
struct fuse *fuse_setup_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op,
2004-12-04 08:40:50 +08:00
char **mountpoint, int *multithreaded,
int *fd)
{
2005-02-02 19:14:04 +08:00
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
2004-12-08 00:46:42 +08:00
sizeof(struct fuse_operations_compat2),
2004-12-04 08:40:50 +08:00
mountpoint, multithreaded, fd, 21);
}
2004-12-08 00:46:42 +08:00
void fuse_teardown(struct fuse *fuse, int fd, char *mountpoint)
2004-10-21 17:35:10 +08:00
{
2005-11-10 17:54:41 +08:00
(void) fd;
2004-10-22 00:33:17 +08:00
if (fuse_instance != fuse)
2004-12-08 00:46:42 +08:00
fprintf(stderr, "fuse: fuse_teardown() with unknown fuse object\n");
2004-10-22 00:33:17 +08:00
else
fuse_instance = NULL;
2004-10-21 17:35:10 +08:00
fuse_unmount(mountpoint);
2005-11-16 21:00:24 +08:00
fuse_destroy(fuse);
2004-10-21 17:35:10 +08:00
free(mountpoint);
}
2004-12-04 08:40:50 +08:00
static int fuse_main_common(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
int compat)
2004-10-21 17:35:10 +08:00
{
2004-10-22 00:33:17 +08:00
struct fuse *fuse;
2004-10-21 17:35:10 +08:00
char *mountpoint;
int multithreaded;
int res;
int fd;
2004-12-04 08:40:50 +08:00
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
&multithreaded, &fd, compat);
2004-10-22 00:33:17 +08:00
if (fuse == NULL)
2004-10-21 17:35:10 +08:00
return 1;
2005-02-02 19:14:04 +08:00
2004-10-21 17:35:10 +08:00
if (multithreaded)
2004-10-22 00:33:17 +08:00
res = fuse_loop_mt(fuse);
2004-10-21 17:35:10 +08:00
else
2004-10-22 00:33:17 +08:00
res = fuse_loop(fuse);
2005-02-02 19:14:04 +08:00
2004-12-08 00:46:42 +08:00
fuse_teardown(fuse, fd, mountpoint);
2004-10-21 17:35:10 +08:00
if (res == -1)
return 1;
2005-02-02 19:14:04 +08:00
2004-10-21 17:35:10 +08:00
return 0;
2001-11-21 18:03:39 +08:00
}
2004-12-08 00:46:42 +08:00
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
size_t op_size)
2004-12-04 08:40:50 +08:00
{
return fuse_main_common(argc, argv, op, op_size, 0);
}
2005-11-12 05:32:42 +08:00
int fuse_main_real_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
op_size, 22);
}
2004-12-12 19:45:24 +08:00
#undef fuse_main
2005-08-03 17:11:06 +08:00
int fuse_main(void)
2004-12-12 19:45:24 +08:00
{
2005-01-19 05:23:41 +08:00
fprintf(stderr, "fuse_main(): This function does not exist\n");
2004-12-12 19:45:24 +08:00
return -1;
}
2004-12-08 00:46:42 +08:00
void fuse_main_compat1(int argc, char *argv[],
const struct fuse_operations_compat1 *op)
2004-12-04 08:40:50 +08:00
{
2005-02-02 19:14:04 +08:00
fuse_main_common(argc, argv, (struct fuse_operations *) op,
2004-12-08 00:46:42 +08:00
sizeof(struct fuse_operations_compat1), 11);
2004-12-04 08:40:50 +08:00
}
2004-12-08 00:46:42 +08:00
int fuse_main_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op)
2004-12-04 08:40:50 +08:00
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
2004-12-08 00:46:42 +08:00
sizeof(struct fuse_operations_compat2), 21);
2004-12-04 08:40:50 +08:00
}
2004-12-08 00:46:42 +08:00
__asm__(".symver fuse_setup_compat2,__fuse_setup@");
2005-11-12 05:32:42 +08:00
__asm__(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2");
2004-12-08 00:46:42 +08:00
__asm__(".symver fuse_teardown,__fuse_teardown@");
__asm__(".symver fuse_main_compat2,fuse_main@");
2005-11-12 05:32:42 +08:00
__asm__(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");