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