[PATCH 3/4] nfs-utils: introduce new statd implementation (3rd part)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Introduce auxiliary files (Makefiles, etc.) and update actools to support
utils/new-statd.

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---

 .gitignore                  |    4 +
 Makefile.am                 |    4 -
 aclocal/libcap.m4           |   15 ++
 aclocal/libsqlite3.m4       |   33 ++++
 aclocal/libtirpc.m4         |    2 
 configure.ac                |   12 ++
 utils/Makefile.am           |    7 +
 utils/new-statd/Makefile.am |  102 ++++++++++++++
 utils/new-statd/main.c      |  319 +++++++++++++++++++++++++++++++++++++++++++
 utils/new-statd/sm-notify.c |  155 +++++++++++++++++++++
 utils/new-statd/sm_inter.x  |  107 ++++++++++++++
 utils/new-statd/start-statd |   12 ++
 utils/new-statd/statd.h     |  135 ++++++++++++++++++
 utils/statd/Makefile.am     |    9 +
 14 files changed, 911 insertions(+), 5 deletions(-)
 create mode 100644 aclocal/libcap.m4
 create mode 100644 aclocal/libsqlite3.m4
 create mode 100644 utils/new-statd/Makefile.am
 create mode 100644 utils/new-statd/main.c
 create mode 100644 utils/new-statd/sm-notify.c
 create mode 100644 utils/new-statd/sm_inter.x
 create mode 100644 utils/new-statd/start-statd
 create mode 100644 utils/new-statd/statd.h

diff --git a/.gitignore b/.gitignore
index 632609e..30e9408 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,6 +49,8 @@ utils/rquotad/rquota.h
 utils/rquotad/rquota_xdr.c
 utils/showmount/showmount
 utils/statd/statd
+utils/new-statd/statd
+utils/new-statd/sm-notify
 tools/locktest/testlk
 tools/getiversion/getiversion
 support/export/mount.h
@@ -59,6 +61,8 @@ utils/statd/sm_inter.h
 utils/statd/sm_inter_clnt.c
 utils/statd/sm_inter_svc.c
 utils/statd/sm_inter_xdr.c
+utils/new-statd/sm_inter.h
+utils/new-statd/sm_inter_xdr.c
 # cscope database files
 cscope.*
 # generic editor backup et al
diff --git a/Makefile.am b/Makefile.am
index b3a6e91..d45dbde 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -54,10 +54,6 @@ install-data-hook:
 	touch $(DESTDIR)$(statedir)/xtab; chmod 644 $(DESTDIR)$(statedir)/xtab
 	touch $(DESTDIR)$(statedir)/etab; chmod 644 $(DESTDIR)$(statedir)/etab
 	touch $(DESTDIR)$(statedir)/rmtab; chmod 644 $(DESTDIR)$(statedir)/rmtab
-	mkdir -p $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak
-	touch $(DESTDIR)$(statedir)/state
-	chmod go-rwx $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state
-	-chown $(statduser) $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state
 
 uninstall-hook:
 	rm $(DESTDIR)$(statedir)/xtab
diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4
new file mode 100644
index 0000000..eabe507
--- /dev/null
+++ b/aclocal/libcap.m4
@@ -0,0 +1,15 @@
+dnl Checks for libcap.so
+dnl
+AC_DEFUN([AC_LIBCAP], [
+
+  dnl look for prctl
+  AC_CHECK_FUNC([prctl], , )
+
+  dnl look for the library; do not add to LIBS if found
+  AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
+  AC_SUBST(LIBCAP)
+
+  AC_CHECK_HEADERS([sys/capability.h], ,
+                   [AC_MSG_ERROR([libcap headers not found.])])
+
+])dnl
diff --git a/aclocal/libsqlite3.m4 b/aclocal/libsqlite3.m4
new file mode 100644
index 0000000..73d1e46
--- /dev/null
+++ b/aclocal/libsqlite3.m4
@@ -0,0 +1,33 @@
+dnl Checks for matching sqlite3 header and library, and
+dnl sufficient sqlite3 version.
+dnl
+AC_DEFUN([AC_SQLITE3_VERS], [
+  AC_CHECK_HEADERS([sqlite3.h], ,)
+
+  dnl look for the library; do not add to LIBS if found
+  AC_CHECK_LIB([sqlite3], [sqlite3_libversion_number], [LIBSQLITE=-lsqlite3], ,)
+  AC_SUBST(LIBSQLITE)
+
+  AC_MSG_CHECKING(for suitable sqlite3 version)
+
+  AC_CACHE_VAL([libsqlite3_cv_is_recent],
+   [
+    saved_LIBS="$LIBS"
+    LIBS=-lsqlite3
+    AC_TRY_RUN([
+	#include <stdio.h>
+	#include <sqlite3.h>
+	int main()
+	{
+		int vers = sqlite3_libversion_number();
+
+		return vers != SQLITE_VERSION_NUMBER ||
+			vers < 3003000;
+	}
+       ], [libsqlite3_cv_is_recent=yes], [libsqlite3_cv_is_recent=no],
+       [libsqlite3_cv_is_recent=unknown])
+    LIBS="$saved_LIBS"])
+
+  AC_MSG_RESULT($libsqlite3_cv_is_recent)
+  AM_CONDITIONAL(CONFIG_SQLITE3, [test "$libsqlite3_cv_is_recent" = "yes"])
+])dnl
diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4
index 9f0fde0..a20894c 100644
--- a/aclocal/libtirpc.m4
+++ b/aclocal/libtirpc.m4
@@ -37,4 +37,6 @@ AC_DEFUN([AC_LIBTIRPC], [
 
   fi
 
+  AM_CONDITIONAL([CONFIG_TIRPC], [test "$enable_tirpc" != "no"])
+
 ])dnl
