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 #define NSM_MAX_TIMEOUT 120 /* don't make this too big */
40 struct nsm_host * next;
50 static char nsm_hostname[256];
52 static int opt_debug = 0;
53 static _Bool opt_update_state = true;
54 static unsigned int opt_max_retry = 15 * 60;
55 static char * opt_srcaddr = 0;
56 static uint16_t opt_srcport = 0;
58 static void notify(const int sock);
59 static int notify_host(int, struct nsm_host *);
60 static void recv_reply(int);
61 static void insert_host(struct nsm_host *);
62 static struct nsm_host *find_host(uint32_t);
63 static int record_pid(void);
65 static struct nsm_host * hosts = NULL;
67 static struct addrinfo *smn_lookup(const char *name)
69 struct addrinfo *ai, hint = {
70 #if HAVE_DECL_AI_ADDRCONFIG
71 .ai_flags = AI_ADDRCONFIG,
72 #endif /* HAVE_DECL_AI_ADDRCONFIG */
74 .ai_protocol = IPPROTO_UDP,
78 error = getaddrinfo(name, NULL, &hint, &ai);
80 xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error));
88 static struct nsm_host *
89 smn_alloc_host(const char *hostname, const time_t timestamp)
91 struct nsm_host *host;
93 host = calloc(1, sizeof(*host));
97 host->name = strdup(hostname);
98 if (host->name == NULL) {
103 host->last_used = timestamp;
104 host->timeout = NSM_TIMEOUT;
105 host->retries = 100; /* force address retry */
110 xlog_warn("Unable to allocate memory");
114 static void smn_forget_host(struct nsm_host *host)
116 xlog(D_CALL, "Removing %s from notify list", host->name);
118 nsm_delete_notified_host(host->name);
122 freeaddrinfo(host->ai);
128 smn_get_host(const char *hostname,
129 __attribute__ ((unused)) const struct sockaddr *sap,
130 __attribute__ ((unused)) const struct mon *m,
131 const time_t timestamp)
133 struct nsm_host *host;
135 host = smn_alloc_host(hostname, timestamp);
140 xlog(D_GENERAL, "Added host %s to notify list", hostname);
145 * Prepare a socket for sending RPC requests
147 * Returns a bound datagram socket file descriptor, or -1 if
151 smn_create_socket(const char *srcaddr, const uint16_t srcport)
153 struct sockaddr_storage address;
154 struct sockaddr *local_addr = (struct sockaddr *)&address;
155 int sock, retry_cnt = 0;
158 sock = socket(AF_INET, SOCK_DGRAM, 0);
160 xlog(L_ERROR, "Failed to create RPC socket: %m");
163 fcntl(sock, F_SETFL, O_NONBLOCK);
165 memset(&address, 0, sizeof(address));
166 local_addr->sa_family = AF_INET; /* Default to IPv4 */
168 /* Bind source IP if provided on command line */
170 struct addrinfo *ai = smn_lookup(srcaddr);
173 "Not a valid hostname or address: \"%s\"",
179 /* We know it's IPv4 at this point */
180 memcpy(local_addr, ai->ai_addr, ai->ai_addrlen);
185 /* Use source port if provided on the command line,
186 * otherwise use bindresvport */
188 nfs_set_port(local_addr, srcport);
189 if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) {
190 xlog(L_ERROR, "Failed to bind RPC socket: %m");
196 struct sockaddr_in *sin = (struct sockaddr_in *)local_addr;
197 (void) bindresvport(sock, sin);
198 /* try to avoid known ports */
199 se = getservbyport(sin->sin_port, "udp");
200 if (se && retry_cnt < 100) {
211 main(int argc, char **argv)
213 int c, sock, force = 0;
216 progname = strrchr(argv[0], '/');
217 if (progname != NULL)
222 while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) {
231 opt_max_retry = atoi(optarg) * 60;
234 opt_update_state = false;
237 opt_srcport = atoi(optarg);
240 opt_srcaddr = optarg;
243 if (!nsm_setup_pathnames(argv[0], optarg))
253 usage: fprintf(stderr,
254 "Usage: %s -notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
255 " [-P /path/to/state/directory] [-v my_host_name]\n",
263 xlog_config(D_ALL, 1);
268 xlog(L_NOTICE, "Version " VERSION " starting");
270 if (nsm_is_default_parentdir()) {
271 if (record_pid() == 0 && force == 0 && opt_update_state) {
272 /* already run, don't try again */
273 xlog(L_NOTICE, "Already notifying clients; Exiting!");
279 strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
281 if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
282 xlog(L_ERROR, "Failed to obtain name of local host: %m");
286 (void)nsm_retire_monitored_hosts();
287 if (nsm_load_notify_list(smn_get_host) == 0) {
288 xlog(D_GENERAL, "No hosts to notify; exiting");
292 nsm_state = nsm_get_state(opt_update_state);
295 nsm_update_kernel_state(nsm_state);
298 xlog(L_NOTICE, "Backgrounding to notify hosts...\n");
300 if (daemon(0, 0) < 0) {
301 xlog(L_ERROR, "unable to background: %m");
310 sock = smn_create_socket(opt_srcaddr, opt_srcport);
314 if (!nsm_drop_privileges(-1))
322 while ((hp = hosts) != 0) {
324 xlog(L_NOTICE, "Unable to notify %s, giving up",
337 notify(const int sock)
342 failtime = time(NULL) + opt_max_retry;
346 time_t now = time(NULL);
347 unsigned int sent = 0;
351 if (failtime && now >= failtime)
354 while (hosts && ((wait = hosts->send_next - now) <= 0)) {
355 /* Never send more than 10 packets at once */
359 /* Remove queue head */
363 if (notify_host(sock, hp))
366 /* Set the timeout for this call, using an
367 exponential timeout strategy */
369 if ((hp->timeout <<= 1) > NSM_MAX_TIMEOUT)
370 hp->timeout = NSM_MAX_TIMEOUT;
371 hp->send_next = now + wait;
379 xlog(D_GENERAL, "Host %s due in %ld seconds",
388 if (poll(&pfd, 1, wait) != 1)
396 * Send notification to a single host
399 notify_host(int sock, struct nsm_host *host)
401 struct sockaddr *sap;
404 if (host->ai == NULL) {
405 host->ai = smn_lookup(host->name);
406 if (host->ai == NULL) {
407 xlog_warn("DNS resolution of %s failed; "
408 "retrying later", host->name);
413 /* If we retransmitted 4 times, reset the port to force
414 * a new portmap lookup (in case statd was restarted).
415 * We also rotate through multiple IP addresses at this
418 if (host->retries >= 4) {
419 /* don't rotate if there is only one addrinfo */
420 if (host->ai->ai_next != NULL) {
421 struct addrinfo *first = host->ai;
422 struct addrinfo **next = &host->ai;
424 /* remove the first entry from the list */
425 host->ai = first->ai_next;
426 first->ai_next = NULL;
427 /* find the end of the list */
428 next = &first->ai_next;
430 next = & (*next)->ai_next;
431 /* put first entry at end */
435 nfs_set_port(host->ai->ai_addr, 0);
439 sap = host->ai->ai_addr;
440 salen = host->ai->ai_addrlen;
442 if (nfs_get_port(sap) == 0)
443 host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
445 host->xid = nsm_xmit_notify(sock, sap, salen,
446 SM_PROG, nsm_hostname, nsm_state);
452 * Extract the returned port number and set up the SM_NOTIFY call.
455 recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
457 uint16_t port = nsm_recv_rpcbind(sap->sa_family, xdr);
459 host->send_next = time(NULL);
463 /* No binding for statd... */
464 xlog(D_GENERAL, "No statd on host %s", host->name);
465 host->timeout = NSM_MAX_TIMEOUT;
466 host->send_next += NSM_MAX_TIMEOUT;
468 nfs_set_port(sap, port);
469 if (host->timeout >= NSM_MAX_TIMEOUT / 4)
470 host->timeout = NSM_MAX_TIMEOUT / 4;
477 * Successful NOTIFY call. Server returns void, so nothing
478 * we need to do here.
481 recv_notify_reply(struct nsm_host *host)
483 xlog(D_GENERAL, "Host %s notified successfully", host->name);
485 smn_forget_host(host);
489 * Receive reply from remote host
495 struct sockaddr *sap;
496 char msgbuf[NSM_MAXMSGSIZE];
501 memset(msgbuf, 0 , sizeof(msgbuf));
502 msglen = recv(sock, msgbuf, sizeof(msgbuf), 0);
506 xlog(D_GENERAL, "Received packet...");
508 memset(&xdr, 0, sizeof(xdr));
509 xdrmem_create(&xdr, msgbuf, (unsigned int)msglen, XDR_DECODE);
510 xid = nsm_parse_reply(&xdr);
514 /* Before we look at the data, find the host struct for
516 if ((hp = find_host(xid)) == NULL)
519 sap = hp->ai->ai_addr;
520 if (nfs_get_port(sap) == 0)
521 recv_rpcbind_reply(sap, hp, &xdr);
523 recv_notify_reply(hp);
530 * Insert host into sorted list
533 insert_host(struct nsm_host *host)
535 struct nsm_host **where, *p;
538 while ((p = *where) != 0) {
539 /* Sort in ascending order of timeout */
540 if (host->send_next < p->send_next)
542 /* If we have the same timeout, put the
543 * most recently used host first.
544 * This makes sure that "recent" hosts
545 * get notified first.
547 if (host->send_next == p->send_next
548 && host->last_used > p->last_used)
558 * Find host given the XID
560 static struct nsm_host *
561 find_host(uint32_t xid)
563 struct nsm_host **where, *p;
566 while ((p = *where) != 0) {
577 * Record pid in /var/run/sm-notify.pid
578 * This file should remain until a reboot, even if the
580 * If file already exists, fail.
582 static int record_pid(void)
588 (void)snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
589 fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
593 len = write(fd, pid, strlen(pid));
594 if ((len < 0) || ((size_t)len != strlen(pid))) {
595 xlog_warn("Writing to pid file failed: errno %d (%m)",