Merged libfuse for OpenIndiana into libfuse-lite

The libfuse used by OpenIndiana has the same features as libfuse-lite
though requiring some code variants. Merging them simplifies supporting
both.

Variants for OpenIndiana are selected when defining __SOLARIS__
This commit is contained in:
Jean-Pierre André 2012-08-22 11:02:36 +02:00
parent 3e4c439520
commit 97342d05bc
12 changed files with 1291 additions and 27 deletions

View File

@ -212,7 +212,7 @@ esac
AC_MSG_CHECKING([fuse compatibility]) AC_MSG_CHECKING([fuse compatibility])
case "${target_os}" in case "${target_os}" in
linux*) linux*|solaris*)
AC_ARG_WITH( AC_ARG_WITH(
[fuse], [fuse],
[AS_HELP_STRING([--with-fuse=<internal|external>],[Select FUSE library: internal or external @<:@default=internal@:>@])], [AS_HELP_STRING([--with-fuse=<internal|external>],[Select FUSE library: internal or external @<:@default=internal@:>@])],
@ -220,7 +220,7 @@ linux*)
[with_fuse="internal"] [with_fuse="internal"]
) )
;; ;;
darwin*|netbsd*|solaris*|kfreebsd*-gnu) darwin*|netbsd*|kfreebsd*-gnu)
with_fuse="external" with_fuse="external"
;; ;;
freebsd*) freebsd*)

View File

@ -624,6 +624,47 @@ void fuse_fs_destroy(struct fuse_fs *fs);
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
void *user_data); void *user_data);
#ifdef __SOLARIS__
/**
* Filesystem module
*
* Filesystem modules are registered with the FUSE_REGISTER_MODULE()
* macro.
*
* If the "-omodules=modname:..." option is present, filesystem
* objects are created and pushed onto the stack with the 'factory'
* function.
*/
struct fuse_module {
/**
* Name of filesystem
*/
const char *name;
/**
* Factory for creating filesystem objects
*
* The function may use and remove options from 'args' that belong
* to this module.
*
* For now the 'fs' vector always contains exactly one filesystem.
* This is the filesystem which will be below the newly created
* filesystem in the stack.
*
* @param args the command line arguments
* @param fs NULL terminated filesystem object vector
* @return the new filesystem object
*/
struct fuse_fs *(*factory)(struct fuse_args *args, struct fuse_fs *fs[]);
struct fuse_module *next;
struct fusemod_so *so;
int ctr;
};
#endif /* __SOLARIS__ */
/* ----------------------------------------------------------- * /* ----------------------------------------------------------- *
* Advanced API for event handling, don't worry about this... * * Advanced API for event handling, don't worry about this... *
* ----------------------------------------------------------- */ * ----------------------------------------------------------- */

View File