diff --git a/configure.ac b/configure.ac
index e0ca70e..c9ef819 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,6 +139,9 @@ AC_ARG_ENABLE(ipv6,
 dnl Check for TI-RPC library and headers
 AC_LIBTIRPC
 
+dnl Check for -lcap
+AC_LIBCAP
+
 # Check whether user wants TCP wrappers support
 AC_TCP_WRAPPERS
 
@@ -256,6 +259,14 @@ fi
 dnl Check for IPv6 support
 AC_IPV6
 
+dnl Check for sqlite3
+AC_SQLITE3_VERS
+
+dnl Build new-statd if TI-RPC and a recent libsqlite3 is present
+if test "$enable_tirpc" = yes; then
+  AM_CONDITIONAL(CONFIG_NEWSTATD, [test "$libsqlite3_cv_is_recent" = "yes"])
+fi
+
 dnl *************************************************************
 dnl Check for headers
 dnl *************************************************************
@@ -389,6 +400,7 @@ AC_CONFIG_FILES([
 	utils/nfsd/Makefile
 	utils/nfsstat/Makefile
 	utils/showmount/Makefile
+	utils/new-statd/Makefile
 	utils/statd/Makefile])
 AC_OUTPUT
 
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 8665183..3acae4c 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -2,6 +2,12 @@
 
 OPTDIRS =
 
+if CONFIG_NEWSTATD
+OPTDIRS += new-statd
+else
+OPTDIRS += statd
+endif
+
 if CONFIG_NFSV4
 OPTDIRS += idmapd
 endif
@@ -20,7 +26,6 @@ SUBDIRS = \
 	nfsd \
 	nfsstat \
 	showmount \
-	statd \
 	$(OPTDIRS)
 
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/new-statd/Makefile.am b/utils/new-statd/Makefile.am
new file mode 100644
index 0000000..281d54e
--- /dev/null
+++ b/utils/new-statd/Makefile.am
@@ -0,0 +1,102 @@
+## Process this file with automake to produce Makefile.in
+
+man8_MANS = statd.man sm-notify.man
+
+GENFILES_XDR	= sm_inter_xdr.c
+GENFILES_H	= sm_inter.h
+GENFILES	= $(GENFILES_XDR) $(GENFILES_H)
+
+RPCPREFIX	= rpc.
+KPREFIX		= @kprefix@
+sbin_PROGRAMS	= statd sm-notify
+dist_sbin_SCRIPTS	= start-statd
+
+statd_SOURCES = file.c hostname.c main.c nlmcall.c \
+		smncall.c svc.c statd.h file.h $(GENFILES)
+statd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS)
+statd_LDADD = $(top_builddir)/support/misc/libmisc.a \
+	      $(top_builddir)/support/nfs/libnfs.a \
+	      $(LIBWRAP) $(LIBSQLITE) $(LIBCAP)
+
+sm_notify_SOURCES = file.c hostname.c sm-notify.c smncall.c \
+		    statd.h file.h $(GENFILES)
+sm_notify_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS)
+sm_notify_LDADD = $(top_builddir)/support/misc/libmisc.a \
+		  $(top_builddir)/support/nfs/libnfs.a \
+		  $(LIBSQLITE) $(LIBCAP)
+
+BUILT_SOURCES = $(GENFILES)
+
+EXTRA_DIST = $(man8_MANS) sm_inter.x
+
+dist-hook:
+	for f in $(GENFILES); do \
+	  rm ${distdir}/$$f; \
+	done
+
+if CONFIG_RPCGEN
+RPCGEN	= $(top_builddir)/tools/rpcgen/rpcgen
+$(RPCGEN):
+	make -C ../../tools/rpcgen all
+else
+RPCGEN = @RPCGEN_PATH@
+endif
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+	test -f $@ && rm -rf $@ || true
+	$(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+	test -f $@ && rm -rf $@ || true
+	$(RPCGEN) -h -o $@ $<
+
+MAINTAINERCLEANFILES = Makefile.in
+
+CLEANFILES = $(GENFILES)
+
+#######################################################################
+# The following allows the current practice of having
+# daemons renamed during the install to include RPCPREFIX
+# and the KPREFIX
+# This could all be done much easier with program_transform_name
+# ( program_transform_name = s/^/$(RPCPREFIX)$(KPREFIX)/ )
+# but that also renames the man pages, which the current
+# practice does not do.
+#
+install-exec-hook:
+	(cd $(DESTDIR)$(sbindir) && \
+	  for p in $(sbin_PROGRAMS); do \
+	    [ $$p = sm-notify ] || mv -f $$p$(EXEEXT) $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\
+	  done)
+uninstall-hook:
+	(cd $(DESTDIR)$(sbindir) && \
+	  for p in $(sbin_PROGRAMS); do \
+	    [ $$p = sm-notify ] || rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\
+	  done)
+
+install-data-hook:
+	if [ ! -d $(DESTDIR)$(statedir) ]; then mkdir -p $(DESTDIR)$(statedir); chown $(statduser) $(DESTDIR)$(statedir); fi
+
+uninstall-hook:
+	rm $(DESTDIR)$(statedir)/statdb
+
+# XXX This makes some assumptions about what automake does.
+# XXX But there is no install-man-hook or install-man-local.
+#
+install-man: install-man8 install-man-links
+uninstall-man: uninstall-man8 uninstall-man-links
+
+install-man-links:
+	(cd $(DESTDIR)$(man8dir) && \
+	  for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \
+	    inst=`echo $$m | sed -e 's/man$$/8/'`; \
+	    rm -f $(RPCPREFIX)$$inst ; \
+	    $(LN_S) $$inst $(RPCPREFIX)$$inst ; \
+	  done)
+
+uninstall-man-links:
+	(cd $(DESTDIR)$(man8dir) && \
+	  for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \
+	    inst=`echo $$m | sed -e 's/man$$/8/'`; \
+	    rm -f $(RPCPREFIX)$$inst ; \
+	  done)
diff --git a/utils/new-statd/main.c b/utils/new-statd/main.c
new file mode 100644
index 0000000..f7b3cfa
--- /dev/null
+++ b/utils/new-statd/main.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/wait.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <errno.h>
+#include <locale.h>
+
+#include "statd.h"
+#include "nfsrpc.h"
+
+static char statd_my_name[SM_MAXSTRLEN];
+static char statd_progname[PATH_MAX];
+static char statd_callout_prog[PATH_MAX];
+char *ha_callout_prog = NULL;
+
+int opt_debug, opt_foreground, opt_notify_port;
+char *opt_name = NULL;
+
+static const char *statd_nsm_pgmtbl[] = {
+	"status",
+	NULL,
+};
+rpcprog_t statd_nsm_program;
+
+static char statd_opts[] = "dFwh?H:n:p:o:P:";
+static struct option statd_longopts[] =
+{
+	{ "debug", 0, 0, 'd', },
+	{ "foreground", 0, 0, 'F', },
+	{ "ha-callout", 1, 0, 'H', },
+	{ "help", 0, 0, 'h', },
+	{ "name", 1, 0, 'n', },
+	{ "notify-port", 1, 0, 'o', },
+	{ "port", 1, 0, 'p', },
+	{ "state-directory-path", 1, 0, 'P', },
+	{ "warm-start", 0, 0, 'w', },
+	{ NULL, 0, 0, '\0', }
+};
+
+static void
+statd_usage(const char *progname)
+{
+	fprintf(stderr, "%s version " VERSION "\n", progname);
+	fprintf(stderr, "usage: %s [options]\n", progname);
+
+	fprintf(stderr, "\t-d, --debug          Enable verbose debug logging\n");
+	fprintf(stderr, "\t-F, --foreground     Foreground mode\n");
+	fprintf(stderr, "\t-H, --ha-callout     Specify a high-availability callout program\n");
+	fprintf(stderr, "\t-h, -?, --help       Print this help\n");
+	fprintf(stderr, "\t-n, --name           Mon_name for SM_NOTIFY requests\n");
+	fprintf(stderr, "\t-o, --notify-port    Source port for notifications\n");
+	fprintf(stderr, "\t-p, --port           Listener port for NSM protocol\n");
+	fprintf(stderr, "\t-P, --state-directory-path  State directory path\n");
+	fprintf(stderr, "\t-w, --warm-start     Do not notify\n");
+}
+
+static void
+statd_signal(int sig)
+{
+	xlog(L_WARNING, "Caught signal %d, unregistering and exiting", sig);
+
+	/*
+	 * POSIX says atexit function isn't called on signal.
+	 */
+	statd_unregister();
+
+	exit(EXIT_SUCCESS);
+}
+
+/*
+ * Prevent multiple copies of statd from running concurrently.
+ * The pid file is automatically unlocked when statd exits.
+ */
+static bool_t
+statd_lock_pidfile(void)
+{
+	const char *filename = STATD_PIDFILE;
+	struct flock pidlock = {
+		.l_type		= F_WRLCK,
+		.l_whence	= SEEK_SET,
+	};
+	char pidbuf[16];
+	ssize_t count;
+	bool_t result;
+	int len, fd;
+
+	result = FALSE;
+
+	len = snprintf(pidbuf, sizeof(pidbuf), "%u\n", getpid());
+	if (__error_check(len, sizeof(pidbuf))) {
+		xlog(L_ERROR, "Pid overflows write buffer");
+		return result;
+	}
+
+	fd = open(filename, O_CREAT|O_WRONLY|O_SYNC|O_NOFOLLOW,
+							S_IWUSR|S_IRUSR);
+	if (fd == -1) {
+		xlog(L_ERROR, "Failed to open %s: %m", filename);
+		return result;
+	}
+
+	if (fcntl(fd, F_SETLK, &pidlock) == -1) {
+		switch (errno) {
+		case EACCES:
+		case EAGAIN:
+			(void)fcntl(fd, F_GETLK, &pidlock);
+			xlog(L_ERROR, "Another statd is running, pid: %u",
+					pidlock.l_pid);
+			break;
+		default:
+			xlog(L_ERROR, "Failed to lock %s: %m", filename);
+		}
+		goto out;
+	}
+
+	if (ftruncate(fd, 0) == -1) {
+		xlog(L_ERROR, "Failed to truncate %s: %m", filename);
+		goto out;
+	}
+
+	count = write(fd, pidbuf, len);
+	if (__exact_error_check(count, len)) {
+		xlog(L_ERROR, "Failed to write %s: %m", filename);
+		goto out;
+	}
+
+	result = TRUE;
+	xlog(D_GENERAL, "Lock acquired on pidfile. Pid: %u", getpid());
+
+out:
+	return result;
+}
+
+int
+main(int argc, char **argv)
+{
+	const struct sigaction statd_sigaction = {
+		.sa_handler	= statd_signal,
+	};
+	char *opt_state_directory = NULL;
+	int opt_listen_port = 0;
+	int opt_warmstart = 0;
+	int arg;
+
+	(void)setlocale(LC_ALL, "");
+	(void)umask(S_IRWXO);
+	xlog_stderr(0);
+	xlog_syslog(1);
+
+	strncpy(statd_progname, basename(argv[0]), sizeof(statd_progname));
+
+	while ((arg = getopt_long(argc, argv,
+					statd_opts, statd_longopts, NULL)) != EOF) {
+		switch (arg) {
+		case 'd':
+			xlog_config(D_ALL, 1);
+			opt_debug++;
+			break;
+		case 'F':
+			xlog_stderr(1);
+			opt_foreground++;
+			break;
+		case 'H':
+			if (strlen(optarg) > sizeof(statd_callout_prog)) {
+				fprintf(stderr, "%s: Invalid HA callout program\n",
+					statd_progname);
+				exit(EXIT_FAILURE);
+			}
+			strncpy(statd_callout_prog, optarg,
+						sizeof(statd_callout_prog));
+			ha_callout_prog = statd_callout_prog;
+			break;
+		case '?':
+		case 'h':
+			statd_usage(statd_progname);
+			exit(EXIT_SUCCESS);
+		case 'n':
+			if (strlen(optarg) > sizeof(statd_my_name)) {
+				fprintf(stderr, "%s: mon_name too long\n",
+					statd_progname);
+				exit(EXIT_FAILURE);
+			}
+			strncpy(statd_my_name, optarg,
+						sizeof(statd_my_name));
+			opt_name = statd_my_name;
+			break;
+		case 'o':
+			opt_notify_port = atoi(optarg);
+			if (opt_notify_port < 1 || opt_notify_port > 65535) {
+				fprintf(stderr,
+					"%s: Invalid notify port number: %s\n",
+					statd_progname, optarg);
+				statd_usage(statd_progname);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'p':
+			opt_listen_port = atoi(optarg);
+			if (opt_listen_port < 1 || opt_listen_port > 65535) {
+				fprintf(stderr,
+					"%s: Invalid listener port number: %s\n",
+					statd_progname, optarg);
+				statd_usage(statd_progname);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'P':
+			opt_state_directory = optarg;
+			break;
+		case 'w':
+			opt_warmstart++;
+			break;
+		default:
+			statd_usage(statd_progname);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (opt_listen_port != 0 && opt_notify_port != 0 &&
+	    opt_listen_port == opt_notify_port) {
+		fprintf(stderr, "Listening and notification ports "
+				"cannot be the same\n");
+		exit(EXIT_FAILURE);
+	}
+
+	xlog_open(statd_progname);
+
+	if (!opt_foreground) {
+		if (daemon(1, 0) < 0) {
+			xlog(L_ERROR, "Failed to background: %m");
+			exit(EXIT_FAILURE);
+		}
+	}
+	xlog(L_NOTICE, "Version " VERSION " starting");
+
+	/*
+	 * ORDER
+	 *
+	 * Make sure the database pathname is validated and
+	 * set up before forking the NLM callback process, to
+	 * ensure it can access the database.
+	 */
+	if (!statd_check_pathname(opt_state_directory))
+		exit(EXIT_FAILURE);
+
+	if (!statd_lock_pidfile())
+		exit(EXIT_FAILURE);
+
+	(void)sigaction(SIGHUP, &statd_sigaction, NULL);
+	(void)sigaction(SIGINT, &statd_sigaction, NULL);
+	(void)sigaction(SIGTERM, &statd_sigaction, NULL);
+
+	if (!statd_init_nlm_callback())
+		exit(EXIT_FAILURE);
+
+	/*
+	 * ORDER
+	 *
+	 * Clear previous NSM listener registrations while we're still
+	 * root.  This should guarantee that we can rip out any previous
+	 * registrations, no matter who made them.
+	 */
+	statd_nsm_program = nfs_getrpcbyname(SM_PROG, statd_nsm_pgmtbl);
+	if (!rpcb_unset(statd_nsm_program, SM_VERS, NULL)) {
+		xlog(L_ERROR, "Failed to remove old NSM registrations");
+		exit(EXIT_FAILURE);
+	}
+
+	if (!statd_drop_privileges(0))
+		exit(EXIT_FAILURE);
+
+	/*
+	 * Note: only the client side needs to send notifications
+	 *       automatically during a system boot.  Server side
+	 *       should invoke statd with opt_warmstart.  More
+	 *       sophisticated logic is forthcoming.
+	 */
+	if (!opt_warmstart && statd_system_rebooted())
+		(void)statd_notify(opt_name, opt_notify_port, SMN_MAX_RETRY);
+	else {
+		xlog(L_NOTICE, "Warm start: preserving monitor list and NSM state");
+		if (opt_debug)
+			statd_dump_monitor_list();
+	}
+
+	statd_svc_create(statd_nsm_program, SM_VERS, opt_listen_port);
+
+	xlog(L_ERROR, "RPC service exited");
+	exit(EXIT_FAILURE);
+}
diff --git a/utils/new-statd/sm-notify.c b/utils/new-statd/sm-notify.c
new file mode 100644
index 0000000..0d3f4c3
--- /dev/null
+++ b/utils/new-statd/sm-notify.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <locale.h>
+
+#include "statd.h"
+
+int opt_debug;
+
+static char smn_progname[PATH_MAX];
+
+static char smn_opts[] = "dfh?m:n:o:P:";
+static struct option smn_longopts[] = {
+	{ "debug", 0, NULL, 'd', },
+	{ "force", 0, NULL, 'f', },
+	{ "help", 0, NULL, 'h', },
+	{ "max-retry", 1, NULL, 'm', },
+	{ "name", 1, NULL, 'n', },
+	{ "notify-port", 1, NULL, 'o', },
+	{ "state-directory-path", 1, NULL, 'P', },
+	{ NULL, 0, NULL, 0, },
+};
+
+static void
+smn_usage(const char *progname)
+{
+	fprintf(stderr, "%s version " VERSION "\n", progname);
+	fprintf(stderr, "usage: %s [options]\n", progname);
+
+	fprintf(stderr, "\t-d, --debug          Enable verbose debug logging\n");
+	fprintf(stderr, "\t-f, --force          Force notification\n");
+	fprintf(stderr, "\t-h, -?, --help       Print this help\n");
+	fprintf(stderr, "\t-m, --max-retry      Minutes to run\n");
+	fprintf(stderr, "\t-n, --name           Specify bind address/mon_name\n");
+	fprintf(stderr, "\t-o, --notify-port    Source port for notifications\n");
+	fprintf(stderr, "\t-P, --state-directory-path  State directory path\n");
+}
+
+int
+main(int argc, char **argv)
+{
+	unsigned long opt_max_retry = SMN_MAX_RETRY;;
+	char *opt_state_directory = NULL;
+	static char mon_name[NI_MAXHOST];
+	char *opt_mon_name = NULL;
+	int opt_notify_port = 0;
+	int opt_force = 0;
+	int arg, cap_net_bind;
+
+	(void)setlocale(LC_ALL, "");
+	(void)umask(S_IRWXO);
+	xlog_stderr(0);
+	xlog_syslog(1);
+
+	strncpy(smn_progname, basename(argv[0]), sizeof(smn_progname));
+
+	while ((arg = getopt_long(argc, argv,
+					smn_opts, smn_longopts, NULL)) != -1) {
+		switch (arg) {
+		case 'd':
+			xlog_config(D_ALL, 1);
+			xlog_stderr(1);
+			opt_debug++;
+			break;
+		case 'f':
+			opt_force++;
+			break;
+		case '?':
+		case 'h':
+			smn_usage(smn_progname);
+			exit(EXIT_SUCCESS);
+		case 'm':
+			opt_max_retry = atoi(optarg) * 60;
+			break;
+		case 'n':
+			if (strlen(optarg) > sizeof(mon_name)) {
+				fprintf(stderr, "%s: Invalid bind address\n",
+					smn_progname);
+				exit(EXIT_FAILURE);
+			}
+			strncpy(mon_name, optarg, sizeof(mon_name));
+			opt_mon_name = mon_name;
+			break;
+		case 'o':
+			opt_notify_port = atoi(optarg);
+			if (opt_notify_port < 1 || opt_notify_port > 65535) {
+				fprintf(stderr, "%s: Invalid port number: %s\n",
+					smn_progname, optarg);
+				smn_usage(smn_progname);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'P':
+			opt_state_directory = optarg;
+			break;
+		default:
+			smn_usage(smn_progname);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	xlog_open(smn_progname);
+
+	if (!opt_debug) {
+		if (daemon(1, 0) < 0) {
+			xlog(L_ERROR, "Failed to background: %m");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (!statd_check_pathname(opt_state_directory))
+		exit(EXIT_FAILURE);
+
+	cap_net_bind = (opt_notify_port > 0 && opt_notify_port < 1024);
+	if (!statd_drop_privileges(cap_net_bind))
+		exit(EXIT_FAILURE);
+
+	xlog(L_NOTICE, "Version " VERSION " starting");
+
+	if (opt_force || statd_system_rebooted()) {
+		if (!statd_notify(opt_mon_name, opt_notify_port, opt_max_retry))
+			exit(EXIT_FAILURE);
+	} else
+		xlog(L_NOTICE, "No hosts to notify");
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/utils/new-statd/sm_inter.x b/utils/new-statd/sm_inter.x
new file mode 100644
index 0000000..413d3e5
--- /dev/null
+++ b/utils/new-statd/sm_inter.x
@@ -0,0 +1,107 @@
+%/*
+% * Copyright 2009 Oracle.  All rights reserved.
+% *
+% * This file is part of nfs-utils.
+% *
+% * nfs-utils is free software; you can redistribute it and/or modify
+% * it under the terms of the GNU General Public License as published by
+% * the Free Software Foundation; either version 2 of the License, or
+% * (at your option) any later version.
+% *
+% * nfs-utils is distributed in the hope that it will be useful,
+% * but WITHOUT ANY WARRANTY; without even the implied warranty of
+% * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% * GNU General Public License for more details.
+% *
+% * You should have received a copy of the GNU General Public License
+% * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+% */
+
+%/*
+% * NSM for Linux.
+% */
+
+/*
+ * RPCL definition of Network Status Monitor, version 1, based on
+ * The Open Group's "Protocols for Interworking: XNFS, Version 3W"
+ */
+
+const SM_MAXSTRLEN = 1024;
+const SM_PRIV_SIZE = 16;
+
+enum res {
+	stat_succ = 0,
+	stat_fail = 1
+};
+
+struct sm_name {
+	string		mon_name<SM_MAXSTRLEN>;
+};
+
+struct sm_stat_res {
+	res		res_stat;
+	int		state;
+};
+
+struct sm_stat {
+	int		state;
+};
+
+struct my_id {
+	string		my_name<SM_MAXSTRLEN>;
+	int		my_prog;
+	int		my_vers;
+	int		my_proc;
+};
+
+struct mon_id {
+	string		mon_name<SM_MAXSTRLEN>;
+	struct		my_id my_id;
+};
+
+struct mon {
+	struct mon_id	mon_id;
+	opaque		priv[SM_PRIV_SIZE];
+};
+
+struct stat_chge {
+	string		mon_name<SM_MAXSTRLEN>;
+	int		state;
+};
+
+program SM_PROG {
+	version SM_VERS {
+		void
+		SM_NULL(void) = 0;
+
+		struct sm_stat_res
+		SM_STAT(struct sm_name) = 1;
+
+		struct sm_stat_res
+		SM_MON(struct mon) = 2;
+
+		struct sm_stat
+		SM_UNMON(struct mon_id) = 3;
+
+		struct sm_stat
+		SM_UNMON_ALL(struct my_id) = 4;
+
+		void
+		SM_SIMU_CRASH(void) = 5;
+
+		void
+		SM_NOTIFY(struct stat_chge) = 6;
+	} = 1;
+} = 100024;
+
+/*
+ * This data type is used for the argument of an unnamed dynamic
+ * NLM RPC procedure call (meaning lockd tells statd what procedure
+ * call number to use) that is private to the Linux lockd and
+ * statd implementation.
+ */
+struct nlm_reboot {
+	string		mon_name<SM_MAXSTRLEN>;
+	int		state;
+	opaque		priv[SM_PRIV_SIZE];
+};
diff --git a/utils/new-statd/start-statd b/utils/new-statd/start-statd
new file mode 100644
index 0000000..da0f65f
--- /dev/null
+++ b/utils/new-statd/start-statd
@@ -0,0 +1,12 @@
+#!/bin/sh -p
+#
+# Sample start-statd script
+#
+# mount.nfs execs this script when mounting a filesystem with locking
+# enabled, but when statd does not seem to be running
+#
+# It should run run statd with whatever flags are appropriate for
+# this site.
+#
+PATH=/sbin:/usr/sbin
+exec rpc.statd
diff --git a/utils/new-statd/statd.h b/utils/new-statd/statd.h
new file mode 100644
index 0000000..b762b03
--- /dev/null
+++ b/utils/new-statd/statd.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2009 Oracle.  All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ */
+
+#ifndef _NFS_UTILS_STATD_STATD_H
+#define _NFS_UTILS_STATD_STATD_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+#include <time.h>
+#include <sqlite3.h>
+
+#include <rpc/types.h>
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+
+#include "sm_inter.h"
+#include "xlog.h"
+
+#define STATD_MONITOR_TABLENAME		"monitor"
+#define STATD_NOTIFY_TABLENAME		"notify"
+#define STATD_INFO_TABLENAME		"info"
+
+#define STATD_KERNEL_NSM_STATE		"/proc/sys/fs/nfs/nsm_local_state"
+#define STATD_PIDFILE			"/var/run/rpc.statd.pid"
+
+/*
+ * Retry timeout for individual NLM callbacks
+ */
+#define STATD_NLM_CALLBACK_TIMEOUT	(30)
+
+/*
+ * Number of times to retry an NLM callback before giving up
+ */
+#define STATD_NLM_CALLBACK_RETRIES	(10)
+
+/*
+ * Retry timeout for individual notification requests
+ */
+#define SMN_TIMEOUT		(5)	/* in seconds */
+
+/*
+ * Timeout for notifying all hosts
+ */
+#define SMN_MAX_RETRY		(15)	/* in minutes */
+
+extern rpcprog_t	statd_nsm_program;
+extern int		statd_my_state;
+
+extern int		opt_debug, opt_foreground, opt_notify_port;
+extern char		*opt_name;
+
+/* file.c */
+extern bool_t	statd_check_pathname(const char *parentdir);
+extern bool_t	statd_drop_privileges(const int keep_bind);
+
+extern int	statd_get_nsm_state(void);
+extern bool_t	statd_update_nsm_state(sqlite3 *db);
+extern bool_t	statd_system_rebooted(void);
+
+extern sqlite3 *statd_open_db(int flags);
+extern void	statd_close_db(sqlite3 *db);
+extern bool_t	statd_prepare_stmt(sqlite3 *db, sqlite3_stmt **stmt,
+				const char *sql);
+extern void	statd_finalize_stmt(sqlite3_stmt *stmt);
+extern bool_t	statd_begin_transaction(sqlite3 *db);
+extern void	statd_end_transaction(sqlite3 *db);
+extern void	statd_rollback_transaction(sqlite3 *db);
+
+extern void	statd_dump_monitor_list(void);
+extern void	statd_print_capabilities(void);
+
+/* hostname.c */
+extern bool_t	statd_localhost_caller(const struct svc_req *rqstp);
+extern struct addrinfo *
+		statd_forward_lookup(const char *hostname, int protocol);
+extern struct addrinfo *
+		statd_get_address_list(const char *hostname,
+				const struct addrinfo *gai_hint);
+extern bool_t	statd_match_hostname(const char *hostname1,
+				const char *hostname2);
+extern bool_t	statd_match_address(const char *hostname,
+				const struct sockaddr *sap);
+
+/* nlmcall.c */
+extern void	statd_queue_nlm_callback(const char *mon_name,
+				const int state, const struct sockaddr *sap);
+extern bool_t	statd_init_nlm_callback(void);
+
+/*
+ * smncall.c
+ */
+extern bool_t	statd_notify(const char *bindaddr, const unsigned short srcport,
+				const unsigned long max_retry_minutes);
+
+/* svc.c */
+extern void	statd_unregister(void);
+extern void	statd_svc_create(const rpcprog_t program,
+				const rpcvers_t version,
+				const uint16_t port);
+
+static inline int
+__error_check(const int len, const size_t buflen)
+{
+	return (len < 0) || ((size_t)len >= buflen);
+}
+
+static inline int
+__exact_error_check(const ssize_t len, const size_t buflen)
+{
+	return (len < 0) || ((size_t)len != buflen);
+}
+
+#endif	/* !_NFS_UTILS_STATD_STATD_H */
diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am
index 8a3ba4e..080bce1 100644
--- a/utils/statd/Makefile.am
+++ b/utils/statd/Makefile.am
@@ -75,6 +75,15 @@ uninstall-hook:
 	    [ $$p = sm-notify ] || rm -f $(RPCPREFIX)$(KPREFIX)$$p$(EXEEXT) ;\
 	  done)
 
+install-data-hook:
+	if [ ! -d $(DESTDIR)$(statedir) ]; then mkdir -p $(DESTDIR)$(statedir); fi
+	mkdir -p $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak
+	touch $(DESTDIR)$(statedir)/state
+	chmod go-rwx $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state
+	-chown $(statduser) $(DESTDIR)$(statedir)/sm $(DESTDIR)$(statedir)/sm.bak $(DESTDIR)$(statedir)/state
+
+uninstall-hook:
+	rm $(DESTDIR)$(statedir)/state
 
 # XXX This makes some assumptions about what automake does.
 # XXX But there is no install-man-hook or install-man-local.

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux