@@ -19,16 +19,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #define FUSE_USE_VERSION 26 -#include #include #include #include #include -#include #include #include #include #include #include @@ -46,17 +44,18 @@ #define APPFS_CACHEDIR "/var/cache/appfs" #endif /* Debugging macros */ #ifdef DEBUG -int appfs_debug_fd = STDERR_FILENO; +FILE *appfs_debug_fd = NULL; #define APPFS_DEBUG(x...) { \ char buf[8192]; \ int bufoff = 0; \ - if (appfs_debug_fd == -1) { \ - appfs_debug_fd = open("/tmp/appfsd.log", O_WRONLY | O_APPEND | O_CREAT, 0600); \ + if (appfs_debug_fd == NULL) { \ + appfs_debug_fd = fopen("/tmp/appfsd.log", "a"); \ }; \ + if (appfs_debug_fd == NULL) { appfs_debug_fd = stderr; } \ bufoff = snprintf(buf, sizeof(buf), "[debug] [t=%llx] %s:%i:%s: ", (unsigned long long) pthread_self(), __FILE__, __LINE__, __func__); \ if (bufoff < sizeof(buf)) { \ bufoff += snprintf(buf + bufoff, sizeof(buf) - bufoff, x); \ }; \ if (bufoff < sizeof(buf)) { \ @@ -63,14 +62,17 @@ bufoff += snprintf(buf + bufoff, sizeof(buf) - bufoff, "\n");\ } \ if (bufoff > sizeof(buf)) { \ bufoff = sizeof(buf); \ }; \ - write(appfs_debug_fd, buf, bufoff); \ + fprintf(appfs_debug_fd, "%.*s", bufoff, buf); \ + fflush(appfs_debug_fd); \ } +#define APPFS_ERROR(x...) APPFS_DEBUG(x) #else #define APPFS_DEBUG(x...) /**/ +#define APPFS_ERROR(x...) fprintf(stderr, x); fprintf(stderr, "\n"); #endif /* * SHA1 Tcl Package initializer, from sha1.o */ @@ -95,11 +97,11 @@ */ pthread_mutex_t appfs_path_info_cache_mutex = PTHREAD_MUTEX_INITIALIZER; int appfs_path_info_cache_size = 8209; struct appfs_pathinfo *appfs_path_info_cache = NULL; -#ifndef TCL_THREADS +#if !defined(TCL_THREADS) || TCL_THREADS != 1 /* * Handle unthreaded Tcl */ pthread_mutex_t appfs_tcl_big_global_lock = PTHREAD_MUTEX_INITIALIZER; #define appfs_call_libtcl_enter pthread_mutex_lock(&appfs_tcl_big_global_lock); @@ -172,11 +174,11 @@ appfs_call_libtcl( interp = Tcl_CreateInterp(); ) if (interp == NULL) { - fprintf(stderr, "Unable to create Tcl Interpreter. Aborting.\n"); + APPFS_ERROR("Unable to create Tcl Interpreter. Aborting."); if (error_string) { *error_string = strdup("Unable to create Tcl interpreter."); } @@ -187,13 +189,13 @@ appfs_call_libtcl( tcl_ret = Tcl_Init(interp); ) if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl. Aborting.\n"); + APPFS_ERROR("Unable to initialize Tcl. Aborting."); appfs_call_libtcl( - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); + APPFS_ERROR("Tcl Error is: %s", Tcl_GetStringResult(interp)); ) if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); @@ -211,13 +213,13 @@ appfs_call_libtcl( tcl_ret = Tcl_Eval(interp, "package ifneeded sha1 1.0 [list load {} sha1]"); ) if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl SHA1. Aborting.\n"); + APPFS_ERROR("Unable to initialize Tcl SHA1. Aborting."); appfs_call_libtcl( - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); + APPFS_ERROR("Tcl Error is: %s", Tcl_GetStringResult(interp)); ) if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); @@ -235,13 +237,13 @@ appfs_call_libtcl( tcl_ret = Tcl_Eval(interp, "package ifneeded appfsd 1.0 [list load {} appfsd]"); ) if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl AppFS Package. Aborting.\n"); + APPFS_ERROR("Unable to initialize Tcl AppFS Package. Aborting."); appfs_call_libtcl( - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); + APPFS_ERROR("Tcl Error is: %s", Tcl_GetStringResult(interp)); ) if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); @@ -264,13 +266,13 @@ tcl_ret = Tcl_Eval(interp, "" #include "pki.tcl.h" ""); appfs_call_libtcl_exit if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl PKI. Aborting.\n"); + APPFS_ERROR("Unable to initialize Tcl PKI. Aborting."); appfs_call_libtcl( - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); + APPFS_ERROR("Tcl Error is: %s", Tcl_GetStringResult(interp)); ) if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); @@ -295,13 +297,13 @@ tcl_ret = Tcl_Eval(interp, "" #include "appfsd.tcl.h" ""); appfs_call_libtcl_exit if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl AppFS script. Aborting.\n"); + APPFS_ERROR("Unable to initialize Tcl AppFS script. Aborting."); appfs_call_libtcl( - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); + APPFS_ERROR("Tcl Error is: %s", Tcl_GetStringResult(interp)); ) if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); @@ -322,11 +324,11 @@ */ appfs_call_libtcl( tcl_setvar_ret = Tcl_SetVar(interp, "::appfs::cachedir", appfs_cachedir, TCL_GLOBAL_ONLY); ) if (tcl_setvar_ret == NULL) { - fprintf(stderr, "Unable to set cache directory. This should never fail.\n"); + APPFS_ERROR("Unable to set cache directory. This should never fail."); if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); ) @@ -347,13 +349,13 @@ */ appfs_call_libtcl( tcl_ret = Tcl_Eval(interp, "::appfs::init"); ) if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl AppFS script (::appfs::init). Aborting.\n"); + APPFS_ERROR("Unable to initialize Tcl AppFS script (::appfs::init). Aborting."); appfs_call_libtcl( - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); + APPFS_ERROR("Tcl Error is: %s", Tcl_GetStringResult(interp)); ) if (error_string) { appfs_call_libtcl( *error_string = strdup(Tcl_GetStringResult(interp)); @@ -564,10 +566,15 @@ static void appfs_simulate_user_fs_leave(void) { setfsuid(0); setfsgid(0); } +#ifdef APPFS_NO_GETPWUID +static char *appfs_get_homedir(uid_t fsuid) { + return(NULL); +} +#else /* * Look up the home directory for a given UID * Returns a C string containing the user's home directory or NULL if * the user's home directory does not exist or is not correctly * configured @@ -616,10 +623,11 @@ retval = strdup(result->pw_dir); return(retval); } +#endif /* * Generate an inode for a given path. The inode should be computed in such * a way that it is unlikely to be duplicated and remains the same for a given * file @@ -1519,11 +1527,22 @@ APPFS_DEBUG("Enter (path = %s, buf, size = %lli, offset = %lli, fd = %lli)", path, (long long) size, (long long) offset, (long long) fi->fh); retval = 0; while (size != 0) { +#ifdef APPFS_NO_PREAD /* XXX:TODO: Write a wrapper function */ + off_t seek_ret; + + seek_ret = lseek(fi->fh, offset, SEEK_SET); + if (seek_ret == offset) { + read_ret = read(fi->fh, buf, size); + } else { + read_ret = -1; + } +#else read_ret = pread(fi->fh, buf, size, offset); +#endif if (read_ret < 0) { APPFS_DEBUG("error: read failed"); return(errno * -1); @@ -1565,11 +1584,27 @@ appfs_get_path_info_cache_rm(path, appfs_get_fsuid()); retval = 0; while (size != 0) { +#ifdef APPFS_NO_PWRITE /* XXX:TODO: Write a wrapper function */ +# if 1 + /* XXX:TODO: Still fails on win32 */ + write_ret = -1; +#else + off_t seek_ret; + + seek_ret = lseek(fi->fh, offset, SEEK_SET); + if (seek_ret == offset) { + write_ret = write(fi->fh, buf, size); + } else { + write_ret = -1; + } +# endif +#else write_ret = pwrite(fi->fh, buf, size, offset); +#endif if (write_ret < 0) { APPFS_DEBUG("error: write failed"); return(errno * -1); @@ -1837,20 +1872,20 @@ const char *sql_ret; int tcl_ret; interp = appfs_create_TclInterp(NULL); if (interp == NULL) { - fprintf(stderr, "Unable to create a Tcl interpreter. Aborting.\n"); + APPFS_ERROR("Unable to create a Tcl interpreter. Aborting."); return(1); } tcl_ret = appfs_Tcl_Eval(interp, 5, "::appfs::db", "eval", sql, "row", "unset -nocomplain row(*); parray row; puts \"----\""); sql_ret = Tcl_GetStringResult(interp); if (tcl_ret != TCL_OK) { - fprintf(stderr, "[error] %s\n", sql_ret); + APPFS_ERROR("[error] %s", sql_ret); return(1); } if (sql_ret && sql_ret[0] != '\0') { @@ -1868,20 +1903,20 @@ const char *tcl_result; int tcl_ret; interp = appfs_create_TclInterp(NULL); if (interp == NULL) { - fprintf(stderr, "Unable to create a Tcl interpreter. Aborting.\n"); + APPFS_ERROR("Unable to create a Tcl interpreter. Aborting."); return(1); } tcl_ret = Tcl_Eval(interp, tcl); tcl_result = Tcl_GetStringResult(interp); if (tcl_ret != TCL_OK) { - fprintf(stderr, "[error] %s\n", Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)); + APPFS_ERROR("[error] %s", Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)); return(1); } if (tcl_result && tcl_result[0] != '\0') { @@ -2018,10 +2053,17 @@ Tcl_PkgProvide(interp, "appfsd", "1.0"); return(TCL_OK); } +#ifdef APPFS_NO_SIGNALS +static void appfs_set_sighandler(void) { + return; +} +#else +#include + /* * Hot-restart support */ /* Initiate a hot-restart */ static void appfs_hot_restart(void) { @@ -2050,10 +2092,23 @@ } return; } +static void appfs_set_sighandler(void) { + void *signal_ret; + + /* + * Register a signal handler for hot-restart requests + */ + signal_ret = signal(SIGHUP, appfs_signal_handler); + if (signal_ret == SIG_ERR) { + APPFS_ERROR("Unable to install signal handler for hot-restart"); + APPFS_ERROR("Hot-restart will not be available."); + } +} +#endif /* * Terminate a thread */ static void appfs_terminate_interp_and_thread(void *_interp) { Tcl_Interp *interp; @@ -2103,11 +2158,11 @@ char fake_arg[3] = {'-', 0, 0}; /* * Default values */ -#ifdef TCL_THREADS +#if defined(TCL_THREADS) && TCL_THREADS == 1 appfs_threaded_tcl = 1; #else appfs_threaded_tcl = 0; #endif @@ -2162,11 +2217,11 @@ fuse_opt_parse(args, NULL, NULL, NULL); fuse_opt_add_arg(args, "-oallow_other"); } else if (strcmp(optstr, "rw") == 0) { /* Ignored */ } else { - fprintf(stderr, "appfsd: invalid option: \"-o %s\"\n", optstr); + APPFS_ERROR("appfsd: invalid option: \"-o %s\"", optstr); free(optstr_s); return(1); } @@ -2202,13 +2257,13 @@ } } if ((optind + 2) != argc) { if ((optind + 2) < argc) { - fprintf(stderr, "Too many arguments\n"); + APPFS_ERROR("Too many arguments"); } else { - fprintf(stderr, "Missing cachedir or mountpoint\n"); + APPFS_ERROR("Missing cachedir or mountpoint"); } appfs_print_help(stderr); return(1); @@ -2248,22 +2303,69 @@ .mkdir = appfs_fuse_mkdir, .chmod = appfs_fuse_chmod, .symlink = appfs_fuse_symlink, }; + +#ifdef APPFS_NO_RLIMIT +static void appfs_set_resource_limits(void) { + return; +} +#else +#include + +static void appfs_set_resource_limits(void) { + struct rlimit number_open_files; + rlim_t number_open_files_max; + int rlimit_ret; + + /* + * Increase resource limits for number of open files + * to the maximum values, since we may be asked to + * hold open many files on behalf of many other processes + */ + number_open_files.rlim_cur = number_open_files.rlim_max = RLIM_INFINITY; + + rlimit_ret = setrlimit(RLIMIT_NOFILE, &number_open_files); + + if (rlimit_ret != 0) { + rlimit_ret = getrlimit(RLIMIT_NOFILE, &number_open_files); + if (rlimit_ret == 0) { + number_open_files_max = number_open_files.rlim_max; + + if (number_open_files_max < (1024 * 1024)) { + number_open_files.rlim_cur = number_open_files.rlim_max = 1024 * 1024; + + rlimit_ret = setrlimit(RLIMIT_NOFILE, &number_open_files); + } else { + number_open_files.rlim_cur = number_open_files.rlim_max; + } + + rlimit_ret = setrlimit(RLIMIT_NOFILE, &number_open_files); + + if (rlimit_ret != 0 && number_open_files.rlim_cur != number_open_files_max) { + number_open_files.rlim_cur = number_open_files.rlim_max = number_open_files_max; + + setrlimit(RLIMIT_NOFILE, &number_open_files); + } + } + } + + return; +} +#endif + /* * Entry point into this program. */ int main(int argc, char **argv) { Tcl_Interp *test_interp; char *test_interp_error; struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - struct rlimit number_open_files; - int pthread_ret, aop_ret, rlimit_ret; - void *signal_ret; + int pthread_ret, aop_ret; char *argv0; - rlim_t number_open_files_max; +int i; /* * Skip passed program name */ if (argc == 0 || argv == NULL) { @@ -2304,11 +2406,11 @@ * to its own Tcl interpreter. Tcl interpreters must be unique per * thread and new threads are dynamically created by FUSE. */ pthread_ret = pthread_key_create(&interpKey, appfs_terminate_interp_and_thread); if (pthread_ret != 0) { - fprintf(stderr, "Unable to create TSD key for Tcl. Aborting.\n"); + APPFS_ERROR("Unable to create TSD key for Tcl. Aborting."); return(1); } /* @@ -2338,19 +2440,10 @@ */ if (argc == 2 && strcmp(argv[0], "--tcl") == 0) { return(appfs_tcl(argv[1])); } - /* - * Register a signal handler for hot-restart requests - */ - signal_ret = signal(SIGHUP, appfs_signal_handler); - if (signal_ret == SIG_ERR) { - fprintf(stderr, "Unable to install signal handler for hot-restart\n"); - fprintf(stderr, "Hot-restart will not be available.\n"); - } - /* * Parse command line arguments */ /** ** Restore argc/argv to original values, replacing argv[0] in case @@ -2380,12 +2473,12 @@ if (test_interp == NULL) { if (test_interp_error == NULL) { test_interp_error = "Unknown error"; } - fprintf(stderr, "Unable to initialize Tcl interpreter for AppFSd:\n"); - fprintf(stderr, "%s\n", test_interp_error); + APPFS_ERROR("Unable to initialize Tcl interpreter for AppFSd:"); + APPFS_ERROR("%s", test_interp_error); return(1); } Tcl_DeleteInterp(test_interp); @@ -2392,45 +2485,15 @@ if (appfs_threaded_tcl) { Tcl_FinalizeNotifier(NULL); } - /* - * Increase resource limits for number of open files - * to the maximum values, since we may be asked to - * hold open many files on behalf of many other processes - */ - number_open_files.rlim_cur = number_open_files.rlim_max = RLIM_INFINITY; - - rlimit_ret = setrlimit(RLIMIT_NOFILE, &number_open_files); - - if (rlimit_ret != 0) { - rlimit_ret = getrlimit(RLIMIT_NOFILE, &number_open_files); - if (rlimit_ret == 0) { - number_open_files_max = number_open_files.rlim_max; - - if (number_open_files_max < (1024 * 1024)) { - number_open_files.rlim_cur = number_open_files.rlim_max = 1024 * 1024; - - rlimit_ret = setrlimit(RLIMIT_NOFILE, &number_open_files); - } else { - number_open_files.rlim_cur = number_open_files.rlim_max; - } - - rlimit_ret = setrlimit(RLIMIT_NOFILE, &number_open_files); - - if (rlimit_ret != 0 && number_open_files.rlim_cur != number_open_files_max) { - number_open_files.rlim_cur = number_open_files.rlim_max = number_open_files_max; - - setrlimit(RLIMIT_NOFILE, &number_open_files); - } - } - } - + appfs_set_resource_limits(); + appfs_set_sighandler(); /* * Enter the FUSE main loop -- this will process any arguments * and start servicing requests. */ appfs_fuse_started = 1; return(fuse_main(args.argc, args.argv, &appfs_operations, NULL)); }