"Fossies" - the Fresh Open Source Software Archive

Member "nfs-utils-2.5.3/utils/statd/statd.c" (20 Feb 2021, 12852 Bytes) of package /linux/misc/nfs-utils-2.5.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "statd.c": 2.5.2_vs_2.5.3.

    1 /* 
    2  * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
    3  * Modified by Olaf Kirch, Oct. 1996.
    4  * Modified by H.J. Lu, 1998.
    5  * Modified by L. Hohberger of Mission Critical Linux, 2000.
    6  *
    7  * NSM for Linux.
    8  */
    9 
   10 #ifdef HAVE_CONFIG_H
   11 #include <config.h>
   12 #endif
   13 
   14 #include <sys/stat.h>
   15 #include <limits.h>
   16 #include <signal.h>
   17 #include <unistd.h>
   18 #include <fcntl.h>
   19 #include <errno.h>
   20 #include <string.h>
   21 #include <getopt.h>
   22 #include <rpc/rpc.h>
   23 #include <rpc/pmap_clnt.h>
   24 #include <rpcmisc.h>
   25 #include <sys/resource.h>
   26 #include <sys/wait.h>
   27 #include <grp.h>
   28 
   29 #include "conffile.h"
   30 #include "statd.h"
   31 #include "nfslib.h"
   32 #include "nfsrpc.h"
   33 #include "nsm.h"
   34 
   35 /* Socket operations */
   36 #include <sys/types.h>
   37 #include <sys/socket.h>
   38 
   39 int run_mode = 0;       /* foreground logging mode */
   40 
   41 /* LH - I had these local to main, but it seemed silly to have 
   42  * two copies of each - one in main(), one static in log.c... 
   43  * It also eliminates the 256-char static in log.c */
   44 static char *name_p = NULL;
   45 
   46 /* PRC: a high-availability callout program can be specified with -H
   47  * When this is done, the program will receive callouts whenever clients
   48  * are added or deleted to the notify list */
   49 char *ha_callout_prog = NULL;
   50 
   51 static struct option longopts[] =
   52 {
   53     { "foreground", 0, 0, 'F' },
   54     { "no-syslog", 0, 0, 'd' },
   55     { "help", 0, 0, 'h' },
   56     { "version", 0, 0, 'v' },
   57     { "outgoing-port", 1, 0, 'o' },
   58     { "port", 1, 0, 'p' },
   59     { "name", 1, 0, 'n' },
   60     { "state-directory-path", 1, 0, 'P' },
   61     { "notify-mode", 0, 0, 'N' },
   62     { "ha-callout", 1, 0, 'H' },
   63     { "no-notify", 0, 0, 'L' },
   64     { "nlm-port", 1, 0, 'T'},
   65     { "nlm-udp-port", 1, 0, 'U'},
   66     { NULL, 0, 0, 0 }
   67 };
   68 
   69 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
   70 stat_chge   SM_stat_chge;
   71 
   72 #ifdef SIMULATIONS
   73 extern void simulator (int, char **);
   74 #endif
   75 
   76 
   77 #ifdef HAVE_TCP_WRAPPER 
   78 #include "tcpwrapper.h"
   79 
   80 static void 
   81 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
   82 {
   83     /* remote host authorization check */
   84     if (!check_default("statd", nfs_getrpccaller(transp), SM_PROG)) {
   85         svcerr_auth (transp, AUTH_FAILED);
   86         return;
   87     }
   88 
   89     sm_prog_1 (rqstp, transp);
   90 }
   91 
   92 #define sm_prog_1 sm_prog_1_wrapper
   93 #endif
   94 
   95 static void
   96 statd_unregister(void) {
   97     nfs_svc_unregister(SM_PROG, SM_VERS);
   98 }
   99 
  100 /*
  101  * Signal handler.
  102  */
  103 static void 
  104 killer (int sig)
  105 {
  106     statd_unregister ();
  107     xlog(D_GENERAL, "Caught signal %d, un-registering and exiting", sig);
  108     exit(0);
  109 }
  110 
  111 static void
  112 sigusr (int sig)
  113 {
  114     extern void my_svc_exit (void);
  115     xlog(D_GENERAL, "Caught signal %d, re-notifying (state %d)", sig,
  116                                 MY_STATE);
  117     my_svc_exit();
  118 }
  119 
  120 /*
  121  * Startup information.
  122  */
  123 static void log_modes(void)
  124 {
  125     char buf[128];      /* watch stack size... */
  126 
  127     /* No flags = no message */
  128     if (!run_mode) return;
  129 
  130     memset(buf,0,128);
  131     sprintf(buf,"Flags: ");
  132     if (run_mode & MODE_NODAEMON)
  133         strcat(buf,"No-Daemon ");
  134     if (run_mode & MODE_LOG_STDERR)
  135         strcat(buf,"Log-STDERR ");
  136 #ifdef HAVE_LIBTIRPC
  137     strcat(buf, "TI-RPC ");
  138 #endif
  139 
  140     xlog_warn("%s", buf);
  141 }
  142 
  143 /*
  144  * Since we do more than standard statd stuff, we might need to
  145  * help the occasional admin. 
  146  */
  147 static void 
  148 usage(void)
  149 {
  150     fprintf(stderr,"usage: %s [options]\n", name_p);
  151     fprintf(stderr,"      -h, -?, --help       Print this help screen.\n");
  152     fprintf(stderr,"      -F, --foreground     Foreground (no-daemon mode)\n");
  153     fprintf(stderr,"      -d, --no-syslog      Verbose logging to stderr.  Foreground mode only.\n");
  154     fprintf(stderr,"      -p, --port           Port to listen on\n");
  155     fprintf(stderr,"      -o, --outgoing-port  Port for outgoing connections\n");
  156     fprintf(stderr,"      -V, -v, --version    Display version information and exit.\n");
  157     fprintf(stderr,"      -n, --name           Specify a local hostname.\n");
  158     fprintf(stderr,"      -P                   State directory path.\n");
  159     fprintf(stderr,"      -N                   Run in notify only mode.\n");
  160     fprintf(stderr,"      -L, --no-notify      Do not perform any notification.\n");
  161     fprintf(stderr,"      -H                   Specify a high-availability callout program.\n");
  162 }
  163 
  164 static const char *pidfile = "/var/run/rpc.statd.pid";
  165 
  166 int pidfd = -1;
  167 static void create_pidfile(void)
  168 {
  169     FILE *fp;
  170 
  171     unlink(pidfile);
  172     fp = fopen(pidfile, "w");
  173     if (!fp)
  174         xlog_err("Opening %s failed: %m\n", pidfile);
  175     fprintf(fp, "%d\n", getpid());
  176     pidfd = dup(fileno(fp));
  177     if (fclose(fp) < 0) {
  178         xlog_warn("Flushing pid file failed: errno %d (%m)\n",
  179             errno);
  180     }
  181 }
  182 
  183 static void truncate_pidfile(void)
  184 {
  185     if (pidfd >= 0) {
  186         if (ftruncate(pidfd, 0) < 0) {
  187             xlog_warn("truncating pid file failed: errno %d (%m)\n",
  188                 errno);
  189         }
  190     }
  191 }
  192 
  193 static void run_sm_notify(int outport)
  194 {
  195     char op[20];
  196     char *av[6];
  197     int ac = 0;
  198 
  199     av[ac++] = "/usr/sbin/sm-notify";
  200     if (run_mode & MODE_NODAEMON)
  201         av[ac++] = "-d";
  202     if (outport) {
  203         sprintf(op, "-p%d", outport);
  204         av[ac++] = op;
  205     }
  206     if (run_mode & STATIC_HOSTNAME) {
  207         av[ac++] = "-v";
  208         av[ac++] = MY_NAME;
  209     }
  210     av[ac] = NULL;
  211     execv(av[0], av);
  212     fprintf(stderr, "%s: failed to run %s\n", name_p, av[0]);
  213     exit(2);
  214 
  215 }
  216 
  217 static void set_nlm_port(char *type, int port)
  218 {
  219     char nbuf[20];
  220     char pathbuf[40];
  221     int fd;
  222     if (!port)
  223         return;
  224     snprintf(nbuf, sizeof(nbuf), "%d", port);
  225     snprintf(pathbuf, sizeof(pathbuf), "/proc/sys/fs/nfs/nlm_%sport", type);
  226     fd = open(pathbuf, O_WRONLY);
  227     if (fd < 0 && errno == ENOENT) {
  228         /* probably module not loaded */
  229         if (system("modprobe lockd"))
  230             {/* ignore return value */};
  231         fd = open(pathbuf, O_WRONLY);
  232     }
  233     if (fd >= 0) {
  234         if (write(fd, nbuf, strlen(nbuf)) != (ssize_t)strlen(nbuf))
  235             fprintf(stderr, "%s: fail to set NLM %s port: %s\n",
  236                 name_p, type, strerror(errno));
  237         close(fd);
  238     } else
  239         fprintf(stderr, "%s: failed to open %s: %s\n", 
  240             name_p, pathbuf, strerror(errno));
  241 }
  242 int port = 0, out_port = 0;
  243 int nlm_udp = 0, nlm_tcp = 0;
  244 
  245 inline static void 
  246 read_statd_conf(char **argv)
  247 {
  248     char *s;
  249 
  250     conf_init_file(NFS_CONFFILE);
  251     xlog_set_debug("statd");
  252 
  253     out_port = conf_get_num("statd", "outgoing-port", out_port);
  254     port = conf_get_num("statd", "port", port);
  255 
  256     MY_NAME = conf_get_str("statd", "name");
  257     if (MY_NAME)
  258         run_mode |= STATIC_HOSTNAME;
  259 
  260     s = conf_get_str("statd", "state-directory-path");
  261     if (s && !nsm_setup_pathnames(argv[0], s))
  262         exit(1);
  263 
  264     s = conf_get_str("statd", "ha-callout");
  265     if (s)
  266         ha_callout_prog = s;
  267 
  268     nlm_tcp = conf_get_num("lockd", "port", nlm_tcp);
  269     /* udp defaults to the same as tcp ! */
  270     nlm_udp = conf_get_num("lockd", "udp-port", nlm_tcp);
  271 
  272     if (conf_get_bool("statd", "no-notify", false))
  273         run_mode |= MODE_NO_NOTIFY;
  274 }
  275 
  276 /*
  277  * Entry routine/main loop.
  278  */
  279 int main (int argc, char **argv)
  280 {
  281     extern char *optarg;
  282     int pid;
  283     int arg;
  284     struct rlimit rlim;
  285     int notify_sockfd;
  286     char *env;
  287 
  288     /* Default: daemon mode, no other options */
  289     run_mode = 0;
  290 
  291     env = getenv("RPC_STATD_NO_NOTIFY");
  292     if (env && atoi(env) > 0)
  293         run_mode |= MODE_NO_NOTIFY;
  294 
  295     /* Log to stderr if there's an error during startup */
  296     xlog_stderr(1);
  297     xlog_syslog(0);
  298 
  299     /* Set the basename */
  300     if ((name_p = strrchr(argv[0],'/')) != NULL) {
  301         name_p ++;
  302     } else {
  303         name_p = argv[0];
  304     }
  305 
  306     /* Set hostname */
  307     MY_NAME = NULL;
  308 
  309     /* Read in config setting */
  310     read_statd_conf(argv);
  311 
  312     /* Process command line switches */
  313     while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:LT:U:", longopts, NULL)) != EOF) {
  314         switch (arg) {
  315         case 'V':   /* Version */
  316         case 'v':
  317             printf("%s version " VERSION "\n",name_p);
  318             exit(0);
  319         case 'F':   /* Foreground/nodaemon mode */
  320             run_mode |= MODE_NODAEMON;
  321             break;
  322         case 'N':
  323             run_mode |= MODE_NOTIFY_ONLY;
  324             break;
  325         case 'L': /* Listen only */
  326             run_mode |= MODE_NO_NOTIFY;
  327             break;
  328         case 'd':   /* No daemon only - log to stderr */
  329             run_mode |= MODE_LOG_STDERR;
  330             break;
  331         case 'o':
  332             out_port = atoi(optarg);
  333             if (out_port < 1 || out_port > 65535) {
  334                 fprintf(stderr, "%s: bad port number: %s\n",
  335                     argv[0], optarg);
  336                 usage();
  337                 exit(1);
  338             }
  339             break;
  340         case 'p':
  341             port = atoi(optarg);
  342             if (port < 1 || port > 65535) {
  343                 fprintf(stderr, "%s: bad port number: %s\n",
  344                     argv[0], optarg);
  345                 usage();
  346                 exit(1);
  347             }
  348             break;
  349         case 'T': /* NLM TCP and UDP port */
  350             nlm_tcp = atoi(optarg);
  351             if (nlm_tcp < 1 || nlm_tcp > 65535) {
  352                 fprintf(stderr, "%s: bad nlm port number: %s\n",
  353                     argv[0], optarg);
  354                 usage();
  355                 exit(1);
  356             }
  357             if (nlm_udp == 0)
  358                 nlm_udp = nlm_tcp;
  359             break;
  360         case 'U': /* NLM  UDP port */
  361             nlm_udp = atoi(optarg);
  362             if (nlm_udp < 1 || nlm_udp > 65535) {
  363                 fprintf(stderr, "%s: bad nlm UDP port number: %s\n",
  364                     argv[0], optarg);
  365                 usage();
  366                 exit(1);
  367             }
  368             break;
  369         case 'n':   /* Specify local hostname */
  370             run_mode |= STATIC_HOSTNAME;
  371             MY_NAME = xstrdup(optarg);
  372             break;
  373         case 'P':
  374             if (!nsm_setup_pathnames(argv[0], optarg))
  375                 exit(1);
  376             break;
  377         case 'H': /* PRC: specify the ha-callout program */
  378             if ((ha_callout_prog = xstrdup(optarg)) == NULL)
  379                 exit(1);
  380             break;
  381         case '?':   /* heeeeeelllllllpppp? heh */
  382         case 'h':
  383             usage();
  384             exit (0);
  385         default:    /* oh dear ... heh */
  386             usage();
  387             exit(-1);
  388         }
  389     }
  390 
  391     /* Refuse to start if another statd is running */
  392     if (nfs_probe_statd()) {
  393         fprintf(stderr, "Statd service already running!\n");
  394         exit(1);
  395     }
  396 
  397     if (port == out_port && port != 0) {
  398         fprintf(stderr, "Listening and outgoing ports cannot be the same!\n");
  399         exit(-1);
  400     }
  401 
  402     if (run_mode & MODE_NOTIFY_ONLY) {
  403         fprintf(stderr, "%s: -N deprecated, consider using /usr/sbin/sm-notify directly\n",
  404             name_p);
  405         run_sm_notify(out_port);
  406     }
  407 
  408     if (!(run_mode & MODE_NODAEMON)) {
  409         run_mode &= ~MODE_LOG_STDERR;   /* Never log to console in
  410                            daemon mode. */
  411     }
  412 
  413     if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
  414         fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
  415                 argv [0], strerror(errno));
  416     else {
  417         /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */
  418         if (rlim.rlim_cur > FD_SETSIZE) {
  419             rlim.rlim_cur = FD_SETSIZE;
  420 
  421             if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) {
  422                 fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n",
  423                     argv [0], strerror(errno));
  424             }
  425         }
  426     }
  427 
  428     set_nlm_port("tcp", nlm_tcp);
  429     set_nlm_port("udp", nlm_udp);
  430 
  431 #ifdef SIMULATIONS
  432     if (argc > 1)
  433         /* LH - I _really_ need to update simulator... */
  434         simulator (--argc, ++argv); /* simulator() does exit() */
  435 #endif
  436 
  437     daemon_init((run_mode & MODE_NODAEMON));
  438 
  439     if (run_mode & MODE_LOG_STDERR) {
  440         xlog_syslog(0);
  441         xlog_stderr(1);
  442         xlog_config(D_ALL, 1);
  443     } else {
  444         xlog_syslog(1);
  445         xlog_stderr(0);
  446     }
  447 
  448     xlog_open(name_p);
  449     xlog(L_NOTICE, "Version " VERSION " starting");
  450 
  451     log_modes();
  452 
  453     signal (SIGHUP, killer);
  454     signal (SIGINT, killer);
  455     signal (SIGTERM, killer);
  456     /* PRC: trap SIGUSR1 to re-read notify list from disk */
  457     signal(SIGUSR1, sigusr);
  458     /* WARNING: the following works on Linux and SysV, but not BSD! */
  459     signal(SIGCHLD, SIG_IGN);
  460     /*
  461      * Ignore SIGPIPE to avoid statd dying when peers close their
  462      * TCP connection while we're trying to reply to them.
  463      */
  464     signal(SIGPIPE, SIG_IGN);
  465 
  466     create_pidfile();
  467     atexit(truncate_pidfile);
  468 
  469     if (! (run_mode & MODE_NO_NOTIFY))
  470         switch (pid = fork()) {
  471         case 0:
  472             run_sm_notify(out_port);
  473             break;
  474         case -1:
  475             break;
  476         default:
  477             waitpid(pid, NULL, 0);
  478         }
  479 
  480     /* Make sure we have a privilege port for calling into the kernel */
  481     if ((notify_sockfd = statd_get_socket()) < 0)
  482         exit(1);
  483 
  484     /* If sm-notify didn't take all the state files, load
  485      * state information into our notify-list so we can
  486      * pass on any SM_NOTIFY that arrives
  487      */
  488     load_state();
  489 
  490     MY_STATE = nsm_get_state(0);
  491     if (MY_STATE == 0)
  492         exit(1);
  493     xlog(D_GENERAL, "Local NSM state number: %d", MY_STATE);
  494     nsm_update_kernel_state(MY_STATE);
  495 
  496     /*
  497      * ORDER
  498      * Clear old listeners while still root, to override any
  499      * permission checking done by rpcbind.
  500      */
  501     statd_unregister();
  502 
  503     /*
  504      * ORDER
  505      */
  506     if (!nsm_drop_privileges(pidfd))
  507         exit(1);
  508 
  509     /*
  510      * ORDER
  511      * Create RPC listeners after dropping privileges.  This permits
  512      * statd to unregister its own listeners when it exits.
  513      */
  514     if (nfs_svc_create("statd", SM_PROG, SM_VERS, sm_prog_1, port) == 0) {
  515         xlog(L_ERROR, "failed to create RPC listeners, exiting");
  516         exit(1);
  517     }
  518     atexit(statd_unregister);
  519 
  520     /* If we got this far, we have successfully started */
  521     daemon_ready();
  522 
  523     for (;;) {
  524         /*
  525          * Handle incoming requests:  SM_NOTIFY socket requests, as
  526          * well as callbacks from lockd.
  527          */
  528         my_svc_run(notify_sockfd);  /* I rolled my own, Olaf made it better... */
  529 
  530         /* Only get here when simulating a crash so we should probably
  531          * start sm-notify running again.  As we have already dropped
  532          * privileges, this might not work, but I don't think
  533          * responding to SM_SIMU_CRASH is an important use cases to
  534          * get perfect.
  535          */
  536         if (! (run_mode & MODE_NO_NOTIFY))
  537             switch (pid = fork()) {
  538             case 0:
  539                 run_sm_notify(out_port);
  540                 break;
  541             case -1:
  542                 break;
  543             default:
  544                 waitpid(pid, NULL, 0);
  545             }
  546 
  547     }
  548     return 0;
  549 }