2 * Send NSM notify calls to all hosts listed in /var/lib/sm
4 * Copyright (C) 2004-2006 Olaf Kirch <okir@suse.de>
11 #include <sys/types.h>
12 #include <sys/socket.h>
15 #include <sys/param.h>
16 #include <sys/syslog.h>
17 #include <arpa/inet.h>
36 # define BASEDIR NFS_STATEDIR
38 # define BASEDIR "/var/lib/nfs"
42 #define DEFAULT_SM_STATE_PATH BASEDIR "/state"
43 #define DEFAULT_SM_DIR_PATH BASEDIR "/sm"
44 #define DEFAULT_SM_BAK_PATH DEFAULT_SM_DIR_PATH ".bak"
46 char *_SM_BASE_PATH = BASEDIR;
47 char *_SM_STATE_PATH = DEFAULT_SM_STATE_PATH;
48 char *_SM_DIR_PATH = DEFAULT_SM_DIR_PATH;
49 char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH;
51 #define NSM_PROG 100024
52 #define NSM_PROGRAM 100024
56 #define NSM_MAX_TIMEOUT 120 /* don't make this too big */
57 #define MAXMSGSIZE 256
60 struct nsm_host * next;
63 struct sockaddr_storage addr;
72 static char nsm_hostname[256];
73 static uint32_t nsm_state;
74 static int opt_debug = 0;
75 static int opt_update_state = 1;
76 static unsigned int opt_max_retry = 15 * 60;
77 static char * opt_srcaddr = 0;
78 static uint16_t opt_srcport = 0;
80 static unsigned int nsm_get_state(int);
81 static void notify(void);
82 static int notify_host(int, struct nsm_host *);
83 static void recv_reply(int);
84 static void backup_hosts(const char *, const char *);
85 static void get_hosts(const char *);
86 static void insert_host(struct nsm_host *);
87 static struct nsm_host *find_host(uint32_t);
88 static int record_pid(void);
89 static void drop_privs(void);
90 static void set_kernel_nsm_state(int state);
92 static struct nsm_host * hosts = NULL;
94 static struct addrinfo *smn_lookup(const char *name)
96 struct addrinfo *ai, hint = {
97 #if HAVE_DECL_AI_ADDRCONFIG
98 .ai_flags = AI_ADDRCONFIG,
99 #endif /* HAVE_DECL_AI_ADDRCONFIG */
100 .ai_family = AF_INET,
101 .ai_protocol = IPPROTO_UDP,
105 error = getaddrinfo(name, NULL, &hint, &ai);
107 xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error));
114 static void smn_forget_host(struct nsm_host *host)
120 freeaddrinfo(host->ai);
126 main(int argc, char **argv)
132 progname = strrchr(argv[0], '/');
133 if (progname != NULL)
138 while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) {
147 opt_max_retry = atoi(optarg) * 60;
150 opt_update_state = 0;
153 opt_srcport = atoi(optarg);
156 opt_srcaddr = optarg;
159 _SM_BASE_PATH = strdup(optarg);
160 _SM_STATE_PATH = malloc(strlen(optarg)+1+sizeof("state"));
161 _SM_DIR_PATH = malloc(strlen(optarg)+1+sizeof("sm"));
162 _SM_BAK_PATH = malloc(strlen(optarg)+1+sizeof("sm.bak"));
163 if (_SM_BASE_PATH == NULL ||
164 _SM_STATE_PATH == NULL ||
165 _SM_DIR_PATH == NULL ||
166 _SM_BAK_PATH == NULL) {
167 fprintf(stderr, "unable to allocate memory");
170 strcat(strcpy(_SM_STATE_PATH, _SM_BASE_PATH), "/state");
171 strcat(strcpy(_SM_DIR_PATH, _SM_BASE_PATH), "/sm");
172 strcat(strcpy(_SM_BAK_PATH, _SM_BASE_PATH), "/sm.bak");
181 usage: fprintf(stderr,
182 "Usage: %s -notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
183 " [-P /path/to/state/directory] [-v my_host_name]\n",
191 xlog_config(D_ALL, 1);
196 xlog(L_NOTICE, "Version " VERSION " starting");
198 if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) {
199 if (record_pid() == 0 && force == 0 && opt_update_state == 1) {
200 /* already run, don't try again */
201 xlog(L_NOTICE, "Already notifying clients; Exiting!");
207 strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
209 if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
210 xlog(L_ERROR, "Failed to obtain name of local host: %m");
214 backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH);
215 get_hosts(_SM_BAK_PATH);
217 /* If there are not hosts to notify, just exit */
219 xlog(D_GENERAL, "No hosts to notify; exiting");
223 /* Get and update the NSM state. This will call sync() */
224 nsm_state = nsm_get_state(opt_update_state);
225 set_kernel_nsm_state(nsm_state);
228 xlog(L_NOTICE, "Backgrounding to notify hosts...\n");
230 if (daemon(0, 0) < 0) {
231 xlog(L_ERROR, "unable to background: %m");
245 while ((hp = hosts) != 0) {
247 xlog(L_NOTICE, "Unable to notify %s, giving up",
262 struct sockaddr_storage address;
263 struct sockaddr *local_addr = (struct sockaddr *)&address;
269 sock = socket(AF_INET, SOCK_DGRAM, 0);
271 xlog(L_ERROR, "Failed to create RPC socket: %m");
274 fcntl(sock, F_SETFL, O_NONBLOCK);
276 memset(&address, 0, sizeof(address));
277 local_addr->sa_family = AF_INET; /* Default to IPv4 */
279 /* Bind source IP if provided on command line */
281 struct addrinfo *ai = smn_lookup(opt_srcaddr);
284 "Not a valid hostname or address: \"%s\"",
289 /* We know it's IPv4 at this point */
290 memcpy(local_addr, ai->ai_addr, ai->ai_addrlen);
295 /* Use source port if provided on the command line,
296 * otherwise use bindresvport */
298 nfs_set_port(local_addr, opt_srcport);
299 if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) {
300 xlog(L_ERROR, "Failed to bind RPC socket: %m");
305 struct sockaddr_in *sin = (struct sockaddr_in *)local_addr;
306 (void) bindresvport(sock, sin);
307 /* try to avoid known ports */
308 se = getservbyport(sin->sin_port, "udp");
309 if (se && retry_cnt < 100) {
317 failtime = time(NULL) + opt_max_retry;
323 time_t now = time(NULL);
324 unsigned int sent = 0;
328 if (failtime && now >= failtime)
331 while (hosts && ((wait = hosts->send_next - now) <= 0)) {
332 /* Never send more than 10 packets at once */
336 /* Remove queue head */
340 if (notify_host(sock, hp))
343 /* Set the timeout for this call, using an
344 exponential timeout strategy */
346 if ((hp->timeout <<= 1) > NSM_MAX_TIMEOUT)
347 hp->timeout = NSM_MAX_TIMEOUT;
348 hp->send_next = now + wait;
356 xlog(D_GENERAL, "Host %s due in %ld seconds",
365 if (poll(&pfd, 1, wait) != 1)
373 * Send notification to a single host
376 notify_host(int sock, struct nsm_host *host)
378 struct sockaddr_storage address;
379 struct sockaddr *dest = (struct sockaddr *)&address;
380 socklen_t destlen = sizeof(address);
381 static unsigned int xid = 0;
382 uint32_t msgbuf[MAXMSGSIZE], *p;
386 xid = getpid() + time(NULL);
390 if (host->ai == NULL) {
391 host->ai = smn_lookup(host->name);
392 if (host->ai == NULL) {
393 xlog_warn("DNS resolution of %s failed; "
394 "retrying later", host->name);
399 memset(msgbuf, 0, sizeof(msgbuf));
401 *p++ = htonl(host->xid);
405 /* If we retransmitted 4 times, reset the port to force
406 * a new portmap lookup (in case statd was restarted).
407 * We also rotate through multiple IP addresses at this
410 if (host->retries >= 4) {
411 /* don't rotate if there is only one addrinfo */
412 if (host->ai->ai_next == NULL)
413 memcpy(&host->addr, host->ai->ai_addr,
414 host->ai->ai_addrlen);
416 struct addrinfo *first = host->ai;
417 struct addrinfo **next = &host->ai;
419 /* remove the first entry from the list */
420 host->ai = first->ai_next;
421 first->ai_next = NULL;
422 /* find the end of the list */
423 next = &first->ai_next;
425 next = & (*next)->ai_next;
426 /* put first entry at end */
428 memcpy(&host->addr, first->ai_addr,
432 nfs_set_port((struct sockaddr *)&host->addr, 0);
436 memcpy(dest, &host->addr, destlen);
437 if (nfs_get_port(dest) == 0) {
438 /* Build a PMAP packet */
439 xlog(D_GENERAL, "Sending portmap query to %s", host->name);
441 nfs_set_port(dest, 111);
442 *p++ = htonl(100000);
450 *p++ = htonl(NSM_PROGRAM);
451 *p++ = htonl(NSM_VERSION);
452 *p++ = htonl(IPPROTO_UDP);
455 /* Build an SM_NOTIFY packet */
456 xlog(D_GENERAL, "Sending SM_NOTIFY to %s", host->name);
458 *p++ = htonl(NSM_PROGRAM);
459 *p++ = htonl(NSM_VERSION);
460 *p++ = htonl(NSM_NOTIFY);
467 len = strlen(nsm_hostname);
469 memcpy(p, nsm_hostname, len);
471 *p++ = htonl(nsm_state);
473 len = (p - msgbuf) << 2;
475 if (sendto(sock, msgbuf, len, 0, dest, destlen) < 0)
476 xlog_warn("Sending Reboot Notification to "
477 "'%s' failed: errno %d (%m)", host->name, errno);
483 * Receive reply from remote host
489 struct sockaddr *sap;
490 uint32_t msgbuf[MAXMSGSIZE], *p, *end;
494 res = recv(sock, msgbuf, sizeof(msgbuf), 0);
498 xlog(D_GENERAL, "Received packet...");
501 end = p + (res >> 2);
504 if (*p++ != htonl(1) /* must be REPLY */
505 || *p++ != htonl(0) /* must be ACCEPTED */
506 || *p++ != htonl(0) /* must be NULL verifier */
508 || *p++ != htonl(0)) /* must be SUCCESS */
511 /* Before we look at the data, find the host struct for
513 if ((hp = find_host(xid)) == NULL)
515 sap = (struct sockaddr *)&hp->addr;
517 if (nfs_get_port(sap) == 0) {
518 /* This was a portmap request */
525 hp->send_next = time(NULL);
527 /* No binding for statd. Delay the next
528 * portmap query for max timeout */
529 xlog(D_GENERAL, "No statd on %s", hp->name);
530 hp->timeout = NSM_MAX_TIMEOUT;
531 hp->send_next += NSM_MAX_TIMEOUT;
533 nfs_set_port(sap, port);
534 if (hp->timeout >= NSM_MAX_TIMEOUT / 4)
535 hp->timeout = NSM_MAX_TIMEOUT / 4;
539 /* Successful NOTIFY call. Server returns void,
540 * so nothing we need to do here (except
541 * check that we didn't read past the end of the
545 xlog(D_GENERAL, "Host %s notified successfully",
552 fail: /* Re-insert the host */
557 * Back up all hosts from the sm directory to sm.bak
560 backup_hosts(const char *dirname, const char *bakname)
565 if (!(dir = opendir(dirname))) {
566 xlog_warn("Failed to open %s: %m", dirname);
570 while ((de = readdir(dir)) != NULL) {
571 char src[1024], dst[1024];
573 if (de->d_name[0] == '.')
576 snprintf(src, sizeof(src), "%s/%s", dirname, de->d_name);
577 snprintf(dst, sizeof(dst), "%s/%s", bakname, de->d_name);
578 if (rename(src, dst) < 0)
579 xlog_warn("Failed to rename %s -> %s: %m", src, dst);
585 * Get all entries from sm.bak and convert them to host entries
588 get_hosts(const char *dirname)
590 struct nsm_host *host;
594 if (!(dir = opendir(dirname))) {
595 xlog_warn("Failed to open %s: %m", dirname);
600 while ((de = readdir(dir)) != NULL) {
604 if (de->d_name[0] == '.')
607 host = calloc(1, sizeof(*host));
609 xlog_warn("Unable to allocate memory");
613 snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
614 if (stat(path, &stb) < 0)
617 host->last_used = stb.st_mtime;
618 host->timeout = NSM_TIMEOUT;
619 host->path = strdup(path);
620 host->name = strdup(de->d_name);
621 host->retries = 100; /* force address retry */
633 * Insert host into sorted list
636 insert_host(struct nsm_host *host)
638 struct nsm_host **where, *p;
641 while ((p = *where) != 0) {
642 /* Sort in ascending order of timeout */
643 if (host->send_next < p->send_next)
645 /* If we have the same timeout, put the
646 * most recently used host first.
647 * This makes sure that "recent" hosts
648 * get notified first.
650 if (host->send_next == p->send_next
651 && host->last_used > p->last_used)
661 * Find host given the XID
663 static struct nsm_host *
664 find_host(uint32_t xid)
666 struct nsm_host **where, *p;
669 while ((p = *where) != 0) {
681 * Retrieve the current NSM state
684 nsm_get_state(int update)
686 char newfile[PATH_MAX];
689 if ((fd = open(_SM_STATE_PATH, O_RDONLY)) < 0) {
690 xlog_warn("%s: %m", _SM_STATE_PATH);
691 xlog_warn("Creating %s, set initial state 1",
696 if (read(fd, &state, sizeof(state)) != sizeof(state)) {
697 xlog_warn("%s: bad file size, setting state = 1",
710 snprintf(newfile, sizeof(newfile),
711 "%s.new", _SM_STATE_PATH);
712 if ((fd = open(newfile, O_CREAT|O_WRONLY, 0644)) < 0) {
713 xlog(L_ERROR, "Cannot create %s: %m", newfile);
716 if (write(fd, &state, sizeof(state)) != sizeof(state)) {
718 "Failed to write state to %s", newfile);
722 if (rename(newfile, _SM_STATE_PATH) < 0) {
724 "Cannot create %s: %m", _SM_STATE_PATH);
734 * Record pid in /var/run/sm-notify.pid
735 * This file should remain until a reboot, even if the
737 * If file already exists, fail.
739 static int record_pid(void)
745 (void)snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
746 fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
750 len = write(fd, pid, strlen(pid));
751 if ((len < 0) || ((size_t)len != strlen(pid))) {
752 xlog_warn("Writing to pid file failed: errno %d (%m)",
760 /* Drop privileges to match owner of state-directory
761 * (in case a reply triggers some unknown bug).
763 static void drop_privs(void)
767 if (stat(_SM_DIR_PATH, &st) == -1 &&
768 stat(_SM_BASE_PATH, &st) == -1) {
773 if (st.st_uid == 0) {
774 xlog_warn("Running as 'root'. "
775 "chown %s to choose different user", _SM_DIR_PATH);
780 if (setgid(st.st_gid) == -1
781 || setuid(st.st_uid) == -1) {
782 xlog(L_ERROR, "Fail to drop privileges");
787 static void set_kernel_nsm_state(int state)
790 const char *file = "/proc/sys/fs/nfs/nsm_local_state";
792 fd = open(file ,O_WRONLY);
795 snprintf(buf, sizeof(buf), "%d", state);
796 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
797 xlog_warn("Writing to '%s' failed: errno %d (%m)",