2 * Send NSM notify calls to all hosts listed in /var/lib/sm
4 * Copyright (C) 2004-2006 Olaf Kirch <okir@suse.de>
12 #include <sys/types.h>
13 #include <sys/socket.h>
16 #include <sys/param.h>
17 #include <sys/syslog.h>
18 #include <arpa/inet.h>
37 /* glibc before 2.3.4 */
38 #ifndef AI_NUMERICSERV
39 #define AI_NUMERICSERV 0
43 #define NSM_MAX_TIMEOUT 120 /* don't make this too big */
46 struct nsm_host * next;
58 static char nsm_hostname[SM_MAXSTRLEN + 1];
60 static int nsm_family = AF_INET;
61 static int opt_debug = 0;
62 static _Bool opt_update_state = true;
63 static unsigned int opt_max_retry = 15 * 60;
64 static char * opt_srcaddr = NULL;
65 static char * opt_srcport = NULL;
67 static void notify(const int sock);
68 static int notify_host(int, struct nsm_host *);
69 static void recv_reply(int);
70 static void insert_host(struct nsm_host *);
71 static struct nsm_host *find_host(uint32_t);
72 static int record_pid(void);
74 static struct nsm_host * hosts = NULL;
77 static struct addrinfo *
78 smn_lookup(const char *name)
80 struct addrinfo *ai = NULL;
81 struct addrinfo hint = {
82 .ai_family = (nsm_family == AF_INET ? AF_INET: AF_UNSPEC),
83 .ai_protocol = (int)IPPROTO_UDP,
87 error = getaddrinfo(name, NULL, &hint, &ai);
89 xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error));
97 static struct nsm_host *
98 smn_alloc_host(const char *hostname, const char *mon_name,
99 const char *my_name, const time_t timestamp)
101 struct nsm_host *host;
103 host = calloc(1, sizeof(*host));
107 host->name = strdup(hostname);
108 host->mon_name = strdup(mon_name);
109 host->my_name = strdup(my_name);
110 if (host->name == NULL ||
111 host->mon_name == NULL ||
112 host->my_name == NULL) {
114 free(host->mon_name);
120 host->last_used = timestamp;
121 host->timeout = NSM_TIMEOUT;
122 host->retries = 100; /* force address retry */
127 xlog_warn("Unable to allocate memory");
131 static void smn_forget_host(struct nsm_host *host)
133 xlog(D_CALL, "Removing %s (%s, %s) from notify list",
134 host->name, host->mon_name, host->my_name);
136 nsm_delete_notified_host(host->name, host->mon_name, host->my_name);
139 free(host->mon_name);
142 freeaddrinfo(host->ai);
148 smn_get_host(const char *hostname,
149 __attribute__ ((unused)) const struct sockaddr *sap,
150 const struct mon *m, const time_t timestamp)
152 struct nsm_host *host;
154 host = smn_alloc_host(hostname,
155 m->mon_id.mon_name, m->mon_id.my_id.my_name, timestamp);
160 xlog(D_GENERAL, "Added host %s to notify list", hostname);
164 #ifdef IPV6_SUPPORTED
165 static int smn_socket(void)
170 * Use an AF_INET socket if IPv6 is disabled on the
173 sock = socket(AF_INET6, SOCK_DGRAM, 0);
175 if (errno != EAFNOSUPPORT) {
176 xlog(L_ERROR, "Failed to create RPC socket: %m");
179 sock = socket(AF_INET, SOCK_DGRAM, 0);
181 xlog(L_ERROR, "Failed to create RPC socket: %m");
185 nsm_family = AF_INET6;
187 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
188 xlog(L_ERROR, "fcntl(3) on RPC socket failed: %m");
193 * TI-RPC over IPv6 (udp6/tcp6) does not handle IPv4. However,
194 * since sm-notify open-codes all of its RPC support, it can
195 * use a single socket and let the local network stack provide
196 * the correct mapping between address families automatically.
197 * This is the same thing that is done in the kernel.
199 if (nsm_family == AF_INET6) {
201 socklen_t zerolen = (socklen_t)sizeof(zero);
203 if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
204 (char *)&zero, zerolen) == -1) {
205 xlog(L_ERROR, "setsockopt(3) on RPC socket failed: %m");
216 #else /* !IPV6_SUPPORTED */
217 static int smn_socket(void)
221 sock = socket(AF_INET, SOCK_DGRAM, 0);
223 xlog(L_ERROR, "Failed to create RPC socket: %m");
227 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
228 xlog(L_ERROR, "fcntl(3) on RPC socket failed: %m");
235 #endif /* !IPV6_SUPPORTED */
238 * If admin specified a source address or srcport, then convert those
239 * to a sockaddr and return it. Otherwise, return an ANYADDR address.
242 static struct addrinfo *
243 smn_bind_address(const char *srcaddr, const char *srcport)
245 struct addrinfo *ai = NULL;
246 struct addrinfo hint = {
247 .ai_flags = AI_NUMERICSERV,
248 .ai_family = nsm_family,
249 .ai_protocol = (int)IPPROTO_UDP,
254 hint.ai_flags |= AI_PASSIVE;
256 /* Do not allow "node" and "service" parameters both to be NULL */
258 error = getaddrinfo(srcaddr, "", &hint, &ai);
260 error = getaddrinfo(srcaddr, srcport, &hint, &ai);
263 "Invalid bind address or port for RPC socket: %s",
264 gai_strerror(error));
273 smn_bindresvport(int sock, struct sockaddr *sap)
275 return bindresvport_sa(sock, sap);
278 #else /* !HAVE_LIBTIRPC */
280 smn_bindresvport(int sock, struct sockaddr *sap)
282 if (sap->sa_family != AF_INET) {
283 errno = EAFNOSUPPORT;
287 return bindresvport(sock, (struct sockaddr_in *)(char *)sap);
289 #endif /* !HAVE_LIBTIRPC */
292 * Prepare a socket for sending RPC requests
294 * Returns a bound datagram socket file descriptor, or -1 if
298 smn_create_socket(const char *srcaddr, const char *srcport)
300 int sock, retry_cnt = 0;
308 ai = smn_bind_address(srcaddr, srcport);
314 /* Use source port if provided on the command line,
315 * otherwise use bindresvport */
317 if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
318 xlog(L_ERROR, "Failed to bind RPC socket: %m");
326 if (smn_bindresvport(sock, ai->ai_addr) == -1) {
328 "bindresvport on RPC socket failed: %m");
334 /* try to avoid known ports */
335 se = getservbyport((int)nfs_get_port(ai->ai_addr), "udp");
336 if (se != NULL && retry_cnt < 100) {
349 main(int argc, char **argv)
351 int c, sock, force = 0;
354 progname = strrchr(argv[0], '/');
355 if (progname != NULL)
360 while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) {
369 opt_max_retry = atoi(optarg) * 60;
372 opt_update_state = false;
375 opt_srcport = optarg;
378 opt_srcaddr = optarg;
381 if (!nsm_setup_pathnames(argv[0], optarg))
391 usage: fprintf(stderr,
392 "Usage: %s -notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
393 " [-P /path/to/state/directory] [-v my_host_name]\n",
401 xlog_config(D_ALL, 1);
406 xlog(L_NOTICE, "Version " VERSION " starting");
408 if (nsm_is_default_parentdir()) {
409 if (record_pid() == 0 && force == 0 && opt_update_state) {
410 /* already run, don't try again */
411 xlog(L_NOTICE, "Already notifying clients; Exiting!");
416 if (opt_srcaddr != NULL) {
417 struct addrinfo *ai = NULL;
418 struct addrinfo hint = {
419 .ai_family = AF_UNSPEC,
420 .ai_flags = AI_NUMERICHOST,
423 if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
424 /* not a presentation address - use it */
425 strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
427 /* was a presentation address - look it up in
428 * /etc/hosts, so it can be used for my_name */
432 hint.ai_flags = AI_CANONNAME;
433 error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
435 xlog(L_ERROR, "Bind address %s is unusable: %s",
436 opt_srcaddr, gai_strerror(error));
439 strncpy(nsm_hostname, ai->ai_canonname,
440 sizeof(nsm_hostname));
445 (void)nsm_retire_monitored_hosts();
446 if (nsm_load_notify_list(smn_get_host) == 0) {
447 xlog(D_GENERAL, "No hosts to notify; exiting");
451 nsm_state = nsm_get_state(opt_update_state);
454 nsm_update_kernel_state(nsm_state);
457 xlog(L_NOTICE, "Backgrounding to notify hosts...\n");
459 if (daemon(0, 0) < 0) {
460 xlog(L_ERROR, "unable to background: %m");
469 sock = smn_create_socket(opt_srcaddr, opt_srcport);
473 if (!nsm_drop_privileges(-1))
481 while ((hp = hosts) != 0) {
483 xlog(L_NOTICE, "Unable to notify %s, giving up",
496 notify(const int sock)
501 failtime = time(NULL) + opt_max_retry;
505 time_t now = time(NULL);
506 unsigned int sent = 0;
510 if (failtime && now >= failtime)
513 while (hosts && ((wait = hosts->send_next - now) <= 0)) {
514 /* Never send more than 10 packets at once */
518 /* Remove queue head */
522 if (notify_host(sock, hp))
525 /* Set the timeout for this call, using an
526 exponential timeout strategy */
528 if ((hp->timeout <<= 1) > NSM_MAX_TIMEOUT)
529 hp->timeout = NSM_MAX_TIMEOUT;
530 hp->send_next = now + wait;
538 xlog(D_GENERAL, "Host %s due in %ld seconds",
547 if (poll(&pfd, 1, wait) != 1)
555 * Send notification to a single host
558 notify_host(int sock, struct nsm_host *host)
560 const char *my_name = (opt_srcaddr != NULL ?
561 nsm_hostname : host->my_name);
562 struct sockaddr *sap;
565 if (host->ai == NULL) {
566 host->ai = smn_lookup(host->name);
567 if (host->ai == NULL) {
568 xlog_warn("DNS resolution of %s failed; "
569 "retrying later", host->name);
574 /* If we retransmitted 4 times, reset the port to force
575 * a new portmap lookup (in case statd was restarted).
576 * We also rotate through multiple IP addresses at this
579 if (host->retries >= 4) {
580 /* don't rotate if there is only one addrinfo */
581 if (host->ai->ai_next != NULL) {
582 struct addrinfo *first = host->ai;
583 struct addrinfo **next = &host->ai;
585 /* remove the first entry from the list */
586 host->ai = first->ai_next;
587 first->ai_next = NULL;
588 /* find the end of the list */
589 next = &first->ai_next;
591 next = & (*next)->ai_next;
592 /* put first entry at end */
596 nfs_set_port(host->ai->ai_addr, 0);
600 sap = host->ai->ai_addr;
601 salen = host->ai->ai_addrlen;
603 if (nfs_get_port(sap) == 0)
604 host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
606 host->xid = nsm_xmit_notify(sock, sap, salen,
607 SM_PROG, my_name, nsm_state);
613 * Extract the returned port number and set up the SM_NOTIFY call.
616 recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
618 uint16_t port = nsm_recv_rpcbind(sap->sa_family, xdr);
620 host->send_next = time(NULL);
624 /* No binding for statd... */
625 xlog(D_GENERAL, "No statd on host %s", host->name);
626 host->timeout = NSM_MAX_TIMEOUT;
627 host->send_next += NSM_MAX_TIMEOUT;
629 nfs_set_port(sap, port);
630 if (host->timeout >= NSM_MAX_TIMEOUT / 4)
631 host->timeout = NSM_MAX_TIMEOUT / 4;
638 * Successful NOTIFY call. Server returns void.
640 * Try sending another SM_NOTIFY with an unqualified "my_name"
641 * argument. Reuse the port number. If "my_name" is already
642 * unqualified, we're done.
645 recv_notify_reply(struct nsm_host *host)
647 char *dot = strchr(host->my_name, '.');
651 host->send_next = time(NULL);
653 if (host->timeout >= NSM_MAX_TIMEOUT / 4)
654 host->timeout = NSM_MAX_TIMEOUT / 4;
657 xlog(D_GENERAL, "Host %s notified successfully", host->name);
658 smn_forget_host(host);
663 * Receive reply from remote host
669 struct sockaddr *sap;
670 char msgbuf[NSM_MAXMSGSIZE];
675 memset(msgbuf, 0 , sizeof(msgbuf));
676 msglen = recv(sock, msgbuf, sizeof(msgbuf), 0);
680 xlog(D_GENERAL, "Received packet...");
682 memset(&xdr, 0, sizeof(xdr));
683 xdrmem_create(&xdr, msgbuf, (unsigned int)msglen, XDR_DECODE);
684 xid = nsm_parse_reply(&xdr);
688 /* Before we look at the data, find the host struct for
690 if ((hp = find_host(xid)) == NULL)
693 sap = hp->ai->ai_addr;
694 if (nfs_get_port(sap) == 0)
695 recv_rpcbind_reply(sap, hp, &xdr);
697 recv_notify_reply(hp);
704 * Insert host into sorted list
707 insert_host(struct nsm_host *host)
709 struct nsm_host **where, *p;
712 while ((p = *where) != 0) {
713 /* Sort in ascending order of timeout */
714 if (host->send_next < p->send_next)
716 /* If we have the same timeout, put the
717 * most recently used host first.
718 * This makes sure that "recent" hosts
719 * get notified first.
721 if (host->send_next == p->send_next
722 && host->last_used > p->last_used)
732 * Find host given the XID
734 static struct nsm_host *
735 find_host(uint32_t xid)
737 struct nsm_host **where, *p;
740 while ((p = *where) != 0) {
751 * Record pid in /var/run/sm-notify.pid
752 * This file should remain until a reboot, even if the
754 * If file already exists, fail.
756 static int record_pid(void)
762 (void)snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
763 fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
767 len = write(fd, pid, strlen(pid));
768 if ((len < 0) || ((size_t)len != strlen(pid))) {
769 xlog_warn("Writing to pid file failed: errno %d (%m)",