diff options
-rw-r--r-- | NOTES | 10 | ||||
-rw-r--r-- | logger/Makefile | 0 | ||||
-rw-r--r-- | logger/src/autodep/logfs/logger_fusefs.py | 98 | ||||
-rw-r--r-- | logger/src/autodep/logfs/logger_hooklib.py | 21 | ||||
-rw-r--r-- | logger/src/hook_fusefs/Makefile | 7 | ||||
-rwxr-xr-x | logger/src/hook_fusefs/hookfs | bin | 0 -> 30961 bytes | |||
-rw-r--r-- | logger/src/hook_fusefs/hookfs.c | 959 |
7 files changed, 1095 insertions, 0 deletions
@@ -0,0 +1,10 @@ +This is few notes mainly for myself. + +1. Format of log record: + <time of event sec since 1970> + <event type: stat, open, read, write> + <name of file> + <returned value> + <errno> + <parent processes>(will be pid) + <allowed/denied>
\ No newline at end of file diff --git a/logger/Makefile b/logger/Makefile new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/logger/Makefile diff --git a/logger/src/autodep/logfs/logger_fusefs.py b/logger/src/autodep/logfs/logger_fusefs.py new file mode 100644 index 0000000..fbd8100 --- /dev/null +++ b/logger/src/autodep/logfs/logger_fusefs.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python2 + +import subprocess +import time +import os +import sys + + +class logger: + socketname='' + readytolaunch=False + mountlist=["/dev/","/proc/","/sys/"] +# rootmountpath="/mnt/logfs_root_"+str(time.time())+"/" + rootmountpath="/mnt/logfs_roott_"+"/" + + def __init__(self, socketname): + self.socketname=socketname + + if os.geteuid() != 0: + print "only root user can use FUSE approach for logging" + exit(1) + + print "mounting root filesystem into %s. Please, DON'T DELETE THIS FOLDER!!" % self.rootmountpath + + for mount in self.mountlist: + try: + os.makedirs(self.rootmountpath+mount) + except OSError,e: + if e.errno==17: # 17 is a "file exists" errno + pass # all is ok + else: + print "failed to make mount directory %s: %s" % (self.rootmountpath+mount,e) + print "this error is fatal" + exit(1) + + ret=subprocess.call(['mount','-o','bind','/',self.rootmountpath]) + if ret!=0: + print "failed to bind root filesystem to %s. Check messages above"%self.rootmountpath + exit(1) + + #env["LOG_SOCKET"]=self.socketname + os.environ["LOG_SOCKET"]=self.socketname + + + ret=subprocess.call(['/home/bay/gsoc/logger/src/hook_fusefs/hookfs',self.rootmountpath, + '-o','allow_other,suid']) + if ret!=0: + print "failed to launch FUSE logger. Check messages above" + + for mount in self.mountlist: + ret=subprocess.call(['mount','-o','bind',mount,self.rootmountpath+mount]) + if ret!=0: + print "failed to mount bind %s directory to %s. Check messages above" % ( + mount,self.rootmountpath) + exit(1) + self.readytolaunch=True; + + def __del__(self): + #we will delete the object manually after execprog + pass + + def execprog(self,prog_name,arguments): + pid=os.fork() + if pid==0: + try: + cwd=os.getcwd() + os.chroot(self.rootmountpath) + os.chdir(cwd) + + env=os.environ.copy() + + os.execvpe(prog_name, arguments, env) + sys.exit(1) + except OSError, e: + print "Error while chrooting and starting a program: %s" % e + sys.exit(1) + + else: + exitcode=os.wait()[1]; + try: + # unmount all manually + self.mountlist.reverse() + for mount in self.mountlist: + ret=subprocess.call(['umount',self.rootmountpath+mount]) + if ret!=0: + print "failed to umount bind %s directory. Check messages above" % ( self.rootmountpath+mount) + ret=subprocess.call(['fusermount','-u',self.rootmountpath]); + if ret!=0: + print "Error while unmounting fuse filesystem. Check messages above" + ret=subprocess.call(['umount',self.rootmountpath]); + if ret!=0: + print "Error while unmounting %s Check messages above" % (self.rootmountpath) + + except OSError, e: + print "Error while unmounting fuse filesystem: %s" % e + sys.exit(1) + + sys.exit(int(exitcode/256)) diff --git a/logger/src/autodep/logfs/logger_hooklib.py b/logger/src/autodep/logfs/logger_hooklib.py new file mode 100644 index 0000000..cf677f4 --- /dev/null +++ b/logger/src/autodep/logfs/logger_hooklib.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python2 + +import os + +class logger: + socketname='' + hooklibpath='/home/bay/gsoc/logger/src/hook_lib/file_hook.so' # TODO: change + + def __init__(self,socketname): + self.socketname=socketname + + def execprog(self,prog_name,arguments): + try: + env=os.environ.copy() + env["LD_PRELOAD"]=self.hooklibpath + env["LOG_SOCKET"]=self.socketname + + os.execvpe(prog_name, arguments, env) + except OSError, e: + print "Failed to launch the programm: %s" % e + sys.exit(1) diff --git a/logger/src/hook_fusefs/Makefile b/logger/src/hook_fusefs/Makefile new file mode 100644 index 0000000..9b79a5c --- /dev/null +++ b/logger/src/hook_fusefs/Makefile @@ -0,0 +1,7 @@ +all: hookfs + +hookfs: hookfs.c + $(CC) -std=c99 -Wall `pkg-config fuse --cflags --libs` -lulockmgr $(CFLAGS) $(LDFLAGS) hookfs.c -o hookfs + +clean: + rm -f hookfs diff --git a/logger/src/hook_fusefs/hookfs b/logger/src/hook_fusefs/hookfs Binary files differnew file mode 100755 index 0000000..b27efc2 --- /dev/null +++ b/logger/src/hook_fusefs/hookfs diff --git a/logger/src/hook_fusefs/hookfs.c b/logger/src/hook_fusefs/hookfs.c new file mode 100644 index 0000000..2047320 --- /dev/null +++ b/logger/src/hook_fusefs/hookfs.c @@ -0,0 +1,959 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org> + Copyright (C) 2011 Alexander Bersenev <bay@hackerdom.ru> + + This program can be distributed under the terms of the GNU GPL. +*/ + +#define PACKAGE_NAME "hookfs" +#define PACKAGE_VERSION "0.1" + +#define FUSE_USE_VERSION 26 + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE + +#include <fuse.h> +#include <ulockmgr.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <sys/time.h> +#include <stddef.h> +#include <assert.h> +#include <sys/mman.h> +#ifdef HAVE_SETXATTR +#include <sys/xattr.h> +#endif +#include <sys/socket.h> +#include <sys/un.h> + + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define MAXSOCKETPATHLEN 108 + +struct hookfs_config { + int argv_debug; +}; + + +int mountpoint_fd = -1; +char *mountpoint = NULL; +FILE * log_file = NULL; +int log_socket=-1; +struct hookfs_config config; + +/* + * Prints a string escaping spaces and '\' + * Does not check input variables +*/ +void __print_escaped(FILE *fh ,const char *s){ + for(;(*s)!=0; s++) { + if(*s==' ') + fprintf(fh,"\\ "); + else if(*s==',') + fprintf(fh,"\\,"); + else if(*s=='\r') + fprintf(fh,"\\r"); + else if(*s=='\n') + fprintf(fh,"\\n"); + else if(*s=='\\') + fprintf(fh,"\\\\"); + else + fprintf(fh,"%c", *s); + } +} + +/* + * Format of log string: time event file flags result parents +*/ +void log_event(const char *event_type, const char *filename, int result, int err, pid_t pid) { + + fprintf(log_file,"%lld ",(unsigned long long)time(NULL)); + + __print_escaped(log_file, event_type); + fprintf(log_file," "); + __print_escaped(log_file, filename); + fprintf(log_file," %d %d %d\n", result, err, pid); + fflush(log_file); +} + + +static int post_getattr(const char *path, int res) { + struct fuse_context * context = fuse_get_context(); + log_event("stat",path,res,errno,context->pid); + return 0; +} + +static int post_read(const char *path, int res) { + struct fuse_context * context = fuse_get_context(); + log_event("read",path,res,errno,context->pid); + return 0; +} + +static int post_write(const char *path, int res) { + struct fuse_context * context = fuse_get_context(); + log_event("write",path,res,errno,context->pid); + return 0; +} + +static int post_open(const char *path, int fd) { + struct fuse_context * context = fuse_get_context(); + log_event("open",path,fd,errno,context->pid); + return 0; +} + +static int post_truncate(const char *path, int res) { + struct fuse_context * context = fuse_get_context(); + log_event("write",path,res,errno,context->pid); + return 0; +} + +struct hook_operations { + int (*post_read)(const char *path, int res); + int (*post_write)(const char *path, int res); + int (*post_open)(const char *path, int fd); + //int (*post_rename)(const char *from, const char *to, int res); + int (*post_getattr)(const char *path, int res); + int (*post_truncate)(const char *path, int res); +}; + +static struct hook_operations hooks = { + .post_read = post_read, + .post_write = post_write, + .post_open = post_open, + //.post_unlink = post_unlink, + //.post_rename = post_rename, + .post_getattr = post_getattr, + .post_truncate = post_truncate, +}; + +#define NOTIFY(function, ...) \ + if (hooks.function) { \ + hooks.function(__VA_ARGS__); \ + } + +static char * malloc_relative_path(const char *path) { + int len = strlen(path); + char * buf = malloc(1 + len + 1); + if (! buf) { + return NULL; + } + + strcpy(buf, "."); + strcpy(buf + 1, path); + return buf; +} + +static void give_to_creator_fd(int fd) { + struct fuse_context * context = fuse_get_context(); + fchown(fd, context->uid, context->gid); +} + +static void give_to_creator_path(const char *path) { + struct fuse_context * context = fuse_get_context(); + lchown(path, context->uid, context->gid); +} + +static int hookfs_getattr(const char *path, struct stat *stbuf) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = lstat(rel_path, stbuf); + free(rel_path); + + NOTIFY(post_getattr, path, res); + + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_fgetattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + + res = fstat(fi->fh, stbuf); + + NOTIFY(post_getattr, path, res); + + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_access(const char *path, int mask) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = access(rel_path, mask); + free(rel_path); + + NOTIFY(post_getattr, path, res); + + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_readlink(const char *path, char *buf, size_t size) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = readlink(rel_path, buf, size - 1); + free(rel_path); + + if (res == -1) + return -errno; + + buf[res] = '\0'; + return 0; +} + +struct hookfs_dirp { + DIR *dp; + struct dirent *entry; + off_t offset; +}; + +static int hookfs_opendir(const char *path, struct fuse_file_info *fi) +{ + struct hookfs_dirp *d = malloc(sizeof(struct hookfs_dirp)); + if (d == NULL) + return -ENOMEM; + + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + d->dp = opendir(rel_path); + free(rel_path); + if (d->dp == NULL) { + free(d); + return -errno; + } + d->offset = 0; + d->entry = NULL; + + fi->fh = (unsigned long) d; + return 0; +} + +static inline struct hookfs_dirp *get_dirp(struct fuse_file_info *fi) +{ + return (struct hookfs_dirp *) (uintptr_t) fi->fh; +} + +static int hookfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + struct hookfs_dirp *d = get_dirp(fi); + + (void) path; + if (offset != d->offset) { + seekdir(d->dp, offset); + d->entry = NULL; + d->offset = offset; + } + while (1) { + struct stat st; + off_t nextoff; + + if (!d->entry) { + d->entry = readdir(d->dp); + if (!d->entry) + break; + } + + memset(&st, 0, sizeof(st)); + st.st_ino = d->entry->d_ino; + st.st_mode = d->entry->d_type << 12; + nextoff = telldir(d->dp); + if (filler(buf, d->entry->d_name, &st, nextoff)) + break; + + d->entry = NULL; + d->offset = nextoff; + } + + return 0; +} + +static int hookfs_releasedir(const char *path, struct fuse_file_info *fi) +{ + struct hookfs_dirp *d = get_dirp(fi); + (void) path; + closedir(d->dp); + free(d); + return 0; +} + +static int hookfs_mknod(const char *path, mode_t mode, dev_t rdev) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res; + if (S_ISFIFO(mode)) + res = mkfifo(rel_path, mode); + else + res = mknod(rel_path, mode, rdev); + if (res == 0) + give_to_creator_path(rel_path); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_mkdir(const char *path, mode_t mode) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = mkdir(rel_path, mode); + if (res == 0) + give_to_creator_path(rel_path); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_unlink(const char *path) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = unlink(rel_path); + free(rel_path); + //NOTIFY(post_unlink, path, res); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_rmdir(const char *path) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = rmdir(rel_path); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_symlink(const char *from, const char *to) +{ + char * rel_to = malloc_relative_path(to); + if (! rel_to) { + return -errno; + } + + int res = symlink(from, rel_to); + if (res == 0) + give_to_creator_path(rel_to); + free(rel_to); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_rename(const char *from, const char *to) +{ + char * rel_from = malloc_relative_path(from); + if (! rel_from) { + return -errno; + } + char * rel_to = malloc_relative_path(to); + if (! rel_to) { + free(rel_from); + return -errno; + } + + int res = rename(rel_from, rel_to); + //NOTIFY(post_rename, from, to, res); + free(rel_from); + free(rel_to); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_link(const char *from, const char *to) +{ + char * rel_from = malloc_relative_path(from); + if (! rel_from) { + return -errno; + } + char * rel_to = malloc_relative_path(to); + if (! rel_to) { + free(rel_from); + return -errno; + } + + int res = link(rel_from, rel_to); + free(rel_from); + if (res == 0) + give_to_creator_path(rel_to); + free(rel_to); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_chmod(const char *path, mode_t mode) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = chmod(rel_path, mode); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_chown(const char *path, uid_t uid, gid_t gid) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = lchown(rel_path, uid, gid); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_truncate(const char *path, off_t size) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = truncate(rel_path, size); + free(rel_path); + + NOTIFY(post_truncate, path, res); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_ftruncate(const char *path, off_t size, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + + res = ftruncate(fi->fh, size); + NOTIFY(post_truncate, path, res); + + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_utimens(const char *path, const struct timespec ts[2]) +{ + int res; + struct timeval tv[2]; + char * rel_path = NULL; + + tv[0].tv_sec = ts[0].tv_sec; + tv[0].tv_usec = ts[0].tv_nsec / 1000; + tv[1].tv_sec = ts[1].tv_sec; + tv[1].tv_usec = ts[1].tv_nsec / 1000; + + rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + res = utimes(rel_path, tv); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int writing_flags(mode_t mode) { + if (((mode & O_WRONLY) == O_WRONLY) + || ((mode & O_RDWR) == O_RDWR) + || ((mode & O_CREAT) == O_CREAT)) { + return 1; + } + return 0; +} + +static int open_safely(const char *rel_path, int flags, mode_t mode) { + int fd = -1; + if (writing_flags(flags)) { + fd = open(rel_path, flags | O_CREAT | O_EXCL, mode); + if (fd == -1) { + /* Try again with original flags */ + fd = open(rel_path, flags, mode); + } else { + give_to_creator_fd(fd); + } + } else { + fd = open(rel_path, flags, mode); + } + return fd; +} + +static int hookfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int fd = open_safely(rel_path, fi->flags, mode); + free(rel_path); + NOTIFY(post_open, path, fd); + if (fd == -1) + return -errno; + + fi->fh = fd; + return 0; +} + +static int hookfs_open(const char *path, struct fuse_file_info *fi) +{ + int fd; + char * rel_path = NULL; + + rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + fd = open_safely(rel_path, fi->flags, 0000); + free(rel_path); + NOTIFY(post_open, path, fd); + + if (fd == -1) + return -errno; + + fi->fh = fd; + return 0; +} + +static int hookfs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + res = pread(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; + + NOTIFY(post_read, path, res); + return res; +} + +static int hookfs_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + int res; + + (void) path; + res = pwrite(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; + + NOTIFY(post_write, path, res); + + return res; +} + +static int hookfs_statfs(const char *path, struct statvfs *stbuf) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = statvfs(rel_path, stbuf); + free(rel_path); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_flush(const char *path, struct fuse_file_info *fi) +{ + int res; + + (void) path; + /* This is called from every close on an open file, so call the + close on the underlying filesystem. But since flush may be + called multiple times for an open file, this must not really + close the file. This is important if used on a network + filesystem like NFS which flush the data/metadata on close() */ + res = close(dup(fi->fh)); + if (res == -1) + return -errno; + + return 0; +} + +static int hookfs_release(const char *path, struct fuse_file_info *fi) +{ + (void) path; + + //int res = + close(fi->fh); + + return 0; +} + +static int hookfs_fsync(const char *path, int isdatasync, + struct fuse_file_info *fi) +{ + int res; + (void) path; + +#ifndef HAVE_FDATASYNC + (void) isdatasync; +#else + if (isdatasync) + res = fdatasync(fi->fh); + else +#endif + res = fsync(fi->fh); + if (res == -1) + return -errno; + + return 0; +} + +#ifdef HAVE_SETXATTR +/* xattr operations are optional and can safely be left unimplemented */ +static int hookfs_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = lsetxattr(rel_path, name, value, size, flags); + free(rel_path); + if (res == -1) + return -errno; + return 0; +} + +static int hookfs_getxattr(const char *path, const char *name, char *value, + size_t size) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = lgetxattr(rel_path, name, value, size); + free(rel_path); + if (res == -1) + return -errno; + return res; +} + +static int hookfs_listxattr(const char *path, char *list, size_t size) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = llistxattr(rel_path, list, size); + free(rel_path); + if (res == -1) + return -errno; + return res; +} + +static int hookfs_removexattr(const char *path, const char *name) +{ + char * rel_path = malloc_relative_path(path); + if (! rel_path) { + return -errno; + } + + int res = lremovexattr(rel_path, name); + free(rel_path); + if (res == -1) + return -errno; + return 0; +} +#endif /* HAVE_SETXATTR */ + +static int hookfs_lock(const char *path, struct fuse_file_info *fi, int cmd, + struct flock *lock) +{ + (void) path; + + return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, + sizeof(fi->lock_owner)); +} + +static void * hookfs_init(struct fuse_conn_info *conn) { + int res = fchdir(mountpoint_fd); + assert(! res); + + close(mountpoint_fd); + mountpoint_fd = -1; + + return NULL; +} + +static void hookfs_destroy() { + fflush(log_file); +} + +static struct fuse_operations hookfs_oper = { + .getattr = hookfs_getattr, + .fgetattr = hookfs_fgetattr, + .access = hookfs_access, + .readlink = hookfs_readlink, + .opendir = hookfs_opendir, + .readdir = hookfs_readdir, + .releasedir = hookfs_releasedir, + .mknod = hookfs_mknod, + .mkdir = hookfs_mkdir, + .symlink = hookfs_symlink, + .unlink = hookfs_unlink, + .rmdir = hookfs_rmdir, + .rename = hookfs_rename, + .link = hookfs_link, + .chmod = hookfs_chmod, + .chown = hookfs_chown, + .truncate = hookfs_truncate, + .ftruncate = hookfs_ftruncate, + .utimens = hookfs_utimens, + .create = hookfs_create, + .open = hookfs_open, + .read = hookfs_read, + .write = hookfs_write, + .statfs = hookfs_statfs, + .flush = hookfs_flush, + .release = hookfs_release, + .fsync = hookfs_fsync, +#ifdef HAVE_SETXATTR + .setxattr = hookfs_setxattr, + .getxattr = hookfs_getxattr, + .listxattr = hookfs_listxattr, + .removexattr = hookfs_removexattr, +#endif + .lock = hookfs_lock, + .init = hookfs_init, + .destroy = hookfs_destroy, + + .flag_nullpath_ok = 1, +}; + +static int try_chdir_to_mountpoint(int argc, char *argv[]) { + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + int err = -1; + + err = fuse_parse_cmdline(&args, &mountpoint, NULL, NULL); + fuse_opt_free_args(&args); + if (err || ! mountpoint) { + fprintf(stderr, "Mountpoint missing\n"); + return 0; + } + + mountpoint_fd = open(mountpoint, O_DIRECTORY|O_RDONLY); + if (err || (mountpoint_fd == -1)) { + fprintf(stderr, "Could not open \"%s\" as a directory.\n", mountpoint); + return 0; + } + + fprintf(stderr, "Switching workdir to mountpoint \"%s\"...\n", mountpoint); + return 1; +} + +void default_config(struct hookfs_config * config) { + config->argv_debug = 0; +} + +enum { + KEY_HELP, + KEY_VERSION, +}; + +#define HOOKFS_OPT(t, p, v) { t, offsetof(struct hookfs_config, p), v } + +static struct fuse_opt hookfs_opts[] = { + HOOKFS_OPT("--argv-debug", argv_debug, 1), + + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_END +}; + +void debug_argv(int argc, char *argv[], const struct hookfs_config * config) { + if (! config->argv_debug) { + return; + } + + for (int i = 0; i < argc; i++) { + fprintf(stderr, "[%d] '%s'\n", i, argv[i]); + } +} + +static int hookfs_handle_opt(void *data, const char *arg, int key, struct fuse_args *outargs) { + struct hookfs_config * config = (struct hookfs_config *)data; + + switch (key) { + case KEY_HELP: + fuse_opt_add_arg(outargs, "-ho"); + debug_argv(outargs->argc, outargs->argv, config); + + fprintf(stderr, + "usage: %s mountpoint [options]\n" + "\n" + "%s options:\n" + " --argv-debug enable argv debugging\n" + " --flush flush log after each write\n" + "\n" + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + " -V --version print version\n" + "\n" + , outargs->argv[0], PACKAGE_NAME); + fuse_main(outargs->argc, outargs->argv, &hookfs_oper, NULL); + exit(1); + + case KEY_VERSION: + fuse_opt_add_arg(outargs, "--version"); + debug_argv(outargs->argc, outargs->argv, config); + + fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); + fuse_main(outargs->argc, outargs->argv, &hookfs_oper, NULL); + exit(0); + } + return 1; +} + +int main(int argc, char *argv[]) { + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + + default_config(&config); + + fuse_opt_parse(&args, &config, hookfs_opts, hookfs_handle_opt); + + fuse_opt_add_arg(&args, "-o" "nonempty"); /* to allow shadowing */ + fuse_opt_add_arg(&args, "-o" "use_ino"); /* to keep hardlinks working */ + fuse_opt_add_arg(&args, "-o" "default_permissions"); /* to enable access checks */ + + debug_argv(args.argc, args.argv, &config); + + char *log_socket_name=getenv("LOG_SOCKET"); + if(log_socket_name==NULL) { + fprintf(stderr,"Using stderr as output for logs " + "because the LOG_SOCKET environment variable isn't defined.\n"); + log_file=stderr; + } else { + if(strlen(log_socket_name)>=MAXSOCKETPATHLEN) { + fprintf(stderr,"Unable to create a unix-socket %s: socket name is too long,exiting\n", log_socket_name); + return 1; + } + + log_socket=socket(AF_UNIX, SOCK_STREAM, 0); + if(log_socket==-1) { + fprintf(stderr,"Unable to create a unix-socket %s: %s\n", log_socket_name, strerror(errno)); + return 1; + } + + struct sockaddr_un serveraddr; + memset(&serveraddr, 0, sizeof(serveraddr)); + serveraddr.sun_family = AF_UNIX; + strcpy(serveraddr.sun_path, log_socket_name); + + int ret=connect(log_socket, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr)); + if(ret==-1) { + fprintf(stderr,"Unable to connect a unix-socket: %s\n", strerror(errno)); + return 1; + } + + log_file=fdopen(log_socket,"r+"); + + if(log_file==NULL) { + fprintf(stderr,"Unable to open a socket for a steam writing: %s\n", strerror(errno)); + exit(1); + } + } + + if (! try_chdir_to_mountpoint(args.argc, args.argv)) { + return 1; + } + + umask(0); + int res = fuse_main(args.argc, args.argv, &hookfs_oper, NULL); + fflush(log_file); + fclose(log_file); + return res; +} |