diff options
Diffstat (limited to 'usr.sbin/yppush')
| -rw-r--r-- | usr.sbin/yppush/Makefile | 28 | ||||
| -rw-r--r-- | usr.sbin/yppush/Makefile.depend | 17 | ||||
| -rw-r--r-- | usr.sbin/yppush/yppush.8 | 178 | ||||
| -rw-r--r-- | usr.sbin/yppush/yppush_extern.h | 42 | ||||
| -rw-r--r-- | usr.sbin/yppush/yppush_main.c | 633 |
5 files changed, 898 insertions, 0 deletions
diff --git a/usr.sbin/yppush/Makefile b/usr.sbin/yppush/Makefile new file mode 100644 index 000000000000..c849d5e08a6b --- /dev/null +++ b/usr.sbin/yppush/Makefile @@ -0,0 +1,28 @@ +RPCDIR= ${SRCTOP}/include/rpcsvc +.PATH: ${RPCDIR} ${SRCTOP}/usr.sbin/ypserv ${SRCTOP}/libexec/ypxfr + +PACKAGE= yp +PROG= yppush +MAN= yppush.8 +SRCS= ypxfr_getmap.c yp_dblookup.c yp_error.c ypxfr_misc.c yppush_main.c \ + ${GENSRCS} +GENSRCS=yp.h yp_clnt.c yppush_svc.c + +CFLAGS+= -I. -I${SRCTOP}/libexec/ypxfr + +WARNS?= 2 + +RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -C + +CLEANFILES= ${GENSRCS} + +yppush_svc.c: yp.x + ${RPCGEN} -DYPPUSH_ONLY -m -o ${.TARGET} ${RPCDIR}/yp.x + +yp_clnt.c: yp.x + ${RPCGEN} -DYPSERV_ONLY -l -o ${.TARGET} ${RPCDIR}/yp.x + +yp.h: yp.x + ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/yp.x + +.include <bsd.prog.mk> diff --git a/usr.sbin/yppush/Makefile.depend b/usr.sbin/yppush/Makefile.depend new file mode 100644 index 000000000000..a2d89550fa2b --- /dev/null +++ b/usr.sbin/yppush/Makefile.depend @@ -0,0 +1,17 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/rpc \ + include/rpcsvc \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/yppush/yppush.8 b/usr.sbin/yppush/yppush.8 new file mode 100644 index 000000000000..e3c91188c40c --- /dev/null +++ b/usr.sbin/yppush/yppush.8 @@ -0,0 +1,178 @@ +.\" 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. 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. +.\" +.Dd February 5, 1995 +.Dt YPPUSH 8 +.Os +.Sh NAME +.Nm yppush +.Nd "force propagation of updated NIS databases" +.Sh SYNOPSIS +.Nm +.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 +The +.Nm +utility 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 +by default: the +.Dq Li NOPUSH=True +entry in the Makefile must first be commented out +(the default +.Fx +configuration assumes a small network with only +a single NIS server; in such a configuration, +.Nm +is not needed). +.Pp +By default, +.Nm +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 +and carry out the transfer. +Any error messages +.Nm +receives from +.Xr ypxfr 8 +via callback will be printed to stderr. +.Pp +The following options are available: +.Bl -tag -width indent +.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 +Specify a timeout value in seconds. +This timeout +controls how long +.Nm +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 +The +.Nm +utility 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 +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 +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 +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 +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 +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: it causes +.Nm +to print debugging messages as it runs. +Specifying this flag twice +makes +.Nm +even more verbose. +.El +.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 yp 8 , +.Xr ypserv 8 , +.Xr ypxfr 8 +.Sh AUTHORS +.An Bill Paul Aq Mt wpaul@ctr.columbia.edu +.Sh BUGS +The mechanism for transferring NIS maps in NIS v1 is different +than that in NIS version 2. +This version of +.Nm +has support for transferring maps to NIS v2 systems only. diff --git a/usr.sbin/yppush/yppush_extern.h b/usr.sbin/yppush/yppush_extern.h new file mode 100644 index 000000000000..9220f0de05a8 --- /dev/null +++ b/usr.sbin/yppush/yppush_extern.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/* 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(void); +extern void yppush_xfrrespprog_1(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 000000000000..2b167846d1b6 --- /dev/null +++ b/usr.sbin/yppush/yppush_main.c @@ -0,0 +1,633 @@ +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * 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. + */ + +#include <sys/cdefs.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <time.h> +#include <unistd.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> +#include <rpcsvc/ypclnt.h> +#include "ypxfr_extern.h" +#include "yppush_extern.h" + +char *progname = "yppush"; +int debug = 1; +int _rpcpmstart = 0; +char *yp_dir = _PATH_YP; + +static char *yppush_mapname = NULL; /* Map to transfer. */ +static char *yppush_domain = NULL; /* Domain in which map resides. */ +static char *yppush_master = NULL; /* Master NIS server for said domain. */ +static int skip_master = 0; /* Do not attempt to push map to master. */ +static int verbose = 0; /* Toggle verbose mode. */ +static unsigned long yppush_transid = 0; +static int yppush_timeout = 80; /* Default timeout. */ +static int yppush_jobs = 1; /* Number of allowed concurrent jobs. */ +static int yppush_running_jobs = 0; /* Number of currently running jobs. */ + +/* Structure for holding information about a running job. */ +struct jobs { + unsigned long tid; + int port; + ypxfrstat stat; + unsigned long prognum; + char *server; + char *map; + int polled; + struct jobs *next; +}; + +static struct jobs *yppush_joblist; /* Linked list of running jobs. */ +static int yppush_svc_run(int); + +/* + * Local error messages. + */ +static const char * +yppusherr_string(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(ypxfrstat status, unsigned long tid) +{ + struct jobs *job; + + job = yppush_joblist; + + while (job != NULL) { + if (job->tid == tid) + break; + job = job->next; + } + + if (job == NULL) { + yp_error("warning: received callback with invalid transaction ID: %lu", + tid); + return (0); + } + + if (job->polled) { + yp_error("warning: received callback with duplicate transaction ID: %lu", + tid); + return (0); + } + + if (verbose > 1) { + yp_error("checking return status: transaction ID: %lu", + job->tid); + } + + if (status != YPXFR_SUCC || verbose) { + yp_error("transfer of map %s to server %s %s", + job->map, job->server, status == YPXFR_SUCC ? + "succeeded" : "failed"); + yp_error("status returned by ypxfr: %s", status > YPXFR_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(int now) +{ + struct jobs *jptr; + int still_pending = 1; + + /* Let all the information trickle in. */ + while (!now && still_pending) { + 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 " : " "); + if (yppush_svc_run (YPPUSH_RESPONSE_TIMEOUT) == 0) { + yp_error("timed out"); + now = 1; + } + } 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(int sig) +{ + yppush_exit (1); +} + +/* + * Dispatch loop for callback RPC services. + * Return value: + * -1 error + * 0 timeout + * >0 request serviced + */ +static int +yppush_svc_run(int timeout_secs) +{ + int rc; + fd_set readfds; + struct timeval timeout; + + timeout.tv_usec = 0; + timeout.tv_sec = timeout_secs; + +retry: + readfds = svc_fdset; + rc = select(svc_maxfd + 1, &readfds, NULL, NULL, &timeout); + switch (rc) { + 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 rc; +} + +/* + * RPC service routines for callbacks. + */ +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(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. + */ +static int +yp_push(char *server, char *map, unsigned long tid) +{ + unsigned long prognum; + int sock = RPC_ANYSOCK; + SVCXPRT *xprt; + struct jobs *job; + + /* Register the job in our linked list of jobs. */ + + /* First allocate job structure */ + if ((job = (struct jobs *)malloc(sizeof (struct jobs))) == NULL) { + yp_error("malloc failed"); + yppush_exit (1); + } + + /* + * Register the callback service on the first free transient + * program number. + */ + xprt = svcudp_create(sock); + for (prognum = 0x40000000; prognum < 0x5FFFFFFF; prognum++) { + if (svc_register(xprt, prognum, 1, + yppush_xfrrespprog_1, IPPROTO_UDP) == TRUE) + break; + } + if (prognum == 0x5FFFFFFF) { + yp_error ("can't register yppush_xfrrespprog_1"); + yppush_exit (1); + } + + /* Initialize the info for this job. */ + job->stat = 0; + job->tid = tid; + job->port = xprt->xp_port; + job->server = strdup(server); + job->map = strdup(map); + job->prognum = prognum; + job->polled = 0; + job->next = yppush_joblist; + yppush_joblist = job; + + 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 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. + */ +static int +yppush_foreach(int status, char *key, int keylen, char *val, int vallen, + char *data) +{ + char *server; + + if (status != YP_TRUE) + return (status); + + asprintf(&server, "%.*s", vallen, val); + + /* + * Do not stop the iteration on the allocation failure. We + * cannot usefully react on low memory condition anyway, and + * the failure is more likely due to insane val. + */ + if (server == NULL) + return (0); + + if (skip_master && strcasecmp(server, yppush_master) == 0) { + free(server); + return (0); + } + + /* + * 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. + */ + while (yppush_running_jobs >= yppush_jobs && (yppush_svc_run (yppush_timeout) > 0)) + ; + + /* Cleared for takeoff: set everything in motion. */ + if (yp_push(server, yppush_mapname, yppush_transid)) { + free(server); + return(yp_errno); + } + + /* Bump the job counter and transaction ID. */ + yppush_running_jobs++; + yppush_transid++; + free(server); + return (0); +} + +static void +usage() +{ + fprintf (stderr, "%s\n%s\n", + "usage: yppush [-d domain] [-t timeout] [-j #parallel jobs] [-h host]", + " [-p path] mapname"); + exit(1); +} + +/* + * Entry point. (About time!) + */ +int +main(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; + + while ((ch = getopt(argc, argv, "d:j:p:h:t:v")) != -1) { + 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"); + 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 (strncasecmp(myname, data.data, data.size) == 0) { + /* I am master server, and no explicit host list was + specified: do not push map to myself -- this will + fail with YPPUSH_AGE anyway. */ + if (yppush_hostlist == NULL) + skip_master = 1; + } else { + yp_error("warning: this host is not the master for %s", + yppush_mapname); +#ifdef NITPICKY + yppush_exit(1); +#endif + } + + yppush_master = malloc(data.size + 1); + strncpy(yppush_master, data.data, data.size); + yppush_master[data.size] = '\0'; + + /* Install some handy handlers. */ + signal(SIGTERM, handler); + signal(SIGINT, handler); + + /* set initial transaction ID */ + yppush_transid = time((time_t *)NULL); + + 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), NULL); + 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); +} |
