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>
33 # define BASEDIR NFS_STATEDIR
35 # define BASEDIR "/var/lib/nfs"
39 #define DEFAULT_SM_STATE_PATH BASEDIR "/state"
40 #define DEFAULT_SM_DIR_PATH BASEDIR "/sm"
41 #define DEFAULT_SM_BAK_PATH DEFAULT_SM_DIR_PATH ".bak"
43 char *_SM_BASE_PATH
= BASEDIR
;
44 char *_SM_STATE_PATH
= DEFAULT_SM_STATE_PATH
;
45 char *_SM_DIR_PATH
= DEFAULT_SM_DIR_PATH
;
46 char *_SM_BAK_PATH
= DEFAULT_SM_BAK_PATH
;
48 #define NSM_PROG 100024
49 #define NSM_PROGRAM 100024
53 #define NSM_MAX_TIMEOUT 120 /* don't make this too big */
54 #define MAXMSGSIZE 256
57 struct nsm_host
* next
;
60 struct sockaddr_storage addr
;
69 static char nsm_hostname
[256];
70 static uint32_t nsm_state
;
71 static int opt_debug
= 0;
72 static int opt_quiet
= 0;
73 static int opt_update_state
= 1;
74 static unsigned int opt_max_retry
= 15 * 60;
75 static char * opt_srcaddr
= 0;
76 static uint16_t opt_srcport
= 0;
77 static int log_syslog
= 0;
79 static unsigned int nsm_get_state(int);
80 static void notify(void);
81 static int notify_host(int, struct nsm_host
*);
82 static void recv_reply(int);
83 static void backup_hosts(const char *, const char *);
84 static void get_hosts(const char *);
85 static void insert_host(struct nsm_host
*);
86 static struct nsm_host
*find_host(uint32_t);
87 static void nsm_log(int fac
, const char *fmt
, ...);
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
;
95 * Address handling utilities
98 static unsigned short smn_get_port(const struct sockaddr
*sap
)
100 switch (sap
->sa_family
) {
102 return ntohs(((struct sockaddr_in
*)sap
)->sin_port
);
104 return ntohs(((struct sockaddr_in6
*)sap
)->sin6_port
);
109 static void smn_set_port(struct sockaddr
*sap
, const unsigned short port
)
111 switch (sap
->sa_family
) {
113 ((struct sockaddr_in
*)sap
)->sin_port
= htons(port
);
116 ((struct sockaddr_in6
*)sap
)->sin6_port
= htons(port
);
121 static struct addrinfo
*smn_lookup(const sa_family_t family
, const char *name
)
123 struct addrinfo
*ai
, hint
= {
125 .ai_protocol
= IPPROTO_UDP
,
128 if (getaddrinfo(name
, NULL
, &hint
, &ai
) != 0)
134 static void smn_forget_host(struct nsm_host
*host
)
140 freeaddrinfo(host
->ai
);
146 main(int argc
, char **argv
)
151 while ((c
= getopt(argc
, argv
, "dm:np:v:qP:f")) != -1) {
160 opt_max_retry
= atoi(optarg
) * 60;
163 opt_update_state
= 0;
166 opt_srcport
= atoi(optarg
);
169 opt_srcaddr
= optarg
;
175 _SM_BASE_PATH
= strdup(optarg
);
176 _SM_STATE_PATH
= malloc(strlen(optarg
)+1+sizeof("state"));
177 _SM_DIR_PATH
= malloc(strlen(optarg
)+1+sizeof("sm"));
178 _SM_BAK_PATH
= malloc(strlen(optarg
)+1+sizeof("sm.bak"));
179 if (_SM_BASE_PATH
== NULL
||
180 _SM_STATE_PATH
== NULL
||
181 _SM_DIR_PATH
== NULL
||
182 _SM_BAK_PATH
== NULL
) {
183 nsm_log(LOG_ERR
, "unable to allocate memory");
186 strcat(strcpy(_SM_STATE_PATH
, _SM_BASE_PATH
), "/state");
187 strcat(strcpy(_SM_DIR_PATH
, _SM_BASE_PATH
), "/sm");
188 strcat(strcpy(_SM_BAK_PATH
, _SM_BASE_PATH
), "/sm.bak");
197 usage
: fprintf(stderr
,
198 "Usage: sm-notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
199 " [-P /path/to/state/directory] [-v my_host_name]\n");
204 openlog("sm-notify", LOG_PID
, LOG_DAEMON
);
206 if (strcmp(_SM_BASE_PATH
, BASEDIR
) == 0) {
207 if (record_pid() == 0 && force
== 0 && opt_update_state
== 1) {
208 /* already run, don't try again */
209 nsm_log(LOG_NOTICE
, "Already notifying clients; Exiting!");
215 strncpy(nsm_hostname
, opt_srcaddr
, sizeof(nsm_hostname
)-1);
217 if (gethostname(nsm_hostname
, sizeof(nsm_hostname
)) < 0) {
218 nsm_log(LOG_ERR
, "Failed to obtain name of local host: %s",
223 backup_hosts(_SM_DIR_PATH
, _SM_BAK_PATH
);
224 get_hosts(_SM_BAK_PATH
);
226 /* If there are not hosts to notify, just exit */
228 nsm_log(LOG_DEBUG
, "No hosts to notify; exiting");
232 /* Get and update the NSM state. This will call sync() */
233 nsm_state
= nsm_get_state(opt_update_state
);
234 set_kernel_nsm_state(nsm_state
);
238 printf("Backgrounding to notify hosts...\n");
240 if (daemon(0, 0) < 0) {
241 nsm_log(LOG_ERR
, "unable to background: %s",
256 while ((hp
= hosts
) != 0) {
259 "Unable to notify %s, giving up",
274 struct sockaddr_storage address
;
275 struct sockaddr
*local_addr
= (struct sockaddr
*)&address
;
281 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
283 nsm_log(LOG_ERR
, "Failed to create RPC socket: %s",
287 fcntl(sock
, F_SETFL
, O_NONBLOCK
);
289 memset(&address
, 0, sizeof(address
));
290 local_addr
->sa_family
= AF_INET
; /* Default to IPv4 */
292 /* Bind source IP if provided on command line */
294 struct addrinfo
*ai
= smn_lookup(AF_INET
, opt_srcaddr
);
297 "Not a valid hostname or address: \"%s\"",
302 /* We know it's IPv4 at this point */
303 memcpy(local_addr
, ai
->ai_addr
, ai
->ai_addrlen
);
308 /* Use source port if provided on the command line,
309 * otherwise use bindresvport */
311 smn_set_port(local_addr
, opt_srcport
);
312 if (bind(sock
, local_addr
, sizeof(struct sockaddr_in
)) < 0) {
313 nsm_log(LOG_ERR
, "Failed to bind RPC socket: %s",
319 struct sockaddr_in
*sin
= (struct sockaddr_in
*)local_addr
;
320 (void) bindresvport(sock
, sin
);
321 /* try to avoid known ports */
322 se
= getservbyport(sin
->sin_port
, "udp");
323 if (se
&& retry_cnt
< 100) {
331 failtime
= time(NULL
) + opt_max_retry
;
337 time_t now
= time(NULL
);
338 unsigned int sent
= 0;
342 if (failtime
&& now
>= failtime
)
345 while (hosts
&& ((wait
= hosts
->send_next
- now
) <= 0)) {
346 /* Never send more than 10 packets at once */
350 /* Remove queue head */
354 if (notify_host(sock
, hp
))
357 /* Set the timeout for this call, using an
358 exponential timeout strategy */
360 if ((hp
->timeout
<<= 1) > NSM_MAX_TIMEOUT
)
361 hp
->timeout
= NSM_MAX_TIMEOUT
;
362 hp
->send_next
= now
+ wait
;
370 nsm_log(LOG_DEBUG
, "Host %s due in %ld seconds",
379 if (poll(&pfd
, 1, wait
) != 1)
387 * Send notification to a single host
390 notify_host(int sock
, struct nsm_host
*host
)
392 struct sockaddr_storage address
;
393 struct sockaddr
*dest
= (struct sockaddr
*)&address
;
394 socklen_t destlen
= sizeof(address
);
395 static unsigned int xid
= 0;
396 uint32_t msgbuf
[MAXMSGSIZE
], *p
;
400 xid
= getpid() + time(NULL
);
404 if (host
->ai
== NULL
) {
405 host
->ai
= smn_lookup(AF_UNSPEC
, host
->name
);
406 if (host
->ai
== NULL
) {
408 "%s doesn't seem to be a valid address,"
409 " skipped", host
->name
);
410 smn_forget_host(host
);
415 memset(msgbuf
, 0, sizeof(msgbuf
));
417 *p
++ = htonl(host
->xid
);
421 /* If we retransmitted 4 times, reset the port to force
422 * a new portmap lookup (in case statd was restarted).
423 * We also rotate through multiple IP addresses at this
426 if (host
->retries
>= 4) {
427 struct addrinfo
*first
= host
->ai
;
428 struct addrinfo
**next
= &host
->ai
;
430 /* remove the first entry from the list */
431 host
->ai
= first
->ai_next
;
432 first
->ai_next
= NULL
;
433 /* find the end of the list */
434 next
= &first
->ai_next
;
436 next
= & (*next
)->ai_next
;
437 /* put first entry at end */
439 memcpy(&host
->addr
, first
->ai_addr
, first
->ai_addrlen
);
440 smn_set_port((struct sockaddr
*)&host
->addr
, 0);
444 memcpy(dest
, &host
->addr
, destlen
);
445 if (smn_get_port(dest
) == 0) {
446 /* Build a PMAP packet */
447 nsm_log(LOG_DEBUG
, "Sending portmap query to %s", host
->name
);
449 smn_set_port(dest
, 111);
450 *p
++ = htonl(100000);
458 *p
++ = htonl(NSM_PROGRAM
);
459 *p
++ = htonl(NSM_VERSION
);
460 *p
++ = htonl(IPPROTO_UDP
);
463 /* Build an SM_NOTIFY packet */
464 nsm_log(LOG_DEBUG
, "Sending SM_NOTIFY to %s", host
->name
);
466 *p
++ = htonl(NSM_PROGRAM
);
467 *p
++ = htonl(NSM_VERSION
);
468 *p
++ = htonl(NSM_NOTIFY
);
475 len
= strlen(nsm_hostname
);
477 memcpy(p
, nsm_hostname
, len
);
479 *p
++ = htonl(nsm_state
);
481 len
= (p
- msgbuf
) << 2;
483 if (sendto(sock
, msgbuf
, len
, 0, dest
, destlen
) < 0)
484 nsm_log(LOG_WARNING
, "Sending Reboot Notification to "
485 "'%s' failed: errno %d (%s)", host
->name
, errno
, strerror(errno
));
491 * Receive reply from remote host
497 struct sockaddr
*sap
;
498 uint32_t msgbuf
[MAXMSGSIZE
], *p
, *end
;
502 res
= recv(sock
, msgbuf
, sizeof(msgbuf
), 0);
506 nsm_log(LOG_DEBUG
, "Received packet...");
509 end
= p
+ (res
>> 2);
512 if (*p
++ != htonl(1) /* must be REPLY */
513 || *p
++ != htonl(0) /* must be ACCEPTED */
514 || *p
++ != htonl(0) /* must be NULL verifier */
516 || *p
++ != htonl(0)) /* must be SUCCESS */
519 /* Before we look at the data, find the host struct for
521 if ((hp
= find_host(xid
)) == NULL
)
523 sap
= (struct sockaddr
*)&hp
->addr
;
525 if (smn_get_port(sap
) == 0) {
526 /* This was a portmap request */
533 hp
->send_next
= time(NULL
);
535 /* No binding for statd. Delay the next
536 * portmap query for max timeout */
537 nsm_log(LOG_DEBUG
, "No statd on %s", hp
->name
);
538 hp
->timeout
= NSM_MAX_TIMEOUT
;
539 hp
->send_next
+= NSM_MAX_TIMEOUT
;
541 smn_set_port(sap
, port
);
542 if (hp
->timeout
>= NSM_MAX_TIMEOUT
/ 4)
543 hp
->timeout
= NSM_MAX_TIMEOUT
/ 4;
547 /* Successful NOTIFY call. Server returns void,
548 * so nothing we need to do here (except
549 * check that we didn't read past the end of the
553 nsm_log(LOG_DEBUG
, "Host %s notified successfully",
560 fail
: /* Re-insert the host */
565 * Back up all hosts from the sm directory to sm.bak
568 backup_hosts(const char *dirname
, const char *bakname
)
573 if (!(dir
= opendir(dirname
))) {
575 "Failed to open %s: %s", dirname
, strerror(errno
));
579 while ((de
= readdir(dir
)) != NULL
) {
580 char src
[1024], dst
[1024];
582 if (de
->d_name
[0] == '.')
585 snprintf(src
, sizeof(src
), "%s/%s", dirname
, de
->d_name
);
586 snprintf(dst
, sizeof(dst
), "%s/%s", bakname
, de
->d_name
);
587 if (rename(src
, dst
) < 0) {
589 "Failed to rename %s -> %s: %m",
597 * Get all entries from sm.bak and convert them to host entries
600 get_hosts(const char *dirname
)
602 struct nsm_host
*host
;
606 if (!(dir
= opendir(dirname
))) {
608 "Failed to open %s: %s", dirname
, strerror(errno
));
613 while ((de
= readdir(dir
)) != NULL
) {
617 if (de
->d_name
[0] == '.')
620 host
= calloc(1, sizeof(*host
));
622 nsm_log(LOG_WARNING
, "Unable to allocate memory");
626 snprintf(path
, sizeof(path
), "%s/%s", dirname
, de
->d_name
);
627 if (stat(path
, &stb
) < 0)
630 host
->last_used
= stb
.st_mtime
;
631 host
->timeout
= NSM_TIMEOUT
;
632 host
->path
= strdup(path
);
633 host
->name
= strdup(de
->d_name
);
634 host
->retries
= 100; /* force address retry */
646 * Insert host into sorted list
649 insert_host(struct nsm_host
*host
)
651 struct nsm_host
**where
, *p
;
654 while ((p
= *where
) != 0) {
655 /* Sort in ascending order of timeout */
656 if (host
->send_next
< p
->send_next
)
658 /* If we have the same timeout, put the
659 * most recently used host first.
660 * This makes sure that "recent" hosts
661 * get notified first.
663 if (host
->send_next
== p
->send_next
664 && host
->last_used
> p
->last_used
)
674 * Find host given the XID
676 static struct nsm_host
*
677 find_host(uint32_t xid
)
679 struct nsm_host
**where
, *p
;
682 while ((p
= *where
) != 0) {
694 * Retrieve the current NSM state
697 nsm_get_state(int update
)
699 char newfile
[PATH_MAX
];
702 if ((fd
= open(_SM_STATE_PATH
, O_RDONLY
)) < 0) {
704 nsm_log(LOG_WARNING
, "%s: %m", _SM_STATE_PATH
);
705 nsm_log(LOG_WARNING
, "Creating %s, set initial state 1",
711 if (read(fd
, &state
, sizeof(state
)) != sizeof(state
)) {
713 "%s: bad file size, setting state = 1",
726 snprintf(newfile
, sizeof(newfile
),
727 "%s.new", _SM_STATE_PATH
);
728 if ((fd
= open(newfile
, O_CREAT
|O_WRONLY
, 0644)) < 0) {
729 nsm_log(LOG_ERR
, "Cannot create %s: %m", newfile
);
732 if (write(fd
, &state
, sizeof(state
)) != sizeof(state
)) {
734 "Failed to write state to %s", newfile
);
738 if (rename(newfile
, _SM_STATE_PATH
) < 0) {
740 "Cannot create %s: %m", _SM_STATE_PATH
);
753 nsm_log(int fac
, const char *fmt
, ...)
757 if (fac
== LOG_DEBUG
&& !opt_debug
)
762 vsyslog(fac
, fmt
, ap
);
764 vfprintf(stderr
, fmt
, ap
);
771 * Record pid in /var/run/sm-notify.pid
772 * This file should remain until a reboot, even if the
774 * If file already exists, fail.
776 static int record_pid(void)
781 snprintf(pid
, 20, "%d\n", getpid());
782 fd
= open("/var/run/sm-notify.pid", O_CREAT
|O_EXCL
|O_WRONLY
, 0600);
785 write(fd
, pid
, strlen(pid
));
790 /* Drop privileges to match owner of state-directory
791 * (in case a reply triggers some unknown bug).
793 static void drop_privs(void)
797 if (stat(_SM_DIR_PATH
, &st
) == -1 &&
798 stat(_SM_BASE_PATH
, &st
) == -1) {
803 if (st
.st_uid
== 0) {
805 "sm-notify running as root. chown %s to choose different user",
811 if (setgid(st
.st_gid
) == -1
812 || setuid(st
.st_uid
) == -1) {
813 nsm_log(LOG_ERR
, "Fail to drop privileges");
818 static void set_kernel_nsm_state(int state
)
822 fd
= open("/proc/sys/fs/nfs/nsm_local_state",O_WRONLY
);
825 snprintf(buf
, sizeof(buf
), "%d", state
);
826 write(fd
, buf
, strlen(buf
));