@ -32,6 +32,11 @@
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) #define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
/* This interface uses 64 bit off_t */
#if defined(__SOLARIS__) && !defined(__x86_64__) && (_FILE_OFFSET_BITS != 64)
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -149,6 +154,41 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args);
*/ */
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
#ifdef __SOLARIS__
/**
* Parse common options
*
* The following options are parsed:
*
* '-f' foreground
* '-d' '-odebug' foreground, but keep the debug option
* '-s' single threaded
* '-h' '--help' help
* '-ho' help without header
* '-ofsname=..' file system name, if not present, then set to the program
* name
*
* All parameters may be NULL
*
* @param args argument vector
* @param mountpoint the returned mountpoint, should be freed after use
* @param multithreaded set to 1 unless the '-s' option is present
* @param foreground set to 1 if one of the relevant options is present
* @return 0 on success, -1 on failure
*/
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
int *multithreaded, int *foreground);
/**
* Go into the background
*
* @param foreground if true, stay in the foreground
* @return 0 on success, -1 on failure
*/
int fuse_daemonize(int foreground);
#endif /* __SOLARIS__ */
/** /**
* Get the version of the library * Get the version of the library
* *

View File

@ -1079,6 +1079,13 @@ int fuse_req_interrupted(fuse_req_t req);
* Filesystem setup * * Filesystem setup *
* ----------------------------------------------------------- */ * ----------------------------------------------------------- */
#ifdef __SOLARIS__
/* Deprecated, don't use */
int fuse_lowlevel_is_lib_option(const char *opt);
#endif /* __SOLARIS__ */
/** /**
* Create a low level session * Create a low level session
* *

View File

@ -6,6 +6,11 @@
See the file COPYING.LIB See the file COPYING.LIB
*/ */
#ifdef __SOLARIS__
/* For pthread_rwlock_t */
#define _GNU_SOURCE
#endif /* __SOLARIS__ */
#include "config.h" #include "config.h"
#include "fuse_i.h" #include "fuse_i.h"
#include "fuse_lowlevel.h" #include "fuse_lowlevel.h"
@ -28,6 +33,10 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/time.h> #include <sys/time.h>
#ifdef __SOLARIS__
#define FUSE_MAX_PATH 4096
#endif /* __SOLARIS__ */
#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1 #define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
#define FUSE_UNKNOWN_INO 0xffffffff #define FUSE_UNKNOWN_INO 0xffffffff
@ -54,13 +63,27 @@ struct fuse_config {
int intr; int intr;
int intr_signal; int intr_signal;
int help; int help;
#ifdef __SOLARIS__
int auto_cache;
char *modules;
#endif /* __SOLARIS__ */
}; };
struct fuse_fs { struct fuse_fs {
struct fuse_operations op; struct fuse_operations op;
void *user_data; void *user_data;
#ifdef __SOLARIS__
struct fuse_module *m;
#endif /* __SOLARIS__ */
}; };
#ifdef __SOLARIS__
struct fusemod_so {
void *handle;
int ctr;
};
#endif /* __SOLARIS__ */
struct fuse { struct fuse {
struct fuse_session *se; struct fuse_session *se;
struct node **name_table; struct node **name_table;
@ -98,6 +121,12 @@ struct node {
uint64_t nlookup; uint64_t nlookup;
int open_count; int open_count;
int is_hidden; int is_hidden;
#ifdef __SOLARIS__
struct timespec stat_updated;
struct timespec mtime;
off_t size;
int cache_valid;
#endif /* __SOLARIS__ */
struct lock *locks; struct lock *locks;
}; };
@ -125,6 +154,107 @@ static pthread_key_t fuse_context_key;
static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
static int fuse_context_ref; static int fuse_context_ref;
#ifdef __SOLARIS__
static struct fusemod_so *fuse_current_so;
static struct fuse_module *fuse_modules;
static int fuse_load_so_name(const char *soname)
{
struct fusemod_so *so;
so = calloc(1, sizeof(struct fusemod_so));
if (!so) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
fuse_current_so = so;
so->handle = dlopen(soname, RTLD_NOW);
fuse_current_so = NULL;
if (!so->handle) {
fprintf(stderr, "fuse: %s\n", dlerror());
goto err;
}
if (!so->ctr) {
fprintf(stderr, "fuse: %s did not register any modules", soname);
goto err;
}
return 0;
err:
if (so->handle)
dlclose(so->handle);
free(so);
return -1;
}
static int fuse_load_so_module(const char *module)
{
int res;
char *soname = malloc(strlen(module) + 64);
if (!soname) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
sprintf(soname, "libfusemod_%s.so", module);
res = fuse_load_so_name(soname);
free(soname);
return res;
}
static struct fuse_module *fuse_find_module(const char *module)
{
struct fuse_module *m;
for (m = fuse_modules; m; m = m->next) {
if (strcmp(module, m->name) == 0) {
m->ctr++;
break;
}
}
return m;
}
static struct fuse_module *fuse_get_module(const char *module)
{
struct fuse_module *m;
pthread_mutex_lock(&fuse_context_lock);
m = fuse_find_module(module);
if (!m) {
int err = fuse_load_so_module(module);
if (!err)
m = fuse_find_module(module);
}
pthread_mutex_unlock(&fuse_context_lock);
return m;
}
static void fuse_put_module(struct fuse_module *m)
{
pthread_mutex_lock(&fuse_context_lock);
assert(m->ctr > 0);
m->ctr--;
if (!m->ctr && m->so) {
struct fusemod_so *so = m->so;
assert(so->ctr > 0);
so->ctr--;
if (!so->ctr) {
struct fuse_module **mp;
for (mp = &fuse_modules; *mp;) {
if ((*mp)->so == so)
*mp = (*mp)->next;
else
mp = &(*mp)->next;
}
dlclose(so->handle);
free(so);
}
}
pthread_mutex_unlock(&fuse_context_lock);
}
#endif /* __SOLARIS__ */
static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
{ {
size_t hash = nodeid % f->id_table_size; size_t hash = nodeid % f->id_table_size;
@ -297,10 +427,15 @@ static struct node *find_node(struct fuse *f, fuse_ino_t parent,
return node; return node;
} }
#ifndef __SOLARIS__
static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name) static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
#else /* __SOLARIS__ */
static char *add_name(char *buf, char *s, const char *name)
#endif /* __SOLARIS__ */
{ {
size_t len = strlen(name); size_t len = strlen(name);
#ifndef __SOLARIS__
if (s - len <= *buf) { if (s - len <= *buf) {
unsigned pathlen = *bufsize - (s - *buf); unsigned pathlen = *bufsize - (s - *buf);
unsigned newbufsize = *bufsize; unsigned newbufsize = *bufsize;
@ -323,6 +458,13 @@ static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
*bufsize = newbufsize; *bufsize = newbufsize;
} }
s -= len; s -= len;
#else /* ! __SOLARIS__ */
s -= len;
if (s <= buf) {
fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
return NULL;
}
#endif /* __SOLARIS__ */
strncpy(s, name, len); strncpy(s, name, len);
s--; s--;
*s = '/'; *s = '/';
@ -332,6 +474,42 @@ static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name) static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
{ {
#ifdef __SOLARIS__
char buf[FUSE_MAX_PATH];
char *s = buf + FUSE_MAX_PATH - 1;
struct node *node;
*s = '\0';
if (name != NULL) {
s = add_name(buf, s, name);
if (s == NULL)
return NULL;
}
pthread_mutex_lock(&f->lock);
for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
node = node->parent) {
if (node->name == NULL) {
s = NULL;
break;
}
s = add_name(buf, s, node->name);
if (s == NULL)
break;
}
pthread_mutex_unlock(&f->lock);
if (node == NULL || s == NULL)
return NULL;
else if (*s == '\0')
return strdup("/");
else
return strdup(s);
#else /* __SOLARIS__ */
unsigned bufsize = 256; unsigned bufsize = 256;
char *buf; char *buf;
char *s; char *s;
@ -376,6 +554,7 @@ static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
out_free: out_free:
free(buf); free(buf);
return NULL; return NULL;
#endif /* __SOLARIS__ */
} }
static char *get_path(struct fuse *f, fuse_ino_t nodeid) static char *get_path(struct fuse *f, fuse_ino_t nodeid)
@ -930,6 +1109,44 @@ static int hide_node(struct fuse *f, const char *oldpath,
return err; return err;
} }
#ifdef __SOLARIS__
static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
{
return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
}
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
static void curr_time(struct timespec *now)
{
static clockid_t clockid = CLOCK_MONOTONIC;
int res = clock_gettime(clockid, now);
if (res == -1 && errno == EINVAL) {
clockid = CLOCK_REALTIME;
res = clock_gettime(clockid, now);
}
if (res == -1) {
perror("fuse: clock_gettime");
abort();
}
}
static void update_stat(struct node *node, const struct stat *stbuf)
{
if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
stbuf->st_size != node->size))
node->cache_valid = 0;
node->mtime.tv_sec = stbuf->st_mtime;
node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
node->size = stbuf->st_size;
curr_time(&node->stat_updated);
}
#endif /* __SOLARIS__ */
static int lookup_path(struct fuse *f, fuse_ino_t nodeid, static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
const char *name, const char *path, const char *name, const char *path,
struct fuse_entry_param *e, struct fuse_file_info *fi) struct fuse_entry_param *e, struct fuse_file_info *fi)
@ -952,6 +1169,13 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
e->generation = node->generation; e->generation = node->generation;
e->entry_timeout = f->conf.entry_timeout; e->entry_timeout = f->conf.entry_timeout;
e->attr_timeout = f->conf.attr_timeout; e->attr_timeout = f->conf.attr_timeout;
#ifdef __SOLARIS__
if (f->conf.auto_cache) {
pthread_mutex_lock(&f->lock);
update_stat(node, &e->attr);
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
set_stat(f, e->ino, &e->attr); set_stat(f, e->ino, &e->attr);
if (f->conf.debug) if (f->conf.debug)
fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino); fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino);
@ -1028,7 +1252,11 @@ static struct fuse *req_fuse_prepare(fuse_req_t req)
return c->ctx.fuse; return c->ctx.fuse;
} }
#ifndef __SOLARIS__
static void reply_err(fuse_req_t req, int err) static void reply_err(fuse_req_t req, int err)
#else /* __SOLARIS__ */
static inline void reply_err(fuse_req_t req, int err)
#endif /* __SOLARIS__ */
{ {
/* fuse_reply_err() uses non-negated errno values */ /* fuse_reply_err() uses non-negated errno values */
fuse_reply_err(req, -err); fuse_reply_err(req, -err);
@ -1067,6 +1295,10 @@ void fuse_fs_destroy(struct fuse_fs *fs)
fuse_get_context()->private_data = fs->user_data; fuse_get_context()->private_data = fs->user_data;
if (fs->op.destroy) if (fs->op.destroy)
fs->op.destroy(fs->user_data); fs->op.destroy(fs->user_data);
#ifdef __SOLARIS__
if (fs->m)
fuse_put_module(fs->m);
#endif /* __SOLARIS__ */
free(fs); free(fs);
} }
@ -1143,6 +1375,13 @@ static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
} }
pthread_rwlock_unlock(&f->tree_lock); pthread_rwlock_unlock(&f->tree_lock);
if (!err) { if (!err) {
#ifdef __SOLARIS__
if (f->conf.auto_cache) {
pthread_mutex_lock(&f->lock);
update_stat(get_node(f, ino), &buf);
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
set_stat(f, ino, &buf); set_stat(f, ino, &buf);
fuse_reply_attr(req, &buf, f->conf.attr_timeout); fuse_reply_attr(req, &buf, f->conf.attr_timeout);
} else } else
@ -1227,6 +1466,13 @@ static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
} }
pthread_rwlock_unlock(&f->tree_lock); pthread_rwlock_unlock(&f->tree_lock);
if (!err) { if (!err) {
#ifdef __SOLARIS__
if (f->conf.auto_cache) {
pthread_mutex_lock(&f->lock);
update_stat(get_node(f, ino), &buf);
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
set_stat(f, ino, &buf); set_stat(f, ino, &buf);
fuse_reply_attr(req, &buf, f->conf.attr_timeout); fuse_reply_attr(req, &buf, f->conf.attr_timeout);
} else } else
@ -1571,6 +1817,47 @@ static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
pthread_rwlock_unlock(&f->tree_lock); pthread_rwlock_unlock(&f->tree_lock);
} }
#ifdef __SOLARIS__
static double diff_timespec(const struct timespec *t1,
const struct timespec *t2)
{
return (t1->tv_sec - t2->tv_sec) +
((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
}
static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
struct fuse_file_info *fi)
{
struct node *node;
pthread_mutex_lock(&f->lock);
node = get_node(f, ino);
if (node->cache_valid) {
struct timespec now;
curr_time(&now);
if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
struct stat stbuf;
int err;
pthread_mutex_unlock(&f->lock);
err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
pthread_mutex_lock(&f->lock);
if (!err)
update_stat(node, &stbuf);
else
node->cache_valid = 0;
}
}
if (node->cache_valid)
fi->keep_cache = 1;
node->cache_valid = 1;
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) struct fuse_file_info *fi)
{ {
@ -1590,6 +1877,11 @@ static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
fi->direct_io = 1; fi->direct_io = 1;
if (f->conf.kernel_cache) if (f->conf.kernel_cache)
fi->keep_cache = 1; fi->keep_cache = 1;
#ifdef __SOLARIS__
if (f->conf.auto_cache)
open_auto_cache(f, ino, path, fi);
#endif /* __SOLARIS__ */
} }
fuse_finish_interrupt(f, req, &d); fuse_finish_interrupt(f, req, &d);
} }
@ -1775,7 +2067,9 @@ static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
} }
} else { } else {
reply_err(req, err); reply_err(req, err);
#ifndef __SOLARIS__
pthread_mutex_destroy(&dh->lock); pthread_mutex_destroy(&dh->lock);
#endif /* ! __SOLARIS__ */
free(dh); free(dh);
} }
free(path); free(path);
@ -1789,12 +2083,17 @@ static int extend_contents(struct fuse_dh *dh, unsigned minsize)
unsigned newsize = dh->size; unsigned newsize = dh->size;
if (!newsize) if (!newsize)
newsize = 1024; newsize = 1024;
#ifndef __SOLARIS__
while (newsize < minsize) { while (newsize < minsize) {
if (newsize >= 0x80000000) if (newsize >= 0x80000000)
newsize = 0xffffffff; newsize = 0xffffffff;
else else
newsize *= 2; newsize *= 2;
} }
#else /* __SOLARIS__ */
while (newsize < minsize)
newsize *= 2;
#endif /* __SOLARIS__ */
newptr = (char *) realloc(dh->contents, newsize); newptr = (char *) realloc(dh->contents, newsize);
if (!newptr) { if (!newptr) {
@ -2501,6 +2800,10 @@ static const struct fuse_opt fuse_lib_opts[] = {
FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
FUSE_LIB_OPT("direct_io", direct_io, 1), FUSE_LIB_OPT("direct_io", direct_io, 1),
FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
#ifdef __SOLARIS__
FUSE_LIB_OPT("auto_cache", auto_cache, 1),
FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
#endif /* __SOLARIS__ */
FUSE_LIB_OPT("umask=", set_mode, 1), FUSE_LIB_OPT("umask=", set_mode, 1),
FUSE_LIB_OPT("umask=%o", umask, 0), FUSE_LIB_OPT("umask=%o", umask, 0),
FUSE_LIB_OPT("uid=", set_uid, 1), FUSE_LIB_OPT("uid=", set_uid, 1),
@ -2514,6 +2817,9 @@ static const struct fuse_opt fuse_lib_opts[] = {
FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
FUSE_LIB_OPT("intr", intr, 1), FUSE_LIB_OPT("intr", intr, 1),
FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
#ifdef __SOLARIS__
FUSE_LIB_OPT("modules=%s", modules, 0),
#endif /* __SOLARIS__ */
FUSE_OPT_END FUSE_OPT_END
}; };
@ -2525,6 +2831,9 @@ static void fuse_lib_help(void)
" -o readdir_ino try to fill in d_ino in readdir\n" " -o readdir_ino try to fill in d_ino in readdir\n"
" -o direct_io use direct I/O\n" " -o direct_io use direct I/O\n"
" -o kernel_cache cache files in kernel\n" " -o kernel_cache cache files in kernel\n"
#ifdef __SOLARIS__
" -o [no]auto_cache enable caching based on modification times\n"
#endif /* __SOLARIS__ */
" -o umask=M set file permissions (octal)\n" " -o umask=M set file permissions (octal)\n"
" -o uid=N set file owner\n" " -o uid=N set file owner\n"
" -o gid=N set file group\n" " -o gid=N set file group\n"
@ -2534,9 +2843,42 @@ static void fuse_lib_help(void)
" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n" " -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
" -o intr allow requests to be interrupted\n" " -o intr allow requests to be interrupted\n"
" -o intr_signal=NUM signal to send on interrupt (%i)\n" " -o intr_signal=NUM signal to send on interrupt (%i)\n"
#ifdef __SOLARIS__
" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
#endif /* __SOLARIS__ */
"\n", FUSE_DEFAULT_INTR_SIGNAL); "\n", FUSE_DEFAULT_INTR_SIGNAL);
} }
#ifdef __SOLARIS__
static void fuse_lib_help_modules(void)
{
struct fuse_module *m;
fprintf(stderr, "\nModule options:\n");
pthread_mutex_lock(&fuse_context_lock);
for (m = fuse_modules; m; m = m->next) {
struct fuse_fs *fs = NULL;
struct fuse_fs *newfs;
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
if (fuse_opt_add_arg(&args, "") != -1 &&
fuse_opt_add_arg(&args, "-h") != -1) {
fprintf(stderr, "\n[%s]\n", m->name);
newfs = m->factory(&args, &fs);
assert(newfs == NULL);
}
fuse_opt_free_args(&args);
}
pthread_mutex_unlock(&fuse_context_lock);
}
int fuse_is_lib_option(const char *opt)
{
return fuse_lowlevel_is_lib_option(opt) ||
fuse_opt_match(fuse_lib_opts, opt);
}
#endif /* __SOLARIS__ */
static int fuse_lib_opt_proc(void *data, const char *arg, int key, static int fuse_lib_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs) struct fuse_args *outargs)
{ {
@ -2585,6 +2927,32 @@ static void fuse_restore_intr_signal(int signum)
sigaction(signum, &sa, NULL); sigaction(signum, &sa, NULL);
} }
#ifdef __SOLARIS__
static int fuse_push_module(struct fuse *f, const char *module,
struct fuse_args *args)
{
struct fuse_fs *newfs;
struct fuse_module *m = fuse_get_module(module);
struct fuse_fs *fs[2];
fs[0] = f->fs;
fs[1] = NULL;
if (!m)
return -1;
newfs = m->factory(args, fs);
if (!newfs) {
fuse_put_module(m);
return -1;
}
newfs->m = m;
f->fs = newfs;
return 0;
}
#endif /* __SOLARIS__ */
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
void *user_data) void *user_data)
{ {
@ -2646,6 +3014,22 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
goto out_free_fs; goto out_free_fs;
#ifdef __SOLARIS__
if (f->conf.modules) {
char *module;
char *next;
for (module = f->conf.modules; module; module = next) {
char *p;
for (p = module; *p && *p != ':'; p++);
next = *p ? p + 1 : NULL;
*p = '\0';
if (module[0] && fuse_push_module(f, module, args) == -1)
goto out_free_fs;
}
}
#endif /* __SOLARIS__ */
if (!f->conf.ac_attr_timeout_set) if (!f->conf.ac_attr_timeout_set)
f->conf.ac_attr_timeout = f->conf.attr_timeout; f->conf.ac_attr_timeout = f->conf.attr_timeout;
@ -2658,14 +3042,21 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
#endif #endif
f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f); f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f);
if (f->se == NULL) { if (f->se == NULL) {
#ifdef __SOLARIS__
if (f->conf.help)
fuse_lib_help_modules();
#endif /* __SOLARIS__ */
goto out_free_fs; goto out_free_fs;
} }
fuse_session_add_chan(f->se, ch); fuse_session_add_chan(f->se, ch);
#ifndef __SOLARIS__
if (f->conf.debug) if (f->conf.debug)
fprintf(stderr, "utime_omit_ok: %i\n", f->utime_omit_ok); fprintf(stderr, "utime_omit_ok: %i\n", f->utime_omit_ok);
#endif /* ! __SOLARIS__ */
f->ctr = 0; f->ctr = 0;
f->generation = 0; f->generation = 0;
/* FIXME: Dynamic hash table */ /* FIXME: Dynamic hash table */
@ -2728,6 +3119,9 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
called on the filesystem without init being called first */ called on the filesystem without init being called first */
fs->op.destroy = NULL; fs->op.destroy = NULL;
fuse_fs_destroy(f->fs); fuse_fs_destroy(f->fs);
#ifdef __SOLARIS__
free(f->conf.modules);
#endif /* __SOLARIS__ */
out_free: out_free:
free(f); free(f);
out_delete_context_key: out_delete_context_key:
@ -2777,7 +3171,9 @@ void fuse_destroy(struct fuse *f)
pthread_mutex_destroy(&f->lock); pthread_mutex_destroy(&f->lock);
pthread_rwlock_destroy(&f->tree_lock); pthread_rwlock_destroy(&f->tree_lock);
fuse_session_destroy(f->se); fuse_session_destroy(f->se);
#ifdef __SOLARIS__
free(f->conf.modules);
#endif /* __SOLARIS__ */
free(f); free(f);
fuse_delete_context_key(); fuse_delete_context_key();
} }

