#include <sys/resource.h>
#include <sys/wait.h>
#include <grp.h>
+
#include "statd.h"
-#include "version.h"
#include "nfslib.h"
+#include "nsm.h"
/* Socket operations */
#include <sys/types.h>
#include <sys/socket.h>
-/* Added to enable specification of state directory path at run-time
- * j_carlos_gomez@yahoo.com
- */
-
-char * DIR_BASE = DEFAULT_DIR_BASE;
-
-char * SM_DIR = DEFAULT_SM_DIR;
-char * SM_BAK_DIR = DEFAULT_SM_BAK_DIR;
-char * SM_STAT_PATH = DEFAULT_SM_STAT_PATH;
-
-/* ----- end of state directory path stuff ------- */
-
int run_mode = 0; /* foreground logging mode */
/* LH - I had these local to main, but it seemed silly to have
* two copies of each - one in main(), one static in log.c...
* It also eliminates the 256-char static in log.c */
-char *name_p = NULL;
-const char *version_p = NULL;
+static char *name_p = NULL;
/* PRC: a high-availability callout program can be specified with -H
* When this is done, the program will receive callouts whenever clients
};
extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
-extern int statd_get_socket(void);
#ifdef SIMULATIONS
extern void simulator (int, char **);
sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
{
/* remote host authorization check */
- if (!check_default("statd", svc_getcaller(transp),
- rqstp->rq_proc, SM_PROG)) {
+ if (!check_default("statd", nfs_getrpccaller(transp), SM_PROG)) {
svcerr_auth (transp, AUTH_FAILED);
return;
}
#define sm_prog_1 sm_prog_1_wrapper
#endif
+static void
+statd_unregister(void) {
+ nfs_svc_unregister(SM_PROG, SM_VERS);
+}
+
/*
* Signal handler.
*/
static void
killer (int sig)
{
- note (N_FATAL, "Caught signal %d, un-registering and exiting.", sig);
- pmap_unset (SM_PROG, SM_VERS);
-
- exit (0);
+ statd_unregister ();
+ xlog_err ("Caught signal %d, un-registering and exiting", sig);
}
static void
sigusr (int sig)
{
extern void my_svc_exit (void);
- dprintf (N_DEBUG, "Caught signal %d, re-notifying (state %d).", sig,
+ xlog(D_GENERAL, "Caught signal %d, re-notifying (state %d)", sig,
MY_STATE);
my_svc_exit();
}
strcat(buf,"No-Daemon ");
if (run_mode & MODE_LOG_STDERR)
strcat(buf,"Log-STDERR ");
+#ifdef HAVE_LIBTIRPC
+ strcat(buf, "TI-RPC ");
+#endif
- note(N_WARNING,buf);
+ xlog_warn(buf);
}
/*
* help the occasional admin.
*/
static void
-usage()
+usage(void)
{
fprintf(stderr,"usage: %s [options]\n", name_p);
fprintf(stderr," -h, -?, --help Print this help screen.\n");
unlink(pidfile);
fp = fopen(pidfile, "w");
if (!fp)
- die("Opening %s failed: %s\n",
- pidfile, strerror(errno));
+ xlog_err("Opening %s failed: %m\n", pidfile);
fprintf(fp, "%d\n", getpid());
pidfd = dup(fileno(fp));
- if (fclose(fp) < 0)
- note(N_WARNING, "Flushing pid file failed.\n");
+ if (fclose(fp) < 0) {
+ xlog_warn("Flushing pid file failed: errno %d (%m)\n",
+ errno);
+ }
}
static void truncate_pidfile(void)
{
- if (pidfd >= 0)
- ftruncate(pidfd, 0);
-}
-
-static void drop_privs(void)
-{
- struct stat st;
-
- if (stat(SM_DIR, &st) == -1 &&
- stat(DIR_BASE, &st) == -1) {
- st.st_uid = 0;
- st.st_gid = 0;
- }
-
- if (st.st_uid == 0) {
- note(N_WARNING, "statd running as root. chown %s to choose different user\n",
- SM_DIR);
- return;
- }
- /* better chown the pid file before dropping, as if it
- * if over nfs we might loose access
- */
- if (pidfd >= 0)
- fchown(pidfd, st.st_uid, st.st_gid);
-
- setgroups(0, NULL);
- if (setgid(st.st_gid) == -1
- || setuid(st.st_uid) == -1) {
- note(N_ERROR, "Fail to drop privileges");
- exit(1);
+ if (pidfd >= 0) {
+ if (ftruncate(pidfd, 0) < 0) {
+ xlog_warn("truncating pid file failed: errno %d (%m)\n",
+ errno);
+ }
}
}
int arg;
int port = 0, out_port = 0;
struct rlimit rlim;
- int once = 1;
int pipefds[2] = { -1, -1};
char status;
/* Default: daemon mode, no other options */
run_mode = 0;
+ xlog_stderr(0);
+ xlog_syslog(1);
/* Set the basename */
if ((name_p = strrchr(argv[0],'/')) != NULL) {
name_p = argv[0];
}
- /* Get the version */
- if ((version_p = strrchr(VERSION,' ')) != NULL) {
- version_p++;
- } else {
- version_p = VERSION;
- }
-
/* Set hostname */
MY_NAME = NULL;
switch (arg) {
case 'V': /* Version */
case 'v':
- printf("%s version %s\n",name_p,version_p);
+ printf("%s version " VERSION "\n",name_p);
exit(0);
case 'F': /* Foreground/nodaemon mode */
run_mode |= MODE_NODAEMON;
MY_NAME = xstrdup(optarg);
break;
case 'P':
-
- if ((DIR_BASE = xstrdup(optarg)) == NULL) {
- fprintf(stderr, "%s: xstrdup(%s) failed!\n",
- argv[0], optarg);
- exit(1);
- }
-
- SM_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm"));
- SM_BAK_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm.bak"));
- SM_STAT_PATH = xmalloc(strlen(DIR_BASE) + 1 + sizeof("state"));
-
- if ((SM_DIR == NULL)
- || (SM_BAK_DIR == NULL)
- || (SM_STAT_PATH == NULL)) {
-
- fprintf(stderr, "%s: xmalloc() failed!\n",
- argv[0]);
+ if (!nsm_setup_pathnames(argv[0], optarg))
exit(1);
- }
- if (DIR_BASE[strlen(DIR_BASE)-1] == '/') {
- sprintf(SM_DIR, "%ssm", DIR_BASE );
- sprintf(SM_BAK_DIR, "%ssm.bak", DIR_BASE );
- sprintf(SM_STAT_PATH, "%sstate", DIR_BASE );
- } else {
- sprintf(SM_DIR, "%s/sm", DIR_BASE );
- sprintf(SM_BAK_DIR, "%s/sm.bak", DIR_BASE );
- sprintf(SM_STAT_PATH, "%s/state", DIR_BASE );
- }
break;
case 'H': /* PRC: specify the ha-callout program */
if ((ha_callout_prog = xstrdup(optarg)) == NULL) {
run_sm_notify(out_port);
}
-
if (!(run_mode & MODE_NODAEMON)) {
run_mode &= ~MODE_LOG_STDERR; /* Never log to console in
daemon mode. */
/* Child. */
close(pipefds[0]);
setsid ();
- if (chdir (DIR_BASE) == -1) {
- perror("statd: Could not chdir");
- exit(1);
- }
while (pipefds[1] <= 2) {
pipefds[1] = dup(pipefds[1]);
/* Child. */
- log_init (name_p,version_p);
+ if (run_mode & MODE_LOG_STDERR) {
+ xlog_syslog(0);
+ xlog_stderr(1);
+ xlog_config(D_ALL, 1);
+ }
+ xlog_open(name_p);
+ xlog(L_NOTICE, "Version " VERSION " starting");
log_modes();
}
/* Make sure we have a privilege port for calling into the kernel */
- statd_get_socket();
+ if (statd_get_socket() < 0)
+ exit(1);
/* If sm-notify didn't take all the state files, load
* state information into our notify-list so we can
*/
load_state();
- for (;;) {
- pmap_unset (SM_PROG, SM_VERS);
+ MY_STATE = nsm_get_state(0);
+ if (MY_STATE == 0)
+ exit(1);
+ xlog(D_GENERAL, "Local NSM state number: %d", MY_STATE);
+ nsm_update_kernel_state(MY_STATE);
- /* If we got this far, we have successfully started, so notify parent */
- if (pipefds[1] > 0) {
- status = 0;
- write(pipefds[1], &status, 1);
- close(pipefds[1]);
- pipefds[1] = -1;
- }
+ /*
+ * ORDER
+ * Clear old listeners while still root, to override any
+ * permission checking done by rpcbind.
+ */
+ statd_unregister();
- /* this registers both UDP and TCP services */
- rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
+ /*
+ * ORDER
+ */
+ if (!nsm_drop_privileges(pidfd))
+ exit(1);
- if (once) {
- once = 0;
- drop_privs();
+ /*
+ * ORDER
+ * Create RPC listeners after dropping privileges. This permits
+ * statd to unregister its own listeners when it exits.
+ */
+ if (nfs_svc_create("statd", SM_PROG, SM_VERS, sm_prog_1, port) == 0) {
+ xlog(L_ERROR, "failed to create RPC listeners, exiting");
+ exit(1);
+ }
+ atexit(statd_unregister);
+
+ /* If we got this far, we have successfully started, so notify parent */
+ if (pipefds[1] > 0) {
+ status = 0;
+ if (write(pipefds[1], &status, 1) != 1) {
+ xlog_warn("writing to parent pipe failed: errno %d (%s)\n",
+ errno, strerror(errno));
}
+ close(pipefds[1]);
+ pipefds[1] = -1;
+ }
+
+ for (;;) {
/*
* Handle incoming requests: SM_NOTIFY socket requests, as
* well as callbacks from lockd.