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