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;
48 const char * mon_name;
59 static char nsm_hostname[SM_MAXSTRLEN + 1];
61 static int nsm_family = AF_INET;
62 static int opt_debug = 0;
63 static _Bool opt_update_state = true;
64 static unsigned int opt_max_retry = 15 * 60;
65 static char * opt_srcaddr = NULL;
66 static char * opt_srcport = NULL;
68 static void notify(const int sock);
69 static int notify_host(int, struct nsm_host *);
70 static void recv_reply(int);
71 static void insert_host(struct nsm_host *);
72 static struct nsm_host *find_host(uint32_t);
73 static int record_pid(void);
75 static struct nsm_host * hosts = NULL;
78 static struct addrinfo *
79 smn_lookup(const char *name)
81 struct addrinfo *ai = NULL;
82 struct addrinfo hint = {
83 .ai_family = (nsm_family == AF_INET ? AF_INET: AF_UNSPEC),
84 .ai_protocol = (int)IPPROTO_UDP,
88 error = getaddrinfo(name, NULL, &hint, &ai);
90 xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error));
97 #ifdef HAVE_GETNAMEINFO
99 smn_get_hostname(const struct sockaddr *sap, const socklen_t salen,
102 char buf[NI_MAXHOST];
105 error = getnameinfo(sap, salen, buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
107 xlog(L_ERROR, "my_name '%s' is unusable: %s",
108 name, gai_strerror(error));
113 #else /* !HAVE_GETNAMEINFO */
115 smn_get_hostname(const struct sockaddr *sap,
116 __attribute__ ((unused)) const socklen_t salen,
119 const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
120 const struct in_addr *addr = &sin->sin_addr;
123 if (sap->sa_family != AF_INET) {
124 xlog(L_ERROR, "my_name '%s' is unusable: Bad address family",
129 hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
131 xlog(L_ERROR, "my_name '%s' is unusable: %s",
132 name, hstrerror(h_errno));
135 return strdup(hp->h_name);
137 #endif /* !HAVE_GETNAMEINFO */
140 * Presentation addresses are converted to their canonical hostnames.
141 * If the IP address does not map to a hostname, it is an error:
142 * we never send a presentation address as the argument of SM_NOTIFY.
144 * If "name" is not a presentation address, it is left alone. This
145 * allows the administrator some flexibility if DNS isn't configured
146 * exactly how sm-notify prefers it.
148 * Returns NUL-terminated C string containing the result, or NULL
149 * if the canonical name doesn't exist or cannot be determined.
150 * The caller must free the result with free(3).
154 smn_verify_my_name(const char *name)
156 struct addrinfo *ai = NULL;
157 struct addrinfo hint = {
158 #ifdef IPV6_SUPPORTED
159 .ai_family = AF_UNSPEC,
160 #else /* !IPV6_SUPPORTED */
161 .ai_family = AF_INET,
162 #endif /* !IPV6_SUPPORTED */
163 .ai_flags = AI_NUMERICHOST,
168 error = getaddrinfo(name, NULL, &hint, &ai);
171 /* @name was a presentation address */
172 retval = smn_get_hostname(ai->ai_addr, ai->ai_addrlen, name);
178 /* @name was not a presentation address */
179 retval = strdup(name);
182 xlog(L_ERROR, "my_name '%s' is unusable: %s",
183 name, gai_strerror(error));
187 xlog(D_GENERAL, "Canonical name for my_name '%s': %s",
193 static struct nsm_host *
194 smn_alloc_host(const char *hostname, const char *mon_name,
195 const char *my_name, const time_t timestamp)
197 struct nsm_host *host;
199 host = calloc(1, sizeof(*host));
204 * mon_name and my_name are preserved so sm-notify can
205 * find the right monitor record to remove when it is
206 * done processing this host.
208 host->name = strdup(hostname);
209 host->mon_name = (const char *)strdup(mon_name);
210 host->my_name = (const char *)strdup(my_name);
211 host->notify_arg = strdup(opt_srcaddr != NULL ?
212 nsm_hostname : my_name);
213 if (host->name == NULL ||
214 host->mon_name == NULL ||
215 host->my_name == NULL ||
216 host->notify_arg == NULL) {
217 free(host->notify_arg);
218 free((void *)host->my_name);
219 free((void *)host->mon_name);
225 host->last_used = timestamp;
226 host->timeout = NSM_TIMEOUT;
227 host->retries = 100; /* force address retry */
232 xlog_warn("Unable to allocate memory");
236 static void smn_forget_host(struct nsm_host *host)
238 xlog(D_CALL, "Removing %s (%s, %s) from notify list",
239 host->name, host->mon_name, host->my_name);
241 nsm_delete_notified_host(host->name, host->mon_name, host->my_name);
243 free(host->notify_arg);
244 free((void *)host->my_name);
245 free((void *)host->mon_name);
248 freeaddrinfo(host->ai);
254 smn_get_host(const char *hostname,
255 __attribute__ ((unused)) const struct sockaddr *sap,
256 const struct mon *m, const time_t timestamp)
258 struct nsm_host *host;
260 host = smn_alloc_host(hostname,
261 m->mon_id.mon_name, m->mon_id.my_id.my_name, timestamp);
269 #ifdef IPV6_SUPPORTED
270 static int smn_socket(void)
275 * Use an AF_INET socket if IPv6 is disabled on the
278 sock = socket(AF_INET6, SOCK_DGRAM, 0);
280 if (errno != EAFNOSUPPORT) {
281 xlog(L_ERROR, "Failed to create RPC socket: %m");
284 sock = socket(AF_INET, SOCK_DGRAM, 0);
286 xlog(L_ERROR, "Failed to create RPC socket: %m");
290 nsm_family = AF_INET6;
292 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
293 xlog(L_ERROR, "fcntl(3) on RPC socket failed: %m");
298 * TI-RPC over IPv6 (udp6/tcp6) does not handle IPv4. However,
299 * since sm-notify open-codes all of its RPC support, it can
300 * use a single socket and let the local network stack provide
301 * the correct mapping between address families automatically.
302 * This is the same thing that is done in the kernel.
304 if (nsm_family == AF_INET6) {
306 socklen_t zerolen = (socklen_t)sizeof(zero);
308 if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
309 (char *)&zero, zerolen) == -1) {
310 xlog(L_ERROR, "setsockopt(3) on RPC socket failed: %m");
321 #else /* !IPV6_SUPPORTED */
322 static int smn_socket(void)
326 sock = socket(AF_INET, SOCK_DGRAM, 0);
328 xlog(L_ERROR, "Failed to create RPC socket: %m");
332 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
333 xlog(L_ERROR, "fcntl(3) on RPC socket failed: %m");
340 #endif /* !IPV6_SUPPORTED */
343 * If admin specified a source address or srcport, then convert those
344 * to a sockaddr and return it. Otherwise, return an ANYADDR address.
347 static struct addrinfo *
348 smn_bind_address(const char *srcaddr, const char *srcport)
350 struct addrinfo *ai = NULL;
351 struct addrinfo hint = {
352 .ai_flags = AI_NUMERICSERV,
353 .ai_family = nsm_family,
354 .ai_protocol = (int)IPPROTO_UDP,
359 hint.ai_flags |= AI_PASSIVE;
361 /* Do not allow "node" and "service" parameters both to be NULL */
363 error = getaddrinfo(srcaddr, "", &hint, &ai);
365 error = getaddrinfo(srcaddr, srcport, &hint, &ai);
368 "Invalid bind address or port for RPC socket: %s",
369 gai_strerror(error));
378 smn_bindresvport(int sock, struct sockaddr *sap)
380 return bindresvport_sa(sock, sap);
383 #else /* !HAVE_LIBTIRPC */
385 smn_bindresvport(int sock, struct sockaddr *sap)
387 if (sap->sa_family != AF_INET) {
388 errno = EAFNOSUPPORT;
392 return bindresvport(sock, (struct sockaddr_in *)(char *)sap);
394 #endif /* !HAVE_LIBTIRPC */
397 * Prepare a socket for sending RPC requests
399 * Returns a bound datagram socket file descriptor, or -1 if
403 smn_create_socket(const char *srcaddr, const char *srcport)
405 int sock, retry_cnt = 0;
413 ai = smn_bind_address(srcaddr, srcport);
419 /* Use source port if provided on the command line,
420 * otherwise use bindresvport */
422 if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
423 xlog(L_ERROR, "Failed to bind RPC socket: %m");
431 if (smn_bindresvport(sock, ai->ai_addr) == -1) {
433 "bindresvport on RPC socket failed: %m");
439 /* try to avoid known ports */
440 se = getservbyport((int)nfs_get_port(ai->ai_addr), "udp");
441 if (se != NULL && retry_cnt < 100) {
454 main(int argc, char **argv)
456 int c, sock, force = 0;
459 progname = strrchr(argv[0], '/');
460 if (progname != NULL)
465 while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) {
474 opt_max_retry = atoi(optarg) * 60;
477 opt_update_state = false;
480 opt_srcport = optarg;
483 opt_srcaddr = optarg;
486 if (!nsm_setup_pathnames(argv[0], optarg))
496 usage: fprintf(stderr,
497 "Usage: %s -notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
498 " [-P /path/to/state/directory] [-v my_host_name]\n",
506 xlog_config(D_ALL, 1);
513 xlog(L_NOTICE, "Version " VERSION " starting");
515 if (nsm_is_default_parentdir()) {
516 if (record_pid() == 0 && force == 0 && opt_update_state) {
517 /* already run, don't try again */
518 xlog(L_NOTICE, "Already notifying clients; Exiting!");
523 if (opt_srcaddr != NULL) {
526 name = smn_verify_my_name(opt_srcaddr);
530 strncpy(nsm_hostname, name, sizeof(nsm_hostname));
534 (void)nsm_retire_monitored_hosts();
535 if (nsm_load_notify_list(smn_get_host) == 0) {
536 xlog(D_GENERAL, "No hosts to notify; exiting");
540 nsm_state = nsm_get_state(opt_update_state);
543 nsm_update_kernel_state(nsm_state);
546 xlog(L_NOTICE, "Backgrounding to notify hosts...\n");
548 if (daemon(0, 0) < 0) {
549 xlog(L_ERROR, "unable to background: %m");
558 sock = smn_create_socket(opt_srcaddr, opt_srcport);
562 if (!nsm_drop_privileges(-1))
570 while ((hp = hosts) != 0) {
572 xlog(L_NOTICE, "Unable to notify %s, giving up",
585 notify(const int sock)
590 failtime = time(NULL) + opt_max_retry;
594 time_t now = time(NULL);
595 unsigned int sent = 0;
599 if (failtime && now >= failtime)
602 while (hosts && ((wait = hosts->send_next - now) <= 0)) {
603 /* Never send more than 10 packets at once */
607 /* Remove queue head */
611 if (notify_host(sock, hp))
614 /* Set the timeout for this call, using an
615 exponential timeout strategy */
617 if ((hp->timeout <<= 1) > NSM_MAX_TIMEOUT)
618 hp->timeout = NSM_MAX_TIMEOUT;
619 hp->send_next = now + wait;
627 xlog(D_GENERAL, "Host %s due in %ld seconds",
636 if (poll(&pfd, 1, wait) != 1)
644 * Send notification to a single host
647 notify_host(int sock, struct nsm_host *host)
649 struct sockaddr *sap;
652 if (host->ai == NULL) {
653 host->ai = smn_lookup(host->name);
654 if (host->ai == NULL) {
655 xlog_warn("DNS resolution of %s failed; "
656 "retrying later", host->name);
661 /* If we retransmitted 4 times, reset the port to force
662 * a new portmap lookup (in case statd was restarted).
663 * We also rotate through multiple IP addresses at this
666 if (host->retries >= 4) {
667 /* don't rotate if there is only one addrinfo */
668 if (host->ai->ai_next != NULL) {
669 struct addrinfo *first = host->ai;
670 struct addrinfo **next = &host->ai;
672 /* remove the first entry from the list */
673 host->ai = first->ai_next;
674 first->ai_next = NULL;
675 /* find the end of the list */
676 next = &first->ai_next;
678 next = & (*next)->ai_next;
679 /* put first entry at end */
683 nfs_set_port(host->ai->ai_addr, 0);
687 sap = host->ai->ai_addr;
688 salen = host->ai->ai_addrlen;
690 if (nfs_get_port(sap) == 0)
691 host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
693 host->xid = nsm_xmit_notify(sock, sap, salen,
694 SM_PROG, host->notify_arg, nsm_state);
700 smn_defer(struct nsm_host *host)
703 host->send_next = time(NULL) + NSM_MAX_TIMEOUT;
704 host->timeout = NSM_MAX_TIMEOUT;
709 smn_schedule(struct nsm_host *host)
713 host->send_next = time(NULL);
714 host->timeout = NSM_TIMEOUT;
719 * Extract the returned port number and set up the SM_NOTIFY call.
722 recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
724 uint16_t port = nsm_recv_rpcbind(sap->sa_family, xdr);
727 /* No binding for statd... */
728 xlog(D_GENERAL, "No statd on host %s", host->name);
731 xlog(D_GENERAL, "Processing rpcbind reply for %s (port %u)",
733 nfs_set_port(sap, port);
739 * Successful NOTIFY call. Server returns void.
741 * Try sending another SM_NOTIFY with an unqualified "my_name"
742 * argument. Reuse the port number. If "my_name" is already
743 * unqualified, we're done.
746 recv_notify_reply(struct nsm_host *host)
748 char *dot = strchr(host->notify_arg, '.');
754 xlog(D_GENERAL, "Host %s notified successfully", host->name);
755 smn_forget_host(host);
760 * Receive reply from remote host
766 struct sockaddr *sap;
767 char msgbuf[NSM_MAXMSGSIZE];
772 memset(msgbuf, 0 , sizeof(msgbuf));
773 msglen = recv(sock, msgbuf, sizeof(msgbuf), 0);
777 xlog(D_GENERAL, "Received packet...");
779 memset(&xdr, 0, sizeof(xdr));
780 xdrmem_create(&xdr, msgbuf, (unsigned int)msglen, XDR_DECODE);
781 xid = nsm_parse_reply(&xdr);
785 /* Before we look at the data, find the host struct for
787 if ((hp = find_host(xid)) == NULL)
790 sap = hp->ai->ai_addr;
791 if (nfs_get_port(sap) == 0)
792 recv_rpcbind_reply(sap, hp, &xdr);
794 recv_notify_reply(hp);
801 * Insert host into notification list, sorted by next send time
804 insert_host(struct nsm_host *host)
806 struct nsm_host **where, *p;
809 while ((p = *where) != 0) {
810 /* Sort in ascending order of timeout */
811 if (host->send_next < p->send_next)
813 /* If we have the same timeout, put the
814 * most recently used host first.
815 * This makes sure that "recent" hosts
816 * get notified first.
818 if (host->send_next == p->send_next
819 && host->last_used > p->last_used)
826 xlog(D_GENERAL, "Added host %s to notify list", host->name);
830 * Find host given the XID
832 static struct nsm_host *
833 find_host(uint32_t xid)
835 struct nsm_host **where, *p;
838 while ((p = *where) != 0) {
849 * Record pid in /var/run/sm-notify.pid
850 * This file should remain until a reboot, even if the
852 * If file already exists, fail.
854 static int record_pid(void)
860 (void)snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
861 fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
865 len = write(fd, pid, strlen(pid));
866 if ((len < 0) || ((size_t)len != strlen(pid))) {
867 xlog_warn("Writing to pid file failed: errno %d (%m)",