View File

@ -1130,18 +1130,6 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
return &req->ctx; return &req->ctx;
} }
/*
* The size of fuse_ctx got extended, so need to be careful about
* incompatibility (i.e. a new binary cannot work with an old
* library).
*/
const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req);
const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req)
{
return fuse_req_ctx(req);
}
//FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4");
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
void *data) void *data)
{ {
@ -1327,6 +1315,15 @@ static int fuse_ll_opt_proc(void *data, const char *arg, int key,
return -1; return -1;
} }
#ifdef __SOLARIS__
int fuse_lowlevel_is_lib_option(const char *opt)
{
return fuse_opt_match(fuse_ll_opts, opt);
}
#endif /* __SOLARIS__ */
static void fuse_ll_destroy(void *data) static void fuse_ll_destroy(void *data)
{ {
struct fuse_ll *f = (struct fuse_ll *) data; struct fuse_ll *f = (struct fuse_ll *) data;
@ -1387,4 +1384,3 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
out: out:
return NULL; return NULL;
} }

View File

@ -165,9 +165,20 @@ struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
{ {
struct fuse_chan *ch = *chp; struct fuse_chan *ch = *chp;
return ch->op.receive(chp, buf, size); return ch->op.receive(chp, buf, size);
} }
#ifdef __SOLARIS__
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
{
int res;
res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
}
#endif /* __SOLARIS__ */
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
{ {
return ch->op.send(ch, iov, count); return ch->op.send(ch, iov, count);
@ -180,4 +191,3 @@ void fuse_chan_destroy(struct fuse_chan *ch)
ch->op.destroy(ch); ch->op.destroy(ch);
free(ch); free(ch);
} }

View File

@ -19,14 +19,20 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pwd.h> #include <pwd.h>
#ifdef __SOLARIS__
#include <sys/mnttab.h>
#else /* __SOLARIS__ */
#include <grp.h>
#include <mntent.h> #include <mntent.h>
#include <sys/fsuid.h>
#endif /* __SOLARIS__ */
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/fsuid.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <grp.h>
#define FUSE_DEV_NEW "/dev/fuse" #define FUSE_DEV_NEW "/dev/fuse"
@ -41,6 +47,32 @@ static int mount_max = 1000;
int drop_privs(void); int drop_privs(void);
int restore_privs(void); int restore_privs(void);
#ifdef __SOLARIS__
/*
* fusermount is not implemented in fuse-lite for Solaris,
* only the minimal functions are provided.
*/
/*
* Solaris doesn't have setfsuid/setfsgid.
* This doesn't really matter anyway as this program shouldn't be made
* suid on Solaris. It should instead be used via a profile with the
* sys_mount privilege.
*/
int drop_privs(void)
{
return (0);
}
int restore_privs(void)
{
return (0);
}
#else /* __SOLARIS__ */
static const char *get_user_name(void) static const char *get_user_name(void)
{ {
struct passwd *pw = getpwuid(getuid()); struct passwd *pw = getpwuid(getuid());
@ -668,3 +700,5 @@ out:
free(mnt); free(mnt);
return res; return res;
} }
#endif /* __SOLARIS__ */

View File

@ -15,6 +15,18 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
struct fuse_chan *ch; struct fuse_chan *ch;
int fd; int fd;
#ifdef __SOLARIS__
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
* would ensue.
*/
do {
fd = open("/dev/null", O_RDWR);
if (fd > 2)
close(fd);
} while (fd >= 0 && fd <= 2);
#endif /* __SOLARIS__ */
fd = fuse_kern_mount(mountpoint, args); fd = fuse_kern_mount(mountpoint, args);
if (fd == -1) if (fd == -1)
return NULL; return NULL;
@ -38,3 +50,12 @@ int fuse_version(void)
return FUSE_VERSION; return FUSE_VERSION;
} }
#ifdef __SOLARIS__
#undef fuse_main
int fuse_main(void);
int fuse_main(void)
{
fprintf(stderr, "fuse_main(): This function does not exist\n");
return -1;
}
#endif /* __SOLARIS__ */

