diff options
Diffstat (limited to '')
-rw-r--r-- | utils/exportd/exportd.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/utils/exportd/exportd.c b/utils/exportd/exportd.c new file mode 100644 index 0000000..a2e370a --- /dev/null +++ b/utils/exportd/exportd.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2021 Red Hat <nfs@redhat.com> + * + * support/exportd/exportd.c + * + * Routines used to support NFSv4 exports + * + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stddef.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> + +#include "nfslib.h" +#include "conffile.h" +#include "exportfs.h" +#include "export.h" + +extern void my_svc_run(void); + +/* Number of mountd threads to start. Default is 1 and + * that's probably enough unless you need hundreds of + * clients to be able to mount at once. */ +static int num_threads = 1; +/* Arbitrary limit on number of threads */ +#define MAX_THREADS 64 + +int manage_gids; +int use_ipaddr = -1; + +static struct option longopts[] = +{ + { "foreground", 0, 0, 'F' }, + { "debug", 1, 0, 'd' }, + { "help", 0, 0, 'h' }, + { "manage-gids", 0, 0, 'g' }, + { "num-threads", 1, 0, 't' }, + { "log-auth", 0, 0, 'l' }, + { "cache-use-ipaddr", 0, 0, 'i' }, + { "ttl", 0, 0, 'T' }, + { NULL, 0, 0, 0 } +}; +static char shortopts[] = "d:fghs:t:liT:"; + +/* + * Signal handlers. + */ +inline static void set_signals(void); + +inline void +cleanup_lockfiles (void) +{ + unlink(etab.lockfn); +} + +static void +killer (int sig) +{ + if (num_threads > 1) { + /* play Kronos and eat our children */ + kill(0, SIGTERM); + cache_wait_for_workers("exportd"); + } + cleanup_lockfiles(); + free_state_path_names(&etab); + xlog (L_NOTICE, "Caught signal %d, exiting.", sig); + + exit(0); +} + +static void +sig_hup (int UNUSED(sig)) +{ + /* don't exit on SIGHUP */ + xlog (L_NOTICE, "Received SIGHUP... Ignoring.\n"); + return; +} + +inline static void +set_signals(void) +{ + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGPIPE, &sa, NULL); + /* WARNING: the following works on Linux and SysV, but not BSD! */ + sigaction(SIGCHLD, &sa, NULL); + + sa.sa_handler = killer; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + sa.sa_handler = sig_hup; + sigaction(SIGHUP, &sa, NULL); +} + +static void +usage(const char *prog, int n) +{ + fprintf(stderr, + "Usage: %s [-f|--foreground] [-h|--help] [-d kind|--debug kind]\n" +" [-g|--manage-gids] [-l|--log-auth] [-i|--cache-use-ipaddr] [-T|--ttl ttl]\n" +" [-s|--state-directory-path path]\n" +" [-t num|--num-threads=num]\n", prog); + exit(n); +} + +inline static void +read_exportd_conf(char *progname, char **argv) +{ + char *s; + int ttl; + + conf_init_file(NFS_CONFFILE); + + xlog_set_debug(progname); + + manage_gids = conf_get_bool("exportd", "manage-gids", manage_gids); + num_threads = conf_get_num("exportd", "threads", num_threads); + if (conf_get_bool("mountd", "cache-use-ipaddr", 0)) + use_ipaddr = 2; + + s = conf_get_str("exportd", "state-directory-path"); + if (s && !state_setup_basedir(argv[0], s)) + exit(1); + + ttl = conf_get_num("mountd", "ttl", default_ttl); + if (ttl > 0) + default_ttl = ttl; +} + +int +main(int argc, char **argv) +{ + char *progname; + int foreground = 0; + int c; + int ttl; + + /* Set the basename */ + if ((progname = strrchr(argv[0], '/')) != NULL) + progname++; + else + progname = argv[0]; + + /* Initialize logging. */ + xlog_open(progname); + + /* Read in config setting */ + read_exportd_conf(progname, argv); + + while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF) { + switch (c) { + case 'd': + xlog_sconfig(optarg, 1); + break; + case 'l': + xlog_sconfig("auth", 1); + break; + case 'f': + foreground++; + break; + case 'g': + manage_gids = 1; + break; + case 'h': + usage(progname, 0); + break; + case 'i': + use_ipaddr = 2; + break; + case 'T': + ttl = atoi(optarg); + if (ttl <= 0) { + fprintf(stderr, "%s: bad ttl number of seconds: %s\n", + argv[0], optarg); + usage(argv[0], 1); + } + default_ttl = ttl; + break; + case 's': + if (!state_setup_basedir(argv[0], optarg)) + exit(1); + break; + case 't': + num_threads = atoi (optarg); + break; + case '?': + default: + usage(progname, 1); + } + + } + + if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) + return 1; + + if (!foreground) + xlog_stderr(0); + + daemon_init(foreground); + + set_signals(); + daemon_ready(); + + /* silently bounds check num_threads */ + if (foreground) + num_threads = 1; + else if (num_threads < 1) + num_threads = 1; + else if (num_threads > MAX_THREADS) + num_threads = MAX_THREADS; + + /* Open cache channel files BEFORE forking so each upcall is + * only handled by one thread. Kernel provides locking for both + * read and write. + */ + cache_open(); + + if (cache_fork_workers(progname, num_threads) == 0) { + /* We forked, waited, and now need to clean up */ + cleanup_lockfiles(); + free_state_path_names(&etab); + xlog(L_NOTICE, "%s: no more workers, exiting\n", progname); + exit(0); + } + + v4clients_init(); + + /* Process incoming upcalls */ + while (cache_process(NULL) >= 0) + ; + + xlog(L_ERROR, "%s: process loop terminated unexpectedly(%m). Exiting...\n", + progname); + + free_state_path_names(&etab); + exit(1); +} |