From 891a3e5d87fb03e2950e0adb1abc0e2b61f0ea4c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 9 Dec 2005 17:43:06 +0000 Subject: updated to use libfuse's option parsing --- sshfs.c | 661 +++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 318 insertions(+), 343 deletions(-) (limited to 'sshfs.c') 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 +#include #include #include #include @@ -27,7 +28,6 @@ #include #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; } -- cgit v1.2.3