static void backup_hosts(const char *, const char *);
static void get_hosts(const char *);
static void insert_host(struct nsm_host *);
-struct nsm_host * find_host(uint32_t);
-void nsm_log(int fac, const char *fmt, ...);
+static struct nsm_host *find_host(uint32_t);
+static void nsm_log(int fac, const char *fmt, ...);
static int record_pid(void);
static void drop_privs(void);
-static void set_kernel_nsm_state(int state);
+static void set_kernel_nsm_state(int state);
static struct nsm_host * hosts = NULL;
}
}
-static struct addrinfo *smn_lookup(const sa_family_t family, const char *name)
+static struct addrinfo *smn_lookup(const char *name)
{
struct addrinfo *ai, hint = {
- .ai_family = family,
+#if HAVE_DECL_AI_ADDRCONFIG
+ .ai_flags = AI_ADDRCONFIG,
+#endif /* HAVE_DECL_AI_ADDRCONFIG */
+ .ai_family = AF_INET,
.ai_protocol = IPPROTO_UDP,
};
+ int error;
+
+ error = getaddrinfo(name, NULL, &hint, &ai);
+ switch (error) {
+ case 0:
+ return ai;
+ case EAI_SYSTEM:
+ if (opt_debug)
+ nsm_log(LOG_ERR, "getaddrinfo(3): %s",
+ strerror(errno));
+ break;
+ default:
+ if (opt_debug)
+ nsm_log(LOG_ERR, "getaddrinfo(3): %s",
+ gai_strerror(error));
+ }
+
+ return NULL;
+}
- if (getaddrinfo(name, NULL, &hint, &ai) != 0)
- return NULL;
+static void smn_forget_host(struct nsm_host *host)
+{
+ unlink(host->path);
+ free(host->path);
+ free(host->name);
+ if (host->ai)
+ freeaddrinfo(host->ai);
- return ai;
+ free(host);
}
int
exit(1);
}
+ log_syslog = 1;
+ openlog("sm-notify", LOG_PID, LOG_DAEMON);
+
if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) {
- if (record_pid() == 0 && force == 0 && opt_update_state == 1)
+ if (record_pid() == 0 && force == 0 && opt_update_state == 1) {
/* already run, don't try again */
+ nsm_log(LOG_NOTICE, "Already notifying clients; Exiting!");
exit(0);
+ }
}
if (opt_srcaddr) {
backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH);
get_hosts(_SM_BAK_PATH);
+ /* If there are not hosts to notify, just exit */
+ if (!hosts) {
+ nsm_log(LOG_DEBUG, "No hosts to notify; exiting");
+ return 0;
+ }
+
/* Get and update the NSM state. This will call sync() */
nsm_state = nsm_get_state(opt_update_state);
set_kernel_nsm_state(nsm_state);
if (!opt_quiet)
printf("Backgrounding to notify hosts...\n");
- openlog("sm-notify", LOG_PID, LOG_DAEMON);
- log_syslog = 1;
-
if (daemon(0, 0) < 0) {
nsm_log(LOG_ERR, "unable to background: %s",
strerror(errno));
/*
* Notify hosts
*/
-void
+static void
notify(void)
{
struct sockaddr_storage address;
/* Bind source IP if provided on command line */
if (opt_srcaddr) {
- struct addrinfo *ai = smn_lookup(AF_INET, opt_srcaddr);
+ struct addrinfo *ai = smn_lookup(opt_srcaddr);
if (!ai) {
nsm_log(LOG_ERR,
"Not a valid hostname or address: \"%s\"",
hp = hosts;
hosts = hp->next;
- if (notify_host(sock, hp)){
- unlink(hp->path);
- free(hp->name);
- free(hp->path);
- free(hp);
+ if (notify_host(sock, hp))
continue;
- }
/* Set the timeout for this call, using an
exponential timeout strategy */
/*
* Send notification to a single host
*/
-int
+static int
notify_host(int sock, struct nsm_host *host)
{
struct sockaddr_storage address;
host->xid = xid++;
if (host->ai == NULL) {
- host->ai = smn_lookup(AF_UNSPEC, host->name);
+ host->ai = smn_lookup(host->name);
if (host->ai == NULL) {
nsm_log(LOG_WARNING,
- "%s doesn't seem to be a valid address,"
- " skipped", host->name);
- return 1;
+ "DNS resolution of %s failed; "
+ "retrying later", host->name);
+ return 0;
}
}
* point.
*/
if (host->retries >= 4) {
- struct addrinfo *first = host->ai;
- struct addrinfo **next = &host->ai;
-
- /* remove the first entry from the list */
- host->ai = first->ai_next;
- first->ai_next = NULL;
- /* find the end of the list */
- next = &first->ai_next;
- while ( *next )
- next = & (*next)->ai_next;
- /* put first entry at end */
- *next = first;
- memcpy(&host->addr, first->ai_addr, first->ai_addrlen);
+ /* don't rotate if there is only one addrinfo */
+ if (host->ai->ai_next == NULL)
+ memcpy(&host->addr, host->ai->ai_addr,
+ host->ai->ai_addrlen);
+ else {
+ struct addrinfo *first = host->ai;
+ struct addrinfo **next = &host->ai;
+
+ /* remove the first entry from the list */
+ host->ai = first->ai_next;
+ first->ai_next = NULL;
+ /* find the end of the list */
+ next = &first->ai_next;
+ while ( *next )
+ next = & (*next)->ai_next;
+ /* put first entry at end */
+ *next = first;
+ memcpy(&host->addr, first->ai_addr,
+ first->ai_addrlen);
+ }
+
smn_set_port((struct sockaddr *)&host->addr, 0);
host->retries = 0;
}
/*
* Receive reply from remote host
*/
-void
+static void
recv_reply(int sock)
{
struct nsm_host *hp;
if (p <= end) {
nsm_log(LOG_DEBUG, "Host %s notified successfully",
hp->name);
- unlink(hp->path);
- free(hp->name);
- free(hp->path);
- free(hp);
- freeaddrinfo(hp->ai);
+ smn_forget_host(hp);
return;
}
}
/*
* Insert host into sorted list
*/
-void
+static void
insert_host(struct nsm_host *host)
{
struct nsm_host **where, *p;
/*
* Find host given the XID
*/
-struct nsm_host *
+static struct nsm_host *
find_host(uint32_t xid)
{
struct nsm_host **where, *p;
/*
* Retrieve the current NSM state
*/
-unsigned int
+static unsigned int
nsm_get_state(int update)
{
char newfile[PATH_MAX];
/*
* Log a message
*/
-void
+static void
nsm_log(int fac, const char *fmt, ...)
{
va_list ap;
fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd < 0)
return 0;
- write(fd, pid, strlen(pid));
+ if (write(fd, pid, strlen(pid)) != strlen(pid)) {
+ nsm_log(LOG_WARNING, "Writing to pid file failed: errno %d(%s)",
+ errno, strerror(errno));
+ }
close(fd);
return 1;
}
static void set_kernel_nsm_state(int state)
{
int fd;
+ const char *file = "/proc/sys/fs/nfs/nsm_local_state";
- fd = open("/proc/sys/fs/nfs/nsm_local_state",O_WRONLY);
+ fd = open(file ,O_WRONLY);
if (fd >= 0) {
char buf[20];
snprintf(buf, sizeof(buf), "%d", state);
- write(fd, buf, strlen(buf));
+ if (write(fd, buf, strlen(buf)) != strlen(buf)) {
+ nsm_log(LOG_WARNING, "Writing to '%s' failed: errno %d (%s)",
+ file, errno, strerror(errno));
+ }
close(fd);
}
}