]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/statd/sm-notify.c
72dcff436fd7f0d9a193dcba1198d1c3e8bfd10d
[nfs-utils.git] / utils / statd / sm-notify.c
1 /*
2  * Send NSM notify calls to all hosts listed in /var/lib/sm
3  *
4  * Copyright (C) 2004-2006 Olaf Kirch <okir@suse.de>
5  */
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/stat.h>
14 #include <sys/poll.h>
15 #include <sys/param.h>
16 #include <sys/syslog.h>
17 #include <arpa/inet.h>
18 #include <dirent.h>
19 #include <time.h>
20 #include <stdio.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <netdb.h>
28 #include <errno.h>
29 #include <grp.h>
30
31 #ifndef BASEDIR
32 # ifdef NFS_STATEDIR
33 #  define BASEDIR               NFS_STATEDIR
34 # else
35 #  define BASEDIR               "/var/lib/nfs"
36 # endif
37 #endif
38
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"
42
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;
47
48 #define NSM_PROG        100024
49 #define NSM_PROGRAM     100024
50 #define NSM_VERSION     1
51 #define NSM_TIMEOUT     2
52 #define NSM_NOTIFY      6
53 #define NSM_MAX_TIMEOUT 120     /* don't make this too big */
54 #define MAXMSGSIZE      256
55
56 struct nsm_host {
57         struct nsm_host *       next;
58         char *                  name;
59         char *                  path;
60         struct sockaddr_storage addr;
61         struct addrinfo         *ai;
62         time_t                  last_used;
63         time_t                  send_next;
64         unsigned int            timeout;
65         unsigned int            retries;
66         unsigned int            xid;
67 };
68
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;
78
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);
91
92 static struct nsm_host *        hosts = NULL;
93
94 /*
95  * Address handling utilities
96  */
97
98 static unsigned short smn_get_port(const struct sockaddr *sap)
99 {
100         switch (sap->sa_family) {
101         case AF_INET:
102                 return ntohs(((struct sockaddr_in *)sap)->sin_port);
103         case AF_INET6:
104                 return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
105         }
106         return 0;
107 }
108
109 static void smn_set_port(struct sockaddr *sap, const unsigned short port)
110 {
111         switch (sap->sa_family) {
112         case AF_INET:
113                 ((struct sockaddr_in *)sap)->sin_port = htons(port);
114                 break;
115         case AF_INET6:
116                 ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
117                 break;
118         }
119 }
120
121 static struct addrinfo *smn_lookup(const char *name)
122 {
123         struct addrinfo *ai, hint = {
124 #if HAVE_DECL_AI_ADDRCONFIG
125                 .ai_flags       = AI_ADDRCONFIG,
126 #endif  /* HAVE_DECL_AI_ADDRCONFIG */
127                 .ai_family      = AF_INET,
128                 .ai_protocol    = IPPROTO_UDP,
129         };
130         int error;
131
132         error = getaddrinfo(name, NULL, &hint, &ai);
133         switch (error) {
134         case 0:
135                 return ai;
136         case EAI_SYSTEM: 
137                 if (opt_debug)
138                         nsm_log(LOG_ERR, "getaddrinfo(3): %s",
139                                         strerror(errno));
140                 break;
141         default:
142                 if (opt_debug)
143                         nsm_log(LOG_ERR, "getaddrinfo(3): %s",
144                                         gai_strerror(error));
145         }
146
147         return NULL;
148 }
149
150 static void smn_forget_host(struct nsm_host *host)
151 {
152         unlink(host->path);
153         free(host->path);
154         free(host->name);
155         if (host->ai)
156                 freeaddrinfo(host->ai);
157
158         free(host);
159 }
160
161 int
162 main(int argc, char **argv)
163 {
164         int     c;
165         int     force = 0;
166
167         while ((c = getopt(argc, argv, "dm:np:v:qP:f")) != -1) {
168                 switch (c) {
169                 case 'f':
170                         force = 1;
171                         break;
172                 case 'd':
173                         opt_debug++;
174                         break;
175                 case 'm':
176                         opt_max_retry = atoi(optarg) * 60;
177                         break;
178                 case 'n':
179                         opt_update_state = 0;
180                         break;
181                 case 'p':
182                         opt_srcport = atoi(optarg);
183                         break;
184                 case 'v':
185                         opt_srcaddr = optarg;
186                         break;
187                 case 'q':
188                         opt_quiet = 1;
189                         break;
190                 case 'P':
191                         _SM_BASE_PATH = strdup(optarg);
192                         _SM_STATE_PATH = malloc(strlen(optarg)+1+sizeof("state"));
193                         _SM_DIR_PATH = malloc(strlen(optarg)+1+sizeof("sm"));
194                         _SM_BAK_PATH = malloc(strlen(optarg)+1+sizeof("sm.bak"));
195                         if (_SM_BASE_PATH == NULL ||
196                             _SM_STATE_PATH == NULL ||
197                             _SM_DIR_PATH == NULL ||
198                             _SM_BAK_PATH == NULL) {
199                                 nsm_log(LOG_ERR, "unable to allocate memory");
200                                 exit(1);
201                         }
202                         strcat(strcpy(_SM_STATE_PATH, _SM_BASE_PATH), "/state");
203                         strcat(strcpy(_SM_DIR_PATH, _SM_BASE_PATH), "/sm");
204                         strcat(strcpy(_SM_BAK_PATH, _SM_BASE_PATH), "/sm.bak");
205                         break;
206
207                 default:
208                         goto usage;
209                 }
210         }
211
212         if (optind < argc) {
213 usage:          fprintf(stderr,
214                         "Usage: sm-notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
215                         "            [-P /path/to/state/directory] [-v my_host_name]\n");
216                 exit(1);
217         }
218
219         log_syslog = 1;
220         openlog("sm-notify", LOG_PID, LOG_DAEMON);
221
222         if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) {
223                 if (record_pid() == 0 && force == 0 && opt_update_state == 1) {
224                         /* already run, don't try again */
225                         nsm_log(LOG_NOTICE, "Already notifying clients; Exiting!");
226                         exit(0);
227                 }
228         }
229
230         if (opt_srcaddr) {
231                 strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
232         } else
233         if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
234                 nsm_log(LOG_ERR, "Failed to obtain name of local host: %s",
235                         strerror(errno));
236                 exit(1);
237         }
238
239         backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH);
240         get_hosts(_SM_BAK_PATH);
241
242         /* If there are not hosts to notify, just exit */
243         if (!hosts) {
244                 nsm_log(LOG_DEBUG, "No hosts to notify; exiting");
245                 return 0;
246         }
247
248         /* Get and update the NSM state. This will call sync() */
249         nsm_state = nsm_get_state(opt_update_state);
250         set_kernel_nsm_state(nsm_state);
251
252         if (!opt_debug) {
253                 if (!opt_quiet)
254                         printf("Backgrounding to notify hosts...\n");
255
256                 if (daemon(0, 0) < 0) {
257                         nsm_log(LOG_ERR, "unable to background: %s",
258                                         strerror(errno));
259                         exit(1);
260                 }
261
262                 close(0);
263                 close(1);
264                 close(2);
265         }
266
267         notify();
268
269         if (hosts) {
270                 struct nsm_host *hp;
271
272                 while ((hp = hosts) != 0) {
273                         hosts = hp->next;
274                         nsm_log(LOG_NOTICE,
275                                 "Unable to notify %s, giving up",
276                                 hp->name);
277                 }
278                 exit(1);
279         }
280
281         exit(0);
282 }
283
284 /*
285  * Notify hosts
286  */
287 static void
288 notify(void)
289 {
290         struct sockaddr_storage address;
291         struct sockaddr *local_addr = (struct sockaddr *)&address;
292         time_t  failtime = 0;
293         int     sock = -1;
294         int retry_cnt = 0;
295
296  retry:
297         sock = socket(AF_INET, SOCK_DGRAM, 0);
298         if (sock < 0) {
299                 nsm_log(LOG_ERR, "Failed to create RPC socket: %s",
300                         strerror(errno));
301                 exit(1);
302         }
303         fcntl(sock, F_SETFL, O_NONBLOCK);
304
305         memset(&address, 0, sizeof(address));
306         local_addr->sa_family = AF_INET;        /* Default to IPv4 */
307
308         /* Bind source IP if provided on command line */
309         if (opt_srcaddr) {
310                 struct addrinfo *ai = smn_lookup(opt_srcaddr);
311                 if (!ai) {
312                         nsm_log(LOG_ERR,
313                                 "Not a valid hostname or address: \"%s\"",
314                                 opt_srcaddr);
315                         exit(1);
316                 }
317
318                 /* We know it's IPv4 at this point */
319                 memcpy(local_addr, ai->ai_addr, ai->ai_addrlen);
320
321                 freeaddrinfo(ai);
322         }
323
324         /* Use source port if provided on the command line,
325          * otherwise use bindresvport */
326         if (opt_srcport) {
327                 smn_set_port(local_addr, opt_srcport);
328                 if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) {
329                         nsm_log(LOG_ERR, "Failed to bind RPC socket: %s",
330                                 strerror(errno));
331                         exit(1);
332                 }
333         } else {
334                 struct servent *se;
335                 struct sockaddr_in *sin = (struct sockaddr_in *)local_addr;
336                 (void) bindresvport(sock, sin);
337                 /* try to avoid known ports */
338                 se = getservbyport(sin->sin_port, "udp");
339                 if (se && retry_cnt < 100) {
340                         retry_cnt++;
341                         close(sock);
342                         goto retry;
343                 }
344         }
345
346         if (opt_max_retry)
347                 failtime = time(NULL) + opt_max_retry;
348
349         drop_privs();
350
351         while (hosts) {
352                 struct pollfd   pfd;
353                 time_t          now = time(NULL);
354                 unsigned int    sent = 0;
355                 struct nsm_host *hp;
356                 long            wait;
357
358                 if (failtime && now >= failtime)
359                         break;
360
361                 while (hosts && ((wait = hosts->send_next - now) <= 0)) {
362                         /* Never send more than 10 packets at once */
363                         if (sent++ >= 10)
364                                 break;
365
366                         /* Remove queue head */
367                         hp = hosts;
368                         hosts = hp->next;
369
370                         if (notify_host(sock, hp))
371                                 continue;
372
373                         /* Set the timeout for this call, using an
374                            exponential timeout strategy */
375                         wait = hp->timeout;
376                         if ((hp->timeout <<= 1) > NSM_MAX_TIMEOUT)
377                                 hp->timeout = NSM_MAX_TIMEOUT;
378                         hp->send_next = now + wait;
379                         hp->retries++;
380
381                         insert_host(hp);
382                 }
383                 if (hosts == NULL)
384                         return;
385
386                 nsm_log(LOG_DEBUG, "Host %s due in %ld seconds",
387                                 hosts->name, wait);
388
389                 pfd.fd = sock;
390                 pfd.events = POLLIN;
391
392                 wait *= 1000;
393                 if (wait < 100)
394                         wait = 100;
395                 if (poll(&pfd, 1, wait) != 1)
396                         continue;
397
398                 recv_reply(sock);
399         }
400 }
401
402 /*
403  * Send notification to a single host
404  */
405 static int
406 notify_host(int sock, struct nsm_host *host)
407 {
408         struct sockaddr_storage address;
409         struct sockaddr *dest = (struct sockaddr *)&address;
410         socklen_t destlen = sizeof(address);
411         static unsigned int     xid = 0;
412         uint32_t                msgbuf[MAXMSGSIZE], *p;
413         unsigned int            len;
414
415         if (!xid)
416                 xid = getpid() + time(NULL);
417         if (!host->xid)
418                 host->xid = xid++;
419
420         if (host->ai == NULL) {
421                 host->ai = smn_lookup(host->name);
422                 if (host->ai == NULL) {
423                         nsm_log(LOG_WARNING,
424                                 "DNS resolution of %s failed; "
425                                 "retrying later", host->name);
426                         return 0;
427                 }
428         }
429
430         memset(msgbuf, 0, sizeof(msgbuf));
431         p = msgbuf;
432         *p++ = htonl(host->xid);
433         *p++ = 0;
434         *p++ = htonl(2);
435
436         /* If we retransmitted 4 times, reset the port to force
437          * a new portmap lookup (in case statd was restarted).
438          * We also rotate through multiple IP addresses at this
439          * point.
440          */
441         if (host->retries >= 4) {
442                 /* don't rotate if there is only one addrinfo */
443                 if (host->ai->ai_next == NULL)
444                         memcpy(&host->addr, host->ai->ai_addr,
445                                                 host->ai->ai_addrlen);
446                 else {
447                         struct addrinfo *first = host->ai;
448                         struct addrinfo **next = &host->ai;
449
450                         /* remove the first entry from the list */
451                         host->ai = first->ai_next;
452                         first->ai_next = NULL;
453                         /* find the end of the list */
454                         next = &first->ai_next;
455                         while ( *next )
456                                 next = & (*next)->ai_next;
457                         /* put first entry at end */
458                         *next = first;
459                         memcpy(&host->addr, first->ai_addr,
460                                                 first->ai_addrlen);
461                 }
462
463                 smn_set_port((struct sockaddr *)&host->addr, 0);
464                 host->retries = 0;
465         }
466
467         memcpy(dest, &host->addr, destlen);
468         if (smn_get_port(dest) == 0) {
469                 /* Build a PMAP packet */
470                 nsm_log(LOG_DEBUG, "Sending portmap query to %s", host->name);
471
472                 smn_set_port(dest, 111);
473                 *p++ = htonl(100000);
474                 *p++ = htonl(2);
475                 *p++ = htonl(3);
476
477                 /* Auth and verf */
478                 *p++ = 0; *p++ = 0;
479                 *p++ = 0; *p++ = 0;
480
481                 *p++ = htonl(NSM_PROGRAM);
482                 *p++ = htonl(NSM_VERSION);
483                 *p++ = htonl(IPPROTO_UDP);
484                 *p++ = 0;
485         } else {
486                 /* Build an SM_NOTIFY packet */
487                 nsm_log(LOG_DEBUG, "Sending SM_NOTIFY to %s", host->name);
488
489                 *p++ = htonl(NSM_PROGRAM);
490                 *p++ = htonl(NSM_VERSION);
491                 *p++ = htonl(NSM_NOTIFY);
492
493                 /* Auth and verf */
494                 *p++ = 0; *p++ = 0;
495                 *p++ = 0; *p++ = 0;
496
497                 /* state change */
498                 len = strlen(nsm_hostname);
499                 *p++ = htonl(len);
500                 memcpy(p, nsm_hostname, len);
501                 p += (len + 3) >> 2;
502                 *p++ = htonl(nsm_state);
503         }
504         len = (p - msgbuf) << 2;
505
506         if (sendto(sock, msgbuf, len, 0, dest, destlen) < 0)
507                 nsm_log(LOG_WARNING, "Sending Reboot Notification to "
508                         "'%s' failed: errno %d (%s)", host->name, errno, strerror(errno));
509         
510         return 0;
511 }
512
513 /*
514  * Receive reply from remote host
515  */
516 static void
517 recv_reply(int sock)
518 {
519         struct nsm_host *hp;
520         struct sockaddr *sap;
521         uint32_t        msgbuf[MAXMSGSIZE], *p, *end;
522         uint32_t        xid;
523         int             res;
524
525         res = recv(sock, msgbuf, sizeof(msgbuf), 0);
526         if (res < 0)
527                 return;
528
529         nsm_log(LOG_DEBUG, "Received packet...");
530
531         p = msgbuf;
532         end = p + (res >> 2);
533
534         xid = ntohl(*p++);
535         if (*p++ != htonl(1)    /* must be REPLY */
536          || *p++ != htonl(0)    /* must be ACCEPTED */
537          || *p++ != htonl(0)    /* must be NULL verifier */
538          || *p++ != htonl(0)
539          || *p++ != htonl(0))   /* must be SUCCESS */
540                 return;
541
542         /* Before we look at the data, find the host struct for
543            this reply */
544         if ((hp = find_host(xid)) == NULL)
545                 return;
546         sap = (struct sockaddr *)&hp->addr;
547
548         if (smn_get_port(sap) == 0) {
549                 /* This was a portmap request */
550                 unsigned int    port;
551
552                 port = ntohl(*p++);
553                 if (p > end)
554                         goto fail;
555
556                 hp->send_next = time(NULL);
557                 if (port == 0) {
558                         /* No binding for statd. Delay the next
559                          * portmap query for max timeout */
560                         nsm_log(LOG_DEBUG, "No statd on %s", hp->name);
561                         hp->timeout = NSM_MAX_TIMEOUT;
562                         hp->send_next += NSM_MAX_TIMEOUT;
563                 } else {
564                         smn_set_port(sap, port);
565                         if (hp->timeout >= NSM_MAX_TIMEOUT / 4)
566                                 hp->timeout = NSM_MAX_TIMEOUT / 4;
567                 }
568                 hp->xid = 0;
569         } else {
570                 /* Successful NOTIFY call. Server returns void,
571                  * so nothing we need to do here (except
572                  * check that we didn't read past the end of the
573                  * packet)
574                  */
575                 if (p <= end) {
576                         nsm_log(LOG_DEBUG, "Host %s notified successfully",
577                                         hp->name);
578                         smn_forget_host(hp);
579                         return;
580                 }
581         }
582
583 fail:   /* Re-insert the host */
584         insert_host(hp);
585 }
586
587 /*
588  * Back up all hosts from the sm directory to sm.bak
589  */
590 static void
591 backup_hosts(const char *dirname, const char *bakname)
592 {
593         struct dirent   *de;
594         DIR             *dir;
595
596         if (!(dir = opendir(dirname))) {
597                 nsm_log(LOG_WARNING,
598                         "Failed to open %s: %s", dirname, strerror(errno));
599                 return;
600         }
601
602         while ((de = readdir(dir)) != NULL) {
603                 char    src[1024], dst[1024];
604
605                 if (de->d_name[0] == '.')
606                         continue;
607
608                 snprintf(src, sizeof(src), "%s/%s", dirname, de->d_name);
609                 snprintf(dst, sizeof(dst), "%s/%s", bakname, de->d_name);
610                 if (rename(src, dst) < 0) {
611                         nsm_log(LOG_WARNING,
612                                 "Failed to rename %s -> %s: %m",
613                                 src, dst);
614                 }
615         }
616         closedir(dir);
617 }
618
619 /*
620  * Get all entries from sm.bak and convert them to host entries
621  */
622 static void
623 get_hosts(const char *dirname)
624 {
625         struct nsm_host *host;
626         struct dirent   *de;
627         DIR             *dir;
628
629         if (!(dir = opendir(dirname))) {
630                 nsm_log(LOG_WARNING,
631                         "Failed to open %s: %s", dirname, strerror(errno));
632                 return;
633         }
634
635         host = NULL;
636         while ((de = readdir(dir)) != NULL) {
637                 struct stat     stb;
638                 char            path[1024];
639
640                 if (de->d_name[0] == '.')
641                         continue;
642                 if (host == NULL)
643                         host = calloc(1, sizeof(*host));
644                 if (host == NULL) {
645                         nsm_log(LOG_WARNING, "Unable to allocate memory");
646                         return;
647                 }
648
649                 snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
650                 if (stat(path, &stb) < 0)
651                         continue;
652
653                 host->last_used = stb.st_mtime;
654                 host->timeout = NSM_TIMEOUT;
655                 host->path = strdup(path);
656                 host->name = strdup(de->d_name);
657                 host->retries = 100; /* force address retry */
658
659                 insert_host(host);
660                 host = NULL;
661         }
662         closedir(dir);
663
664         if (host)
665                 free(host);
666 }
667
668 /*
669  * Insert host into sorted list
670  */
671 static void
672 insert_host(struct nsm_host *host)
673 {
674         struct nsm_host **where, *p;
675
676         where = &hosts;
677         while ((p = *where) != 0) {
678                 /* Sort in ascending order of timeout */
679                 if (host->send_next < p->send_next)
680                         break;
681                 /* If we have the same timeout, put the
682                  * most recently used host first.
683                  * This makes sure that "recent" hosts
684                  * get notified first.
685                  */
686                 if (host->send_next == p->send_next
687                  && host->last_used > p->last_used)
688                         break;
689                 where = &p->next;
690         }
691
692         host->next = *where;
693         *where = host;
694 }
695
696 /*
697  * Find host given the XID
698  */
699 static struct nsm_host *
700 find_host(uint32_t xid)
701 {
702         struct nsm_host **where, *p;
703
704         where = &hosts;
705         while ((p = *where) != 0) {
706                 if (p->xid == xid) {
707                         *where = p->next;
708                         return p;
709                 }
710                 where = &p->next;
711         }
712         return NULL;
713 }
714
715
716 /*
717  * Retrieve the current NSM state
718  */
719 static unsigned int
720 nsm_get_state(int update)
721 {
722         char            newfile[PATH_MAX];
723         int             fd, state;
724
725         if ((fd = open(_SM_STATE_PATH, O_RDONLY)) < 0) {
726                 if (!opt_quiet) {
727                         nsm_log(LOG_WARNING, "%s: %m", _SM_STATE_PATH);
728                         nsm_log(LOG_WARNING, "Creating %s, set initial state 1",
729                                 _SM_STATE_PATH);
730                 }
731                 state = 1;
732                 update = 1;
733         } else {
734                 if (read(fd, &state, sizeof(state)) != sizeof(state)) {
735                         nsm_log(LOG_WARNING,
736                                 "%s: bad file size, setting state = 1",
737                                 _SM_STATE_PATH);
738                         state = 1;
739                         update = 1;
740                 } else {
741                         if (!(state & 1))
742                                 state += 1;
743                 }
744                 close(fd);
745         }
746
747         if (update) {
748                 state += 2;
749                 snprintf(newfile, sizeof(newfile),
750                                 "%s.new", _SM_STATE_PATH);
751                 if ((fd = open(newfile, O_CREAT|O_WRONLY, 0644)) < 0) {
752                         nsm_log(LOG_ERR, "Cannot create %s: %m", newfile);
753                         exit(1);
754                 }
755                 if (write(fd, &state, sizeof(state)) != sizeof(state)) {
756                         nsm_log(LOG_ERR,
757                                 "Failed to write state to %s", newfile);
758                         exit(1);
759                 }
760                 close(fd);
761                 if (rename(newfile, _SM_STATE_PATH) < 0) {
762                         nsm_log(LOG_ERR,
763                                 "Cannot create %s: %m", _SM_STATE_PATH);
764                         exit(1);
765                 }
766                 sync();
767         }
768
769         return state;
770 }
771
772 /*
773  * Log a message
774  */
775 static void
776 nsm_log(int fac, const char *fmt, ...)
777 {
778         va_list ap;
779
780         if (fac == LOG_DEBUG && !opt_debug)
781                 return;
782
783         va_start(ap, fmt);
784         if (log_syslog)
785                 vsyslog(fac, fmt, ap);
786         else {
787                 vfprintf(stderr, fmt, ap);
788                 fputs("\n", stderr);
789         }
790         va_end(ap);
791 }
792
793 /*
794  * Record pid in /var/run/sm-notify.pid
795  * This file should remain until a reboot, even if the
796  * program exits.
797  * If file already exists, fail.
798  */
799 static int record_pid(void)
800 {
801         char pid[20];
802         int fd;
803
804         snprintf(pid, 20, "%d\n", getpid());
805         fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
806         if (fd < 0)
807                 return 0;
808         if (write(fd, pid, strlen(pid)) != strlen(pid))  {
809                 nsm_log(LOG_WARNING, "Writing to pid file failed: errno %d(%s)",
810                         errno, strerror(errno));
811         }
812         close(fd);
813         return 1;
814 }
815
816 /* Drop privileges to match owner of state-directory
817  * (in case a reply triggers some unknown bug).
818  */
819 static void drop_privs(void)
820 {
821         struct stat st;
822
823         if (stat(_SM_DIR_PATH, &st) == -1 &&
824             stat(_SM_BASE_PATH, &st) == -1) {
825                 st.st_uid = 0;
826                 st.st_gid = 0;
827         }
828
829         if (st.st_uid == 0) {
830                 nsm_log(LOG_WARNING,
831                         "sm-notify running as root. chown %s to choose different user",
832                     _SM_DIR_PATH);
833                 return;
834         }
835
836         setgroups(0, NULL);
837         if (setgid(st.st_gid) == -1
838             || setuid(st.st_uid) == -1) {
839                 nsm_log(LOG_ERR, "Fail to drop privileges");
840                 exit(1);
841         }
842 }
843
844 static void set_kernel_nsm_state(int state)
845 {
846         int fd;
847         const char *file = "/proc/sys/fs/nfs/nsm_local_state";
848
849         fd = open(file ,O_WRONLY);
850         if (fd >= 0) {
851                 char buf[20];
852                 snprintf(buf, sizeof(buf), "%d", state);
853                 if (write(fd, buf, strlen(buf)) != strlen(buf)) {
854                         nsm_log(LOG_WARNING, "Writing to '%s' failed: errno %d (%s)",
855                                 file, errno, strerror(errno));
856                 }
857                 close(fd);
858         }
859 }