View File

@ -12,6 +12,7 @@
#include "mount_util.h" #include "mount_util.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <stddef.h> #include <stddef.h>
@ -23,6 +24,21 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/mount.h> #include <sys/mount.h>
#ifdef __SOLARIS__
#define FUSERMOUNT_PROG "fusermount"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
#ifndef FUSERMOUNT_DIR
#define FUSERMOUNT_DIR "/usr"
#endif /* FUSERMOUNT_DIR */
#ifndef HAVE_FORK
#define fork() vfork()
#endif
#endif /* __SOLARIS__ */
#ifndef MS_DIRSYNC #ifndef MS_DIRSYNC
#define MS_DIRSYNC 128 #define MS_DIRSYNC 128
#endif #endif
@ -44,8 +60,16 @@ struct mount_opts {
int allow_root; int allow_root;
int ishelp; int ishelp;
int flags; int flags;
#ifdef __SOLARIS__
int nonempty;
int blkdev; int blkdev;
char *fsname; char *fsname;
char *subtype;
char *subtype_opt;
#else
int blkdev;
char *fsname;
#endif
char *mtab_opts; char *mtab_opts;
char *fusermount_opts; char *fusermount_opts;
char *kernel_opts; char *kernel_opts;
@ -54,6 +78,42 @@ struct mount_opts {
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
static const struct fuse_opt fuse_mount_opts[] = { static const struct fuse_opt fuse_mount_opts[] = {
#ifdef __SOLARIS__
FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("fsname=%s", fsname),
FUSE_MOUNT_OPT("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
FUSE_OPT_KEY("-g", KEY_KERN_FLAG),
FUSE_OPT_KEY("-m", KEY_KERN_FLAG),
FUSE_OPT_KEY("-O", KEY_KERN_FLAG),
FUSE_OPT_KEY("setuid", KEY_KERN_OPT),
FUSE_OPT_KEY("nosetuid", KEY_KERN_OPT),
FUSE_OPT_KEY("devices", KEY_KERN_OPT),
FUSE_OPT_KEY("nodevices", KEY_KERN_OPT),
FUSE_OPT_KEY("exec", KEY_KERN_OPT),
FUSE_OPT_KEY("noexec", KEY_KERN_OPT),
FUSE_OPT_KEY("nbmand", KEY_KERN_OPT),
FUSE_OPT_KEY("nonbmand", KEY_KERN_OPT),
#else /* __SOLARIS__ */
FUSE_MOUNT_OPT("allow_other", allow_other), FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root), FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("blkdev", blkdev), FUSE_MOUNT_OPT("blkdev", blkdev),
@ -83,6 +143,7 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
FUSE_OPT_KEY("atime", KEY_KERN_FLAG), FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
#endif /* __SOLARIS__ */
FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION), FUSE_OPT_KEY("-V", KEY_VERSION),
@ -90,6 +151,42 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_END FUSE_OPT_END
}; };
#ifdef __SOLARIS__
static void mount_help(void)
{
fprintf(stderr,
" -o allow_other allow access to other users\n"
" -o allow_root allow access to root\n"
" -o nonempty allow mounts over non-empty file/dir\n"
" -o default_permissions enable permission checking by kernel\n"
" -o fsname=NAME set filesystem name\n"
" -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
" -o max_read=N set maximum size of read requests\n"
"\n"
);
}
static void exec_fusermount(const char *argv[])
{
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
execvp(FUSERMOUNT_PROG, (char **) argv);
}
static void mount_version(void)
{
int pid = fork();
if (!pid) {
const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
exec_fusermount(argv);
_exit(1);
} else if (pid != -1)
waitpid(pid, NULL, 0);
}
#endif /* __SOLARIS__ */
struct mount_flags { struct mount_flags {
const char *opt; const char *opt;
unsigned long flag; unsigned long flag;
@ -101,6 +198,7 @@ static struct mount_flags mount_flags[] = {
{"ro", MS_RDONLY, 1}, {"ro", MS_RDONLY, 1},
{"suid", MS_NOSUID, 0}, {"suid", MS_NOSUID, 0},
{"nosuid", MS_NOSUID, 1}, {"nosuid", MS_NOSUID, 1},
#ifndef __SOLARIS__
{"dev", MS_NODEV, 0}, {"dev", MS_NODEV, 0},
{"nodev", MS_NODEV, 1}, {"nodev", MS_NODEV, 1},
{"exec", MS_NOEXEC, 0}, {"exec", MS_NOEXEC, 0},
@ -110,9 +208,42 @@ static struct mount_flags mount_flags[] = {
{"atime", MS_NOATIME, 0}, {"atime", MS_NOATIME, 0},
{"noatime", MS_NOATIME, 1}, {"noatime", MS_NOATIME, 1},
{"dirsync", MS_DIRSYNC, 1}, {"dirsync", MS_DIRSYNC, 1},
#else /* __SOLARIS__ */
{"-g", MS_GLOBAL, 1}, /* 1eaf4 */
{"-m", MS_NOMNTTAB, 1}, /* 1eb00 */
{"-O", MS_OVERLAY, 1}, /* 1eb0c */
#endif /* __SOLARIS__ */
{NULL, 0, 0} {NULL, 0, 0}
}; };
#ifdef __SOLARIS__
/*
* See comments in fuse_kern_mount()
*/
struct solaris_mount_opts {
int nosuid;
int setuid;
int nosetuid;
int devices;
int nodevices;
};
#define SOLARIS_MOUNT_OPT(t, p, n) \
{ t, offsetof(struct solaris_mount_opts, p), n }
static const struct fuse_opt solaris_mnt_opts[] = {
SOLARIS_MOUNT_OPT("suid", setuid, 1),
SOLARIS_MOUNT_OPT("suid", devices, 1),
SOLARIS_MOUNT_OPT("nosuid", nosuid, 1),
SOLARIS_MOUNT_OPT("setuid", setuid, 1),
SOLARIS_MOUNT_OPT("nosetuid", nosetuid, 1),
SOLARIS_MOUNT_OPT("devices", devices, 1),
SOLARIS_MOUNT_OPT("nodevices", nodevices, 1),
FUSE_OPT_END
};
#endif /* __SOLARIS__ */
static void set_mount_flag(const char *s, int *flags) static void set_mount_flag(const char *s, int *flags)
{ {
int i; int i;
@ -156,23 +287,85 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key,
case KEY_FUSERMOUNT_OPT: case KEY_FUSERMOUNT_OPT:
return fuse_opt_add_opt(&mo->fusermount_opts, arg); return fuse_opt_add_opt(&mo->fusermount_opts, arg);
#ifdef __SOLARIS__
case KEY_SUBTYPE_OPT:
return fuse_opt_add_opt(&mo->subtype_opt, arg);
#endif /* __SOLARIS__ */
case KEY_MTAB_OPT: case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg); return fuse_opt_add_opt(&mo->mtab_opts, arg);
case KEY_HELP: case KEY_HELP:
#ifdef __SOLARIS__
mount_help();
#endif /* __SOLARIS__ */
mo->ishelp = 1; mo->ishelp = 1;
break; break;
case KEY_VERSION: case KEY_VERSION:
#ifdef __SOLARIS__
mount_version();
#endif /* __SOLARIS__ */
mo->ishelp = 1; mo->ishelp = 1;
break; break;
} }
return 1; return 1;
} }
#ifdef __SOLARIS__
/* return value:
* >= 0 => fd
* -1 => error
*/
static int receive_fd(int fd)
{
struct msghdr msg;
struct iovec iov;
char buf[1];
int rv;
size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
struct cmsghdr *cmsg;
iov.iov_base = buf;
iov.iov_len = 1;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* old BSD implementations should use msg_accrights instead of
* msg_control; the interface is different. */
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
if (rv == -1) {
perror("recvmsg");
return -1;
}
if(!rv) {
/* EOF */
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg->cmsg_type == SCM_RIGHTS) {
fprintf(stderr, "got control message of unknown type %d\n",
cmsg->cmsg_type);
return -1;
}
return *(int*)CMSG_DATA(cmsg);
}
#endif /* __SOLARIS__ */
void fuse_kern_unmount(const char *mountpoint, int fd) void fuse_kern_unmount(const char *mountpoint, int fd)
{ {
int res; int res;
#ifdef __SOLARIS__
int pid;
#endif /* __SOLARIS__ */
if (!mountpoint) if (!mountpoint)
return; return;
@ -188,11 +381,214 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
if (res == 1 && (pfd.revents & POLLERR)) if (res == 1 && (pfd.revents & POLLERR))
return; return;
} }
#ifndef __SOLARIS__
close(fd); close(fd);
fusermount(1, 0, 1, "", mountpoint); fusermount(1, 0, 1, "", mountpoint);
#else /* __SOLARIS__ */
if (geteuid() == 0) {
fuse_mnt_umount("fuse", mountpoint, 1);
return;
}
res = umount2(mountpoint, 2);
if (res == 0)
return;
pid = fork();
if(pid == -1)
return;
if(pid == 0) {
const char *argv[] =
{ FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL };
exec_fusermount(argv);
_exit(1);
}
waitpid(pid, NULL, 0);
#endif /* __SOLARIS__ */
} }
#ifdef __SOLARIS__
static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
int quiet)
{
int fds[2], pid;
int res;
int rv;
if (!mountpoint) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
perror("fuse: socketpair() failed");
return -1;
}
pid = fork();
if(pid == -1) {
perror("fuse: fork() failed");
close(fds[0]);
close(fds[1]);
return -1;
}
if(pid == 0) {
char env[10];
const char *argv[32];
int a = 0;
if (quiet) {
int fd = open("/dev/null", O_RDONLY);
dup2(fd, 1);
dup2(fd, 2);
}
argv[a++] = FUSERMOUNT_PROG;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = "--";
argv[a++] = mountpoint;
argv[a++] = NULL;
close(fds[1]);
fcntl(fds[0], F_SETFD, 0);
snprintf(env, sizeof(env), "%i", fds[0]);
setenv(FUSE_COMMFD_ENV, env, 1);
exec_fusermount(argv);
perror("fuse: failed to exec fusermount");
_exit(1);
}
close(fds[0]);
rv = receive_fd(fds[1]);
close(fds[1]);
waitpid(pid, NULL, 0); /* bury zombie */
return rv;
}
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
const char *mnt_opts)
{
char tmp[128];
const char *devname = "/dev/fuse";
char *source = NULL;
char *type = NULL;
struct stat stbuf;
int fd;
int res;
if (!mnt) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
res = lstat(mnt, &stbuf);
if (res == -1) {
fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
mnt, strerror(errno));
return -1;
}
if (!mo->nonempty) {
res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size);
if (res == -1)
return -1;
}
fd = open(devname, O_RDWR);
if (fd == -1) {
if (errno == ENODEV || errno == ENOENT)
fprintf(stderr,
"fuse: device not found, try 'modprobe fuse' first\n");
else
fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
strerror(errno));
return -1;
}
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
stbuf.st_mode & S_IFMT, getuid(), getgid());
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
if (res == -1)
goto out_close;
source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
(mo->subtype ? strlen(mo->subtype) : 0) +
strlen(devname) + 32);
type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
if (!type || !source) {
fprintf(stderr, "fuse: failed to allocate memory\n");
goto out_close;
}
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->subtype) {
strcat(type, ".");
strcat(type, mo->subtype);
}
strcpy(source,
mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
/* JPA added two final zeroes */
res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0,
mo->kernel_opts, MAX_MNTOPT_STR, 0, 0);
if (res == -1 && errno == EINVAL && mo->subtype) {
/* Probably missing subtype support */
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->fsname) {
if (!mo->blkdev)
sprintf(source, "%s#%s", mo->subtype, mo->fsname);
} else {
strcpy(source, type);
}
/* JPA two null args added */
res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0,
mo->kernel_opts, MAX_MNTOPT_STR, 0, 0);
}
if (res == -1) {
/*
* Maybe kernel doesn't support unprivileged mounts, in this
* case try falling back to fusermount
*/
if (errno == EPERM) {
res = -2;
} else {
int errno_save = errno;
if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
fprintf(stderr, "fuse: 'fuseblk' support missing\n");
else
fprintf(stderr, "fuse: mount failed: %s\n",
strerror(errno_save));
}
goto out_close;
}
return fd;
out_umount:
umount2(mnt, 2); /* lazy umount */
out_close:
free(type);
free(source);
close(fd);
return res;
}
#endif /* __SOLARIS__ */
static int get_mnt_flag_opts(char **mnt_optsp, int flags) static int get_mnt_flag_opts(char **mnt_optsp, int flags)
{ {
int i; int i;
@ -213,14 +609,59 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
struct mount_opts mo; struct mount_opts mo;
int res = -1; int res = -1;
char *mnt_opts = NULL; char *mnt_opts = NULL;
#ifdef __SOLARIS__
struct solaris_mount_opts smo;
struct fuse_args sa = FUSE_ARGS_INIT(0, NULL);
#endif /* __SOLARIS__ */
memset(&mo, 0, sizeof(mo)); memset(&mo, 0, sizeof(mo));
#ifndef __SOLARIS__
if (getuid()) if (getuid())
mo.flags = MS_NOSUID | MS_NODEV; mo.flags = MS_NOSUID | MS_NODEV;
#else /* __SOLARIS__ */
mo.flags = 0;
memset(&smo, 0, sizeof(smo));
if (args != NULL) {
while (args->argv[sa.argc] != NULL)
fuse_opt_add_arg(&sa, args->argv[sa.argc]);
}
#endif /* __SOLARIS__ */
if (args && if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
#ifndef __SOLARIS__
return -1; return -1;
#else /* __SOLARIS__ */
goto out; /* if SOLARIS, clean up 'sa' */
/*
* In Solaris, nosuid is equivalent to nosetuid + nodevices. We only
* have MS_NOSUID for mount flags (no MS_(NO)SETUID, etc.). But if
* we set that as a default, it restricts specifying just nosetuid
* or nodevices; there is no way for the user to specify setuid +
* nodevices or vice-verse. So we parse the existing options, then
* add restrictive defaults if needed.
*/
if (fuse_opt_parse(&sa, &smo, solaris_mnt_opts, NULL) == -1)
goto out;
if (smo.nosuid || (!smo.nodevices && !smo.devices
&& !smo.nosetuid && !smo.setuid)) {
mo.flags |= MS_NOSUID;
} else {
/*
* Defaults; if neither nodevices|devices,nosetuid|setuid has
* been specified, add the default negative option string. If
* both have been specified (i.e., -osuid,nosuid), leave them
* alone; the last option will have precedence.
*/
if (!smo.nodevices && !smo.devices)
if (fuse_opt_add_opt(&mo.kernel_opts, "nodevices") == -1)
goto out;
if (!smo.nosetuid && !smo.setuid)
if (fuse_opt_add_opt(&mo.kernel_opts, "nosetuid") == -1)
goto out;
}
#endif /* __SOLARIS__ */
if (mo.allow_other && mo.allow_root) { if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
@ -233,6 +674,7 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
res = -1; res = -1;
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
goto out; goto out;
#ifndef __SOLARIS__
if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1) if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1)
goto out; goto out;
if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1) if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1)
@ -243,15 +685,48 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
goto out; goto out;
if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0) if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0)
goto out; goto out;
res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint); res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint);
#else /* __SOLARIS__ */
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
goto out;
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
goto out;
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
if (res == -2) {
if (mo.fusermount_opts &&
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
if (mo.subtype) {
char *tmp_opts = NULL;
res = -1;
if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
free(tmp_opts);
goto out;
}
res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
free(tmp_opts);
if (res == -1)
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
} else {
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
}
}
#endif /* __SOLARIS__ */
out: out:
free(mnt_opts); free(mnt_opts);
#ifdef __SOLARIS__
fuse_opt_free_args(&sa);
free(mo.subtype);
free(mo.subtype_opt);
#endif /* __SOLARIS__ */
free(mo.fsname); free(mo.fsname);
free(mo.fusermount_opts); free(mo.fusermount_opts);
free(mo.kernel_opts); free(mo.kernel_opts);
free(mo.mtab_opts); free(mo.mtab_opts);
return res; return res;
} }

