summaryrefslogtreecommitdiffstats
path: root/usr.sbin/yppush
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1996-01-12 07:03:33 +0000
committerwpaul <wpaul@FreeBSD.org>1996-01-12 07:03:33 +0000
commit226cb5fee95f97eebee115381c5d7c4800d544c8 (patch)
tree20b92da117675d48f09a3b446b0d992a76bb5a30 /usr.sbin/yppush
parent48229bd2a16f4f312353e0d1061659a4082ac85d (diff)
parent57e5d5b64973afaf302bb895f9b39c3bd058ede1 (diff)
downloadFreeBSD-src-226cb5fee95f97eebee115381c5d7c4800d544c8.zip
FreeBSD-src-226cb5fee95f97eebee115381c5d7c4800d544c8.tar.gz
This commit was generated by cvs2svn to compensate for changes in r13394,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'usr.sbin/yppush')
-rw-r--r--usr.sbin/yppush/Makefile26
-rw-r--r--usr.sbin/yppush/yppush.8172
-rw-r--r--usr.sbin/yppush/yppush_extern.h44
-rw-r--r--usr.sbin/yppush/yppush_main.c683
4 files changed, 925 insertions, 0 deletions
diff --git a/usr.sbin/yppush/Makefile b/usr.sbin/yppush/Makefile
new file mode 100644
index 0000000..e8aaea6
--- /dev/null
+++ b/usr.sbin/yppush/Makefile
@@ -0,0 +1,26 @@
+# $Id: Makefile,v 1.6 1995/12/16 04:03:02 wpaul Exp $
+
+PROG= yppush
+SRCS= yp_clnt.c ypxfr_getmap.c yp_dblookup.c yppush_svc.c \
+ yp_error.c ypxfr_misc.c yppush_main.c
+
+.PATH: ${.CURDIR}/../ypserv ${.CURDIR}/../../libexec/ypxfr
+
+MAN8= yppush.8
+CFLAGS+=-I. -I${.CURDIR}/../../libexec/ypxfr
+
+CLEANFILES= yp.h yp_clnt.c yppush_svc.c
+
+RPCSRC= ${.DESTDIR}/usr/include/rpcsvc/yp.x
+RPCGEN= rpcgen -C
+
+yppush_svc.c: ${RPCSRC} yp.h
+ ${RPCGEN} -DYPPUSH_ONLY -m -o ${.TARGET} ${RPCSRC}
+
+yp_clnt.c: ${RPCSRC} yp.h
+ ${RPCGEN} -DYPSERV_ONLY -l -o ${.TARGET} ${RPCSRC}
+
+yp.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/yppush/yppush.8 b/usr.sbin/yppush/yppush.8
new file mode 100644
index 0000000..6c2563b
--- /dev/null
+++ b/usr.sbin/yppush/yppush.8
@@ -0,0 +1,172 @@
+.\" Copyright (c) 1991, 1993, 1995
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: yppush.8,v 1.2 1996/01/12 06:21:52 wpaul Exp wpaul $
+.\"
+.Dd February 5, 1995
+.Dt YPPUSH 8
+.Os
+.Sh NAME
+.Nm yppush
+.Nd "force propagation of updated NIS databases"
+.Sh SYNOPSIS
+.Nm yppush
+.Op Fl d Ar domain
+.Op Fl t Ar timeout
+.Op Fl j Ar #parallel jobs
+.Op Fl h Ar host
+.Op Fl p Ar path
+.Op Fl v
+.Ar mapname
+.Sh DESCRIPTION
+.Nm yppush
+distributes updated NIS databases (or
+.Pa maps )
+from an NIS master server to NIS slave servers within an NIS
+domain. It is normally only run on the NIS master by
+.Pa /var/yp/Makefile
+whenever any of the NIS maps are updated. Note that
+.Pa /var/yp/Makefile
+does not invoke
+.Nm yppush
+by default: the
+.Nm NOPUSH=True
+entry in the Makefile must first be commented out
+(the default FreeBSD configuration assumes a small network with only
+a single NIS server; in such a configuration,
+.Nm yppush
+is not needed).
+.Pp
+By default,
+.Nm yppush
+determines the names of the slave servers for a domain by searching the
+.Pa ypservers
+map. A destination host (or a list of hosts) can also be manually
+specified on the command line.
+Once it has a complete list of slave servers, it sends a 'map transfer'
+request to each slave, which in turn reads a copy of the map from
+the master NIS server using
+.Xr ypxfr 8 .
+Included within each request is the name of the map to be copied
+and some special information required by
+.Xr ypxfr 8
+to successfully 'callback' to
+.Nm yppush
+and carry out the transfer. Any error messages
+.Nm yppush
+receives from
+.Xr ypxfr 8
+via callback will be printed to stderr.
+.Pp
+.Sh OPTIONS
+The following options are supported by
+.Nm yppush :
+.Bl -tag -width flag
+.It Fl d Ar domain
+Specify a particular domain. The NIS domain of
+the local host system is used by default. If the local host's domain
+name is not set, the domain name must be specified with this flag.
+.It Fl t Ar timeout
+The
+.Fl t
+flag is used to specify a timeout value in seconds. This timeout
+controls how long
+.Nm yppush
+will wait for a response from a slave server before sending a
+map transfer request to the next slave server in its list.
+.It Fl j Ar #parallel jobs
+.Nm yppush
+normally performs transfers serially, meaning that it will
+send a map transfer request to one slave server and then wait for
+it to respond before moving on to the next slave server. In environments
+with many slaves, it is more efficient to initiate several map transfers
+at once so that the transfers can take place in parallel. The
+.Fl j
+flag is used to specify the desired number of parallel jobs:
+.Nm yppush
+will initiate the specified number of transfers immediately and
+listen for responses. If the number of specified parallel jobs is
+less than the number of slave servers,
+.Nm yppush
+will initiate only the number of specified jobs and then wait
+for some of them to finish before starting any more.
+.Pp
+Note that
+.Nm yppush
+handles callbacks asynchronously, which means that it will collect
+and display the callback information received from
+.Xr ypxfr 8
+as soon as it arrives, even it arrives before all of the map
+transfer requests have been sent.
+.It Fl h Ar host
+The
+.Fl h
+flag can be used to transfer a map to a user-specified machine or
+group of machines instead of the list of servers contained in
+the
+.Pa ypservers
+map. A list of hosts can be specified by using multiple
+instances of the
+.Fl h
+flag.
+.It Fl p Ar path
+By default,
+.Nm yppush
+expects all the local NIS maps to be stored under
+.Pa /var/yp .
+The
+.Fl p
+flag can be used to specify an alternate path in the event that
+the system administrator decides to store the NIS maps somewhere else.
+.It Fl v
+Verbose mode: causes
+.Nm yppush
+to print debugging messages as it runs. Note specifying this flag twice
+makes
+.Nm yppush
+even more verbose.
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/yp/[domainname]/ypservers
+The NIS ypservers map containing the names of all servers in
+a particular NIS domain.
+.El
+.Sh SEE ALSO
+.Xr ypserv 8 ,
+.Xr ypxfr 8 ,
+.Xr yp 8
+.Sh BUGS
+The mechanism for transfering NIS maps in NIS v1 is different
+that that in NIS version 2. This version of
+.Nm yppush
+has support for transfering maps to NIS v2 systems only.
+.Sh AUTHOR
+Bill Paul <wpaul@ctr.columbia.edu>
diff --git a/usr.sbin/yppush/yppush_extern.h b/usr.sbin/yppush/yppush_extern.h
new file mode 100644
index 0000000..3448b84
--- /dev/null
+++ b/usr.sbin/yppush/yppush_extern.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: yppush_extern.h,v 1.5 1996/01/12 06:21:52 wpaul Exp $
+ */
+
+/* Privately defined error codes. */
+#define YPPUSH_TIMEDOUT 255 /* Timed out trying to talk to ypserv */
+#define YPPUSH_NOHOST 254 /* No such host */
+#define YPPUSH_YPSERV 252 /* Failed to contact ypserv. */
+#define YPPUSH_PMAP 251 /* Portmapper failure. */
+#ifndef YPPUSH_RESPONSE_TIMEOUT
+#define YPPUSH_RESPONSE_TIMEOUT 5*60
+#endif
+extern int _rpc_dtablesize __P((void));
+extern void yppush_xfrrespprog_1 __P(( struct svc_req *, SVCXPRT * ));
diff --git a/usr.sbin/yppush/yppush_main.c b/usr.sbin/yppush/yppush_main.c
new file mode 100644
index 0000000..79d2dac
--- /dev/null
+++ b/usr.sbin/yppush/yppush_main.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: yppush_main.c,v 1.24 1996/01/12 06:21:52 wpaul Exp wpaul $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <rpc/clnt.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/yp.h>
+struct dom_binding {};
+#include <rpcsvc/ypclnt.h>
+#include "ypxfr_extern.h"
+#include "yppush_extern.h"
+
+#ifndef lint
+static const char rcsid[] = "$Id: yppush_main.c,v 1.24 1996/01/12 06:21:52 wpaul Exp wpaul $";
+#endif
+
+char *progname = "yppush";
+int debug = 1;
+int _rpcpmstart = 0;
+char *yp_dir = _PATH_YP;
+
+char *yppush_mapname = NULL; /* Map to transfer. */
+char *yppush_domain = NULL; /* Domain in which map resides. */
+char *yppush_master = NULL; /* Master NIS server for said domain. */
+int verbose = 0; /* Toggle verbose mode. */
+unsigned long yppush_transid = 0;
+int yppush_timeout = 80; /* Default timeout. */
+int yppush_jobs = 0; /* Number of allowed concurrent jobs. */
+int yppush_running_jobs = 0; /* Number of currently running jobs. */
+int yppush_pausing = 0; /* Flag set when longjmp()s are allowed. */
+jmp_buf env;
+
+/* Structure for holding information about a running job. */
+struct jobs {
+ unsigned long tid;
+ int pid;
+ int sock;
+ int port;
+ ypxfrstat stat;
+ unsigned long prognum;
+ char *server;
+ char *map;
+ int polled;
+ struct jobs *next;
+};
+
+struct jobs *yppush_joblist; /* Linked list of running jobs. */
+
+/*
+ * Local error messages.
+ */
+static char *yppusherr_string(err)
+ int err;
+{
+ switch(err) {
+ case YPPUSH_TIMEDOUT: return("transfer or callback timed out");
+ case YPPUSH_YPSERV: return("failed to contact ypserv");
+ case YPPUSH_NOHOST: return("no such host");
+ case YPPUSH_PMAP: return("portmapper failure");
+ default: return("unknown error code");
+ }
+}
+
+/*
+ * Report state of a job.
+ */
+static int yppush_show_status(status, tid)
+ ypxfrstat status;
+ unsigned long tid;
+{
+ struct jobs *job;
+
+ job = yppush_joblist;
+
+ while(job) {
+ if (job->tid == tid)
+ break;
+ job = job->next;
+ }
+
+ if (job->polled) {
+ return(0);
+ }
+
+ if (verbose > 1)
+ yp_error("Checking return status: Transaction ID: %lu",
+ job->tid);
+ if (status != YPPUSH_SUCC || verbose) {
+ yp_error("Transfer of map %s to server %s %s.",
+ job->map, job->server, status == YPPUSH_SUCC ?
+ "succeeded" : "failed");
+ yp_error("status returned by ypxfr: %s", status > YPPUSH_AGE ?
+ yppusherr_string(status) :
+ ypxfrerr_string(status));
+ }
+
+ job->polled = 1;
+
+ svc_unregister(job->prognum, 1);
+
+ yppush_running_jobs--;
+ return(0);
+}
+
+/* Exit routine. */
+static void yppush_exit(now)
+ int now;
+{
+ struct jobs *jptr;
+ int still_pending = 1234;
+
+ /* Let all the information trickle in. */
+ while(!now && still_pending) {
+ yppush_pausing++;
+ setjmp(env); /* more magic */
+ jptr = yppush_joblist;
+ still_pending = 0;
+ while (jptr) {
+ if (jptr->polled == 0) {
+ still_pending++;
+ if (verbose > 1)
+ yp_error("%s has not responded",
+ jptr->server);
+ } else {
+ if (verbose > 1)
+ yp_error("%s has responded",
+ jptr->server);
+ }
+ jptr = jptr->next;
+ }
+ if (still_pending) {
+ if (verbose > 1)
+ yp_error("%d transfer%sstill pending",
+ still_pending,
+ still_pending > 1 ? "s " : " ");
+ alarm(YPPUSH_RESPONSE_TIMEOUT);
+ pause();
+ yppush_pausing = 0;
+ alarm(0);
+ } else {
+ if (verbose)
+ yp_error("all transfers complete");
+ break;
+ }
+ }
+
+
+ /* All stats collected and reported -- kill all the stragglers. */
+ jptr = yppush_joblist;
+ while(jptr) {
+ if (!jptr->polled)
+ yp_error("warning: exiting with transfer \
+to %s (transid = %lu) still pending.", jptr->server, jptr->tid);
+ svc_unregister(jptr->prognum, 1);
+ jptr = jptr->next;
+ }
+
+ exit(0);
+}
+
+/*
+ * Handler for 'normal' signals.
+ */
+
+static void handler(sig)
+ int sig;
+{
+ if (sig == SIGTERM || sig == SIGINT || sig == SIGABRT) {
+ yppush_jobs = 0;
+ yppush_exit(1);
+ }
+
+ if (sig == SIGALRM) {
+ alarm(0);
+ }
+
+ return;
+}
+
+/*
+ * Dispatch loop for callback RPC services.
+ */
+static void yppush_svc_run()
+{
+#ifdef FD_SETSIZE
+ fd_set readfds;
+#else
+ int readfds;
+#endif /* def FD_SETSIZE */
+ struct timeval timeout;
+
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 5;
+
+retry:
+#ifdef FD_SETSIZE
+ readfds = svc_fdset;
+#else
+ readfds = svc_fds;
+#endif /* def FD_SETSIZE */
+ switch (select(_rpc_dtablesize(), &readfds, NULL, NULL, &timeout)) {
+ case -1:
+ if (errno == EINTR)
+ goto retry;
+ yp_error("select failed: %s", strerror(errno));
+ break;
+ case 0:
+ yp_error("select() timed out");
+ break;
+ default:
+ svc_getreqset(&readfds);
+ break;
+ }
+ return;
+}
+
+/*
+ * Special handler for asynchronous socket I/O. We mark the
+ * sockets of the callback handlers as O_ASYNC and handle SIGIO
+ * events here, which will occur when the callback handler has
+ * something interesting to tell us.
+ */
+static void async_handler(sig)
+ int sig;
+{
+ yppush_svc_run();
+
+ /* reset any pending alarms. */
+ alarm(0);
+ kill(getpid(), SIGALRM);
+ if (yppush_pausing)
+ longjmp(env, 1);
+ return;
+}
+
+/*
+ * RPC service routines for callback listener process
+ */
+void *
+yppushproc_null_1_svc(void *argp, struct svc_req *rqstp)
+{
+ static char * result;
+ /* Do nothing -- RPC conventions call for all a null proc. */
+ return((void *) &result);
+}
+
+void *
+yppushproc_xfrresp_1_svc(yppushresp_xfr *argp, struct svc_req *rqstp)
+{
+ static char * result;
+ yppush_show_status(argp->status, argp->transid);
+ return((void *) &result);
+}
+
+/*
+ * Transmit a YPPROC_XFR request to ypserv.
+ */
+static int yppush_send_xfr(job)
+ struct jobs *job;
+{
+ ypreq_xfr req;
+/* ypresp_xfr *resp; */
+ DBT key, data;
+ CLIENT *clnt;
+ struct rpc_err err;
+ struct timeval timeout;
+
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 0;
+
+ /*
+ * The ypreq_xfr structure has a member of type map_parms,
+ * which seems to require the order number of the map.
+ * It isn't actually used at the other end (at least the
+ * FreeBSD ypserv doesn't use it) but we fill it in here
+ * for the sake of completeness.
+ */
+ key.data = "YP_LAST_MODIFIED";
+ key.size = sizeof ("YP_LAST_MODIFIED") - 1;
+
+ if (yp_get_record(yppush_domain, yppush_mapname, &key, &data,
+ 1) != YP_TRUE) {
+ yp_error("failed to read order number from %s: %s: %s",
+ yppush_mapname, yperr_string(yp_errno),
+ strerror(errno));
+ return(1);
+ }
+
+ /* Fill in the request arguments */
+ req.map_parms.ordernum = atoi(data.data);
+ req.map_parms.domain = yppush_domain;
+ req.map_parms.peer = yppush_master;
+ req.map_parms.map = job->map;
+ req.transid = job->tid;
+ req.prog = job->prognum;
+ req.port = job->port;
+
+ /* Get a handle to the remote ypserv. */
+ if ((clnt = clnt_create(job->server, YPPROG, YPVERS, "udp")) == NULL) {
+ yp_error("%s: %s",job->server,clnt_spcreateerror("couldn't \
+create udp handle to NIS server"));
+ switch(rpc_createerr.cf_stat) {
+ case RPC_UNKNOWNHOST:
+ job->stat = YPPUSH_NOHOST;
+ break;
+ case RPC_PMAPFAILURE:
+ job->stat = YPPUSH_PMAP;
+ break;
+ default:
+ job->stat = YPPUSH_RPC;
+ break;
+ }
+ return(1);
+ }
+
+ /*
+ * Reduce timeout to nothing since we may not
+ * get a response from ypserv and we don't want to block.
+ */
+ if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE)
+ yp_error("failed to set timeout on ypproc_xfr call");
+
+ /* Invoke the ypproc_xfr service. */
+ if (ypproc_xfr_2(&req, clnt) == NULL) {
+ clnt_geterr(clnt, &err);
+ if (err.re_status != RPC_SUCCESS &&
+ err.re_status != RPC_TIMEDOUT) {
+ yp_error("%s: %s", job->server, clnt_sperror(clnt,
+ "yp_xfr failed"));
+ job->stat = YPPUSH_YPSERV;
+ clnt_destroy(clnt);
+ return(1);
+ }
+ }
+
+ clnt_destroy(clnt);
+
+ return(0);
+}
+
+/*
+ * Main driver function. Register the callback service, add the transfer
+ * request to the internal list, send the YPPROC_XFR request to ypserv
+ * do other magic things.
+ */
+int yp_push(server, map, tid)
+ char *server;
+ char *map;
+ unsigned long tid;
+{
+ unsigned long prognum;
+ int sock = RPC_ANYSOCK;
+ SVCXPRT *xprt;
+ struct jobs *job;
+
+ /*
+ * Register the callback service on the first free
+ * transient program number.
+ */
+ xprt = svcudp_create(sock);
+ for (prognum = 0x4000000; prognum < 0x5FFFFFF; prognum++) {
+ if (svc_register(xprt, prognum, 1,
+ yppush_xfrrespprog_1, IPPROTO_UDP) == TRUE)
+ break;
+ }
+
+ /* Register the job in our linked list of jobs. */
+ if ((job = (struct jobs *)malloc(sizeof (struct jobs))) == NULL) {
+ yp_error("malloc failed: %s", strerror(errno));
+ yppush_exit(1);
+ }
+
+ /* Initialize the info for this job. */
+ job->stat = 0;
+ job->tid = tid;
+ job->port = xprt->xp_port;
+ job->sock = xprt->xp_sock; /*XXX: Evil!! EEEEEEEVIL!!! */
+ job->server = strdup(server);
+ job->map = strdup(map);
+ job->prognum = prognum;
+ job->polled = 0;
+ job->next = yppush_joblist;
+ yppush_joblist = job;
+
+ /*
+ * Set the RPC sockets to asynchronous mode. This will
+ * cause the system to smack us with a SIGIO when an RPC
+ * callback is delivered. This in turn allows us to handle
+ * the callback even though we may be in the middle of doing
+ * something else at the time.
+ *
+ * XXX This is a horrible thing to do for two reasons,
+ * both of which have to do with portability:
+ * 1) We really ought not to be sticking our grubby mits
+ * into the RPC service transport handle like this.
+ * 2) Even in this day and age, there are still some *NIXes
+ * that don't support async socket I/O.
+ */
+ if (fcntl(xprt->xp_sock, F_SETOWN, getpid()) == -1 ||
+ fcntl(xprt->xp_sock, F_SETFL, O_ASYNC) == -1) {
+ yp_error("failed to set async I/O mode: %s",
+ strerror(errno));
+ yppush_exit(1);
+ }
+
+ if (verbose) {
+ yp_error("initiating transfer: %s -> %s (transid = %lu)",
+ yppush_mapname, server, tid);
+ }
+
+ /*
+ * Send the XFR request to ypserv. We don't have to wait for
+ * a response here since we can handle them asynchronously.
+ */
+
+ if (yppush_send_xfr(job)){
+ /* Transfer request blew up. */
+ yppush_show_status(job->stat ? job->stat :
+ YPPUSH_YPSERV,job->tid);
+ } else {
+ if (verbose > 1)
+ yp_error("%s has been called", server);
+ }
+
+ return(0);
+}
+
+/*
+ * Called for each entry in the ypservers map from yp_get_map(), which
+ * is our private yp_all() routine.
+ */
+int yppush_foreach(status, key, keylen, val, vallen, data)
+ int status;
+ char *key;
+ int keylen;
+ char *val;
+ int vallen;
+ char *data;
+{
+ char server[YPMAXRECORD + 2];
+
+ if (status != YP_TRUE)
+ return (status);
+
+ snprintf(server, sizeof(server), "%.*s", vallen, val);
+
+ /*
+ * Restrict the number of concurrent jobs. If yppush_jobs number
+ * of jobs have already been dispatched and are still pending,
+ * wait for one of them to finish so we can reuse its slot.
+ */
+ if (yppush_jobs <= 1) {
+ yppush_pausing++;
+ while (!setjmp(env) && yppush_running_jobs) {
+ alarm(yppush_timeout);
+ pause();
+ alarm(0);
+ }
+ yppush_pausing = 0;
+ } else {
+ yppush_pausing++;
+ while (!setjmp(env) && yppush_running_jobs >= yppush_jobs) {
+ alarm(yppush_timeout);
+ pause();
+ alarm(0);
+ }
+ yppush_pausing = 0;
+ }
+
+ /* Cleared for takeoff: set everything in motion. */
+ if (yp_push(&server, yppush_mapname, yppush_transid))
+ return(yp_errno);
+
+ /* Bump the job counter and transaction ID. */
+ yppush_running_jobs++;
+ yppush_transid++;
+ return (0);
+}
+
+static void usage()
+{
+ fprintf (stderr, "%s: [-d domain] [-t timeout] [-j #parallel jobs] \
+[-h host] [-p path] mapname\n", progname);
+ exit(1);
+}
+
+/*
+ * Entry point. (About time!)
+ */
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+ DBT key, data;
+ char myname[MAXHOSTNAMELEN];
+ struct hostlist {
+ char *name;
+ struct hostlist *next;
+ };
+ struct hostlist *yppush_hostlist = NULL;
+ struct hostlist *tmp;
+ struct sigaction sa;
+
+ while ((ch = getopt(argc, argv, "d:j:p:h:t:v")) != EOF) {
+ switch(ch) {
+ case 'd':
+ yppush_domain = optarg;
+ break;
+ case 'j':
+ yppush_jobs = atoi(optarg);
+ if (yppush_jobs <= 0)
+ yppush_jobs = 1;
+ break;
+ case 'p':
+ yp_dir = optarg;
+ break;
+ case 'h': /* we can handle multiple hosts */
+ if ((tmp = (struct hostlist *)malloc(sizeof(struct hostlist))) == NULL) {
+ yp_error("malloc() failed: %s", strerror(errno));
+ yppush_exit(1);
+ }
+ tmp->name = strdup(optarg);
+ tmp->next = yppush_hostlist;
+ yppush_hostlist = tmp;
+ break;
+ case 't':
+ yppush_timeout = atoi(optarg);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ yppush_mapname = argv[0];
+
+ if (yppush_mapname == NULL) {
+ /* "No guts, no glory." */
+ usage();
+ }
+
+ /*
+ * If no domain was specified, try to find the default
+ * domain. If we can't find that, we're doomed and must bail.
+ */
+ if (yppush_domain == NULL) {
+ char *yppush_check_domain;
+ if (!yp_get_default_domain(&yppush_check_domain) &&
+ !_yp_check(&yppush_check_domain)) {
+ yp_error("no domain specified and NIS not running");
+ usage();
+ } else
+ yp_get_default_domain(&yppush_domain);
+ }
+
+ /* Check to see that we are the master for this map. */
+
+ if (gethostname ((char *)&myname, sizeof(myname))) {
+ yp_error("failed to get name of local host: %s",
+ strerror(errno));
+ yppush_exit(1);
+ }
+
+ key.data = "YP_MASTER_NAME";
+ key.size = sizeof("YP_MASTER_NAME") - 1;
+
+ if (yp_get_record(yppush_domain, yppush_mapname,
+ &key, &data, 1) != YP_TRUE) {
+ yp_error("couldn't open %s map: %s", yppush_mapname,
+ strerror(errno));
+ yppush_exit(1);
+ }
+
+ if (strncmp(myname, data.data, data.size)) {
+ yp_error("this host is not the master for %s",yppush_mapname);
+ yppush_exit(1);
+ }
+
+ yppush_master = strdup(data.data);
+ yppush_master[data.size] = '\0';
+
+ /* Install some handy handlers. */
+ signal(SIGALRM, handler);
+ signal(SIGTERM, handler);
+ signal(SIGINT, handler);
+ signal(SIGABRT, handler);
+
+ /*
+ * Set up the SIGIO handler. Make sure that some of the
+ * other signals are blocked while the handler is running so
+ * select() doesn't get interrupted.
+ */
+ sigaddset(&sa.sa_mask, SIGIO); /* Goes without saying. */
+ sigaddset(&sa.sa_mask, SIGPIPE);
+ sigaddset(&sa.sa_mask, SIGCHLD);
+ sigaddset(&sa.sa_mask, SIGALRM);
+ sigaddset(&sa.sa_mask, SIGINT);
+ sa.sa_handler = async_handler;
+
+ sigaction(SIGIO, &sa, NULL);
+
+ /* set initial transaction ID */
+ time(&yppush_transid);
+
+ if (yppush_hostlist) {
+ /*
+ * Host list was specified on the command line:
+ * kick off the transfers by hand.
+ */
+ tmp = yppush_hostlist;
+ while(tmp) {
+ yppush_foreach(YP_TRUE, NULL, 0, tmp->name,
+ strlen(tmp->name));
+ tmp = tmp->next;
+ }
+ } else {
+ /*
+ * Do a yp_all() on the ypservers map and initiate a ypxfr
+ * for each one.
+ */
+ ypxfr_get_map("ypservers", yppush_domain,
+ "localhost", yppush_foreach);
+ }
+
+ if (verbose > 1)
+ yp_error("all jobs dispatched");
+
+ /* All done -- normal exit. */
+ yppush_exit(0);
+
+ /* Just in case. */
+ exit(0);
+}
OpenPOWER on IntegriCloud