aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Makefile.am2
-rw-r--r--cache.c213
-rw-r--r--cache.h2
-rw-r--r--opts.c130
-rw-r--r--opts.h20
-rw-r--r--sshfs.c661
7 files changed, 417 insertions, 615 deletions
diff --git a/ChangeLog b/ChangeLog
index c3b136e..ae97538 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-12-09 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Use new option parsing interface of FUSE
+
2005-11-28 Miklos Szeredi <miklos@szeredi.hu>
* Set statvfs::f_frsize
diff --git a/Makefile.am b/Makefile.am
index 1192634..0b5298b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = sshfs
-sshfs_SOURCES = sshfs.c cache.c opts.c cache.h opts.h
+sshfs_SOURCES = sshfs.c cache.c cache.h
sshfs_CPPFLAGS = -DFUSE_USE_VERSION=25
diff --git a/cache.c b/cache.c
index 40ad0e3..8e44488 100644
--- a/cache.c
+++ b/cache.c
@@ -7,6 +7,7 @@
*/
#include "cache.h"
+#include <fuse_opt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,17 +15,23 @@
#include <glib.h>
#include <pthread.h>
-#include "opts.h"
-
#define DEFAULT_CACHE_TIMEOUT 20
#define MAX_CACHE_SIZE 10000
#define MIN_CACHE_CLEAN_INTERVAL 5
#define CACHE_CLEAN_INTERVAL 60
-static int cache_on = 1;
-static unsigned cache_stat_timeout = DEFAULT_CACHE_TIMEOUT;
-static unsigned cache_dir_timeout = DEFAULT_CACHE_TIMEOUT;
-static unsigned cache_link_timeout = DEFAULT_CACHE_TIMEOUT;
+struct cache {
+ int on;
+ unsigned stat_timeout;
+ unsigned dir_timeout;
+ unsigned link_timeout;
+ struct fuse_cache_operations *next_oper;
+ GHashTable *table;
+ pthread_mutex_t lock;
+ time_t last_cleaned;
+};
+
+static struct cache cache;
struct node {
struct stat stat;
@@ -43,11 +50,6 @@ struct fuse_cache_dirhandle {
GPtrArray *dir;
};
-static struct fuse_cache_operations *next_oper;
-static GHashTable *cache;
-static pthread_mutex_t cache_lock;
-static time_t last_cleaned;
-
static void free_node(gpointer node_)
{
struct node *node = (struct node *) node_;
@@ -67,22 +69,23 @@ static int cache_clean_entry(void *key_, struct node *node, time_t *now)
static void cache_clean(void)
{
time_t now = time(NULL);
- if (now > last_cleaned + MIN_CACHE_CLEAN_INTERVAL &&
- (g_hash_table_size(cache) > MAX_CACHE_SIZE ||
- now > last_cleaned + CACHE_CLEAN_INTERVAL)) {
- g_hash_table_foreach_remove(cache, (GHRFunc) cache_clean_entry, &now);
- last_cleaned = now;
+ if (now > cache.last_cleaned + MIN_CACHE_CLEAN_INTERVAL &&
+ (g_hash_table_size(cache.table) > MAX_CACHE_SIZE ||
+ now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) {
+ g_hash_table_foreach_remove(cache.table,
+ (GHRFunc) cache_clean_entry, &now);
+ cache.last_cleaned = now;
}
}
static struct node *cache_lookup(const char *path)
{
- return (struct node *) g_hash_table_lookup(cache, path);
+ return (struct node *) g_hash_table_lookup(cache.table, path);
}
static void cache_purge(const char *path)
{
- g_hash_table_remove(cache, path);
+ g_hash_table_remove(cache.table, path);
}
static void cache_purge_parent(const char *path)
@@ -90,7 +93,7 @@ static void cache_purge_parent(const char *path)
const char *s = strrchr(path, '/');
if (s) {
if (s == path)
- g_hash_table_remove(cache, "/");
+ g_hash_table_remove(cache.table, "/");
else {
char *parent = g_strndup(path, s - path);
cache_purge(parent);
@@ -101,27 +104,27 @@ static void cache_purge_parent(const char *path)
static void cache_invalidate(const char *path)
{
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
cache_purge(path);
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
}
static void cache_invalidate_dir(const char *path)
{
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache_purge_parent(path);
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
}
static void cache_do_rename(const char *from, const char *to)
{
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
cache_purge(from);
cache_purge(to);
cache_purge_parent(from);
cache_purge_parent(to);
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
}
static struct node *cache_get(const char *path)
@@ -130,7 +133,7 @@ static struct node *cache_get(const char *path)
if (node == NULL) {
char *pathcopy = g_strdup(path);
node = g_new0(struct node, 1);
- g_hash_table_insert(cache, pathcopy, node);
+ g_hash_table_insert(cache.table, pathcopy, node);
}
return node;
}
@@ -140,15 +143,15 @@ static void cache_add_attr(const char *path, const struct stat *stbuf)
struct node *node;
time_t now;
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
node->stat = *stbuf;
- node->stat_valid = time(NULL) + cache_stat_timeout;
+ node->stat_valid = time(NULL) + cache.stat_timeout;
if (node->stat_valid > node->valid)
node->valid = node->stat_valid;
cache_clean();
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
}
static void cache_add_dir(const char *path, char **dir)
@@ -156,16 +159,16 @@ static void cache_add_dir(const char *path, char **dir)
struct node *node;
time_t now;
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_strfreev(node->dir);
node->dir = dir;
- node->dir_valid = time(NULL) + cache_dir_timeout;
+ node->dir_valid = time(NULL) + cache.dir_timeout;
if (node->dir_valid > node->valid)
node->valid = node->dir_valid;
cache_clean();
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
}
static size_t my_strnlen(const char *s, size_t maxsize)
@@ -180,23 +183,23 @@ static void cache_add_link(const char *path, const char *link, size_t size)
struct node *node;
time_t now;
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_free(node->link);
node->link = g_strndup(link, my_strnlen(link, size-1));
- node->link_valid = time(NULL) + cache_link_timeout;
+ node->link_valid = time(NULL) + cache.link_timeout;
if (node->link_valid > node->valid)
node->valid = node->link_valid;
cache_clean();
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
}
static int cache_get_attr(const char *path, struct stat *stbuf)
{
struct node *node;
int err = -EAGAIN;
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
@@ -205,7 +208,7 @@ static int cache_get_attr(const char *path, struct stat *stbuf)
err = 0;
}
}
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
return err;
}
@@ -213,7 +216,7 @@ static int cache_getattr(const char *path, struct stat *stbuf)
{
int err = cache_get_attr(path, stbuf);
if (err) {
- err = next_oper->oper.getattr(path, stbuf);
+ err = cache.next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf);
}
@@ -225,19 +228,19 @@ static int cache_readlink(const char *path, char *buf, size_t size)
struct node *node;
int err;
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->link_valid - now >= 0) {
strncpy(buf, node->link, size-1);
buf[size-1] = '\0';
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
return 0;
}
}
- pthread_mutex_unlock(&cache_lock);
- err = next_oper->oper.readlink(path, buf, size);
+ pthread_mutex_unlock(&cache.lock);
+ err = cache.next_oper->oper.readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
@@ -265,24 +268,24 @@ static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
char **dir;
struct node *node;
- pthread_mutex_lock(&cache_lock);
+ pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL && node->dir != NULL) {
time_t now = time(NULL);
if (node->dir_valid - now >= 0) {
for(dir = node->dir; *dir != NULL; dir++)
filler(h, *dir, 0, 0);
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
return 0;
}
}
- pthread_mutex_unlock(&cache_lock);
+ pthread_mutex_unlock(&cache.lock);
ch.path = path;
ch.h = h;
ch.filler = filler;
ch.dir = g_ptr_array_new();
- err = next_oper->cache_getdir(path, &ch, cache_dirfill);
+ err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
if (!err)
@@ -306,12 +309,12 @@ static int cache_unity_getdir(const char *path, fuse_dirh_t h,
struct fuse_cache_dirhandle ch;
ch.h = h;
ch.filler = filler;
- return next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
+ return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
}
static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
{
- int err = next_oper->oper.mknod(path, mode, rdev);
+ int err = cache.next_oper->oper.mknod(path, mode, rdev);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -319,7 +322,7 @@ static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
static int cache_mkdir(const char *path, mode_t mode)
{
- int err = next_oper->oper.mkdir(path, mode);
+ int err = cache.next_oper->oper.mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -327,7 +330,7 @@ static int cache_mkdir(const char *path, mode_t mode)
static int cache_unlink(const char *path)
{
- int err = next_oper->oper.unlink(path);
+ int err = cache.next_oper->oper.unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -335,7 +338,7 @@ static int cache_unlink(const char *path)
static int cache_rmdir(const char *path)
{
- int err = next_oper->oper.rmdir(path);
+ int err = cache.next_oper->oper.rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -343,7 +346,7 @@ static int cache_rmdir(const char *path)
static int cache_symlink(const char *from, const char *to)
{
- int err = next_oper->oper.symlink(from, to);
+ int err = cache.next_oper->oper.symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
@@ -351,7 +354,7 @@ static int cache_symlink(const char *from, const char *to)
static int cache_rename(const char *from, const char *to)
{
- int err = next_oper->oper.rename(from, to);
+ int err = cache.next_oper->oper.rename(from, to);
if (!err)
cache_do_rename(from, to);
return err;
@@ -359,7 +362,7 @@ static int cache_rename(const char *from, const char *to)
static int cache_link(const char *from, const char *to)
{
- int err = next_oper->oper.link(from, to);
+ int err = cache.next_oper->oper.link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
@@ -369,7 +372,7 @@ static int cache_link(const char *from, const char *to)
static int cache_chmod(const char *path, mode_t mode)
{
- int err = next_oper->oper.chmod(path, mode);
+ int err = cache.next_oper->oper.chmod(path, mode);
if (!err)
cache_invalidate(path);
return err;
@@ -377,7 +380,7 @@ static int cache_chmod(const char *path, mode_t mode)
static int cache_chown(const char *path, uid_t uid, gid_t gid)
{
- int err = next_oper->oper.chown(path, uid, gid);
+ int err = cache.next_oper->oper.chown(path, uid, gid);
if (!err)
cache_invalidate(path);
return err;
@@ -385,7 +388,7 @@ static int cache_chown(const char *path, uid_t uid, gid_t gid)
static int cache_truncate(const char *path, off_t size)
{
- int err = next_oper->oper.truncate(path, size);
+ int err = cache.next_oper->oper.truncate(path, size);
if (!err)
cache_invalidate(path);
return err;
@@ -393,7 +396,7 @@ static int cache_truncate(const char *path, off_t size)
static int cache_utime(const char *path, struct utimbuf *buf)
{
- int err = next_oper->oper.utime(path, buf);
+ int err = cache.next_oper->oper.utime(path, buf);
if (!err)
cache_invalidate(path);
return err;
@@ -402,7 +405,7 @@ static int cache_utime(const char *path, struct utimbuf *buf)
static int cache_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
- int res = next_oper->oper.write(path, buf, size, offset, fi);
+ int res = cache.next_oper->oper.write(path, buf, size, offset, fi);
if (res >= 0)
cache_invalidate(path);
return res;
@@ -412,7 +415,7 @@ static int cache_write(const char *path, const char *buf, size_t size,
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
- int err = next_oper->oper.create(path, mode, fi);
+ int err = cache.next_oper->oper.create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -421,7 +424,7 @@ static int cache_create(const char *path, mode_t mode,
static int cache_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
- int err = next_oper->oper.ftruncate(path, size, fi);
+ int err = cache.next_oper->oper.ftruncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
@@ -432,7 +435,7 @@ static int cache_fgetattr(const char *path, struct stat *stbuf,
{
int err = cache_get_attr(path, stbuf);
if (err) {
- err = next_oper->oper.fgetattr(path, stbuf, fi);
+ err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf);
}
@@ -481,10 +484,10 @@ static void cache_unity_fill(struct fuse_cache_operations *oper,
struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
{
static struct fuse_operations cache_oper;
- next_oper = oper;
+ cache.next_oper = oper;
cache_unity_fill(oper, &cache_oper);
- if (cache_on) {
+ if (cache.on) {
cache_oper.getattr = oper->oper.getattr ? cache_getattr : NULL;
cache_oper.readlink = oper->oper.readlink ? cache_readlink : NULL;
cache_oper.getdir = oper->cache_getdir ? cache_getdir : NULL;
@@ -505,10 +508,10 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
cache_oper.ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL;
cache_oper.fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL;
#endif
- pthread_mutex_init(&cache_lock, NULL);
- cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- free_node);
- if (cache == NULL) {
+ pthread_mutex_init(&cache.lock, NULL);
+ cache.table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ free_node);
+ if (cache.table == NULL) {
fprintf(stderr, "failed to create cache\n");
return NULL;
}
@@ -516,61 +519,31 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
return &cache_oper;
}
-enum {
- COPT_CACHE,
- COPT_TIMEOUT,
- COPT_STAT_TIMEOUT,
- COPT_DIR_TIMEOUT,
- COPT_LINK_TIMEOUT,
- COPT_LAST /* Last entry in this list! */
-};
-
-static struct opt cache_opts[] = {
- [COPT_CACHE] = { .optname = "cache" },
- [COPT_TIMEOUT] = { .optname = "cache_timeout" },
- [COPT_STAT_TIMEOUT] = { .optname = "cache_stat_timeout" },
- [COPT_DIR_TIMEOUT] = { .optname = "cache_dir_timeout" },
- [COPT_LINK_TIMEOUT] = { .optname = "cache_link_timeout" },
- [COPT_LAST] = { .optname = NULL }
-};
-
-static int get_timeout(int sel, unsigned *timeoutp)
+static int cache_opt_proc(void *data, const char *arg, int key)
{
- struct opt *o = &cache_opts[sel];
- if (!o->present)
- return 0;
- if (opt_get_unsigned(o, timeoutp) == -1)
- return -1;
+ (void) data, (void) arg, (void) key;
return 1;
}
-int cache_parse_options(int *argcp, char *argv[])
+static const struct fuse_opt cache_opts[] = {
+ { "cache=yes", offsetof(struct cache, on), 1 },
+ { "cache=no", offsetof(struct cache, on), 0 },
+ { "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
+ { "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
+ { "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 },
+ { "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
+ { "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
+ { "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 },
+ FUSE_OPT_END
+};
+
+int cache_parse_options(int *argcp, char **argvp[])
{
- unsigned timeout;
- int res;
- process_options(argcp, argv, cache_opts, 1);
- if (cache_opts[COPT_CACHE].present) {
- char *val = cache_opts[COPT_CACHE].value;
- if (!val || !val[0] ||
- (strcmp(val, "yes") != 0 && strcmp(val, "no") != 0)) {
- fprintf(stderr, "Invalid or missing value for 'cache' option\n");
- return -1;
- }
- if (strcmp(val, "yes") == 0)
- cache_on = 1;
- else
- cache_on = 0;
- }
- if ((res = get_timeout(COPT_TIMEOUT, &timeout)) == -1)
- return -1;
- if (res == 1) {
- cache_stat_timeout = timeout;
- cache_dir_timeout = timeout;
- cache_link_timeout = timeout;
- }
- if(get_timeout(COPT_STAT_TIMEOUT, &cache_stat_timeout) == -1 ||
- get_timeout(COPT_DIR_TIMEOUT, &cache_dir_timeout) == -1 ||
- get_timeout(COPT_LINK_TIMEOUT, &cache_link_timeout) == -1)
- return -1;
- return 0;
+ cache.stat_timeout = DEFAULT_CACHE_TIMEOUT;
+ cache.dir_timeout = DEFAULT_CACHE_TIMEOUT;
+ cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
+ cache.on = 1;
+
+ return fuse_opt_parse(0, NULL, &cache, cache_opts, cache_opt_proc,
+ argcp, argvp);
}
diff --git a/cache.h b/cache.h
index b0b93b1..052c787 100644
--- a/cache.h
+++ b/cache.h
@@ -23,4 +23,4 @@ struct fuse_cache_operations {
};
struct fuse_operations *cache_init(struct fuse_cache_operations *oper);
-int cache_parse_options(int *argcp, char *argv[]);
+int cache_parse_options(int *argcp, char **argv[]);
diff --git a/opts.c b/opts.c
deleted file mode 100644
index 8cc3d76..0000000
--- a/opts.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- Mount option parsing
- Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU GPL.
- See the file COPYING.
-*/
-
-#include "opts.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
-
-static int process_option(char *arg, struct opt opts[], int case_sensitive)
-{
- int i;
- char *eq = strchr(arg, '=');
- if (eq)
- *eq = '\0';
-
- for (i = 0; opts[i].optname != NULL; i++) {
- if (case_sensitive) {
- if (strcmp(opts[i].optname, arg) == 0)
- break;
- } else if (strcasecmp(opts[i].optname, arg) == 0)
- break;
- }
- if (opts[i].optname == NULL) {
- if (eq)
- *eq = '=';
- return 0;
- }
- opts[i].present = 1;
- if (eq) {
- if (opts[i].value)
- g_free(opts[i].value);
- opts[i].value = g_strdup(eq+1);
- }
- return 1;
-}
-
-static int process_option_group(char *arg, struct opt opts[],
- int case_sensitive)
-{
- int remove = 1;
- char *prevcomma = NULL;
- while (1) {
- int remove_one;
- char *comma = strchr(arg, ',');
- if (comma)
- *comma = '\0';
- remove_one = process_option(arg, opts, case_sensitive);
- if (remove_one) {
- if (comma)
- memmove(arg, comma + 1, strlen(comma + 1) + 1);
- } else {
- remove = 0;
- if (comma)
- arg = comma + 1;
- if (prevcomma)
- *prevcomma = ',';
- prevcomma = comma;
- }
- if (!comma)
- break;
- }
- return remove;
-}
-
-void process_options(int *argcp, char *argv[], struct opt opts[],
- int case_sensitive)
-{
- int argctr;
- int newargctr;
-
- for (argctr = 1, newargctr = 1; argctr < *argcp; argctr++) {
- char *arg = argv[argctr];
- int removed = 0;
- if (arg[0] == '-' && arg[1] == 'o') {
- if (arg[2])
- removed = process_option_group(arg+2, opts, case_sensitive);
- else {
- if (argctr + 1 < *argcp) {
- argctr++;
- arg = argv[argctr];
- removed = process_option_group(arg, opts, case_sensitive);
- if (removed)
- g_free(argv[argctr-1]);
- else if (argctr != newargctr)
- argv[newargctr++] = argv[argctr-1];
- }
- }
- }
- if (removed)
- g_free(arg);
- else {
- if(argctr != newargctr)
- argv[newargctr] = arg;
- newargctr++;
- }
- }
- *argcp = newargctr;
-}
-
-int opt_get_unsigned(const struct opt *o, unsigned *valp)
-{
- char *end;
- unsigned val;
- if (!o->value || !o->value[0]) {
- fprintf(stderr, "Missing value for '%s' option\n", o->optname);
- return -1;
- }
- val = strtoul(o->value, &end, 0);
- if (end[0]) {
- fprintf(stderr, "Invalid value for '%s' option\n", o->optname);
- return -1;
- }
- *valp = val;
- return 0;
-}
-
-char *opt_get_string(const struct opt *o)
-{
- if (!o->value || !o->value[0]) {
- fprintf(stderr, "Missing value for '%s' option\n", o->optname);
- return NULL;
- }
- return o->value;
-}
diff --git a/opts.h b/opts.h
deleted file mode 100644
index 196c047..0000000
--- a/opts.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- Mount option parsing
- Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU GPL.
- See the file COPYING.
-*/
-
-struct opt {
- const char *optname;
- int present;
- char *value;
-};
-
-void process_options(int *argcp, char *argv[], struct opt opts[],
- int case_sensitive);
-
-int opt_get_unsigned(const struct opt *o, unsigned *valp);
-
-char *opt_get_string(const struct opt *o);
diff --git a/sshfs.c b/sshfs.c
index 2fbc26c..78519ba 100644
--- a/sshfs.c
+++ b/sshfs.c
@@ -9,6 +9,7 @@
#include "config.h"
#include <fuse.h>
+#include <fuse_opt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -27,7 +28,6 @@
#include <glib.h>
#include "cache.h"
-#include "opts.h"
#if FUSE_VERSION >= 23
#define SSHFS_USE_INIT
@@ -94,27 +94,6 @@
#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
-static unsigned int randseed;
-
-static int infd;
-static int outfd;
-static int connver;
-static int server_version;
-static unsigned ssh_ver = 2;
-static char *sftp_server = NULL;
-static int debug = 0;
-static int reconnect = 0;
-static int sync_write = 0;
-static int sync_read = 0;
-static int rename_workaround = 0;
-static int detect_uid = 0;
-static unsigned remote_uid;
-static unsigned local_uid;
-static int remote_uid_detected = 0;
-static char *base_path;
-static char *host;
-static unsigned blksize = 4096;
-
struct buffer {
uint8_t *p;
size_t len;
@@ -162,86 +141,120 @@ struct sshfs_file {
int connver;
};
-static GHashTable *reqtab;
-static pthread_mutex_t lock;
-static int processing_thread_started;
-
-
-static struct opt ssh_opts[] = {
- { .optname = "AddressFamily" },
- { .optname = "BatchMode" },
- { .optname = "BindAddress" },
- { .optname = "ChallengeResponseAuthentication" },
- { .optname = "CheckHostIP" },
- { .optname = "Cipher" },
- { .optname = "Ciphers" },
- { .optname = "Compression" },
- { .optname = "CompressionLevel" },
- { .optname = "ConnectionAttempts" },
- { .optname = "ConnectTimeout" },
- { .optname = "GlobalKnownHostsFile" },
- { .optname = "GSSAPIAuthentication" },
- { .optname = "GSSAPIDelegateCredentials" },
- { .optname = "HostbasedAuthentication" },
- { .optname = "HostKeyAlgorithms" },
- { .optname = "HostKeyAlias" },
- { .optname = "HostName" },
- { .optname = "IdentityFile" },
- { .optname = "IdentitiesOnly" },
- { .optname = "LogLevel" },
- { .optname = "MACs" },
- { .optname = "NoHostAuthenticationForLocalhost" },
- { .optname = "NumberOfPasswordPrompts" },
- { .optname = "PasswordAuthentication" },
- { .optname = "Port" },
- { .optname = "PreferredAuthentications" },
- { .optname = "ProxyCommand" },
- { .optname = "PubkeyAuthentication" },
- { .optname = "RhostsRSAAuthentication" },
- { .optname = "RSAAuthentication" },
- { .optname = "ServerAliveInterval" },
- { .optname = "ServerAliveCountMax" },
- { .optname = "SmartcardDevice" },
- { .optname = "StrictHostKeyChecking" },
- { .optname = "TCPKeepAlive" },
- { .optname = "UsePrivilegedPort" },
- { .optname = "UserKnownHostsFile" },
- { .optname = "VerifyHostKeyDNS" },
- { .optname = NULL }
+struct sshfs {
+ const char *progname;
+ char *directport;
+ char *ssh_command;
+ char *sftp_server;
+ char **ssh_args;
+ int ssh_argc;
+ int rename_workaround;
+ int detect_uid;
+ unsigned max_read;
+ unsigned ssh_ver;
+ int sync_write;
+ int sync_read;
+ int debug;
+ int reconnect;
+ char *host;
+ char *base_path;
+ GHashTable *reqtab;
+ pthread_mutex_t lock;
+ int processing_thread_started;
+ unsigned int randseed;
+ int infd;
+ int outfd;
+ int connver;
+ int server_version;
+ unsigned remote_uid;
+ unsigned local_uid;
+ int remote_uid_detected;
+ unsigned blksize;
+};
+
+static struct sshfs sshfs;
+
+static const char *ssh_opts[] = {
+ "AddressFamily",
+ "BatchMode",
+ "BindAddress",
+ "ChallengeResponseAuthentication",
+ "CheckHostIP",
+ "Cipher",
+ "Ciphers",
+ "Compression",
+ "CompressionLevel",
+ "ConnectionAttempts",
+ "ConnectTimeout",
+ "GlobalKnownHostsFile",
+ "GSSAPIAuthentication",
+ "GSSAPIDelegateCredentials",
+ "HostbasedAuthentication",
+ "HostKeyAlgorithms",
+ "HostKeyAlias",
+ "HostName",
+ "IdentityFile",
+ "IdentitiesOnly",
+ "LogLevel",
+ "MACs",
+ "NoHostAuthenticationForLocalhost",
+ "NumberOfPasswordPrompts",
+ "PasswordAuthentication",
+ "Port",
+ "PreferredAuthentications",
+ "ProxyCommand",
+ "PubkeyAuthentication",
+ "RhostsRSAAuthentication",
+ "RSAAuthentication",
+ "ServerAliveInterval",
+ "ServerAliveCountMax",
+ "SmartcardDevice",
+ "StrictHostKeyChecking",
+ "TCPKeepAlive",
+ "UsePrivilegedPort",
+ "UserKnownHostsFile",
+ "VerifyHostKeyDNS",
+ NULL,
};
enum {
- SOPT_DIRECTPORT,
- SOPT_SSHCMD,
- SOPT_SYNC_WRITE,
- SOPT_SYNC_READ,
- SOPT_MAX_READ,
- SOPT_DEBUG,
- SOPT_RECONNECT,
- SOPT_WORKAROUND,
- SOPT_IDMAP,
- SOPT_PROTOCOL,
- SOPT_SFTPSERVER,
- SOPT_LAST /* Last entry in this list! */
+ KEY_PORT,
+ KEY_COMPRESS,
+ KEY_HELP,
+ KEY_VERSION,
};
-static struct opt sshfs_opts[] = {
- [SOPT_DIRECTPORT] = { .optname = "directport" },
- [SOPT_SSHCMD] = { .optname = "ssh_command" },
- [SOPT_SYNC_WRITE] = { .optname = "sshfs_sync" },
- [SOPT_SYNC_READ] = { .optname = "no_readahead" },
- [SOPT_MAX_READ] = { .optname = "max_read" },
- [SOPT_DEBUG] = { .optname = "sshfs_debug" },
- [SOPT_RECONNECT] = { .optname = "reconnect" },
- [SOPT_WORKAROUND] = { .optname = "workaround" },
- [SOPT_IDMAP] = { .optname = "idmap" },
- [SOPT_PROTOCOL] = { .optname = "ssh_protocol" },
- [SOPT_SFTPSERVER] = { .optname = "sftp_server" },
- [SOPT_LAST] = { .optname = NULL }
+#define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
+#define SSHFS_KEY(t, k) { t, FUSE_OPT_OFFSET_KEY, k }
+
+static struct fuse_opt sshfs_opts[] = {
+ SSHFS_OPT("directport=%s", directport, 0),
+ SSHFS_OPT("ssh_command=%s", ssh_command, 0),
+ SSHFS_OPT("sftp_server=%s", sftp_server, 0),
+ SSHFS_OPT("max_read=%u", max_read, 0),
+ SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0),
+ SSHFS_OPT("-1", ssh_ver, 1),
+ SSHFS_OPT("workaround=none", rename_workaround, 0),
+ SSHFS_OPT("workaround=rename", rename_workaround, 1),
+ SSHFS_OPT("workaround=all", rename_workaround, 1),
+ SSHFS_OPT("idmap=none", detect_uid, 0),
+ SSHFS_OPT("idmap=user", detect_uid, 1),
+ SSHFS_OPT("sshfs_sync", sync_write, 1),
+ SSHFS_OPT("no_readahead", sync_read, 1),
+ SSHFS_OPT("sshfs_debug", debug, 1),
+ SSHFS_OPT("reconnect", reconnect, 1),
+
+ SSHFS_KEY("-p ", KEY_PORT),
+ SSHFS_KEY("-C", KEY_COMPRESS),
+ SSHFS_KEY("-V", KEY_VERSION),
+ SSHFS_KEY("--version", KEY_VERSION),
+ SSHFS_KEY("-h", KEY_HELP),
+ SSHFS_KEY("--help", KEY_HELP),
+ FUSE_OPT_END
};
#define DEBUG(format, args...) \
- do { if (debug) fprintf(stderr, format, args); } while(0)
+ do { if (sshfs.debug) fprintf(stderr, format, args); } while(0)
static const char *type_name(uint8_t type)
{
@@ -318,8 +331,10 @@ static inline void buf_init(struct buffer *buf, size_t size)
{
if (size) {
buf->p = (uint8_t *) malloc(size);
- if (!buf->p)
+ if (!buf->p) {
+ fprintf(stderr, "sshfs: memory allocation failed\n");
exit(1);
+ }
} else
buf->p = NULL;
buf->len = 0;
@@ -347,8 +362,10 @@ static void buf_resize(struct buffer *buf, size_t len)
{
buf->size = (buf->len + len + 63) & ~31;
buf->p = (uint8_t *) realloc(buf->p, buf->size);
- if (!buf->p)
+ if (!buf->p) {
+ fprintf(stderr, "sshfs: memory allocation failed\n");
exit(1);
+ }
}
static inline void buf_check_add(struct buffer *buf, size_t len)
@@ -407,7 +424,8 @@ static inline void buf_add_string(struct buffer *buf, const char *str)
static inline void buf_add_path(struct buffer *buf, const char *path)
{
- char *realpath = g_strdup_printf("%s%s", base_path, path[1] ? path+1 : ".");
+ char *realpath =
+ g_strdup_printf("%s%s", sshfs.base_path, path[1] ? path+1 : ".");
buf_add_string(buf, realpath);
g_free(realpath);
}
@@ -523,16 +541,17 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
}
}
- if (remote_uid_detected && uid == remote_uid)
- uid = local_uid;
+ if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
+ uid = sshfs.local_uid;
memset(stbuf, 0, sizeof(struct stat));
stbuf->st_mode = mode;
stbuf->st_nlink = 1;
stbuf->st_size = size;
- if (blksize) {
- stbuf->st_blksize = blksize;
- stbuf->st_blocks = ((size + blksize - 1) & ~(blksize - 1)) >> 9;
+ if (sshfs.blksize) {
+ stbuf->st_blksize = sshfs.blksize;
+ stbuf->st_blocks =
+ ((size + sshfs.blksize - 1) & ~(sshfs.blksize - 1)) >> 9;
}
stbuf->st_uid = uid;
stbuf->st_gid = gid;
@@ -571,19 +590,24 @@ static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
return 0;
}
-static int start_ssh(char *host)
+static void ssh_add_arg(const char *arg)
+{
+ if (fuse_opt_add_arg(&sshfs.ssh_argc, &sshfs.ssh_args, arg) == -1)
+ _exit(1);
+}
+
+static int start_ssh(void)
{
int inpipe[2];
int outpipe[2];
- int i;
int pid;
if (pipe(inpipe) == -1 || pipe(outpipe) == -1) {
perror("failed to create pipe");
return -1;
}
- infd = inpipe[0];
- outfd = outpipe[1];
+ sshfs.infd = inpipe[0];
+ sshfs.outfd = outpipe[1];
pid = fork();
if (pid == -1) {
@@ -591,23 +615,14 @@ static int start_ssh(char *host)
return -1;
} else if (pid == 0) {
int devnull;
- int argctr = 0;
- char *ssh_args[sizeof(ssh_opts)/sizeof(struct opt) + 32];
- char *ssh_cmd;
- char veropt[64];
devnull = open("/dev/null", O_WRONLY);
- if (sshfs_opts[SOPT_SSHCMD].present)
- ssh_cmd = sshfs_opts[SOPT_SSHCMD].value;
- else
- ssh_cmd = "ssh";
-
if (dup2(outpipe[0], 0) == -1 || dup2(inpipe[1], 1) == -1) {
perror("failed to redirect input/output");
_exit(1);
}
- if (!debug && devnull != -1)
+ if (!sshfs.debug && devnull != -1)
dup2(devnull, 2);
close(devnull);
@@ -627,33 +642,8 @@ static int start_ssh(char *host)
}
chdir("/");
- ssh_args[argctr++] = ssh_cmd;
- sprintf(veropt, "-%i", ssh_ver);
- ssh_args[argctr++] = veropt;
- ssh_args[argctr++] = "-x";
- ssh_args[argctr++] = "-a";
- ssh_args[argctr++] = "-oClearAllForwardings=yes";
- for (i = 0; ssh_opts[i].optname != NULL; i++) {
- if (ssh_opts[i].present) {
- char *val = ssh_opts[i].value;
- char *sopt = g_strdup_printf("-o%s=%s", ssh_opts[i].optname,
- val ? val : "");
- ssh_args[argctr++] = sopt;
- }
- }
- ssh_args[argctr++] = host;
- if (!sftp_server) {
- if (ssh_ver == 1)
- sftp_server = SFTP_SERVER_PATH;
- else
- sftp_server = "sftp";
- }
- if (ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
- ssh_args[argctr++] = "-s";
- ssh_args[argctr++] = sftp_server;
- ssh_args[argctr++] = NULL;
-
- execvp(ssh_cmd, ssh_args);
+ execvp(sshfs.ssh_args[0], sshfs.ssh_args);
+ perror("execvp");
_exit(1);
}
waitpid(pid, NULL, 0);
@@ -690,8 +680,8 @@ static int connect_to(char *host, char *port)
}
freeaddrinfo(ai);
- infd = sock;
- outfd = sock;
+ sshfs.infd = sock;
+ sshfs.outfd = sock;
return 0;
}
@@ -701,7 +691,7 @@ static int do_write(struct buffer *buf)
size_t size = buf->len;
int res;
while (size) {
- res = write(outfd, p, size);
+ res = write(sshfs.outfd, p, size);
if (res == -1) {
perror("write");
return -1;
@@ -741,7 +731,7 @@ static int do_read(struct buffer *buf)
uint8_t *p = buf->p;
size_t size = buf->size;
while (size) {
- res = read(infd, p, size);
+ res = read(sshfs.infd, p, size);
if (res == -1) {
perror("read");
return -1;
@@ -803,9 +793,9 @@ static void chunk_put(struct read_chunk *chunk)
static void chunk_put_locked(struct read_chunk *chunk)
{
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
chunk_put(chunk);
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
}
static int clean_req(void *key_, struct request *req)
@@ -841,14 +831,14 @@ static void *process_requests(void *data_)
if (buf_get_uint32(&buf, &id) == -1)
break;
- pthread_mutex_lock(&lock);
- req = (struct request *) g_hash_table_lookup(reqtab,
+ pthread_mutex_lock(&sshfs.lock);
+ req = (struct request *) g_hash_table_lookup(sshfs.reqtab,
GUINT_TO_POINTER(id));
if (req == NULL)
fprintf(stderr, "request %i not found\n", id);
else
- g_hash_table_remove(reqtab, GUINT_TO_POINTER(id));
- pthread_mutex_unlock(&lock);
+ g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
+ pthread_mutex_unlock(&sshfs.lock);
if (req != NULL) {
struct timeval now;
unsigned int difftime;
@@ -864,28 +854,28 @@ static void *process_requests(void *data_)
sem_post(&req->ready);
else {
if (req->end_func) {
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
req->end_func(req);
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
}
request_free(req);
}
} else
buf_free(&buf);
}
- if (!reconnect) {
+ if (!sshfs.reconnect) {
/* harakiri */
kill(getpid(), SIGTERM);
} else {
- pthread_mutex_lock(&lock);
- processing_thread_started = 0;
- close(infd);
- infd = -1;
- close(outfd);
- outfd = -1;
- g_hash_table_foreach_remove(reqtab, (GHRFunc) clean_req, NULL);
- connver ++;
- pthread_mutex_unlock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
+ sshfs.processing_thread_started = 0;
+ close(sshfs.infd);
+ sshfs.infd = -1;
+ close(sshfs.outfd);
+ sshfs.outfd = -1;
+ g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, NULL);
+ sshfs.connver ++;
+ pthread_mutex_unlock(&sshfs.lock);
}
return NULL;
}
@@ -910,8 +900,8 @@ static int sftp_init()
if (buf_get_uint32(&buf, &version) == -1)
goto out;
- server_version = version;
- DEBUG("Server version: %i\n", server_version);
+ sshfs.server_version = version;
+ DEBUG("Server version: %i\n", sshfs.server_version);
if (version > PROTO_VERSION)
fprintf(stderr, "Warning: server uses version: %i, we support: %i\n",
version, PROTO_VERSION);
@@ -963,13 +953,13 @@ static void sftp_detect_uid()
if (!(flags & SSH_FILEXFER_ATTR_UIDGID))
goto out;
- remote_uid = stbuf.st_uid;
- local_uid = getuid();
- remote_uid_detected = 1;
- DEBUG("remote_uid = %i\n", remote_uid);
+ sshfs.remote_uid = stbuf.st_uid;
+ sshfs.local_uid = getuid();
+ sshfs.remote_uid_detected = 1;
+ DEBUG("remote_uid = %i\n", sshfs.remote_uid);
out:
- if (!remote_uid_detected)
+ if (!sshfs.remote_uid_detected)
fprintf(stderr, "failed to detect remote user ID\n");
buf_free(&buf);
@@ -979,10 +969,10 @@ static int connect_remote(void)
{
int err;
- if (sshfs_opts[SOPT_DIRECTPORT].present)
- err = connect_to(host, sshfs_opts[SOPT_DIRECTPORT].value);
+ if (sshfs.directport)
+ err = connect_to(sshfs.host, sshfs.directport);
else
- err = start_ssh(host);
+ err = start_ssh();
if (!err)
err = sftp_init();
@@ -993,10 +983,10 @@ static int start_processing_thread(void)
{
int err;
pthread_t thread_id;
- if (processing_thread_started)
+ if (sshfs.processing_thread_started)
return 0;
- if (outfd == -1) {
+ if (sshfs.outfd == -1) {
err = connect_remote();
if (err)
return -EIO;
@@ -1008,14 +998,14 @@ static int start_processing_thread(void)
return -EIO;
}
pthread_detach(thread_id);
- processing_thread_started = 1;
+ sshfs.processing_thread_started = 1;
return 0;
}
#ifdef SSHFS_USE_INIT
static void *sshfs_init(void)
{
- if (detect_uid)
+ if (sshfs.detect_uid)
sftp_detect_uid();
start_processing_thread();
@@ -1039,7 +1029,7 @@ static int sftp_request_common(uint8_t type, const struct buffer *buf,
sem_init(&req->ready, 0, 0);
buf_init(&req->reply, 0);
buf_init(&buf2, buf->len + 4);
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
if (begin_func)
begin_func(req);
id = sftp_get_id();
@@ -1047,20 +1037,20 @@ static int sftp_request_common(uint8_t type, const struct buffer *buf,
buf_add_mem(&buf2, buf->p, buf->len);
err = start_processing_thread();
if (err) {
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
goto out;
}
- g_hash_table_insert(reqtab, GUINT_TO_POINTER(id), req);
+ g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req);
gettimeofday(&req->start, NULL);
DEBUG("[%05i] %s\n", id, type_name(type));
err = -EIO;
if (sftp_send(type, &buf2) == -1) {
- g_hash_table_remove(reqtab, GUINT_TO_POINTER(id));
- pthread_mutex_unlock(&lock);
+ g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
+ pthread_mutex_unlock(&sshfs.lock);
goto out;
}
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
if (expect_type == 0) {
buf_free(&buf2);
@@ -1111,9 +1101,9 @@ static int sftp_request_common(uint8_t type, const struct buffer *buf,
out:
if (end_func) {
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
end_func(req);
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
}
buf_free(&buf2);
request_free(req);
@@ -1157,7 +1147,7 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
struct buffer buf;
struct buffer name;
- if (server_version < 3)
+ if (sshfs.server_version < 3)
return -EPERM;
buf_init(&buf, 0);
@@ -1259,7 +1249,7 @@ static int sshfs_symlink(const char *from, const char *to)
int err;
struct buffer buf;
- if (server_version < 3)
+ if (sshfs.server_version < 3)
return -EPERM;
/* openssh sftp server doesn't follow standard: link target and
@@ -1310,7 +1300,7 @@ static void random_string(char *str, int length)
{
int i;
for (i = 0; i < length; i++)
- *str++ = (char)('0' + rand_r(&randseed) % 10);
+ *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10);
*str = '\0';
}
@@ -1318,7 +1308,7 @@ static int sshfs_rename(const char *from, const char *to)
{
int err;
err = sshfs_do_rename(from, to);
- if (err == -EPERM && rename_workaround) {
+ if (err == -EPERM && sshfs.rename_workaround) {
size_t tolen = strlen(to);
if (tolen + RENAME_TEMP_CHARS < PATH_MAX) {
int tmperr;
@@ -1411,7 +1401,7 @@ static int sshfs_utime(const char *path, struct utimbuf *ubuf)
static inline int sshfs_file_is_conn(struct sshfs_file *sf)
{
- return sf->connver == connver;
+ return sf->connver == sshfs.connver;
}
static int sshfs_open_common(const char *path, mode_t mode,
@@ -1445,7 +1435,7 @@ static int sshfs_open_common(const char *path, mode_t mode,
/* Assume random read after open */
sf->is_seq = 0;
sf->next_pos = 0;
- sf->connver = connver;
+ sf->connver = sshfs.connver;
buf_init(&buf, 0);
buf_add_path(&buf, path);
buf_add_uint32(&buf, pflags);
@@ -1481,22 +1471,22 @@ static int sshfs_flush(const char *path, struct fuse_file_info *fi)
if (!sshfs_file_is_conn(sf))
return -EIO;
- if (sync_write)
+ if (sshfs.sync_write)
return 0;
(void) path;
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
if (!list_empty(&sf->write_reqs)) {
curr_list = sf->write_reqs.prev;
list_del(&sf->write_reqs);
list_init(&sf->write_reqs);
list_add(&write_reqs, curr_list);
while (!list_empty(&write_reqs))
- pthread_cond_wait(&sf->write_finished, &lock);
+ pthread_cond_wait(&sf->write_finished, &sshfs.lock);
}
err = sf->write_error;
sf->write_error = 0;
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
return err;
}
@@ -1620,10 +1610,10 @@ static int submit_read(struct sshfs_file *sf, size_t size, off_t offset,
chunk->refs = 1;
err = sshfs_send_async_read(sf, chunk);
if (!err) {
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
chunk_put(*chunkp);
*chunkp = chunk;
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
} else
chunk_put(chunk);
@@ -1668,12 +1658,12 @@ static int sshfs_async_read(struct sshfs_file *sf, char *rbuf, size_t size,
size_t origsize = size;
int curr_is_seq;
- pthread_mutex_lock(&lock);
+ pthread_mutex_lock(&sshfs.lock);
curr_is_seq = sf->is_seq;
sf->is_seq = (sf->next_pos == offset);
sf->next_pos = offset + size;
chunk = search_read_chunk(sf, offset);
- pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(&sshfs.lock);
if (chunk && chunk->size < size) {
chunk_prev = chunk;
@@ -1716,7 +1706,7 @@ static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
if (!sshfs_file_is_conn(sf))
return -EIO;
- if (sync_read)
+ if (sshfs.sync_read)
return sshfs_sync_read(sf, rbuf, size, offset);
else
return sshfs_async_read(sf, rbuf, size, offset);
@@ -1765,7 +1755,7 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size,
buf_add_buf(&buf, handle);
buf_add_uint64(&buf, offset);
buf_add_data(&buf, &data);
- if (!sync_write && !sf->write_error)
+ if (!sshfs.sync_write && !sf->write_error)
err = sftp_request_async(SSH_FXP_WRITE, &buf, sshfs_write_begin,
sshfs_write_end, sf);
else
@@ -1780,7 +1770,7 @@ static int sshfs_statfs(const char *path, struct statvfs *buf)
(void) path;
buf->f_namemax = 255;
- buf->f_bsize = blksize;
+ buf->f_bsize = sshfs.blksize;
buf->f_frsize = 512;
buf->f_blocks = 999999999 * 2;
buf->f_bfree = 999999999 * 2;
@@ -1862,9 +1852,9 @@ static int sshfs_fgetattr(const char *path, struct stat *stbuf,
static int processing_init(void)
{
- pthread_mutex_init(&lock, NULL);
- reqtab = g_hash_table_new(NULL, NULL);
- if (!reqtab) {
+ pthread_mutex_init(&sshfs.lock, NULL);
+ sshfs.reqtab = g_hash_table_new(NULL, NULL);
+ if (!sshfs.reqtab) {
fprintf(stderr, "failed to create hash table\n");
return -1;
}
@@ -1940,152 +1930,126 @@ static void usage(const char *progname)
exit(1);
}
+static int is_ssh_opt(const char *arg)
+{
+ if (arg[0] != '-') {
+ unsigned arglen = strlen(arg);
+ const char **o;
+ for (o = ssh_opts; *o; o++) {
+ unsigned olen = strlen(*o);
+ if (arglen > olen && arg[olen] == '=' &&
+ strncasecmp(arg, *o, olen) == 0)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int sshfs_opt_proc(void *data, const char *arg, int key)
+{
+ char *tmp;
+ (void) data;
+
+ switch (key) {
+ case FUSE_OPT_KEY_OPT:
+ if (is_ssh_opt(arg)) {
+ tmp = g_strdup_printf("-o%s", arg);
+ ssh_add_arg(tmp);
+ g_free(tmp);
+ return 0;
+ }
+ return 1;
+
+ case FUSE_OPT_KEY_NONOPT:
+ if (!sshfs.host && strchr(arg, ':')) {
+ sshfs.host = strdup(arg);
+ return 0;
+ }
+ return 1;
+
+ case KEY_PORT:
+ tmp = g_strdup_printf("-oPort=%s", arg + 2);
+ ssh_add_arg(tmp);
+ g_free(tmp);
+ return 0;
+
+ case KEY_COMPRESS:
+ ssh_add_arg("-oCompression=yes");
+ return 0;
+
+ case KEY_HELP:
+ usage(sshfs.progname);
+
+ case KEY_VERSION:
+ fprintf(stderr, "SSHFS version %s\n", PACKAGE_VERSION);
+ exit(0);
+
+ default:
+ fprintf(stderr, "internal error\n");
+ abort();
+ }
+}
+
int main(int argc, char *argv[])
{
- char *fsname;
int res;
- int argctr;
- unsigned max_read = 65536;
- int newargc = 0;
- char **newargv = (char **) malloc((argc + 10) * sizeof(char *));
- newargv[newargc++] = argv[0];
-
- for (argctr = 1; argctr < argc; argctr++) {
- char *arg = argv[argctr];
- if (arg[0] == '-') {
- switch (arg[1]) {
- case '-':
- if (strcmp(arg+2, "help") == 0)
- goto help;
- else if (strcmp(arg+2, "version") == 0)
- goto version;
- break;
-
- case 'V':
- version:
- fprintf(stderr, "SSHFS version %s\n", PACKAGE_VERSION);
- exit(0);
- break;
-
- case 'h':
- help:
- usage(argv[0]);
- break;
-
- case 'C':
- if (!arg[2])
- arg = "-oCompression=yes";
- break;
-
- case '1':
- if (!arg[2])
- arg = "-ossh_protocol=1";
- break;
-
- case 'p':
- if (arg[2] || argctr + 1 < argc) {
- char *newarg;
- if (arg[2])
- arg = arg + 2;
- else
- arg = argv[++argctr];
- newarg = malloc(strlen(arg)+32);
- sprintf(newarg, "-oPort=%s", arg);
- arg = newarg;
- }
- break;
- }
- newargv[newargc++] = g_strdup(arg);
- } else if (!host && strchr(arg, ':'))
- host = g_strdup(arg);
- else
- newargv[newargc++] = g_strdup(arg);
- }
- if (!host) {
+ int argcout;
+ char **argvout;
+ char *tmp;
+ char *fsname;
+ char *base_path;
+ const char *sftp_server;
+
+ sshfs.progname = argv[0];
+ sshfs.blksize = 4096;
+ sshfs.max_read = 65536;
+ sshfs.ssh_ver = 2;
+ ssh_add_arg("ssh");
+ ssh_add_arg("-x");
+ ssh_add_arg("-a");
+ ssh_add_arg("-oClearAllForwardings=yes");
+
+ if (fuse_opt_parse(argc, argv, &sshfs, sshfs_opts, sshfs_opt_proc,
+ &argcout, &argvout) == -1)
+ exit(1);
+
+ if (!sshfs.host) {
fprintf(stderr, "missing host\n");
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
exit(1);
}
- fsname = g_strdup(host);
- base_path = strchr(host, ':');
+ fsname = g_strdup(sshfs.host);
+ base_path = strchr(sshfs.host, ':');
*base_path++ = '\0';
if (base_path[0] && base_path[strlen(base_path)-1] != '/')
- base_path = g_strdup_printf("%s/", base_path);
+ sshfs.base_path = g_strdup_printf("%s/", base_path);
else
- base_path = g_strdup(base_path);
-
- process_options(&newargc, newargv, sshfs_opts, 1);
- if (sshfs_opts[SOPT_SYNC_WRITE].present)
- sync_write = 1;
- if (sshfs_opts[SOPT_SYNC_READ].present)
- sync_read = 1;
- if (sshfs_opts[SOPT_DEBUG].present)
- debug = 1;
- if (sshfs_opts[SOPT_WORKAROUND].present) {
- struct opt *o = &sshfs_opts[SOPT_WORKAROUND];
- char *s = opt_get_string(o);
- if (!s)
- exit(1);
+ sshfs.base_path = g_strdup(base_path);
- for (s = strtok(s, ":"); s; s = strtok(NULL, ":")) {
- if (strcmp(s, "none") == 0)
- ;
- else if (strcmp(s, "all") == 0)
- rename_workaround = 1;
- else if (strcmp(s, "rename") == 0)
- rename_workaround = 1;
- else {
- fprintf(stderr, "Invalid value for '%s' option\n", o->optname);
- exit(1);
- }
- }
+ if (sshfs.ssh_command) {
+ free(sshfs.ssh_args[0]);
+ sshfs.ssh_args[0] = sshfs.ssh_command;
}
- if (sshfs_opts[SOPT_IDMAP].present) {
- struct opt *o = &sshfs_opts[SOPT_IDMAP];
- char *idmap = opt_get_string(o);
- if (!idmap)
- exit(1);
- if (strcmp(idmap, "none") == 0)
- detect_uid = 0;
- else if (strcmp(idmap, "user") == 0)
- detect_uid = 1;
- else {
- fprintf(stderr, "Invalid value for '%s' option\n", o->optname);
- exit(1);
- }
- }
- if (sshfs_opts[SOPT_RECONNECT].present)
- reconnect = 1;
- if (sshfs_opts[SOPT_MAX_READ].present) {
- unsigned val;
- if (opt_get_unsigned(&sshfs_opts[SOPT_MAX_READ], &val) == -1)
- exit(1);
+ tmp = g_strdup_printf("-%i", sshfs.ssh_ver);
+ ssh_add_arg(tmp);
+ g_free(tmp);
+ ssh_add_arg(sshfs.host);
+ if (sshfs.sftp_server)
+ sftp_server = sshfs.sftp_server;
+ else if (sshfs.ssh_ver == 1)
+ sftp_server = SFTP_SERVER_PATH;
+ else
+ sftp_server = "sftp";
- if (val < max_read)
- max_read = val;
- }
- if (sshfs_opts[SOPT_PROTOCOL].present) {
- if (opt_get_unsigned(&sshfs_opts[SOPT_PROTOCOL], &ssh_ver) == -1)
- exit(1);
- }
- if (sshfs_opts[SOPT_SFTPSERVER].present) {
- sftp_server = opt_get_string(&sshfs_opts[SOPT_SFTPSERVER]);
- if (!sftp_server)
- exit(1);
- }
- if (sshfs_opts[SOPT_DIRECTPORT].present)
- res = connect_to(host, sshfs_opts[SOPT_DIRECTPORT].value);
- else {
- process_options(&newargc, newargv, ssh_opts, 0);
- res = start_ssh(host);
- }
- if (res == -1)
- exit(1);
+ if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
+ ssh_add_arg("-s");
- res = sftp_init();
- if (res == -1)
+ ssh_add_arg(sftp_server);
+ free(sshfs.sftp_server);
+
+ if (connect_remote() == -1)
exit(1);
#ifndef SSHFS_USE_INIT
@@ -2097,15 +2061,26 @@ int main(int argc, char *argv[])
if (res == -1)
exit(1);
- res = cache_parse_options(&newargc, newargv);
+ res = cache_parse_options(&argcout, &argvout);
if (res == -1)
exit(1);
- randseed = time(0);
+ sshfs.randseed = time(0);
+
+ if (sshfs.max_read > 65536)
+ sshfs.max_read = 65536;
- newargv[newargc++] = g_strdup_printf("-omax_read=%u", max_read);
- newargv[newargc++] = g_strdup_printf("-ofsname=sshfs#%s", fsname);
+ tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read);
+ fuse_opt_add_arg(&argcout, &argvout, tmp);
+ g_free(tmp);
+ tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
+ fuse_opt_add_arg(&argcout, &argvout, tmp);
+ g_free(tmp);
g_free(fsname);
- newargv[newargc] = NULL;
- return fuse_main(newargc, newargv, cache_init(&sshfs_oper));
+ res = fuse_main(argcout, argvout, cache_init(&sshfs_oper));
+ fuse_opt_free_args(argvout);
+ fuse_opt_free_args(sshfs.ssh_args);
+ free(sshfs.directport);
+
+ return res;
}