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