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