From c74532a864caea0ca126dc8e9f4914e7c8e86898 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 11 Jan 2010 19:10:49 -0500 Subject: [PATCH] statd: Use the new nsm_ file.c calls in sm_notify Replace open-coded accesses to on-disk NSM data with calls to the new libnsm.a API. One major change is that sync(2) is no longer called when the NSM state number is updated at boot time. Otherwise sm-notify should behave much the same as it did before. Signed-off-by: Chuck Lever Signed-off-by: Steve Dickson --- utils/statd/sm-notify.c | 288 +++++++++------------------------------- 1 file changed, 63 insertions(+), 225 deletions(-) diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c index 0dba891..581234e 100644 --- a/utils/statd/sm-notify.c +++ b/utils/statd/sm-notify.c @@ -8,6 +8,7 @@ #include #endif +#include #include #include #include @@ -29,25 +30,9 @@ #include #include "xlog.h" +#include "nsm.h" #include "nfsrpc.h" -#ifndef BASEDIR -# ifdef NFS_STATEDIR -# define BASEDIR NFS_STATEDIR -# else -# define BASEDIR "/var/lib/nfs" -# endif -#endif - -#define DEFAULT_SM_STATE_PATH BASEDIR "/state" -#define DEFAULT_SM_DIR_PATH BASEDIR "/sm" -#define DEFAULT_SM_BAK_PATH DEFAULT_SM_DIR_PATH ".bak" - -char *_SM_BASE_PATH = BASEDIR; -char *_SM_STATE_PATH = DEFAULT_SM_STATE_PATH; -char *_SM_DIR_PATH = DEFAULT_SM_DIR_PATH; -char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH; - #define NSM_PROG 100024 #define NSM_PROGRAM 100024 #define NSM_VERSION 1 @@ -59,7 +44,6 @@ char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH; struct nsm_host { struct nsm_host * next; char * name; - char * path; struct sockaddr_storage addr; struct addrinfo *ai; time_t last_used; @@ -70,24 +54,19 @@ struct nsm_host { }; static char nsm_hostname[256]; -static uint32_t nsm_state; +static int nsm_state; static int opt_debug = 0; -static int opt_update_state = 1; +static _Bool opt_update_state = true; static unsigned int opt_max_retry = 15 * 60; static char * opt_srcaddr = 0; static uint16_t opt_srcport = 0; -static unsigned int nsm_get_state(int); static void notify(void); static int notify_host(int, struct nsm_host *); static void recv_reply(int); -static void backup_hosts(const char *, const char *); -static void get_hosts(const char *); static void insert_host(struct nsm_host *); static struct nsm_host *find_host(uint32_t); static int record_pid(void); -static void drop_privs(void); -static void set_kernel_nsm_state(int state); static struct nsm_host * hosts = NULL; @@ -111,10 +90,39 @@ static struct addrinfo *smn_lookup(const char *name) return ai; } +__attribute_malloc__ +static struct nsm_host * +smn_alloc_host(const char *hostname, const time_t timestamp) +{ + struct nsm_host *host; + + host = calloc(1, sizeof(*host)); + if (host == NULL) + goto out_nomem; + + host->name = strdup(hostname); + if (host->name == NULL) { + free(host); + goto out_nomem; + } + + host->last_used = timestamp; + host->timeout = NSM_TIMEOUT; + host->retries = 100; /* force address retry */ + + return host; + +out_nomem: + xlog_warn("Unable to allocate memory"); + return NULL; +} + static void smn_forget_host(struct nsm_host *host) { - unlink(host->path); - free(host->path); + xlog(D_CALL, "Removing %s from notify list", host->name); + + nsm_delete_notified_host(host->name); + free(host->name); if (host->ai) freeaddrinfo(host->ai); @@ -122,6 +130,23 @@ static void smn_forget_host(struct nsm_host *host) free(host); } +static unsigned int +smn_get_host(const char *hostname, + __attribute__ ((unused)) const struct sockaddr *sap, + __attribute__ ((unused)) const struct mon *m, + const time_t timestamp) +{ + struct nsm_host *host; + + host = smn_alloc_host(hostname, timestamp); + if (host == NULL) + return 0; + + insert_host(host); + xlog(D_GENERAL, "Added host %s to notify list", hostname); + return 1; +} + int main(int argc, char **argv) { @@ -147,7 +172,7 @@ main(int argc, char **argv) opt_max_retry = atoi(optarg) * 60; break; case 'n': - opt_update_state = 0; + opt_update_state = false; break; case 'p': opt_srcport = atoi(optarg); @@ -156,20 +181,8 @@ main(int argc, char **argv) opt_srcaddr = optarg; break; case 'P': - _SM_BASE_PATH = strdup(optarg); - _SM_STATE_PATH = malloc(strlen(optarg)+1+sizeof("state")); - _SM_DIR_PATH = malloc(strlen(optarg)+1+sizeof("sm")); - _SM_BAK_PATH = malloc(strlen(optarg)+1+sizeof("sm.bak")); - if (_SM_BASE_PATH == NULL || - _SM_STATE_PATH == NULL || - _SM_DIR_PATH == NULL || - _SM_BAK_PATH == NULL) { - fprintf(stderr, "unable to allocate memory"); + if (!nsm_setup_pathnames(argv[0], optarg)) exit(1); - } - strcat(strcpy(_SM_STATE_PATH, _SM_BASE_PATH), "/state"); - strcat(strcpy(_SM_DIR_PATH, _SM_BASE_PATH), "/sm"); - strcat(strcpy(_SM_BAK_PATH, _SM_BASE_PATH), "/sm.bak"); break; default: @@ -195,8 +208,8 @@ usage: fprintf(stderr, xlog_open(progname); xlog(L_NOTICE, "Version " VERSION " starting"); - if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) { - if (record_pid() == 0 && force == 0 && opt_update_state == 1) { + if (nsm_is_default_parentdir()) { + if (record_pid() == 0 && force == 0 && opt_update_state) { /* already run, don't try again */ xlog(L_NOTICE, "Already notifying clients; Exiting!"); exit(0); @@ -211,18 +224,16 @@ usage: fprintf(stderr, exit(1); } - backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH); - get_hosts(_SM_BAK_PATH); - - /* If there are not hosts to notify, just exit */ - if (!hosts) { + (void)nsm_retire_monitored_hosts(); + if (nsm_load_notify_list(smn_get_host) == 0) { xlog(D_GENERAL, "No hosts to notify; exiting"); return 0; } - /* Get and update the NSM state. This will call sync() */ nsm_state = nsm_get_state(opt_update_state); - set_kernel_nsm_state(nsm_state); + if (nsm_state == 0) + exit(1); + nsm_update_kernel_state(nsm_state); if (!opt_debug) { xlog(L_NOTICE, "Backgrounding to notify hosts...\n"); @@ -316,7 +327,8 @@ notify(void) if (opt_max_retry) failtime = time(NULL) + opt_max_retry; - drop_privs(); + if (!nsm_drop_privileges(-1)) + exit(1); while (hosts) { struct pollfd pfd; @@ -553,82 +565,6 @@ fail: /* Re-insert the host */ insert_host(hp); } -/* - * Back up all hosts from the sm directory to sm.bak - */ -static void -backup_hosts(const char *dirname, const char *bakname) -{ - struct dirent *de; - DIR *dir; - - if (!(dir = opendir(dirname))) { - xlog_warn("Failed to open %s: %m", dirname); - return; - } - - while ((de = readdir(dir)) != NULL) { - char src[1024], dst[1024]; - - if (de->d_name[0] == '.') - continue; - - snprintf(src, sizeof(src), "%s/%s", dirname, de->d_name); - snprintf(dst, sizeof(dst), "%s/%s", bakname, de->d_name); - if (rename(src, dst) < 0) - xlog_warn("Failed to rename %s -> %s: %m", src, dst); - } - closedir(dir); -} - -/* - * Get all entries from sm.bak and convert them to host entries - */ -static void -get_hosts(const char *dirname) -{ - struct nsm_host *host; - struct dirent *de; - DIR *dir; - - if (!(dir = opendir(dirname))) { - xlog_warn("Failed to open %s: %m", dirname); - return; - } - - host = NULL; - while ((de = readdir(dir)) != NULL) { - struct stat stb; - char path[1024]; - - if (de->d_name[0] == '.') - continue; - if (host == NULL) - host = calloc(1, sizeof(*host)); - if (host == NULL) { - xlog_warn("Unable to allocate memory"); - return; - } - - snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name); - if (stat(path, &stb) < 0) - continue; - - host->last_used = stb.st_mtime; - host->timeout = NSM_TIMEOUT; - host->path = strdup(path); - host->name = strdup(de->d_name); - host->retries = 100; /* force address retry */ - - insert_host(host); - host = NULL; - } - closedir(dir); - - if (host) - free(host); -} - /* * Insert host into sorted list */ @@ -676,60 +612,6 @@ find_host(uint32_t xid) return NULL; } - -/* - * Retrieve the current NSM state - */ -static unsigned int -nsm_get_state(int update) -{ - char newfile[PATH_MAX]; - int fd, state; - - if ((fd = open(_SM_STATE_PATH, O_RDONLY)) < 0) { - xlog_warn("%s: %m", _SM_STATE_PATH); - xlog_warn("Creating %s, set initial state 1", - _SM_STATE_PATH); - state = 1; - update = 1; - } else { - if (read(fd, &state, sizeof(state)) != sizeof(state)) { - xlog_warn("%s: bad file size, setting state = 1", - _SM_STATE_PATH); - state = 1; - update = 1; - } else { - if (!(state & 1)) - state += 1; - } - close(fd); - } - - if (update) { - state += 2; - snprintf(newfile, sizeof(newfile), - "%s.new", _SM_STATE_PATH); - if ((fd = open(newfile, O_CREAT|O_WRONLY, 0644)) < 0) { - xlog(L_ERROR, "Cannot create %s: %m", newfile); - exit(1); - } - if (write(fd, &state, sizeof(state)) != sizeof(state)) { - xlog(L_ERROR, - "Failed to write state to %s", newfile); - exit(1); - } - close(fd); - if (rename(newfile, _SM_STATE_PATH) < 0) { - xlog(L_ERROR, - "Cannot create %s: %m", _SM_STATE_PATH); - exit(1); - } - sync(); - } - - return state; -} - /* * Record pid in /var/run/sm-notify.pid * This file should remain until a reboot, even if the @@ -756,47 +638,3 @@ static int record_pid(void) (void)close(fd); return 1; } - -/* Drop privileges to match owner of state-directory - * (in case a reply triggers some unknown bug). - */ -static void drop_privs(void) -{ - struct stat st; - - if (stat(_SM_DIR_PATH, &st) == -1 && - stat(_SM_BASE_PATH, &st) == -1) { - st.st_uid = 0; - st.st_gid = 0; - } - - if (st.st_uid == 0) { - xlog_warn("Running as 'root'. " - "chown %s to choose different user", _SM_DIR_PATH); - return; - } - - setgroups(0, NULL); - if (setgid(st.st_gid) == -1 - || setuid(st.st_uid) == -1) { - xlog(L_ERROR, "Fail to drop privileges"); - exit(1); - } -} - -static void set_kernel_nsm_state(int state) -{ - int fd; - const char *file = "/proc/sys/fs/nfs/nsm_local_state"; - - fd = open(file ,O_WRONLY); - if (fd >= 0) { - char buf[20]; - snprintf(buf, sizeof(buf), "%d", state); - if (write(fd, buf, strlen(buf)) != strlen(buf)) { - xlog_warn("Writing to '%s' failed: errno %d (%m)", - file, errno); - } - close(fd); - } -} -- 2.39.2