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