From: Miklos Szeredi Date: Fri, 26 Oct 2001 14:55:42 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: fuse_0_9~14 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=90d8bef61c8c40472ddfb1aafeeb6473ec51a053;p=qemu-gpiodev%2Flibfuse.git *** empty log message *** --- diff --git a/Makefile b/Makefile index f8810fd..f264b78 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,8 @@ CC = gcc KCFLAGS = -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe KCPPFLAGS = -I /lib/modules/`uname -r`/build/include/ -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -CFLAGS = -Wall -W -g +CFLAGS = -Wall -W -g `glib-config --cflags` +LDFLAGS = `glib-config --libs` CPPFLAGS = all: fuse.o fusemount diff --git a/dev.c b/dev.c index b6b9930..16d8ad1 100644 --- a/dev.c +++ b/dev.c @@ -12,6 +12,10 @@ #include #include #include +#include + +#define ICSIZE sizeof(struct fuse_in_common) +#define OCSIZE sizeof(struct fuse_out_common) static struct proc_dir_entry *proc_fs_fuse; struct proc_dir_entry *proc_fuse_dev; @@ -38,8 +42,8 @@ static int request_wait_answer(struct fuse_req *req) return ret; } -void request_send(struct fuse_conn *fc, struct fuse_inparam *in, - struct fuse_outparam *out, int valuret) +void request_send(struct fuse_conn *fc, struct fuse_in *in, + struct fuse_out *out) { int ret; struct fuse_req *req; @@ -50,13 +54,18 @@ void request_send(struct fuse_conn *fc, struct fuse_inparam *in, return; } - req->param.u.i = *in; - req->size = sizeof(req->param); + req->in = in; + req->out = out; req->done = 0; init_waitqueue_head(&req->waitq); spin_lock(&fuse_lock); - req->param.unique = fc->reqctr ++; + if(fc->file == NULL) { + ret = -ENOTCONN; + goto out; + } + + req->in->h.unique = fc->reqctr ++; list_add_tail(&req->list, &fc->pending); fc->outstanding ++; /* FIXME: Wait until the number of outstanding requests drops @@ -64,16 +73,17 @@ void request_send(struct fuse_conn *fc, struct fuse_inparam *in, wake_up(&fc->waitq); ret = request_wait_answer(req); fc->outstanding --; - *out = req->param.u.o; list_del(&req->list); + + out: kfree(req); spin_unlock(&fuse_lock); if(ret) out->result = ret; - else if (out->result < -512 || (out->result > 0 && !valuret)) { + else if (out->result <= -512 || out->result > 0) { printk("Bad result from client: %i\n", out->result); - out->result = -EIO; + out->result = -EPROTO; } } @@ -99,13 +109,13 @@ static int request_wait(struct fuse_conn *fc) return ret; } + static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, loff_t *off) { ssize_t ret; struct fuse_conn *fc = file->private_data; struct fuse_req *req; - struct fuse_param param; size_t size; spin_lock(&fuse_lock); @@ -113,13 +123,10 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, if(ret) goto err; - printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id); - req = list_entry(fc->pending.next, struct fuse_req, list); - param = req->param; - size = req->size; + size = ICSIZE + req->in->argsize; - ret = -EIO; + ret = -EPROTO; if(nbytes < size) { printk("fuse_dev_read: buffer too small (%i)\n", size); goto err; @@ -129,7 +136,8 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, list_add_tail(&req->list, &fc->processing); spin_unlock(&fuse_lock); - if(copy_to_user(buf, ¶m, size)) + if(copy_to_user(buf, &req->in->c, ICSIZE) || + copy_to_user(buf + ICSIZE, req->in->arg, req->in->argsize)) return -EFAULT; return size; @@ -147,9 +155,8 @@ static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique) list_for_each(entry, &fc->processing) { struct fuse_req *tmp; tmp = list_entry(entry, struct fuse_req, list); - if(tmp->param.unique == unique) { + if(tmp->in->c.unique == unique) { req = tmp; - list_del_init(&req->list); break; } } @@ -161,25 +168,36 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf, size_t nbytes, loff_t *off) { struct fuse_conn *fc = file->private_data; - struct fuse_param param; struct fuse_req *req; + struct fuse_out_common oc; + char *tmpbuf; - printk(KERN_DEBUG "fuse_dev_write[%i]\n", fc->id); - - if(nbytes < sizeof(param.unique) || nbytes > sizeof(param)) { - printk("fuse_dev_write: write is short or long\n"); - return -EIO; + if(nbytes > 2 * PAGE_SIZE) { + printk("fuse_dev_write: write is too long\n"); + return -EPROTO; } + + tmpbuf = (char *) __get_free_pages(GFP_KERNEL, 1); + if(!tmpbuf) + return -ENOMEM; - if(copy_from_user(¶m, buf, nbytes)) + if(copy_from_user(tmpbuf, buf, nbytes)) return -EFAULT; - + spin_lock(&fuse_lock); - req = request_find(fc, param.unique); + req = request_find(fc, oc.unique); + if(req == NULL) printk("fuse_dev_write[%i]: unknown request: %i", fc->id, - param.unique); + oc.unique); + + + else { + struct fuse_outparam *out = ¶m.u.o; + if(req->param.u.i.opcode == FUSE_OPEN && out->result == 0) + out->u.open_internal.file = fget(out->u.open.fd); + req->param = param; req->done = 1; wake_up(&req->waitq); @@ -231,8 +249,6 @@ static int fuse_dev_open(struct inode *inode, struct file *file) { struct fuse_conn *fc; - printk(KERN_DEBUG "fuse_dev_open\n"); - fc = new_conn(); if(!fc) return -ENOMEM; @@ -240,19 +256,29 @@ static int fuse_dev_open(struct inode *inode, struct file *file) fc->file = file; file->private_data = fc; - printk(KERN_DEBUG "new connection: %i\n", fc->id); - return 0; } +static void end_requests(struct list_head *head) +{ + while(!list_empty(head)) { + struct fuse_req *req; + req = list_entry(head->next, struct fuse_req, list); + list_del_init(&req->list); + req->done = 1; + req->param.u.o.result = -ECONNABORTED; + wake_up(&req->waitq); + } +} + static int fuse_dev_release(struct inode *inode, struct file *file) { struct fuse_conn *fc = file->private_data; - printk(KERN_DEBUG "fuse_dev_release[%i]\n", fc->id); - spin_lock(&fuse_lock); fc->file = NULL; + end_requests(&fc->pending); + end_requests(&fc->processing); fuse_release_conn(fc); spin_unlock(&fuse_lock); return 0; diff --git a/dir.c b/dir.c index 6fa5959..7a3ccc2 100644 --- a/dir.c +++ b/dir.c @@ -6,65 +6,255 @@ See the file COPYING. */ - #include "fuse_i.h" #include #include +#include +#include +#include + +static void change_attributes(struct inode *inode, struct fuse_attr *attr) +{ + inode->i_mode = attr->mode; + inode->i_nlink = attr->nlink; + inode->i_uid = attr->uid; + inode->i_gid = attr->gid; + inode->i_size = attr->size; + inode->i_blksize = attr->blksize; + inode->i_blocks = attr->blocks; + inode->i_atime = attr->atime; + inode->i_mtime = attr->mtime; + inode->i_ctime = attr->ctime; +} + +static void init_inode(struct inode *inode, struct fuse_attr *attr) +{ + change_attributes(inode, attr); + + if(S_ISREG(inode->i_mode)) + fuse_file_init(inode); + else if(S_ISDIR(inode->i_mode)) + fuse_dir_init(inode); + else if(S_ISLNK(inode->i_mode)) + fuse_symlink_init(inode); + else + init_special_inode(inode, inode->i_mode, attr->rdev); +} static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) { - printk(KERN_DEBUG "fuse_lookup: %li\n", dir->i_ino); + struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_inparam in; + struct fuse_outparam out; + struct inode *inode; + + in.opcode = FUSE_LOOKUP; + in.ino = dir->i_ino; + strcpy(in.u.lookup.name, entry->d_name.name); + + request_send(fc, &in, &out); + + if(out.result) + return ERR_PTR(out.result); + + inode = iget(dir->i_sb, out.u.lookup.ino); + if(!inode) + return ERR_PTR(-ENOMEM); + + init_inode(inode, &out.u.lookup.attr); + d_add(entry, inode); return NULL; } static int fuse_permission(struct inode *inode, int mask) { - printk(KERN_DEBUG "fuse_permission: %li, 0%o\n", inode->i_ino, mask); return 0; } static int fuse_revalidate(struct dentry *dentry) { - printk(KERN_DEBUG "fuse_revalidate: %li\n", - dentry->d_inode->i_ino); + struct inode *inode = dentry->d_inode; + struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_inparam in; + struct fuse_outparam out; - return 0; + in.opcode = FUSE_GETATTR; + in.ino = inode->i_ino; + + request_send(fc, &in, &out); + + if(out.result == 0) + change_attributes(inode, &out.u.getattr.attr); + + return out.result; } -static int fuse_readdir(struct file *file, void *dirent, filldir_t filldir) + + +#define DIR_BUFSIZE 2048 + +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) { - printk(KERN_DEBUG "fuse_readdir: %li\n", - file->f_dentry->d_inode->i_ino); + struct file *cfile = file->private_data; + char *buf; + char *p; + int ret; + size_t nbytes; + buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL); + if(!buf) + return -ENOMEM; + + ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE); + if(ret < 0) { + printk("fuse_readdir: failed to read container file\n"); + goto out; + } + nbytes = ret; + p = buf; + ret = 0; + while(nbytes >= FUSE_NAME_OFFSET) { + struct fuse_dirent *dirent = (struct fuse_dirent *) p; + size_t reclen = FUSE_DIRENT_SIZE(dirent); + int err; + if(dirent->namelen > NAME_MAX) { + printk("fuse_readdir: name too long\n"); + ret = -EPROTO; + goto out; + } + if(reclen > nbytes) + break; + + err = filldir(dstbuf, dirent->name, dirent->namelen, + file->f_pos, dirent->ino, dirent->type); + if(err) { + ret = err; + break; + } + p += reclen; + file->f_pos += reclen; + nbytes -= reclen; + ret ++; + } + + out: + kfree(buf); + return ret; +} + + + +static int read_link(struct dentry *dentry, char **bufp) +{ + struct inode *inode = dentry->d_inode; + struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_in in; + struct fuse_out out; + unsigned long page; + + page = __get_free_page(GFP_KERNEL); + if(!page) + return -ENOMEM; + + in.c.opcode = FUSE_READLINK; + in.c.ino = inode->i_ino; + in.argsize = 0; + out.arg = (void *) page; + out.argsize = PAGE_SIZE; + + request_send(fc, &in, &out); + if(out.c.result) { + __free_page(page); + return out.c.result; + } + + *bufp = (char *) page; + (*bufp)[PAGE_SIZE - 1] = 0; return 0; } +static void free_link(char *link) +{ + __free_page((unsigned long) link); +} + +static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + int ret; + char *link; + + ret = read_link(dentry, &link); + if(ret) + return ret; + + ret = vfs_readlink(dentry, buffer, buflen, link); + free_link(link); + return ret; +} + +static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + int ret; + char *link; + + ret = read_link(dentry, &link); + if(ret) + return ret; + + ret = vfs_follow_link(nd, link); + free_link(link); + return ret; +} + static int fuse_open(struct inode *inode, struct file *file) { struct fuse_conn *fc = inode->i_sb->u.generic_sbp; struct fuse_inparam in; struct fuse_outparam out; + struct file *cfile = NULL; - printk(KERN_DEBUG "fuse_open: %li\n", inode->i_ino); - in.opcode = FUSE_OPEN; - in.u.open.ino = inode->i_ino; + in.ino = inode->i_ino; in.u.open.flags = file->f_flags & ~O_EXCL; - request_send(fc, &in, &out, 0); + request_send(fc, &in, &out); + + if(out.result == 0) { + struct inode *inode; + cfile = out.u.open_internal.file; + if(!cfile) { + printk("fuse_open: invalid container file\n"); + return -EPROTO; + } + inode = cfile->f_dentry->d_inode; + if(!S_ISREG(inode->i_mode)) { + printk("fuse_open: container is not a regular file\n"); + fput(cfile); + return -EPROTO; + } - printk(KERN_DEBUG " fuse_open: <%i> %i\n", out.result, out.u.open.fd); + file->private_data = cfile; + } return out.result; } static int fuse_release(struct inode *inode, struct file *file) { - printk(KERN_DEBUG "fuse_release: %li\n", inode->i_ino); + struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct file *cfile = file->private_data; + struct fuse_inparam in; + struct fuse_outparam out; - return 0; + if(cfile) + fput(cfile); + + in.opcode = FUSE_RELEASE; + request_send(fc, &in, &out); + + return out.result; } static struct inode_operations fuse_dir_inode_operations = @@ -81,12 +271,38 @@ static struct file_operations fuse_dir_operations = { release: fuse_release, }; +static struct inode_operations fuse_file_inode_operations = +{ + permission: fuse_permission, + revalidate: fuse_revalidate, +}; + +static struct file_operations fuse_file_operations = { +}; + +static struct inode_operations fuse_symlink_inode_operations = +{ + readlink: fuse_readlink, + follow_link: fuse_follow_link, + revalidate: fuse_revalidate, +}; + void fuse_dir_init(struct inode *inode) { inode->i_op = &fuse_dir_inode_operations; inode->i_fop = &fuse_dir_operations; } +void fuse_file_init(struct inode *inode) +{ + inode->i_op = &fuse_file_inode_operations; + inode->i_fop = &fuse_file_operations; +} + +void fuse_symlink_init(struct inode *inode) +{ + inode->i_op = &fuse_symlink_inode_operations; +} /* * Local Variables: diff --git a/fuse.h b/fuse.h index 32c2609..04faf9d 100644 --- a/fuse.h +++ b/fuse.h @@ -6,6 +6,7 @@ See the file COPYING. */ +#include #define FUSE_MOUNT_VERSION 1 @@ -14,39 +15,92 @@ struct fuse_mount_data { int fd; }; +#define FUSE_ROOT_INO 1 + +struct fuse_attr { + unsigned short mode; + unsigned short nlink; + unsigned short uid; + unsigned short gid; + unsigned short rdev; + unsigned long size; + unsigned long blksize; + unsigned long blocks; + unsigned long atime; + unsigned long mtime; + unsigned long ctime; +}; + enum fuse_opcode { + FUSE_LOOKUP, + FUSE_GETATTR, + FUSE_READLINK, FUSE_OPEN, FUSE_RELEASE, }; -struct fuse_inparam { - enum fuse_opcode opcode; - union { - struct { - unsigned int ino; - int flags; - } open; - } u; +/* Conservative buffer size for the client */ +#define FUSE_MAX_IN 8192 + +struct fuse_in_open { + int flag; }; -struct fuse_outparam { - int result; - union { - struct { - int fd; - } open; - } u; +struct fuse_out_open { + int fd; +}; + +struct fuse_in_lookup { + char name[NAME_MAX + 1]; +}; + +struct fuse_out_lookup { + unsigned long ino; + struct fuse_attr attr; +}; + +struct fuse_out_getattr { + struct fuse_attr attr; }; -struct fuse_param { +struct fuse_out_readlink { + char link[PATH_MAX + 1]; +}; + +struct fuse_in_common { + int unique; + enum fuse_opcode opcode; + unsigned long ino; +}; + +struct fuse_out_common { int unique; int result; - union { - struct fuse_inparam i; - struct fuse_outparam o; - } u; }; +struct fuse_in { + struct fuse_in_common c; + size_t argsize; + void *arg; +}; + +struct fuse_out { + struct fuse_out_common c; + size_t argsize; + void *arg; +}; + +struct fuse_dirent { + unsigned long ino; + unsigned short namelen; + unsigned char type; + char name[NAME_MAX + 1]; +}; + +#define FUSE_NAME_OFFSET ((size_t) ((struct fuse_dirent *) 0)->name) +#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(long) - 1) & ~(sizeof(long) - 1)) +#define FUSE_DIRENT_SIZE(d) \ + FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) /* * Local Variables: diff --git a/fuse_i.h b/fuse_i.h index a7a907f..5f80620 100644 --- a/fuse_i.h +++ b/fuse_i.h @@ -54,11 +54,14 @@ struct fuse_req { /** The request list */ struct list_head list; - /** The size of the parameters */ - size_t size; + /** The request input parameters */ + struct fuse_in *in; - /** The request parameters */ - struct fuse_param param; + /** The request result */ + struct fuse_out *out; + + /** The file returned by open */ + struct file *file; /** The request wait queue */ wait_queue_head_t waitq; @@ -67,6 +70,11 @@ struct fuse_req { int done; }; +struct fuse_out_open_internal { + file *file; +}; + + /** * The proc entry for the client device ("/proc/fs/fuse/dev") */ @@ -82,6 +90,16 @@ extern spinlock_t fuse_lock; */ void fuse_dir_init(struct inode *inode); +/** + * Fill in the file operations + */ +void fuse_file_init(struct inode *inode); + +/** + * Fill in the symlink operations + */ +void fuse_symlink_init(struct inode *inode); + /** * Check if the connection can be released, and if yes, then free the * connection structure @@ -111,10 +129,9 @@ void fuse_fs_cleanup(void); /** * Send a request * - * @valuret: if true then the request can return a positive value */ -void request_send(struct fuse_conn *fc, struct fuse_inparam *in, - struct fuse_outparam *out, int valuret); +void request_send(struct fuse_conn *fc, struct fuse_in *in, + struct fuse_out *out); /* * Local Variables: diff --git a/fusemount.c b/fusemount.c index 3ae2932..574a3fd 100644 --- a/fusemount.c +++ b/fusemount.c @@ -9,18 +9,172 @@ #include "fuse.h" #include +#include #include #include #include #include +#include +#include +#include +#include +#include #include #include #include +#include + +static char *mount_dir; + +const char *basedir = "/tmp/pro"; + +struct node { + char *name; + unsigned long ino; +}; + +static GNode *root; +static GHashTable *nodetab; +static unsigned long inoctr = FUSE_ROOT_INO; + +static GNode *new_node(const char *name, unsigned long ino) +{ + struct node *node = g_new0(struct node, 1); + GNode *gn = g_node_new(node); + + node->name = g_strdup(name); + node->ino = ino; + + return gn; +} + +static unsigned long find_node(unsigned long ino, const char *name) +{ + GNode *cn; + GNode *pn = g_hash_table_lookup(nodetab, (gpointer) ino); + if(pn == NULL) { + fprintf(stderr, "Can't find parent node %li\n", ino); + return 0; + } + + for(cn = pn->children; cn != NULL; cn = cn->next) { + struct node *node = (struct node *) cn->data; + if(strcmp(node->name, name) == 0) + return node->ino; + } + + do inoctr++; + while(!inoctr && g_hash_table_lookup(nodetab, (gpointer) ino) != NULL); + + cn = new_node(name, inoctr); + g_node_insert(pn, -1, cn); + g_hash_table_insert(nodetab, (gpointer) inoctr, cn); + + return inoctr; +} + +static char *real_path(unsigned long ino) +{ + GString *s; + char *ss; + GNode *gn = g_hash_table_lookup(nodetab, (gpointer) ino); + + if(gn == NULL) { + fprintf(stderr, "Can't find node %li\n", ino); + return NULL; + } + + s = g_string_new(""); + for(; gn != NULL; gn = gn->parent) { + g_string_prepend(s, ((struct node *) gn->data)->name); + g_string_prepend_c(s, '/'); + } + g_string_prepend(s, basedir); + ss = s->str; + g_string_free(s, FALSE); + + return ss; +} + +static int get_dir(unsigned long dir) +{ + int dirfd; + struct fuse_dirent dirent; + DIR *dp; + struct dirent *de; + size_t reclen; + char *path; + + path = real_path(dir); + if(path == NULL) + return -ENOENT; + + dp = opendir(path); + g_free(path); + if(dp == NULL) { + perror(path); + return -errno; + } + dirfd = open("/tmp/dirtmp", O_RDWR | O_TRUNC | O_CREAT, 0600); + if(dirfd == -1) { + perror("/tmp/dirtmp"); + exit(1); + } + while((de = readdir(dp)) != NULL) { + unsigned long ino = find_node(dir, de->d_name); + assert(ino != 0); + + dirent.ino = ino; + dirent.namelen = strlen(de->d_name); + assert(dirent.namelen <= NAME_MAX); + strcpy(dirent.name, de->d_name); + dirent.type = de->d_type; + + reclen = FUSE_DIRENT_SIZE(&dirent); + write(dirfd, &dirent, reclen); + } + closedir(dp); + + return dirfd; +} + +static int get_attributes(unsigned long ino, struct fuse_attr *attr) +{ + char *path; + struct stat buf; + int res; + + path = real_path(ino); + if(path == NULL) + return -ENOENT; + + res = stat(path, &buf); + g_free(path); + if(res == -1) + return -errno; + + attr->mode = buf.st_mode; + attr->nlink = buf.st_nlink; + attr->uid = buf.st_uid; + attr->gid = buf.st_gid; + attr->rdev = buf.st_rdev; + attr->size = buf.st_size; + attr->blksize = buf.st_blksize; + attr->blocks = buf.st_blocks; + attr->atime = buf.st_atime; + attr->mtime = buf.st_mtime; + attr->ctime = buf.st_ctime; + + return 0; +} static void loop(int devfd) { int res; struct fuse_param param; + struct fuse_outparam out; + struct fuse_inparam in; + int dirfd; while(1) { res = read(devfd, ¶m, sizeof(param)); @@ -28,15 +182,53 @@ static void loop(int devfd) perror("read"); exit(1); } - + printf("unique: %i, opcode: %i\n", param.unique, param.u.i.opcode); - param.u.o.result = 0; - + + dirfd = -1; + in = param.u.i; + switch(in.opcode) { + case FUSE_LOOKUP: + out.u.lookup.ino = find_node(in.ino, in.u.lookup.name); + if(out.u.lookup.ino == 0) + out.result = -ENOENT; + else + out.result = get_attributes(out.u.lookup.ino, + &out.u.lookup.attr); + break; + + case FUSE_GETATTR: + out.result = get_attributes(in.ino, &out.u.getattr.attr); + break; + + case FUSE_OPEN: + dirfd = get_dir(in.ino); + if(dirfd >= 0) { + out.u.open.fd = dirfd; + out.result = 0; + } + else + out.result = dirfd; + break; + + case FUSE_RELEASE: + out.result = 0; + break; + + default: + out.result = -EOPNOTSUPP; + } + param.u.o = out; + res = write(devfd, ¶m, sizeof(param)); if(res == -1) { perror("write"); exit(1); } + if(dirfd != -1) { + close(dirfd); + unlink("/tmp/dirtmp"); + } } } @@ -81,10 +273,98 @@ static int mount_fuse(const char *dev, const char *dir, int devfd) return 0; } +int unmount_fuse(const char *dir) +{ + int res; + FILE *fdold, *fdnew; + struct mntent *entp; + + res = umount(dir); + + if(res == -1) { + fprintf(stderr, "umount failed: %s\n", strerror(errno)); + return -1; + } + + fdold = setmntent("/etc/mtab", "r"); + if(fdold == NULL) { + fprintf(stderr, "setmntent(\"/etc/mtab\") failed: %s\n", + strerror(errno)); + return -1; + } + + fdnew = setmntent("/etc/mtab~", "w"); + if(fdnew == NULL) { + fprintf(stderr, "setmntent(\"/etc/mtab~\") failed: %s\n", + strerror(errno)); + return -1; + } + + do { + entp = getmntent(fdold); + if(entp != NULL) { + if(strcmp(entp->mnt_dir, dir) != 0) { + res = addmntent(fdnew, entp); + if(res != 0) { + fprintf(stderr, "addmntent() failed: %s\n", + strerror(errno)); + } + } + } + } while(entp != NULL); + + endmntent(fdold); + endmntent(fdnew); + + res = rename("/etc/mtab~", "/etc/mtab"); + if(res == -1) { + fprintf(stderr, "rename(\"/etc/mtab~\", \"/etc/mtab\") failed: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + +void cleanup() +{ + unmount_fuse(mount_dir); +} + + +void exit_handler() +{ + exit(0); +} + +void set_signal_handlers() +{ + struct sigaction sa; + + sa.sa_handler = exit_handler; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; + + if (sigaction(SIGHUP, &sa, NULL) == -1 || + sigaction(SIGINT, &sa, NULL) == -1 || + sigaction(SIGTERM, &sa, NULL) == -1) { + + perror("Cannot set exit signal handlers"); + exit(1); + } + + sa.sa_handler = SIG_IGN; + + if(sigaction(SIGPIPE, &sa, NULL) == -1) { + perror("Cannot set ignored signals"); + exit(1); + } +} + + int main(int argc, char *argv[]) { const char *dev; - const char *dir; int devfd; if(argc < 3) { @@ -93,7 +373,7 @@ int main(int argc, char *argv[]) } dev = argv[1]; - dir = argv[2]; + mount_dir = argv[2]; devfd = open(dev, O_RDWR); if(devfd == -1) { @@ -101,9 +381,19 @@ int main(int argc, char *argv[]) exit(1); } - mount_fuse(dev, dir, devfd); + mount_fuse(dev, mount_dir, devfd); + + set_signal_handlers(); + atexit(cleanup); + + root = new_node("/", FUSE_ROOT_INO); + nodetab = g_hash_table_new(NULL, NULL); + g_hash_table_insert(nodetab, (gpointer) FUSE_ROOT_INO, root); loop(devfd); return 0; } + + + diff --git a/inode.c b/inode.c index 590a80d..5c2b743 100644 --- a/inode.c +++ b/inode.c @@ -17,17 +17,13 @@ static void fuse_read_inode(struct inode *inode) { - printk(KERN_DEBUG "fuse_read_inode: %li\n", inode->i_ino); - - + /* No op */ } static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = sb->u.generic_sbp; - printk(KERN_DEBUG "fuse_put_super[%i]\n", fc->id); - spin_lock(&fuse_lock); fc->sb = NULL; fuse_release_conn(fc); @@ -47,8 +43,6 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d) struct file *file; struct inode *ino; - printk(KERN_DEBUG "fuse_read_super\n"); - if(d == NULL) { printk("fuse_read_super: Bad mount data\n"); return NULL; @@ -116,8 +110,6 @@ static struct super_block *fuse_read_super(struct super_block *sb, return NULL; } - printk(KERN_DEBUG "root inode: %ld/%d\n", root->i_ino, root->i_dev); - spin_lock(&fuse_lock); fc = get_conn(data); if(fc == NULL) diff --git a/util.c b/util.c index c20ab64..57b1a90 100644 --- a/util.c +++ b/util.c @@ -20,7 +20,6 @@ spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED; void fuse_release_conn(struct fuse_conn *fc) { if(fc->sb == NULL && fc->file == NULL) { - printk(KERN_DEBUG "fuse: release connection: %i\n", fc->id); kfree(fc); } }