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