diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | cache.c | 213 | ||||
-rw-r--r-- | cache.h | 2 | ||||
-rw-r--r-- | opts.c | 130 | ||||
-rw-r--r-- | opts.h | 20 | ||||
-rw-r--r-- | sshfs.c | 661 |
7 files changed, 417 insertions, 615 deletions
@@ -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 @@ -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); } @@ -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[]); @@ -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; -} @@ -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); @@ -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; } |