View File

@ -15,11 +15,245 @@
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <mntent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#ifdef __SOLARIS__
#else /* __SOLARIS__ */
#include <mntent.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/param.h> #include <sys/param.h>
#endif /* __SOLARIS__ */
#ifdef __SOLARIS__
char *mkdtemp(char *template);
#ifndef _PATH_MOUNTED
#define _PATH_MOUNTED "/etc/mnttab"
#endif /* _PATH_MOUNTED */
#ifndef IGNORE_MTAB
static int mtab_needs_update(const char *mnt)
{
struct stat stbuf;
/* If mtab is within new mount, don't touch it */
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
_PATH_MOUNTED[strlen(mnt)] == '/')
return 0;
if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))
return 0;
return 1;
}
#endif /* IGNORE_MTAB */
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
{
int res;
int status;
#ifndef IGNORE_MTAB
if (!mtab_needs_update(mnt))
return 0;
#endif /* IGNORE_MTAB */
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
setuid(geteuid());
/*
* hide in a directory, where mount isn't able to resolve
* fsname as a valid path
*/
tmp = mkdtemp(templ);
if (!tmp) {
fprintf(stderr, "%s: failed to create temporary directory\n",
progname);
exit(1);
}
if (chdir(tmp)) {
fprintf(stderr, "%s: failed to chdir to %s: %s\n",
progname, tmp, strerror(errno));
exit(1);
}
rmdir(tmp);
execl("/sbin/mount", "/sbin/mount", "-F", type, "-o", opts,
fsname, mnt, NULL);
fprintf(stderr, "%s: failed to execute /sbin/mount: %s\n", progname,
strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
return 0;
}
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
{
int res;
int status;
#ifndef IGNORE_MTAB
if (!mtab_needs_update(mnt))
return 0;
#endif /* IGNORE_MTAB */
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
setuid(geteuid());
execl("/sbin/umount", "/sbin/umount", !lazy ? "-f" : NULL, mnt,
NULL);
fprintf(stderr, "%s: failed to execute /sbin/umount: %s\n", progname,
strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
return 0;
}
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
{
char buf[PATH_MAX];
char *copy;
char *dst;
char *end;
char *lastcomp;
const char *toresolv;
if (!orig[0]) {
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
return NULL;
}
copy = strdup(orig);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return NULL;
}
toresolv = copy;
lastcomp = NULL;
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
if (end[0] != '/') {
char *tmp;
end[1] = '\0';
tmp = strrchr(copy, '/');
if (tmp == NULL) {
lastcomp = copy;
toresolv = ".";
} else {
lastcomp = tmp + 1;
if (tmp == copy)
toresolv = "/";
}
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
lastcomp = NULL;
toresolv = copy;
}
else if (tmp)
tmp[0] = '\0';
}
if (realpath(toresolv, buf) == NULL) {
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
strerror(errno));
free(copy);
return NULL;
}
if (lastcomp == NULL)
dst = strdup(buf);
else {
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
if (dst) {
unsigned buflen = strlen(buf);
if (buflen && buf[buflen-1] == '/')
sprintf(dst, "%s%s", buf, lastcomp);
else
sprintf(dst, "%s/%s", buf, lastcomp);
}
}
free(copy);
if (dst == NULL)
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return dst;
}
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize)
{
int isempty = 1;
if (S_ISDIR(rootmode)) {
struct dirent *ent;
DIR *dp = opendir(mnt);
if (dp == NULL) {
fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n",
progname, strerror(errno));
return -1;
}
while ((ent = readdir(dp)) != NULL) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0) {
isempty = 0;
break;
}
}
closedir(dp);
} else if (rootsize)
isempty = 0;
if (!isempty) {
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
return -1;
}
return 0;
}
int fuse_mnt_check_fuseblk(void)
{
char buf[256];
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return 1;
while (fgets(buf, sizeof(buf), f))
if (strstr(buf, "fuseblk\n")) {
fclose(f);
return 1;
}
fclose(f);
return 0;
}
#else /* __SOLARIS__ */
static int mtab_needs_update(const char *mnt) static int mtab_needs_update(const char *mnt)
{ {
@ -217,3 +451,5 @@ int fuse_mnt_check_fuseblk(void)
fclose(f); fclose(f);
return 0; return 0;
} }
#endif /* __SOLARIS__ */

View File

@ -14,6 +14,14 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig); char *fuse_mnt_resolve_path(const char *progname, const char *orig);
int fuse_mnt_check_fuseblk(void); int fuse_mnt_check_fuseblk(void);
#ifdef __SOLARIS__
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize);
#else /* __SOLARIS__ */
int fusermount(int unmount, int quiet, int lazy, const char *opts, int fusermount(int unmount, int quiet, int lazy, const char *opts,
const char *origmnt); const char *origmnt);
#endif /* __SOLARIS__ */