summaryrefslogtreecommitdiffstats
path: root/utils/statd
diff options
context:
space:
mode:
authorhjl <hjl>1999-10-18 23:21:12 +0000
committerhjl <hjl>1999-10-18 23:21:12 +0000
commit8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9 (patch)
tree0904ef8554ed680fe3244fa618685e1fb7ea148b /utils/statd
downloadnfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.gz
nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.xz
nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.zip
Initial revision
Diffstat (limited to 'utils/statd')
-rw-r--r--utils/statd/COPYING340
-rw-r--r--utils/statd/COPYRIGHT25
-rw-r--r--utils/statd/Makefile58
-rw-r--r--utils/statd/TODO13
-rw-r--r--utils/statd/callback.c53
-rw-r--r--utils/statd/log.c108
-rw-r--r--utils/statd/log.h41
-rw-r--r--utils/statd/misc.c72
-rw-r--r--utils/statd/monitor.c287
-rw-r--r--utils/statd/notify.c75
-rw-r--r--utils/statd/notlist.c125
-rw-r--r--utils/statd/notlist.h111
-rw-r--r--utils/statd/rmtcall.c406
-rw-r--r--utils/statd/sim_sm_inter.x32
-rw-r--r--utils/statd/simu.c29
-rw-r--r--utils/statd/simulate.c225
-rw-r--r--utils/statd/sm_inter.x132
-rw-r--r--utils/statd/stat.c37
-rw-r--r--utils/statd/statd.c122
-rw-r--r--utils/statd/statd.h58
-rw-r--r--utils/statd/statd.man53
-rw-r--r--utils/statd/state.c126
-rw-r--r--utils/statd/svc_run.c128
-rw-r--r--utils/statd/system.h18
-rw-r--r--utils/statd/version.h7
25 files changed, 2681 insertions, 0 deletions
diff --git a/utils/statd/COPYING b/utils/statd/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/utils/statd/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/utils/statd/COPYRIGHT b/utils/statd/COPYRIGHT
new file mode 100644
index 0000000..7b91031
--- /dev/null
+++ b/utils/statd/COPYRIGHT
@@ -0,0 +1,25 @@
+rpc.statd -- Network Status Monitor (NSM) protocol daemon for Linux.
+Copyright (C) 1995-1999 Jeffrey A. Uphoff
+
+This program 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.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
+
+Jeffrey A. Uphoff
+Transmeta Corporation
+2540 Mission College Blvd.
+Santa Clara, CA, 95054
+USA
+
+Phone: +1-408-919-6458
+Internet: juphoff@transmeta.com
diff --git a/utils/statd/Makefile b/utils/statd/Makefile
new file mode 100644
index 0000000..3a3a794
--- /dev/null
+++ b/utils/statd/Makefile
@@ -0,0 +1,58 @@
+# Copyright (C) 1995-1999 Jeffrey A. Uphoff
+# Adapted for linux-nfs build tree by Olaf Kirch, 1996.
+#
+# NSM for Linux.
+
+# Uncomment for embedded client-side simulation functions.
+#SIMUL = -DSIMULATIONS
+
+# Undefined is normal, defined provides debug logging.
+#DEBUG = -DDEBUG
+
+##################################################################
+# no user-serviceable parts below this line
+##################################################################
+PROGRAM = statd
+PREFIX = rpc.
+OBJS = $(SRCS:.c=.o)
+CCOPTS = $(DEBUG) $(SIMUL)
+LIBS = -lexport
+
+SRCS = $(RPCSRCS) $(SIMSRCS) \
+ callback.c notlist.c log.c misc.c monitor.c notify.c simu.c \
+ stat.c statd.c state.c svc_run.c rmtcall.c
+HDRS = $(RPCHDRS) $(SIMHDRS)
+
+RPCSRCS = sm_inter_clnt.c sm_inter_svc.c sm_inter_xdr.c
+RPCHDRS = sm_inter.h
+
+ifdef SIMUL
+SIMSRCS = sim_sm_inter_clnt.c sim_sm_inter_svc.c
+SIMHDRS = sim_sm_inter.h
+SRCS += simulate.c
+endif
+
+MAN8 = statd
+
+include $(TOP)rules.mk
+
+AFLAGS += -Wno-unused
+
+$(RPCHDRS) $(RPCSRCS): sm_inter.x
+ $(RM) $(RPCHDRS) $(RPCSRCS)
+ $(RPCGEN) -h -o sm_inter.h $<
+ $(RPCGEN) -l -o sm_inter_clnt.c $<
+ $(RPCGEN) -m -o sm_inter_svc.c $<
+ $(RPCGEN) -c -o sm_inter_xdr.c $<
+
+$(SIMHDRS) $(SIMSRCS): sim_sm_inter.x
+ $(RM) $(SIMHDRS) $(SIMSRCS)
+ $(RPCGEN) -h -o sim_sm_inter.h $<
+ $(RPCGEN) -l -o sim_sm_inter_clnt.c $<
+ $(RPCGEN) -m -o sim_sm_inter_svc.c $<
+
+clean::
+ $(RM) $(PROGRAM)
+
+distclean::
+ $(RM) $(RPCHDRS) $(RPCSRCS) $(SIMHDRS) $(SIMSRCS)
diff --git a/utils/statd/TODO b/utils/statd/TODO
new file mode 100644
index 0000000..0ee050a
--- /dev/null
+++ b/utils/statd/TODO
@@ -0,0 +1,13 @@
+Some things still left to do (not a comprehensive list):
+
+* Go through Olaf's extensive changes (especially the list and callback
+ handling, which is the meat of the server) and understand everything
+ that he's done.
+
+* Continue checking for security holes.
+
+* Handle multiple SM_MON requests that are identical save for the "priv"
+ information. How should I do this? No spec's...(it's not really
+ supposed to happen). [Did Olaf already address this?]
+
+* BETTER CODE COMMENTS!
diff --git a/utils/statd/callback.c b/utils/statd/callback.c
new file mode 100644
index 0000000..e3fad6a
--- /dev/null
+++ b/utils/statd/callback.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, Oct. 1996.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#include "statd.h"
+#include "notlist.h"
+
+/* Callback notify list. */
+notify_list *cbnl = NULL;
+
+
+/*
+ * Services SM_NOTIFY requests.
+ * Any clients that have asked us to monitor that host are put on
+ * the global callback list, which is processed as soon as statd
+ * returns to svc_run.
+ */
+void *
+sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp)
+{
+ notify_list *lp, *call;
+ static char *result = NULL;
+
+ dprintf(L_DEBUG, "Received SM_NOTIFY from %s, state: %d",
+ argp->mon_name, argp->state);
+
+ if ((lp = rtnl) != NULL) {
+ log(L_WARNING, "SM_NOTIFY from %s--nobody looking!",
+ argp->mon_name, argp->state);
+ return ((void *) &result);
+ }
+
+ /* okir change: statd doesn't remove the remote host from its
+ * internal monitor list when receiving an SM_NOTIFY call from
+ * it. Lockd will want to continue monitoring the remote host
+ * until it issues an SM_UNMON call.
+ */
+ while ((lp = nlist_gethost(lp, argp->mon_name, 0)) != NULL) {
+ if (NL_STATE(lp) != argp->state) {
+ NL_STATE(lp) = argp->state;
+ call = nlist_clone(lp);
+ NL_TYPE(call) = NOTIFY_CALLBACK;
+ nlist_insert(&notify, call);
+ }
+ lp = NL_NEXT(lp);
+ }
+
+ return ((void *) &result);
+}
diff --git a/utils/statd/log.c b/utils/statd/log.c
new file mode 100644
index 0000000..38f7d3a
--- /dev/null
+++ b/utils/statd/log.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 1995 Olaf Kirch
+ * Modified by Jeffrey A. Uphoff, 1995, 1997, 1999.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * log.c - logging functions for lockd/statd
+ * 260295 okir started with simply syslog logging.
+ */
+
+#include "config.h"
+
+#include <syslog.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/types.h>
+#include "log.h"
+
+static char progname[256];
+static pid_t mypid;
+ /* Turns on logging to console/stderr. */
+static int opt_debug = 0; /* Will be command-line option, eventually */
+
+void
+log_init(char *name)
+{
+ char *sp;
+
+ openlog(name, LOG_PID, LOG_LOCAL5);
+ if ((sp = strrchr(name, '/')) != NULL)
+ name = ++sp;
+ strncpy(progname, name, sizeof (progname) - 1);
+ progname[sizeof (progname) - 1] = '\0';
+ mypid = getpid();
+}
+
+void
+log_background(void)
+{
+ /* NOP */
+}
+
+void
+log_enable(int level)
+{
+ opt_debug = 1;
+}
+
+int
+log_enabled(int level)
+{
+ return opt_debug;
+}
+
+void
+die(char *fmt, ...)
+{
+ char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf (buffer, 1024, fmt, ap);
+ va_end(ap);
+ buffer[1023]=0;
+
+ log(L_FATAL, "%s", buffer);
+
+#ifndef DEBUG
+ exit (2);
+#else
+ abort(); /* make a core */
+#endif
+}
+
+void
+log(int level, char *fmt, ...)
+{
+ char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf (buffer, 1024, fmt, ap);
+ va_end(ap);
+ buffer[1023]=0;
+
+ if (level < L_DEBUG) {
+ syslog(level, buffer);
+ }
+
+ if (opt_debug) {
+ time_t now;
+ struct tm * tm;
+
+ time(&now);
+ tm = localtime(&now);
+ fprintf (stderr, "%02d.%02d.%02d %02d:%02d:%02d %s[%d]: %s\n",
+ tm->tm_mday, tm->tm_mon, tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ progname, mypid,
+ buffer);
+ }
+}
diff --git a/utils/statd/log.h b/utils/statd/log.h
new file mode 100644
index 0000000..f00bb63
--- /dev/null
+++ b/utils/statd/log.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1995 Olaf Kirch
+ * Modified by Jeffrey A. Uphoff, 1996, 1997, 1999.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * logging functionality
+ * 260295 okir
+ */
+
+#ifndef _LOCKD_LOG_H_
+#define _LOCKD_LOG_H_
+
+#include <syslog.h>
+
+void log_init(char *name);
+void log_background(void);
+void log_enable(int facility);
+int log_enabled(int facility);
+void log(int level, char *fmt, ...);
+void die(char *fmt, ...);
+
+/*
+ * Map per-application severity to system severity. What's fatal for
+ * lockd is merely an itching spot from the universe's point of view.
+ */
+#define L_CRIT LOG_CRIT
+#define L_FATAL LOG_ERR
+#define L_ERROR LOG_WARNING
+#define L_WARNING LOG_NOTICE
+#define L_DEBUG LOG_DEBUG
+
+#ifdef DEBUG
+#define dprintf log
+#else
+#define dprintf if (0) log
+#endif
+
+#endif /* _LOCKD_LOG_H_ */
diff --git a/utils/statd/misc.c b/utils/statd/misc.c
new file mode 100644
index 0000000..42f6e57
--- /dev/null
+++ b/utils/statd/misc.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 1995-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include "statd.h"
+#include "notlist.h"
+
+/*
+ * Error-checking malloc() wrapper.
+ */
+void *
+xmalloc (size_t size)
+{
+ void *ptr;
+
+ if (size == 0)
+ return ((void *)NULL);
+
+ if (!(ptr = malloc (size)))
+ /* SHIT! SHIT! SHIT! */
+ die ("malloc failed");
+
+ return (ptr);
+}
+
+
+/*
+ * Error-checking strdup() wrapper.
+ */
+char *
+xstrdup (const char *string)
+{
+ char *result;
+
+ /* Will only fail if underlying malloc() fails (ENOMEM). */
+ if (!(result = strdup (string)))
+ die ("strdup failed");
+
+ return (result);
+}
+
+
+/*
+ * Call with check=1 to verify that this host is not still on the rtnl
+ * before unlinking file.
+ */
+void
+xunlink (char *path, char *host, short int check)
+{
+ char *tozap;
+
+ tozap=alloca (strlen(path)+strlen(host)+2);
+ sprintf (tozap, "%s/%s", path, host);
+
+ if (!check || !nlist_gethost(rtnl, host, 0))
+ if (unlink (tozap) == -1)
+ log (L_ERROR, "unlink (%s): %s", tozap, strerror (errno));
+ else
+ dprintf (L_DEBUG, "Unlinked %s", tozap);
+ else
+ dprintf (L_DEBUG, "Not unlinking %s--host still monitored.", tozap);
+}
diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c
new file mode 100644
index 0000000..5a782dc
--- /dev/null
+++ b/utils/statd/monitor.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 1995-1999 Jeffrey A. Uphoff
+ * Major rewrite by Olaf Kirch, Dec. 1996.
+ * Modified by H.J. Lu, 1998.
+ * Tighter access control, Olaf Kirch June 1999.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include "misc.h"
+#include "statd.h"
+#include "notlist.h"
+
+notify_list * rtnl = NULL; /* Run-time notify list. */
+
+
+/*
+ * Services SM_MON requests.
+ */
+struct sm_stat_res *
+sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
+{
+ static sm_stat_res result;
+ char *mon_name = argp->mon_id.mon_name,
+ *my_name = argp->mon_id.my_id.my_name;
+ struct my_id *id = &argp->mon_id.my_id;
+ char *path;
+ int fd;
+ notify_list *clnt;
+ struct in_addr my_addr;
+#ifdef RESTRICTED_STATD
+ struct in_addr mon_addr, caller;
+#else
+ struct hostent *hostinfo = NULL;
+#endif
+
+ /* Assume that we'll fail. */
+ result.res_stat = STAT_FAIL;
+ result.state = -1; /* State is undefined for STAT_FAIL. */
+
+ /* Restrict access to statd.
+ * In the light of CERT CA-99.05, we tighten access to
+ * statd. --okir
+ */
+#ifdef RESTRICTED_STATD
+ /* 1. Reject anyone not calling from 127.0.0.1.
+ * Ignore the my_name specified by the caller, and
+ * use "127.0.0.1" instead.
+ */
+ caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+ if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
+ log(L_WARNING,
+ "Call to statd from non-local host %s",
+ inet_ntoa(caller));
+ goto failure;
+ }
+ my_addr.s_addr = htonl(INADDR_LOOPBACK);
+ my_name = "127.0.0.1";
+
+ /* 2. Reject any registrations for non-lockd services.
+ * This is specific to the linux kernel lockd, which
+ * makes the callback procedure part of the lockd interface.
+ */
+ if (id->my_proc != 100021) {
+ log(L_WARNING,
+ "Attempt to register callback to service %d",
+ id->my_proc);
+ goto failure;
+ }
+
+ /* 3. mon_name must be an address in dotted quad.
+ * Again, specific to the linux kernel lockd.
+ */
+ if (!inet_aton(mon_name, &mon_addr)) {
+ log(L_WARNING,
+ "Attempt to register host %s (not a dotted quad)",
+ mon_name);
+ goto failure;
+ }
+#else
+ /*
+ * Check hostnames. If I can't look them up, I won't monitor. This
+ * might not be legal, but it adds a little bit of safety and sanity.
+ */
+
+ /* must check for /'s in hostname! See CERT's CA-96.09 for details. */
+ if (strchr(mon_name, '/')) {
+ log(L_CRIT, "SM_MON request for hostname containing '/': %s",
+ mon_name);
+ log(L_CRIT, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
+ goto failure;
+ } else if (gethostbyname(mon_name) == NULL) {
+ log(L_WARNING, "gethostbyname error for %s", mon_name);
+ goto failure;
+ } else if (!(hostinfo = gethostbyname(my_name))) {
+ log(L_WARNING, "gethostbyname error for %s", my_name);
+ goto failure;
+ } else
+ my_addr = *(struct in_addr *) hostinfo->h_addr;
+#endif
+
+ /*
+ * Hostnames checked OK.
+ * Now check to see if this is a duplicate, and warn if so.
+ * I will also return STAT_FAIL. (I *think* this is how I should
+ * handle it.)
+ *
+ * Olaf requests that I allow duplicate SM_MON requests for
+ * hosts due to the way he is coding lockd. No problem,
+ * I'll just do a quickie success return and things should
+ * be happy.
+ */
+ if (rtnl) {
+ notify_list *temp = rtnl;
+
+ while ((temp = nlist_gethost(temp, mon_name, 0))) {
+ if (matchhostname(NL_MY_NAME(temp), my_name) &&
+ NL_MY_PROC(temp) == id->my_proc &&
+ NL_MY_PROG(temp) == id->my_prog &&
+ NL_MY_VERS(temp) == id->my_vers) {
+ /* Hey! We already know you guys! */
+ dprintf(L_DEBUG,
+ "Duplicate SM_MON request for %s "
+ "from procedure on %s",
+ mon_name, my_name);
+
+ /* But we'll let you pass anyway. */
+ result.res_stat = STAT_SUCC;
+ result.state = MY_STATE;
+ return (&result);
+ }
+ temp = NL_NEXT(temp);
+ }
+ }
+
+ /*
+ * We're committed...ignoring errors. Let's hope that a malloc()
+ * doesn't fail. (I should probably fix this assumption.)
+ */
+ if (!(clnt = nlist_new(my_name, mon_name, 0))) {
+ log(L_WARNING, "out of memory");
+ goto failure;
+ }
+
+ NL_ADDR(clnt) = my_addr;
+ NL_MY_PROG(clnt) = id->my_prog;
+ NL_MY_VERS(clnt) = id->my_vers;
+ NL_MY_PROC(clnt) = id->my_proc;
+ memcpy(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE);
+
+ /*
+ * Now, Create file on stable storage for host.
+ */
+
+ path=xmalloc(strlen(SM_DIR)+strlen(mon_name)+2);
+ sprintf(path, SM_DIR "/%s", mon_name);
+ if ((fd = open(path, O_WRONLY|O_SYNC|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
+ /* Didn't fly. We won't monitor. */
+ log(L_ERROR, "creat(%s) failed: %m", path);
+ nlist_free(NULL, clnt);
+ free(path);
+ goto failure;
+ }
+ free(path);
+ nlist_insert(&rtnl, clnt);
+ close(fd);
+
+ result.res_stat = STAT_SUCC;
+ result.state = MY_STATE;
+ dprintf(L_DEBUG, "MONITORING %s for %s", mon_name, my_name);
+ return (&result);
+
+failure:
+ log(L_WARNING, "STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
+ return (&result);
+}
+
+
+/*
+ * Services SM_UNMON requests.
+ *
+ * There is no statement in the X/Open spec's about returning an error
+ * for requests to unmonitor a host that we're *not* monitoring. I just
+ * return the state of the NSM when I get such foolish requests for lack
+ * of any better ideas. (I also log the "offense.")
+ */
+struct sm_stat *
+sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
+{
+ static sm_stat result;
+ notify_list *clnt;
+ char *mon_name = argp->mon_name,
+ *my_name = argp->my_id.my_name;
+ struct my_id *id = &argp->my_id;
+
+ result.state = MY_STATE;
+
+ /* Check if we're monitoring anyone. */
+ if (!(clnt = rtnl)) {
+ log(L_WARNING,
+ "Received SM_UNMON request from %s for %s while not "
+ "monitoring any hosts.", my_name, argp->mon_name);
+ return (&result);
+ }
+
+ /*
+ * OK, we are. Now look for appropriate entry in run-time list.
+ * There should only be *one* match on this, since I block "duplicate"
+ * SM_MON calls. (Actually, duplicate calls are allowed, but only one
+ * entry winds up in the list the way I'm currently handling them.)
+ */
+ while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
+ if (matchhostname(NL_MY_NAME(clnt), my_name) &&
+ NL_MY_PROC(clnt) == id->my_proc &&
+ NL_MY_PROG(clnt) == id->my_prog &&
+ NL_MY_VERS(clnt) == id->my_vers) {
+ /* Match! */
+ dprintf(L_DEBUG, "UNMONITORING %s for %s",
+ mon_name, my_name);
+ nlist_free(&rtnl, clnt);
+ xunlink(SM_DIR, mon_name, 1);
+
+ return (&result);
+ } else
+ clnt = NL_NEXT(clnt);
+ }
+
+ log(L_WARNING, "Received erroneous SM_UNMON request from %s for %s",
+ my_name, mon_name);
+ return (&result);
+}
+
+
+struct sm_stat *
+sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
+{
+ short int count = 0;
+ static sm_stat result;
+ notify_list *clnt;
+
+ result.state = MY_STATE;
+
+ if (!(clnt = rtnl)) {
+ log(L_WARNING, "Received SM_UNMON_ALL request from %s "
+ "while not monitoring any hosts", argp->my_name);
+ return (&result);
+ }
+
+ while ((clnt = nlist_gethost(clnt, argp->my_name, 1))) {
+ if (NL_MY_PROC(clnt) == argp->my_proc &&
+ NL_MY_PROG(clnt) == argp->my_prog &&
+ NL_MY_VERS(clnt) == argp->my_vers) {
+ /* Watch stack! */
+ char mon_name[SM_MAXSTRLEN + 1];
+ notify_list *temp;
+
+ dprintf(L_DEBUG,
+ "UNMONITORING (SM_UNMON_ALL) %s for %s",
+ NL_MON_NAME(clnt), NL_MY_NAME(clnt));
+ strncpy(mon_name, NL_MON_NAME(clnt),
+ sizeof (mon_name) - 1);
+ mon_name[sizeof (mon_name) - 1] = '\0';
+ temp = NL_NEXT(clnt);
+ nlist_free(&rtnl, clnt);
+ xunlink(SM_DIR, mon_name, 1);
+ ++count;
+ clnt = temp;
+ } else
+ clnt = NL_NEXT(clnt);
+ }
+
+ if (!count) {
+ dprintf(L_DEBUG, "SM_UNMON_ALL request from %s with no "
+ "SM_MON requests from it.", argp->my_name);
+ }
+
+ return (&result);
+}
diff --git a/utils/statd/notify.c b/utils/statd/notify.c
new file mode 100644
index 0000000..89d2946
--- /dev/null
+++ b/utils/statd/notify.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, Oct. 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * NSM notify list handling.
+ */
+
+#include "config.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include "misc.h"
+#include "statd.h"
+#include "notlist.h"
+
+/*
+ * Initial (startup) notify list.
+ */
+notify_list *inl = NULL;
+
+
+/*
+ * Get list of hosts from stable storage, build list of hosts to
+ * contact. These hosts are added to the global RPC notify list
+ * which is processed as soon as statd enters svc_run.
+ */
+void
+notify_hosts(void)
+{
+ DIR *nld;
+ struct dirent *de;
+ notify_list *call;
+
+ if (!(nld = opendir(SM_BAK_DIR))) {
+ perror("opendir");
+ exit(errno);
+ }
+
+ while ((de = readdir(nld))) {
+ if (de->d_name[0] == '.')
+ continue;
+
+ /* The following can happen for loopback NFS mounts
+ * (e.g. with cfsd) */
+ if (matchhostname(de->d_name, MY_NAME)
+ || matchhostname(de->d_name, "localhost")) {
+ char *fname;
+ fname=xmalloc(strlen(SM_BAK_DIR)+sizeof(de->d_name)+2);
+ dprintf(L_DEBUG, "We're on our own notify list?!?");
+ sprintf(fname, SM_BAK_DIR "/%s", de->d_name);
+ if (unlink(fname))
+ log(L_ERROR, "unlink(%s): %s",
+ fname, strerror(errno));
+ free(fname);
+ continue;
+ }
+
+ call = nlist_new(MY_NAME, de->d_name, -1);
+ NL_TYPE(call) = NOTIFY_REBOOT;
+ nlist_insert(&notify, call);
+ }
+
+ if (closedir(nld) == -1) {
+ perror("closedir");
+ exit(1);
+ }
+}
diff --git a/utils/statd/notlist.c b/utils/statd/notlist.c
new file mode 100644
index 0000000..bc0c294
--- /dev/null
+++ b/utils/statd/notlist.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * Simple list management for notify list
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "misc.h"
+#include "statd.h"
+#include "notlist.h"
+
+notify_list *
+nlist_new(char *my_name, char *mon_name, int state)
+{
+ notify_list *new;
+
+ if (!(new = (notify_list *) xmalloc(sizeof(notify_list))))
+ return NULL;
+ memset(new, 0, sizeof(*new));
+
+ NL_TIMES(new) = MAX_TRIES;
+ NL_STATE(new) = state;
+ if (!(NL_MY_NAME(new) = xstrdup(my_name))
+ || !(NL_MON_NAME(new) = xstrdup(mon_name)))
+ return NULL;
+
+ return new;
+}
+
+void
+nlist_insert(notify_list **head, notify_list *entry)
+{
+ notify_list *next = *head, *tail = entry;
+
+ /* Find end of list to be inserted */
+ while (tail->next)
+ tail = tail->next;
+
+ if (next)
+ next->prev = tail;
+ tail->next = next;
+ *head = entry;
+}
+
+void
+nlist_insert_timer(notify_list **head, notify_list *entry)
+{
+ /* Find first entry with higher timeout value */
+ while (*head && NL_WHEN(*head) <= NL_WHEN(entry))
+ head = &(*head)->next;
+ nlist_insert(head, entry);
+}
+
+void
+nlist_remove(notify_list **head, notify_list *entry)
+{
+ notify_list *prev = entry->prev,
+ *next = entry->next;
+
+ if (next)
+ next->prev = prev;
+ if (prev)
+ prev->next = next;
+ else
+ *head = next;
+ entry->next = entry->prev = NULL;
+}
+
+notify_list *
+nlist_clone(notify_list *entry)
+{
+ notify_list *new;
+
+ new = nlist_new(NL_MY_NAME(entry), NL_MON_NAME(entry), NL_STATE(entry));
+ NL_MY_PROG(new) = NL_MY_PROG(entry);
+ NL_MY_VERS(new) = NL_MY_VERS(entry);
+ NL_MY_PROC(new) = NL_MY_PROC(entry);
+ NL_ADDR(new) = NL_ADDR(entry);
+ memcpy(NL_PRIV(new), NL_PRIV(entry), SM_PRIV_SIZE);
+
+ return new;
+}
+
+void
+nlist_free(notify_list **head, notify_list *entry)
+{
+ if (head)
+ nlist_remove(head, entry);
+ if (NL_MY_NAME(entry))
+ free(NL_MY_NAME(entry));
+ if (NL_MON_NAME(entry))
+ free(NL_MON_NAME(entry));
+ free(entry);
+}
+
+void
+nlist_kill(notify_list **head)
+{
+ while (*head)
+ nlist_free(head, *head);
+}
+
+/*
+ * Walk a list looking for a matching name in the NL_MON_NAME field.
+ */
+notify_list *
+nlist_gethost(notify_list *list, char *host, int myname)
+{
+ notify_list *lp;
+
+ for (lp = list; lp; lp = lp->next) {
+ if (matchhostname(host, myname? NL_MY_NAME(lp) : NL_MON_NAME(lp)))
+ return lp;
+ }
+
+ return (notify_list *) NULL;
+}
diff --git a/utils/statd/notlist.h b/utils/statd/notlist.h
new file mode 100644
index 0000000..0c6709c
--- /dev/null
+++ b/utils/statd/notlist.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Major rewrite by Olaf Kirch, Dec. 1996.
+ *
+ * NSM for Linux.
+ */
+
+#include <netinet/in.h>
+
+/*
+ * Primary information structure.
+ */
+struct notify_list {
+ mon mon; /* Big honkin' NSM structure. */
+ struct in_addr addr; /* IP address for callback. */
+ unsigned short port; /* port number for callback */
+ short int times; /* Counter used for various things. */
+ int state; /* For storing notified state for callbacks. */
+ struct notify_list *next; /* Linked list forward pointer. */
+ struct notify_list *prev; /* Linked list backward pointer. */
+ u_int32_t xid; /* XID of MS_NOTIFY RPC call */
+ time_t when; /* notify: timeout for re-xmit */
+ int type; /* type of notify (REBOOT/CALLBACK) */
+};
+
+typedef struct notify_list notify_list;
+
+#define NOTIFY_REBOOT 0 /* notify remote of our reboot */
+#define NOTIFY_CALLBACK 1 /* notify client of remote reboot */
+
+/*
+ * Global Variables
+ */
+extern notify_list * rtnl; /* Run-time notify list */
+extern notify_list * notify; /* Pending RPC calls */
+
+/*
+ * List-handling functions
+ */
+extern notify_list * nlist_new(char *, char *, int);
+extern void nlist_insert(notify_list **, notify_list *);
+extern void nlist_remove(notify_list **, notify_list *);
+extern void nlist_insert_timer(notify_list **, notify_list *);
+extern notify_list * nlist_clone(notify_list *);
+extern void nlist_free(notify_list **, notify_list *);
+extern void nlist_kill(notify_list **);
+extern notify_list * nlist_gethost(notify_list *, char *, int);
+
+/*
+ * List-handling macros.
+ * THESE INHERIT INFORMATION FROM PREVIOUSLY-DEFINED MACROS.
+ * (So don't change their order unless you study them first!)
+ */
+#define NL_NEXT(L) ((L)->next)
+#define NL_FIRST NL_NEXT
+#define NL_PREV(L) ((L)->prev)
+#define NL_DATA(L) ((L)->mon)
+#define NL_ADDR(L) ((L)->addr)
+#define NL_STATE(L) ((L)->state)
+#define NL_TIMES(L) ((L)->times)
+#define NL_MON_ID(L) (NL_DATA((L)).mon_id)
+#define NL_PRIV(L) (NL_DATA((L)).priv)
+#define NL_MON_NAME(L) (NL_MON_ID((L)).mon_name)
+#define NL_MY_ID(L) (NL_MON_ID((L)).my_id)
+#define NL_MY_NAME(L) (NL_MY_ID((L)).my_name)
+#define NL_MY_PROC(L) (NL_MY_ID((L)).my_proc)
+#define NL_MY_PROG(L) (NL_MY_ID((L)).my_prog)
+#define NL_MY_VERS(L) (NL_MY_ID((L)).my_vers)
+#define NL_WHEN(L) ((L)->when)
+#define NL_TYPE(L) ((L)->type)
+
+#if 0
+#define NL_ADD_NO_ZERO(LIST, ITEM)\
+ NL_PREV(NL_FIRST((LIST))) = (ITEM);\
+ NL_NEXT((ITEM)) = NL_FIRST((LIST));\
+ NL_FIRST((LIST)) = (ITEM);\
+ NL_PREV((ITEM)) = (LIST);\
+ NL_TIMES((ITEM)) = 0;
+
+#define NL_ADD(LIST, ITEM)\
+ NL_ADD_NO_ZERO((LIST), (ITEM));\
+ NL_ADDR((ITEM)) = 0;\
+ NL_STATE((ITEM)) = 0;
+
+#define NL_DEL(ITEM)\
+ NL_NEXT(NL_PREV((ITEM))) = NL_NEXT((ITEM));\
+ NL_PREV(NL_NEXT((ITEM))) = NL_PREV((ITEM));
+
+#define NL_FREE(ITEM)\
+ if (NL_MY_NAME ((ITEM)))\
+ free (NL_MY_NAME ((ITEM)));\
+ if (NL_MON_NAME ((ITEM)))\
+ free (NL_MON_NAME((ITEM)));\
+ free ((ITEM));
+
+#define NL_DEL_FREE(ITEM)\
+ NL_DEL((ITEM))\
+ NL_FREE((ITEM))
+
+/* Yuck. Kludge. */
+#define NL_COPY(SRC, DEST)\
+ NL_TIMES((DEST)) = NL_TIMES((SRC));\
+ NL_STATE((DEST)) = NL_TIMES((SRC));\
+ NL_MY_PROC((DEST)) = NL_MY_PROC((SRC));\
+ NL_MY_PROG((DEST)) = NL_MY_PROG((SRC));\
+ NL_MY_VERS((DEST)) = NL_MY_VERS((SRC));\
+ NL_MON_NAME((DEST)) = xstrdup (NL_MON_NAME((SRC)));\
+ NL_MY_NAME((DEST)) = xstrdup (NL_MY_NAME((SRC)));\
+ memcpy (&NL_ADDR((DEST)), &NL_ADDR((SRC)), sizeof (u_long));\
+ memcpy (NL_PRIV((DEST)), NL_PRIV((SRC)), SM_PRIV_SIZE);
+#endif
diff --git a/utils/statd/rmtcall.c b/utils/statd/rmtcall.c
new file mode 100644
index 0000000..a08c4b1
--- /dev/null
+++ b/utils/statd/rmtcall.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 1996, 1999 Olaf Kirch
+ * Modified by Jeffrey A. Uphoff, 1997-1999.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * After reboot, notify all hosts on our notify list. In order not to
+ * hang statd with delivery to dead hosts, we perform all RPC calls in
+ * parallel.
+ *
+ * It would have been nice to use the portmapper's rmtcall feature,
+ * but that's not possible for security reasons (the portmapper would
+ * have to forward the call with root privs for most statd's, which
+ * it won't if it's worth its money).
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_rmt.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include "sm_inter.h"
+#include "statd.h"
+#include "notlist.h"
+#include "log.h"
+
+#define MAXMSGSIZE (2048 / sizeof(unsigned int))
+
+static unsigned long xid = 0; /* RPC XID counter */
+static int sockfd = -1; /* notify socket */
+
+/*
+ * Initialize callback socket
+ */
+static int
+get_socket(void)
+{
+ struct sockaddr_in sin;
+
+ if (sockfd >= 0)
+ return sockfd;
+
+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ log(L_CRIT, "Can't create socket: %m");
+ return -1;
+ }
+
+ FD_SET(sockfd, &SVC_FDSET);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ if (bindresvport(sockfd, &sin) < 0) {
+ dprintf(L_WARNING,
+ "process_hosts: can't bind to reserved port\n");
+ }
+
+ return sockfd;
+}
+
+/*
+ * Try to resolve host name for notify/callback request
+ *
+ * When compiled with RESTRICTED_STATD defined, we expect all
+ * host names to be dotted quads. See monitor.c for details. --okir
+ */
+#ifdef RESTRICTED_STATD
+static int
+try_to_resolve(notify_list *lp)
+{
+ char *hname;
+
+ if (NL_TYPE(lp) == NOTIFY_REBOOT)
+ hname = NL_MON_NAME(lp);
+ else
+ hname = NL_MY_NAME(lp);
+ if (!inet_aton(hname, &(NL_ADDR(lp)))) {
+ log(L_ERROR, "%s is not an dotted-quad address", hname);
+ NL_TIMES(lp) = 0;
+ return 0;
+ }
+
+ /* XXX: In order to handle multi-homed hosts, we could do
+ * a reverse lookup, a forward lookup, and cycle through
+ * all the addresses.
+ */
+ return 1;
+}
+#else
+static int
+try_to_resolve(notify_list *lp)
+{
+ struct hostent *hp;
+ char *hname;
+
+ if (NL_TYPE(lp) == NOTIFY_REBOOT)
+ hname = NL_MON_NAME(lp);
+ else
+ hname = NL_MY_NAME(lp);
+
+ dprintf(L_DEBUG, "Trying to resolve %s.", hname);
+ if (!(hp = gethostbyname(hname))) {
+ herror("gethostbyname");
+ NL_TIMES(lp) -= 1;
+ return 0;
+ }
+
+ if (hp->h_addrtype != AF_INET) {
+ log(L_ERROR, "%s is not an AF_INET address", hname);
+ NL_TIMES(lp) = 0;
+ return 0;
+ }
+
+ /* FIXME: should try all addresses for multi-homed hosts in
+ * alternation because one interface might be down/unreachable. */
+ NL_ADDR(lp) = *(struct in_addr *) hp->h_addr;
+
+ dprintf(L_DEBUG, "address of %s is %s", hname, inet_ntoa(NL_ADDR(lp)));
+ return 1;
+}
+#endif
+
+static unsigned long
+xmit_call(int sockfd, struct sockaddr_in *sin,
+ u_int32_t prog, u_int32_t vers, u_int32_t proc,
+ xdrproc_t func, void *obj)
+/* __u32 prog, __u32 vers, __u32 proc, xdrproc_t func, void *obj) */
+{
+ unsigned int msgbuf[MAXMSGSIZE], msglen;
+ struct rpc_msg mesg;
+ struct pmap pmap;
+ XDR xdr, *xdrs = &xdr;
+ int err;
+
+ if (!xid)
+ xid = getpid() + time(NULL);
+
+ mesg.rm_xid = ++xid;
+ mesg.rm_direction = CALL;
+ mesg.rm_call.cb_rpcvers = 2;
+ if (sin->sin_port == 0) {
+ sin->sin_port = htons(PMAPPORT);
+ mesg.rm_call.cb_prog = PMAPPROG;
+ mesg.rm_call.cb_vers = PMAPVERS;
+ mesg.rm_call.cb_proc = PMAPPROC_GETPORT;
+ pmap.pm_prog = prog;
+ pmap.pm_vers = vers;
+ pmap.pm_prot = IPPROTO_UDP;
+ pmap.pm_port = 0;
+ func = (xdrproc_t) xdr_pmap;
+ obj = &pmap;
+ } else {
+ mesg.rm_call.cb_prog = prog;
+ mesg.rm_call.cb_vers = vers;
+ mesg.rm_call.cb_proc = proc;
+ }
+ mesg.rm_call.cb_cred.oa_flavor = AUTH_NULL;
+ mesg.rm_call.cb_cred.oa_base = (caddr_t) NULL;
+ mesg.rm_call.cb_cred.oa_length = 0;
+ mesg.rm_call.cb_verf.oa_flavor = AUTH_NULL;
+ mesg.rm_call.cb_verf.oa_base = (caddr_t) NULL;
+ mesg.rm_call.cb_verf.oa_length = 0;
+
+ /* Create XDR memory object for encoding */
+ xdrmem_create(xdrs, (caddr_t) msgbuf, sizeof(msgbuf), XDR_ENCODE);
+
+ /* Encode the RPC header part and payload */
+ if (!xdr_callmsg(xdrs, &mesg) || !func(xdrs, obj)) {
+ dprintf(L_WARNING, "xmit_mesg: can't encode RPC message!\n");
+ xdr_destroy(xdrs);
+ return 0;
+ }
+
+ /* Get overall length of datagram */
+ msglen = xdr_getpos(xdrs);
+
+ if ((err = sendto(sockfd, msgbuf, msglen, 0,
+ (struct sockaddr *) sin, sizeof(*sin))) < 0) {
+ dprintf(L_WARNING, "xmit_mesg: sendto failed: %m");
+ } else if (err != msglen) {
+ dprintf(L_WARNING, "xmit_mesg: short write: %m\n");
+ }
+
+ xdr_destroy(xdrs);
+
+ return err == msglen? xid : 0;
+}
+
+static notify_list *
+recv_rply(int sockfd, struct sockaddr_in *sin, u_long *portp)
+{
+ unsigned int msgbuf[MAXMSGSIZE], msglen;
+ struct rpc_msg mesg;
+ notify_list *lp = NULL;
+ XDR xdr, *xdrs = &xdr;
+ int alen = sizeof(*sin);
+
+ /* Receive message */
+ if ((msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
+ (struct sockaddr *) sin, &alen)) < 0) {
+ dprintf(L_WARNING, "recv_rply: recvfrom failed: %m");
+ return NULL;
+ }
+
+ /* Create XDR object for decoding buffer */
+ xdrmem_create(xdrs, (caddr_t) msgbuf, msglen, XDR_DECODE);
+
+ memset(&mesg, 0, sizeof(mesg));
+ mesg.rm_reply.rp_acpt.ar_results.where = NULL;
+ mesg.rm_reply.rp_acpt.ar_results.proc = (xdrproc_t) xdr_void;
+
+ if (!xdr_replymsg(xdrs, &mesg)) {
+ log(L_WARNING, "recv_rply: can't decode RPC message!\n");
+ goto done;
+ }
+
+ if (mesg.rm_reply.rp_stat != 0) {
+ log(L_WARNING, "recv_rply: [%s] RPC status %d\n",
+ inet_ntoa(sin->sin_addr),
+ mesg.rm_reply.rp_stat);
+ goto done;
+ }
+ if (mesg.rm_reply.rp_acpt.ar_stat != 0) {
+ log(L_WARNING, "recv_rply: [%s] RPC status %d\n",
+ inet_ntoa(sin->sin_addr),
+ mesg.rm_reply.rp_acpt.ar_stat);
+ goto done;
+ }
+
+ for (lp = notify; lp != NULL; lp = lp->next) {
+ if (lp->xid != xid)
+ continue;
+ if (lp->addr.s_addr != sin->sin_addr.s_addr) {
+ char addr [18];
+ strncpy (addr, inet_ntoa(lp->addr),
+ sizeof (addr) - 1);
+ addr [sizeof (addr) - 1] = '\0';
+ dprintf(L_WARNING, "address mismatch: "
+ "expected %s, got %s\n",
+ addr, inet_ntoa(sin->sin_addr));
+ }
+ if (lp->port == 0) {
+ if (!xdr_u_long(xdrs, portp)) {
+ log(L_WARNING, "recv_rply: [%s] "
+ "can't decode reply body!\n",
+ inet_ntoa(sin->sin_addr));
+ lp = NULL;
+ goto done;
+ }
+ }
+ break;
+ }
+
+done:
+ xdr_destroy(xdrs);
+ return lp;
+}
+
+/*
+ * Notify operation for a single list entry
+ */
+static int
+process_entry(int sockfd, notify_list *lp)
+{
+ struct sockaddr_in sin;
+ struct status new_status;
+ xdrproc_t func;
+ void *objp;
+ u_int32_t proc, vers, prog;
+/* __u32 proc, vers, prog; */
+
+ if (lp->addr.s_addr == INADDR_ANY && !try_to_resolve(lp))
+ return NL_TIMES(lp);
+ if (NL_TIMES(lp) == 0) {
+ log(L_DEBUG, "Cannot notify %s, giving up.\n",
+ inet_ntoa(NL_ADDR(lp)));
+ return 0;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = lp->port;
+ sin.sin_addr = lp->addr;
+
+ switch (NL_TYPE(lp)) {
+ case NOTIFY_REBOOT:
+ prog = SM_PROG;
+ vers = SM_VERS;
+ proc = SM_NOTIFY;
+ func = (xdrproc_t) xdr_stat_chge;
+ objp = &SM_stat_chge;
+ break;
+ case NOTIFY_CALLBACK:
+ prog = NL_MY_PROG(lp);
+ vers = NL_MY_VERS(lp);
+ proc = NL_MY_PROC(lp);
+ func = (xdrproc_t) xdr_status;
+ objp = &new_status;
+ new_status.mon_name = NL_MON_NAME(lp);
+ new_status.state = NL_STATE(lp);
+ memcpy(new_status.priv, NL_PRIV(lp), SM_PRIV_SIZE);
+ break;
+ default:
+ log(L_ERROR, "notify_host: unknown notify type %d",
+ NL_TYPE(lp));
+ return 0;
+ }
+
+ lp->xid = xmit_call(sockfd, &sin, prog, vers, proc, func, objp);
+ if (!lp->xid) {
+ log(L_WARNING, "notify_host: failed to notify %s\n",
+ inet_ntoa(lp->addr));
+ }
+ NL_TIMES(lp) -= 1;
+
+ return 1;
+}
+
+/*
+ * Process a datagram received on the notify socket
+ */
+int
+process_reply(FD_SET_TYPE *rfds)
+{
+ struct sockaddr_in sin;
+ notify_list *lp;
+ u_long port;
+
+ if (sockfd == -1 || !FD_ISSET(sockfd, rfds))
+ return 0;
+
+ if (!(lp = recv_rply(sockfd, &sin, &port)))
+ return 1;
+
+ if (lp->port == 0) {
+ if (port != 0) {
+ lp->port = htons((unsigned short) port);
+ process_entry(sockfd, lp);
+ NL_WHEN(lp) = time(NULL) + NOTIFY_TIMEOUT;
+ nlist_remove(&notify, lp);
+ nlist_insert_timer(&notify, lp);
+ return 1;
+ }
+ log(L_WARNING, "recv_rply: [%s] service %d not registered",
+ inet_ntoa(lp->addr),
+ NL_TYPE(lp) == NOTIFY_REBOOT? SM_PROG : NL_MY_PROG(lp));
+ } else if (NL_TYPE(lp) == NOTIFY_REBOOT) {
+ dprintf(L_DEBUG, "Notification of %s succeeded.",
+ NL_MON_NAME(lp));
+ xunlink(SM_BAK_DIR, NL_MON_NAME(lp), 0);
+ } else {
+ dprintf(L_DEBUG, "Callback to %s (for %d) succeeded.",
+ NL_MY_NAME(lp), NL_MON_NAME(lp));
+ }
+ nlist_free(&notify, lp);
+ return 1;
+}
+
+/*
+ * Process a notify list, either for notifying remote hosts after reboot
+ * or for calling back (local) statd clients when the remote has notified
+ * us of a crash.
+ */
+int
+process_notify_list(void)
+{
+ notify_list *entry;
+ time_t now;
+ int fd;
+
+ if ((fd = get_socket()) < 0)
+ return 0;
+
+ while ((entry = notify) != NULL && NL_WHEN(entry) < time(&now)) {
+ if (process_entry(fd, entry)) {
+ NL_WHEN(entry) = time(NULL) + NOTIFY_TIMEOUT;
+ nlist_remove(&notify, entry);
+ nlist_insert_timer(&notify, entry);
+ } else if (NL_TYPE(entry) == NOTIFY_CALLBACK) {
+ log(L_ERROR,
+ "Can't callback %s (%d,%d), giving up.",
+ NL_MY_NAME(entry),
+ NL_MY_PROG(entry),
+ NL_MY_VERS(entry));
+ nlist_free(&notify, entry);
+ } else {
+ log(L_ERROR,
+ "Can't notify %s, giving up.",
+ NL_MON_NAME(entry));
+ xunlink(SM_BAK_DIR, NL_MON_NAME(entry), 0);
+ nlist_free(&notify, entry);
+ }
+ }
+
+ return 1;
+}
diff --git a/utils/statd/sim_sm_inter.x b/utils/statd/sim_sm_inter.x
new file mode 100644
index 0000000..4346199
--- /dev/null
+++ b/utils/statd/sim_sm_inter.x
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+#ifdef RPC_CLNT
+%#include <string.h>
+#endif
+
+program SIM_SM_PROG {
+ version SIM_SM_VERS {
+ void SIM_SM_MON(struct status) = 1;
+ } = 1;
+} = 200048;
+
+const SM_MAXSTRLEN = 1024;
+const SM_PRIV_SIZE = 16;
+
+/*
+ * structure of the status message sent back by the status monitor
+ * when monitor site status changes
+ */
+%#ifndef SM_INTER_X
+struct status {
+ string mon_name<SM_MAXSTRLEN>;
+ int state;
+ opaque priv[SM_PRIV_SIZE]; /* stored private information */
+};
+%#endif /* SM_INTER_X */
diff --git a/utils/statd/simu.c b/utils/statd/simu.c
new file mode 100644
index 0000000..fa4e3a6
--- /dev/null
+++ b/utils/statd/simu.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#include "statd.h"
+#include "notlist.h"
+
+extern void my_svc_exit (void);
+
+
+/*
+ * Services SM_SIMU_CRASH requests.
+ */
+void *
+sm_simu_crash_1_svc (void *argp, struct svc_req *rqstp)
+{
+ static char *result = NULL;
+
+ log (L_WARNING, "*** SIMULATING CRASH! ***");
+ my_svc_exit ();
+
+ if (rtnl)
+ nlist_kill (&rtnl);
+
+ return ((void *)&result);
+}
diff --git a/utils/statd/simulate.c b/utils/statd/simulate.c
new file mode 100644
index 0000000..4b8d59c
--- /dev/null
+++ b/utils/statd/simulate.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#ifndef SIMULATIONS
+# error How the hell did we get here?
+#endif
+
+/* If we're running the simulator, we're debugging. Pretty simple. */
+#ifndef DEBUG
+# define DEBUG
+#endif
+
+#include <signal.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include "statd.h"
+#include "sim_sm_inter.h"
+
+static void daemon_simulator (void);
+static void sim_killer (int sig);
+static void simulate_crash (char *);
+static void simulate_mon (char *, char *, char *, char *, char *);
+static void simulate_stat (char *, char *);
+static void simulate_unmon (char *, char *, char *, char *);
+static void simulate_unmon_all (char *, char *, char *);
+
+static int sim_port = 0;
+
+extern void sim_sm_prog_1 (struct svc_req *, register SVCXPRT);
+extern void svc_exit (void);
+
+void
+simulator (int argc, char **argv)
+{
+ log_enable (1);
+
+ if (argc == 2)
+ if (!strcasecmp (*argv, "crash"))
+ simulate_crash (*(&argv[1]));
+
+ if (argc == 3) {
+ if (!strcasecmp (*argv, "stat"))
+ simulate_stat (*(&argv[1]), *(&argv[2]));
+ }
+ if (argc == 4) {
+ if (!strcasecmp (*argv, "unmon_all"))
+ simulate_unmon_all (*(&argv[1]), *(&argv[2]), *(&argv[3]));
+ }
+ if (argc == 5) {
+ if (!strcasecmp (*argv, "unmon"))
+ simulate_unmon (*(&argv[1]), *(&argv[2]), *(&argv[3]), *(&argv[4]));
+ }
+ if (argc == 6) {
+ if (!strcasecmp (*argv, "mon"))
+ simulate_mon (*(&argv[1]), *(&argv[2]), *(&argv[3]), *(&argv[4]),
+ *(&argv[5]));
+ }
+ die ("WTF? Give me something I can use!");
+}
+
+static void
+simulate_mon (char *calling, char *monitoring, char *as, char *proggy,
+ char *fool)
+{
+ CLIENT *client;
+ sm_stat_res *result;
+ mon mon;
+
+ dprintf (L_DEBUG, "Calling %s (as %s) to monitor %s", calling, as,
+ monitoring);
+
+ if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
+ die ("%s", clnt_spcreateerror ("clnt_create"));
+
+ memcpy (mon.priv, fool, SM_PRIV_SIZE);
+ mon.mon_id.my_id.my_name = xstrdup (as);
+ sim_port = atoi (proggy) * SIM_SM_PROG;
+ mon.mon_id.my_id.my_prog = sim_port; /* Pseudo-dummy */
+ mon.mon_id.my_id.my_vers = SIM_SM_VERS;
+ mon.mon_id.my_id.my_proc = SIM_SM_MON;
+ mon.mon_id.mon_name = monitoring;
+
+ if (!(result = sm_mon_1 (&mon, client)))
+ die ("%s", clnt_sperror (client, "sm_mon_1"));
+
+ free (mon.mon_id.my_id.my_name);
+
+ if (result->res_stat != STAT_SUCC) {
+ log (L_FATAL, "SM_MON request failed, state: %d", result->state);
+ exit (0);
+ } else {
+ dprintf (L_DEBUG, "SM_MON result successful, state: %d\n", result->state);
+ dprintf (L_DEBUG, "Waiting for callback.");
+ daemon_simulator ();
+ exit (0);
+ }
+}
+
+static void
+simulate_unmon (char *calling, char *unmonitoring, char *as, char *proggy)
+{
+ CLIENT *client;
+ sm_stat *result;
+ mon_id mon_id;
+
+ dprintf (L_DEBUG, "Calling %s (as %s) to unmonitor %s", calling, as,
+ unmonitoring);
+
+ if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
+ die ("%s", clnt_spcreateerror ("clnt_create"));
+
+ mon_id.my_id.my_name = xstrdup (as);
+ mon_id.my_id.my_prog = atoi (proggy) * SIM_SM_PROG;
+ mon_id.my_id.my_vers = SIM_SM_VERS;
+ mon_id.my_id.my_proc = SIM_SM_MON;
+ mon_id.mon_name = unmonitoring;
+
+ if (!(result = sm_unmon_1 (&mon_id, client)))
+ die ("%s", clnt_sperror (client, "sm_unmon_1"));
+
+ free (mon_id.my_id.my_name);
+ dprintf (L_DEBUG, "SM_UNMON request returned state: %d\n", result->state);
+ exit (0);
+}
+
+static void
+simulate_unmon_all (char *calling, char *as, char *proggy)
+{
+ CLIENT *client;
+ sm_stat *result;
+ my_id my_id;
+
+ dprintf (L_DEBUG, "Calling %s (as %s) to unmonitor all hosts", calling, as);
+
+ if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
+ die ("%s", clnt_spcreateerror ("clnt_create"));
+
+ my_id.my_name = xstrdup (as);
+ my_id.my_prog = atoi (proggy) * SIM_SM_PROG;
+ my_id.my_vers = SIM_SM_VERS;
+ my_id.my_proc = SIM_SM_MON;
+
+ if (!(result = sm_unmon_all_1 (&my_id, client)))
+ die ("%s", clnt_sperror (client, "sm_unmon_all_1"));
+
+ free (my_id.my_name);
+ dprintf (L_DEBUG, "SM_UNMON_ALL request returned state: %d\n", result->state);
+ exit (0);
+}
+
+static void
+simulate_crash (char *host)
+{
+ CLIENT *client;
+
+ if ((client = clnt_create (host, SM_PROG, SM_VERS, "udp")) == NULL)
+ die ("%s", clnt_spcreateerror ("clnt_create"));
+
+ if (!sm_simu_crash_1 (NULL, client))
+ die ("%s", clnt_sperror (client, "sm_simu_crash_1"));
+
+ exit (0);
+}
+
+static void
+simulate_stat (char *calling, char *monitoring)
+{
+ CLIENT *client;
+ sm_name checking;
+ sm_stat_res *result;
+
+ if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
+ die ("%s", clnt_spcreateerror ("clnt_create"));
+
+ checking.mon_name = monitoring;
+
+ if (!(result = sm_stat_1 (&checking, client)))
+ die ("%s", clnt_sperror (client, "sm_stat_1"));
+
+ if (result->res_stat == STAT_SUCC)
+ dprintf (L_DEBUG, "STAT_SUCC from %s for %s, state: %d", calling,
+ monitoring, result->state);
+ else
+ dprintf (L_DEBUG, "STAT_FAIL from %s for %s, state: %d", calling,
+ monitoring, result->state);
+
+ exit (0);
+}
+
+static void
+sim_killer (int sig)
+{
+ log (L_FATAL, "Simulator caught signal %d, un-registering and exiting.", sig);
+ pmap_unset (sim_port, SIM_SM_VERS);
+ exit (0);
+}
+
+static void
+daemon_simulator (void)
+{
+ signal (SIGHUP, sim_killer);
+ signal (SIGINT, sim_killer);
+ signal (SIGTERM, sim_killer);
+ pmap_unset (sim_port, SIM_SM_VERS);
+ do_regist (sim_port, sim_sm_prog_1);
+/* do_regist (sim_port, (__dispatch_fn_t)sim_sm_prog_1); */
+ svc_run ();
+ pmap_unset (sim_port, SIM_SM_VERS);
+}
+
+void *
+sim_sm_mon_1_svc (struct status *argp, struct svc_req *rqstp)
+{
+ static char *result;
+
+ dprintf (L_DEBUG, "Recieved state %d for mon_name %s (opaque \"%s\")",
+ argp->state, argp->mon_name, argp->priv);
+ svc_exit ();
+ return ((void *)&result);
+}
diff --git a/utils/statd/sm_inter.x b/utils/statd/sm_inter.x
new file mode 100644
index 0000000..5232a28
--- /dev/null
+++ b/utils/statd/sm_inter.x
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 1986 Sun Microsystems, Inc.
+ * Modified by Jeffrey A. Uphoff, 1995, 1997-1999.
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * Status monitor protocol specification
+ */
+
+#ifdef RPC_CLNT
+%#include <string.h>
+#endif
+
+program SM_PROG {
+ version SM_VERS {
+ /* res_stat = stat_succ if status monitor agrees to monitor */
+ /* res_stat = stat_fail if status monitor cannot monitor */
+ /* if res_stat == stat_succ, state = state number of site sm_name */
+ struct sm_stat_res SM_STAT(struct sm_name) = 1;
+
+ /* res_stat = stat_succ if status monitor agrees to monitor */
+ /* res_stat = stat_fail if status monitor cannot monitor */
+ /* stat consists of state number of local site */
+ struct sm_stat_res SM_MON(struct mon) = 2;
+
+ /* stat consists of state number of local site */
+ struct sm_stat SM_UNMON(struct mon_id) = 3;
+
+ /* stat consists of state number of local site */
+ 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;
+
+const SM_MAXSTRLEN = 1024;
+const SM_PRIV_SIZE = 16;
+
+struct sm_name {
+ string mon_name<SM_MAXSTRLEN>;
+};
+
+struct my_id {
+ string my_name<SM_MAXSTRLEN>; /* name of the site iniates the monitoring request*/
+ int my_prog; /* rpc program # of the requesting process */
+ int my_vers; /* rpc version # of the requesting process */
+ int my_proc; /* rpc procedure # of the requesting process */
+};
+
+struct mon_id {
+ string mon_name<SM_MAXSTRLEN>; /* name of the site to be monitored */
+ struct my_id my_id;
+};
+
+
+struct mon {
+ struct mon_id mon_id;
+ opaque priv[SM_PRIV_SIZE]; /* private information to store at monitor for requesting process */
+};
+
+struct stat_chge {
+ string mon_name<SM_MAXSTRLEN>; /* name of the site that had the state change */
+ int state;
+};
+
+/*
+ * state # of status monitor monitonically increases each time
+ * status of the site changes:
+ * an even number (>= 0) indicates the site is down and
+ * an odd number (> 0) indicates the site is up;
+ */
+struct sm_stat {
+ int state; /* state # of status monitor */
+};
+
+enum res {
+ stat_succ = 0, /* status monitor agrees to monitor */
+ stat_fail = 1 /* status monitor cannot monitor */
+};
+
+struct sm_stat_res {
+ res res_stat;
+ int state;
+};
+
+/*
+ * structure of the status message sent back by the status monitor
+ * when monitor site status changes
+ */
+struct status {
+ string mon_name<SM_MAXSTRLEN>;
+ int state;
+ opaque priv[SM_PRIV_SIZE]; /* stored private information */
+};
+
+%#define SM_INTER_X
diff --git a/utils/statd/stat.c b/utils/statd/stat.c
new file mode 100644
index 0000000..021e786
--- /dev/null
+++ b/utils/statd/stat.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 1995, 1997, 1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#include <netdb.h>
+#include "statd.h"
+
+/*
+ * Services SM_STAT requests.
+ *
+ * According the the X/Open spec's on this procedure: "Implementations
+ * should not rely on this procedure being operative. In many current
+ * implementations of the NSM it will always return a 'STAT_FAIL'
+ * status." My implementation is operative; it returns 'STAT_SUCC'
+ * whenever it can resolve the hostname that it's being asked to
+ * monitor, and returns 'STAT_FAIL' otherwise.
+ */
+struct sm_stat_res *
+sm_stat_1_svc (struct sm_name *argp, struct svc_req *rqstp)
+{
+ static sm_stat_res result;
+
+ if (gethostbyname (argp->mon_name) == NULL) {
+ log (L_WARNING, "gethostbyname error for %s", argp->mon_name);
+ result.res_stat = STAT_FAIL;
+ dprintf (L_DEBUG, "STAT_FAIL for %s", argp->mon_name);
+ } else {
+ result.res_stat = STAT_SUCC;
+ dprintf (L_DEBUG, "STAT_SUCC for %s", argp->mon_name);
+ }
+ result.state = MY_STATE;
+ return(&result);
+}
diff --git a/utils/statd/statd.c b/utils/statd/statd.c
new file mode 100644
index 0000000..3b76e30
--- /dev/null
+++ b/utils/statd/statd.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, Oct. 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#include <limits.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include "statd.h"
+#include "version.h"
+
+short int restart = 0;
+int _rpcpmstart = 0; /* flags for tirpc rpcgen */
+int _rpcfdtype = 0;
+int _rpcsvcdirty = 0;
+
+extern void sm_prog_1 (struct svc_req *, register SVCXPRT);
+
+#ifdef SIMULATIONS
+extern void simulator (int, char **);
+#endif
+
+
+/*
+ * Signal handler.
+ */
+static void
+killer (int sig)
+{
+ log (L_FATAL, "Caught signal %d, un-registering and exiting.", sig);
+ pmap_unset (SM_PROG, SM_VERS);
+ exit (0);
+}
+
+
+/*
+ * Entry routine/main loop.
+ */
+int
+main (int argc, char **argv)
+{
+ int pid;
+ int foreground = 0;
+
+ log_init (argv[0]);
+
+ if (argc == 2 && strcmp (argv [1], "-F") == 0) {
+ foreground = 1;
+ argc--;
+ argv++;
+ }
+
+#ifdef SIMULATIONS
+ if (argc > 1)
+ simulator (--argc, ++argv); /* simulator() does exit() */
+#endif
+
+ if (!foreground) {
+ int filedes;
+
+ if ((pid = fork ()) < 0) {
+ perror ("Could not fork");
+ exit (1);
+ } else if (pid != 0) {
+ /* Parent. */
+ exit (0);
+ }
+ /* Child. */
+ setsid ();
+ chdir (DIR_BASE);
+
+ for (filedes = 0; filedes < OPEN_MAX; filedes++) {
+ close (filedes);
+ }
+ }
+
+ /* Child. */
+ signal (SIGHUP, killer);
+ signal (SIGINT, killer);
+ signal (SIGTERM, killer);
+
+ for (;;) {
+ pmap_unset (SM_PROG, SM_VERS);
+ change_state ();
+ shuffle_dirs ();
+ notify_hosts ();
+ ++restart;
+ do_regist (SM_PROG, sm_prog_1);
+ my_svc_run (); /* I rolled my own, Olaf made it better... */
+ }
+ return 0;
+}
+
+
+/*
+ * Register services.
+ */
+void
+do_regist(u_long prog, void (*sm_prog_1)())
+/* do_regist(u_long prog, __dispatch_fn_t sm_prog_1) */
+{
+ SVCXPRT *transp;
+
+ if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL)
+ die("cannot create udp service.");
+
+ if (!svc_register(transp, prog, SM_VERS, sm_prog_1, IPPROTO_UDP))
+ die("unable to register (SM_PROG, SM_VERS, udp).");
+
+ if ((transp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
+ die("cannot create tcp service.");
+
+ if (!svc_register(transp, prog, SM_VERS, sm_prog_1, IPPROTO_TCP))
+ die("unable to register (SM_PROG, SM_VERS, tcp).");
+}
diff --git a/utils/statd/statd.h b/utils/statd/statd.h
new file mode 100644
index 0000000..77a179a
--- /dev/null
+++ b/utils/statd/statd.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, Dec. 1996.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#include "sm_inter.h"
+#include "system.h"
+#include "log.h"
+
+/*
+ * Paths and filenames.
+ */
+#if defined(NFS_STATEDIR)
+# define DIR_BASE NFS_STATEDIR "/"
+#else
+# define DIR_BASE "/var/lib/nfs/"
+#endif
+#define SM_DIR DIR_BASE "sm"
+#define SM_BAK_DIR DIR_BASE "sm.bak"
+#define SM_STAT_PATH DIR_BASE "state"
+
+/*
+ * Status definitions.
+ */
+#define STAT_FAIL stat_fail
+#define STAT_SUCC stat_succ
+
+/*
+ * Function prototypes.
+ */
+extern void change_state(void);
+extern void do_regist(u_long, void (*)());
+extern void my_svc_run(void);
+extern void notify_hosts(void);
+extern void shuffle_dirs(void);
+extern int process_notify_list(void);
+extern int process_reply(FD_SET_TYPE *);
+extern char * xstrdup(const char *);
+extern void * xmalloc(size_t);
+extern void xunlink (char *, char *, short int);
+
+/*
+ * Host status structure and macros.
+ */
+stat_chge SM_stat_chge;
+#define MY_NAME SM_stat_chge.mon_name
+#define MY_STATE SM_stat_chge.state
+
+/*
+ * Some timeout values. (Timeout values are in whole seconds.)
+ */
+#define CALLBACK_TIMEOUT 3 /* For client call-backs. */
+#define NOTIFY_TIMEOUT 5 /* For status-change notifications. */
+#define SELECT_TIMEOUT 10 /* Max select() timeout when work to do. */
+#define MAX_TRIES 5 /* Max number of tries for any host. */
diff --git a/utils/statd/statd.man b/utils/statd/statd.man
new file mode 100644
index 0000000..373cf77
--- /dev/null
+++ b/utils/statd/statd.man
@@ -0,0 +1,53 @@
+.\"
+.\" statd(8)
+.\"
+.\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de>
+.\" Modified by Jeffrey A. Uphoff, 1999.
+.TH rpc.statd 8 "11 June 1999"
+.SH NAME
+rpc.statd \- NSM status monitor
+.SH SYNOPSIS
+.B "/usr/sbin/rpc.statd [-F]
+.SH DESCRIPTION
+The
+.B rpc.statd
+server implements the NSM (Network Status Monitor) RPC protocol.
+This service is somewhat misnomed, since it doesn't actually provide
+active monitoring as one might suspect; instead, NSM implements a
+reboot notification service. It is used by the NFS file locking service,
+.BR rpc.lockd ,
+to implement lock recovery when the NFS server machine crashes and
+reboots.
+.SS Operation
+For each NFS client or server machine to be monitored,
+.B rpc.statd
+creates a file in
+.BR /var/lib/nfs/sm .
+When starting, it iterates through these files and notifies the
+peer
+.B rpc.statd
+on those machines.
+.SH OPTIONS
+.TP
+.B -F
+By default,
+.B rpc.statd
+forks and puts itself in the background when started. The
+.B -F
+argument tells it to remain in the foreground. This option is
+mainly for debugging purposes.
+.SH FILES
+.BR /var/lib/nfs/sm/state
+.br
+.BR /var/lib/nfs/sm/*
+.br
+.BR /var/lib/nfs/sm.bak/*
+.SH SEE ALSO
+.BR rpc.nfsd(8)
+.SH AUTHORS
+.br
+Jeff Uphoff <juphoff@transmeta.com>
+.br
+Olaf Kirch <okir@monad.swb.de>
+.br
+H.J. Lu <hjl@gnu.org>
diff --git a/utils/statd/state.c b/utils/statd/state.c
new file mode 100644
index 0000000..101c00b
--- /dev/null
+++ b/utils/statd/state.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+#include "config.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "statd.h"
+
+
+/*
+ * Most NSM's keep the status number in an ASCII file. I'm keeping it
+ * as an int (4-byte binary) for now...
+ */
+void
+change_state (void)
+{
+ int fd, size;
+ extern short int restart;
+
+ if ((fd = open (SM_STAT_PATH, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) == -1)
+ die ("open (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if ((size = read (fd, &MY_STATE, sizeof MY_STATE)) == -1)
+ die ("read (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if (size != 0 && size != sizeof MY_STATE) {
+ log (L_ERROR, "Error in status file format...correcting.");
+
+ if (close (fd) == -1)
+ die ("close (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if ((fd = creat (SM_STAT_PATH, S_IRUSR | S_IWUSR)) == -1)
+ die ("creat (%s): %s", SM_STAT_PATH, strerror (errno));
+ }
+ log (L_DEBUG, "New state: %u", (++MY_STATE % 2) ? MY_STATE : ++MY_STATE);
+
+ if (lseek (fd, 0, SEEK_SET) == -1)
+ die ("lseek (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if (write (fd, &MY_STATE, sizeof MY_STATE) != sizeof MY_STATE)
+ die ("write (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if (fsync (fd) == -1)
+ log (L_ERROR, "fsync (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if (close (fd) == -1)
+ log (L_ERROR, "close (%s): %s", SM_STAT_PATH, strerror (errno));
+
+ if (!restart) {
+ char fullhost[SM_MAXSTRLEN + 1];
+ struct hostent *hostinfo;
+
+ if (gethostname (fullhost, SM_MAXSTRLEN) == -1)
+ die ("gethostname: %s", strerror (errno));
+
+ if ((hostinfo = gethostbyname (fullhost)) == NULL)
+ log (L_ERROR, "gethostbyname error for %s", fullhost);
+ else {
+ strncpy (fullhost, hostinfo->h_name, sizeof (fullhost) - 1);
+ fullhost[sizeof (fullhost) - 1] = '\0';
+ }
+
+ MY_NAME = xstrdup (fullhost);
+ }
+}
+
+
+/*
+ * Fairly traditional use of two directories for this.
+ */
+void
+shuffle_dirs (void)
+{
+ DIR *nld;
+ struct dirent *de;
+ struct stat st;
+ char *src, *dst;
+ int len1, len2, len;
+
+ if (stat (SM_DIR, &st) == -1 && errno != ENOENT)
+ die ("stat (%s): %s", SM_DIR, strerror (errno));
+
+ if (!S_ISDIR (st.st_mode))
+ if (mkdir (SM_DIR, S_IRWXU) == -1)
+ die ("mkdir (%s): %s", SM_DIR, strerror (errno));
+
+ memset (&st, 0, sizeof st);
+
+ if (stat (SM_BAK_DIR, &st) == -1 && errno != ENOENT)
+ die ("stat (%s): %s", SM_BAK_DIR, strerror (errno));
+
+ if (!S_ISDIR (st.st_mode))
+ if (mkdir (SM_BAK_DIR, S_IRWXU) == -1)
+ die ("mkdir (%s): %s", SM_BAK_DIR, strerror (errno));
+
+ if (!(nld = opendir (SM_DIR)))
+ die ("opendir (%s): %s", SM_DIR, strerror (errno));
+
+ len1=strlen(SM_DIR);
+ len2=strlen(SM_BAK_DIR);
+ while ((de = readdir (nld))) {
+ if (de->d_name[0] == '.')
+ continue;
+ len=strlen(de->d_name);
+ src=xmalloc(len1+len+2);
+ dst=xmalloc(len2+len+2);
+ sprintf (src, "%s/%s", SM_DIR, de->d_name);
+ sprintf (dst, "%s/%s", SM_BAK_DIR, de->d_name);
+ if (rename (src, dst) == -1)
+ die ("rename (%s to %s): %s", SM_DIR, SM_BAK_DIR, strerror (errno));
+ free(src);
+ free(dst);
+ }
+ if (closedir (nld) == -1)
+ log (L_ERROR, "closedir (%s): %s", SM_DIR, strerror (errno));
+}
diff --git a/utils/statd/svc_run.c b/utils/statd/svc_run.c
new file mode 100644
index 0000000..8f6d9fe
--- /dev/null
+++ b/utils/statd/svc_run.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1984 Sun Microsystems, Inc.
+ * Modified by Jeffrey A. Uphoff, 1995, 1997-1999.
+ * Modified by Olaf Kirch, 1996.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * This has been modified for my own evil purposes to prevent deadlocks
+ * when two hosts start NSM's simultaneously and try to notify each
+ * other (which mainly occurs during testing), or to stop and smell the
+ * roses when I have callbacks due.
+ * --Jeff Uphoff.
+ */
+
+/*
+ * This is the RPC server side idle loop.
+ * Wait for input, call server program.
+ */
+#include "config.h"
+#include <errno.h>
+#include "statd.h"
+#include "notlist.h"
+
+static int svc_stop = 0;
+
+/*
+ * This is the global notify list onto which all SM_NOTIFY and CALLBACK
+ * requests are put.
+ */
+notify_list * notify = NULL;
+
+/*
+ * Jump-off function.
+ */
+void
+my_svc_exit(void)
+{
+ svc_stop = 1;
+}
+
+
+/*
+ * The heart of the server. A crib from libc for the most part...
+ */
+void
+my_svc_run(void)
+{
+ FD_SET_TYPE readfds;
+ int selret;
+ time_t now;
+
+ svc_stop = 0;
+
+ for (;;) {
+ if (svc_stop)
+ return;
+
+ /* Ah, there are some notifications to be processed */
+ while (notify && NL_WHEN(notify) <= time(&now)) {
+ process_notify_list();
+ }
+
+ readfds = SVC_FDSET;
+ if (notify) {
+ struct timeval tv;
+
+ tv.tv_sec = NL_WHEN(notify) - now;
+ tv.tv_usec = 0;
+ dprintf(L_DEBUG, "Waiting for reply... (timeo %d)",
+ tv.tv_sec);
+ selret = select(FD_SETSIZE, &readfds,
+ (void *) 0, (void *) 0, &tv);
+ } else {
+ dprintf(L_DEBUG, "Waiting for client connections.");
+ selret = select(FD_SETSIZE, &readfds,
+ (void *) 0, (void *) 0, (struct timeval *) 0);
+ }
+
+ switch (selret) {
+ case -1:
+ if (errno == EINTR || errno == ECONNREFUSED
+ || errno == ENETUNREACH || errno == EHOSTUNREACH)
+ continue;
+ log(L_ERROR, "my_svc_run() - select: %m");
+ return;
+
+ case 0:
+ /* A notify/callback timed out. */
+ continue;
+
+ default:
+ selret -= process_reply(&readfds);
+ if (selret)
+ svc_getreqset(&readfds);
+ }
+ }
+}
diff --git a/utils/statd/system.h b/utils/statd/system.h
new file mode 100644
index 0000000..a1739c4
--- /dev/null
+++ b/utils/statd/system.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 1996 Olaf Kirch
+ * Modified by Jeffrey A. Uphoff, 1997, 1999.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * System-dependent declarations
+ */
+
+#ifdef FD_SETSIZE
+# define FD_SET_TYPE fd_set
+# define SVC_FDSET svc_fdset
+#else
+# define FD_SET_TYPE int
+# define SVC_FDSET svc_fds
+#endif
diff --git a/utils/statd/version.h b/utils/statd/version.h
new file mode 100644
index 0000000..12f16bd
--- /dev/null
+++ b/utils/statd/version.h
@@ -0,0 +1,7 @@
+/*
+ * Copyright (C) 1997-1999 Jeffrey A. Uphoff
+ *
+ * NSM for Linux.
+ */
+
+#define STATD_RELEASE "1.1.1"