diff options
author | wpaul <wpaul@FreeBSD.org> | 1996-01-12 07:03:33 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1996-01-12 07:03:33 +0000 |
commit | 226cb5fee95f97eebee115381c5d7c4800d544c8 (patch) | |
tree | 20b92da117675d48f09a3b446b0d992a76bb5a30 /usr.sbin/yppush | |
parent | 48229bd2a16f4f312353e0d1061659a4082ac85d (diff) | |
parent | 57e5d5b64973afaf302bb895f9b39c3bd058ede1 (diff) | |
download | FreeBSD-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/Makefile | 26 | ||||
-rw-r--r-- | usr.sbin/yppush/yppush.8 | 172 | ||||
-rw-r--r-- | usr.sbin/yppush/yppush_extern.h | 44 | ||||
-rw-r--r-- | usr.sbin/yppush/yppush_main.c | 683 |
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); +} |