RPCPREFIX = rpc.
KPREFIX = @kprefix@
sbin_PROGRAMS = statd sm-notify
-statd_SOURCES = 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 \
+statd_SOURCES = callback.c notlist.c log.c misc.c monitor.c \
+ simu.c stat.c statd.c svc_run.c rmtcall.c \
sm_inter_clnt.c sm_inter_svc.c sm_inter_xdr.c log.h \
notlist.h statd.h system.h version.h sm_inter.h
sm_notify_SOURCES = sm-notify.c
if (NL_STATE(lp) != argp->state) {
NL_STATE(lp) = argp->state;
call = nlist_clone(lp);
- NL_TYPE(call) = NOTIFY_CALLBACK;
nlist_insert(¬ify, call);
}
lp = NL_NEXT(lp);
+++ /dev/null
-/*
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#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(N_DEBUG, "We're on our own notify list?!?");
- sprintf(fname, "%s/%s", SM_BAK_DIR, de->d_name);
- if (unlink(fname))
- note(N_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(¬ify, call);
- }
-
- if (closedir(nld) == -1) {
- perror("closedir");
- exit(1);
- }
-}
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
*/
#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)
* Initialize callback socket
*/
int
-statd_get_socket(int port)
+statd_get_socket(void)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
- /*
- * If a local hostname is given (-n option to statd), bind to the address
- * specified. This is required to support clients that ignore the mon_name in
- * the statd protocol but use the source address from the request packet.
- */
- if (MY_NAME) {
- struct hostent *hp = gethostbyname(MY_NAME);
- if (hp)
- sin.sin_addr = *(struct in_addr *) hp->h_addr;
- }
- if (port != 0) {
- sin.sin_port = htons(port);
- if (bind(sockfd, &sin, sizeof(sin)) == 0)
- goto out_success;
- note(N_CRIT, "statd: failed to bind to outgoing port, %d\n"
- " falling back on randomly chosen port\n", port);
- }
+
if (bindresvport(sockfd, &sin) < 0) {
dprintf(N_WARNING,
"process_hosts: can't bind to reserved port\n");
}
-out_success:
return sockfd;
}
-#ifdef HAVE_IFADDRS_H
-/*
- * Using the NL_ADDR(lp), reset (if needed) the hostname
- * that will be put in the SM_NOTIFY to the hostname
- * that is associated with the network interface
- * that was monitored
- */
-static void
-reset_my_name(notify_list *lp)
-{
- struct ifaddrs *ifa = NULL, *ifap;
- struct in_addr netaddr, tmp;
- struct sockaddr_in *sin, *nsin;
- struct hostent *hp;
-
- netaddr.s_addr = inet_netof(NL_ADDR(lp));
- if (getifaddrs(&ifa) >= 0) {
- for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
- if (!(ifap->ifa_flags & IFF_UP))
- continue;
-
- note(N_DEBUG, "ifa_name %s\n", ifap->ifa_name);
- if (ifap->ifa_addr == NULL)
- continue;
- if (ifap->ifa_addr->sa_family != AF_INET)
- continue;
-
- sin = (struct sockaddr_in *)ifap->ifa_addr;
- nsin = (struct sockaddr_in *)ifap->ifa_netmask;
- tmp.s_addr = sin->sin_addr.s_addr & nsin->sin_addr.s_addr;
- if (memcmp(&tmp.s_addr, &netaddr.s_addr, sizeof(netaddr.s_addr)))
- continue;
- hp = gethostbyaddr((char *)&sin->sin_addr,
- sizeof(sin->sin_addr), AF_INET);
- if (hp == NULL)
- continue;
- if (strcmp(NL_MY_NAME(lp), hp->h_name)) {
- free(NL_MY_NAME(lp));
- NL_MY_NAME(lp)= strdup(hp->h_name);
- note(N_DEBUG, "NL_MY_NAME %s\n", NL_MY_NAME(lp));
- }
- }
- }
- return;
-}
-#endif /* HAVE_IFADDRS_H */
/*
* Try to resolve host name for notify/callback request
*
{
char *hname;
- if (NL_TYPE(lp) == NOTIFY_REBOOT)
- hname = NL_MON_NAME(lp);
- else
- hname = NL_MY_NAME(lp);
+ hname = NL_MY_NAME(lp);
if (!inet_aton(hname, &(NL_ADDR(lp)))) {
note(N_ERROR, "%s is not an dotted-quad address", hname);
NL_TIMES(lp) = 0;
struct hostent *hp;
char *hname;
- if (NL_TYPE(lp) == NOTIFY_REBOOT)
- hname = NL_MON_NAME(lp);
- else
- hname = NL_MY_NAME(lp);
+ hname = NL_MY_NAME(lp);
dprintf(N_DEBUG, "Trying to resolve %s.", hname);
if (!(hp = gethostbyname(hname))) {
{
struct sockaddr_in sin;
struct status new_status;
- stat_chge new_stat;
xdrproc_t func;
void *objp;
u_int32_t proc, vers, prog;
sin.sin_port = lp->port;
/* LH - moved address into switch */
- switch (NL_TYPE(lp)) {
- case NOTIFY_REBOOT:
- prog = SM_PROG;
- vers = SM_VERS;
- proc = SM_NOTIFY;
-
- /* Use source address for notify replies */
- sin.sin_addr = lp->addr;
- /*
- * Unless a static hostname has been defined
- * set the NL_MY_NAME(lp) hostname to the
- * one associated with the network interface
- */
-#ifdef HAVE_IFADDRS_H
- if (!(run_mode & STATIC_HOSTNAME))
- reset_my_name(lp);
-#endif /* HAVE_IFADDRS_H */
- func = (xdrproc_t) xdr_stat_chge;
- new_stat.state = MY_STATE;
- new_stat.mon_name = NL_MY_NAME(lp);
+ prog = NL_MY_PROG(lp);
+ vers = NL_MY_VERS(lp);
+ proc = NL_MY_PROC(lp);
- objp = &new_stat;
- break;
- case NOTIFY_CALLBACK:
- prog = NL_MY_PROG(lp);
- vers = NL_MY_VERS(lp);
- proc = NL_MY_PROC(lp);
-
- /* __FORCE__ loopback for callbacks to lockd ... */
- /* Just in case we somehow ignored it thus far */
- sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- 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:
- note(N_ERROR, "notify_host: unknown notify type %d",
- NL_TYPE(lp));
- return 0;
- }
+ /* __FORCE__ loopback for callbacks to lockd ... */
+ /* Just in case we somehow ignored it thus far */
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ 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);
lp->xid = xmit_call(sockfd, &sin, prog, vers, proc, func, objp);
if (!lp->xid) {
return 1;
}
note(N_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(N_DEBUG, "Notification of %s succeeded.",
- NL_MON_NAME(lp));
- xunlink(SM_BAK_DIR, NL_MON_NAME(lp), 0);
+ inet_ntoa(lp->addr), NL_MY_PROG(lp));
} else {
dprintf(N_DEBUG, "Callback to %s (for %d) succeeded.",
NL_MY_NAME(lp), NL_MON_NAME(lp));
time_t now;
int fd;
- if ((fd = statd_get_socket(0)) < 0)
+ if ((fd = statd_get_socket()) < 0)
return 0;
while ((entry = notify) != NULL && NL_WHEN(entry) < time(&now)) {
NL_WHEN(entry) = time(NULL) + NOTIFY_TIMEOUT;
nlist_remove(¬ify, entry);
nlist_insert_timer(¬ify, entry);
- } else if (NL_TYPE(entry) == NOTIFY_CALLBACK) {
+ } else {
note(N_ERROR,
"Can't callback %s (%d,%d), giving up.",
NL_MY_NAME(entry),
NL_MY_PROG(entry),
NL_MY_VERS(entry));
nlist_free(¬ify, entry);
- } else {
- note(N_ERROR,
- "Can't notify %s, giving up.",
- NL_MON_NAME(entry));
- /* PRC: do the HA callout */
- ha_callout("del-client", NL_MON_NAME(entry), NL_MY_NAME(entry), -1);
- xunlink(SM_BAK_DIR, NL_MON_NAME(entry), 0);
- nlist_free(¬ify, entry);
}
}
#include <rpc/pmap_clnt.h>
#include <rpcmisc.h>
#include <sys/resource.h>
+#include <sys/wait.h>
#include <grp.h>
#include "statd.h"
#include "version.h"
/* ----- end of state directory path stuff ------- */
-short int restart = 0;
int run_mode = 0; /* foreground logging mode */
/* LH - I had these local to main, but it seemed silly to have
};
extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
-extern int statd_get_socket(int port);
+extern int statd_get_socket(void);
#ifdef SIMULATIONS
extern void simulator (int, char **);
killer (int sig)
{
note (N_FATAL, "Caught signal %d, un-registering and exiting.", sig);
- if (!(run_mode & MODE_NOTIFY_ONLY))
- pmap_unset (SM_PROG, SM_VERS);
+ pmap_unset (SM_PROG, SM_VERS);
exit (0);
}
static void
sigusr (int sig)
{
+ extern void my_svc_exit (void);
dprintf (N_DEBUG, "Caught signal %d, re-notifying (state %d).", sig,
MY_STATE);
- re_notify = 1;
+ my_svc_exit();
}
/*
if (run_mode & MODE_LOG_STDERR)
strcat(buf,"Log-STDERR ");
- if (run_mode & MODE_NOTIFY_ONLY)
- {
- strcat(buf,"Notify-Only ");
- }
note(N_WARNING,buf);
- /* future: IP aliasing
- if (run_mode & MODE_NOTIFY_ONLY)
- {
- dprintf(N_DEBUG,"Notify IP: %s",svr_addr);
- } */
}
/*
}
}
+static void run_sm_notify(int outport)
+{
+ char op[20];
+ char *av[6];
+ int ac = 0;
+
+ av[ac++] = "/usr/sbin/sm-notify";
+ if (run_mode & MODE_NODAEMON)
+ av[ac++] = "-d";
+ if (outport) {
+ sprintf(op, "-p%d", outport);
+ av[ac++] = op;
+ }
+ if (run_mode & STATIC_HOSTNAME) {
+ av[ac++] = "-N";
+ av[ac++] = MY_NAME;
+ }
+ av[ac] = NULL;
+ fprintf(stderr, "%s: -N deprecated, consider using /usr/sbin/sm-notify directly\n",
+ name_p);
+ execv(av[0], av);
+ fprintf(stderr, "%s: failed to run %s\n", name_p, av[0]);
+ exit(2);
+
+}
/*
* Entry routine/main loop.
*/
exit(-1);
}
+ if (run_mode & MODE_NOTIFY_ONLY)
+ run_sm_notify(out_port);
+
+
if (!(run_mode & MODE_NODAEMON)) {
run_mode &= ~MODE_LOG_STDERR; /* Never log to console in
daemon mode. */
*/
signal(SIGPIPE, SIG_IGN);
- /* initialize out_port */
- statd_get_socket(out_port);
-
create_pidfile();
atexit(truncate_pidfile);
+
+ switch (pid = fork()) {
+ case 0:
+ run_sm_notify(out_port);
+ break;
+ case -1:
+ break;
+ default:
+ waitpid(pid, NULL, 0);
+ }
+
drop_privs();
for (;;) {
- if (!(run_mode & MODE_NOTIFY_ONLY)) {
- /* Do not do pmap_unset() when running in notify mode.
- * We may clear the portmapper record for a statd not
- * running in notify mode disabling it.
- * Juan C. Gomez j_carlos_gomez@yahoo.com
- */
- pmap_unset (SM_PROG, SM_VERS);
- }
- change_state ();
- shuffle_dirs (); /* Move directory names around */
+ pmap_unset (SM_PROG, SM_VERS);
/* If we got this far, we have successfully started, so notify parent */
if (pipefds[1] > 0) {
pipefds[1] = -1;
}
- notify_hosts (); /* Send out notify requests */
- ++restart;
-
/* this registers both UDP and TCP services */
- if (!(run_mode & MODE_NOTIFY_ONLY)) {
- rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
- }
+ rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
/*
* Handle incoming requests: SM_NOTIFY socket requests, as
*/
my_svc_run(); /* I rolled my own, Olaf made it better... */
- if ((run_mode & MODE_NOTIFY_ONLY))
- break;
+ /* Only get here when simulating a crash so we should probably
+ * start sm-notify running again. As we have already dropped
+ * privileges, this might not work, but I don't think
+ * responding to SM_SIMU_CRASH is an important use cases to
+ * get perfect.
+ */
+ switch (pid = fork()) {
+ case 0:
+ run_sm_notify(out_port);
+ break;
+ case -1:
+ break;
+ default:
+ waitpid(pid, NULL, 0);
+ }
}
return 0;
}
extern char *name_p; /* program basename */
extern const char *version_p; /* program version */
-extern int re_notify; /* time to re-read notify list */
+++ /dev/null
-/*
- * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
- * Modified by Olaf Kirch, 1996.
- * Modified by H.J. Lu, 1998.
- *
- * NSM for Linux.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#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;
-
- 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) {
- note (N_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));
- }
- note (N_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)
- note (N_ERROR, "fsync (%s): %s", SM_STAT_PATH, strerror (errno));
-
- if (close (fd) == -1)
- note (N_ERROR, "close (%s): %s", SM_STAT_PATH, strerror (errno));
-
- if (MY_NAME == NULL) {
- char fullhost[SM_MAXSTRLEN + 1];
- struct hostent *hostinfo;
-
- if (gethostname (fullhost, SM_MAXSTRLEN) == -1)
- die ("gethostname: %s", strerror (errno));
-
- if ((hostinfo = gethostbyname (fullhost)) == NULL)
- note (N_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)
- note (N_ERROR, "closedir (%s): %s", SM_DIR, strerror (errno));
-}
* requests are put.
*/
notify_list * notify = NULL;
-int re_notify = 0;
/*
* Jump-off function.
for (;;) {
if (svc_stop)
return;
- if (re_notify) {
- change_state();
- dprintf(N_DEBUG, "Notifying...(new state %d)",
- MY_STATE);
- notify_hosts();
- re_notify = 0;
- }
/* Ah, there are some notifications to be processed */
while (notify && NL_WHEN(notify) <= time(&now)) {
tv.tv_sec);
selret = select(FD_SETSIZE, &readfds,
(void *) 0, (void *) 0, &tv);
- } else if (run_mode & MODE_NOTIFY_ONLY)
- return;
- else {
+ } else {
dprintf(N_DEBUG, "Waiting for client connections.");
selret = select(FD_SETSIZE, &readfds,
(void *) 0, (void *) 0, (struct timeval *) 0);