113394Swpaul/*
213394Swpaul * Copyright (c) 1995
313394Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
413394Swpaul *
513394Swpaul * Redistribution and use in source and binary forms, with or without
613394Swpaul * modification, are permitted provided that the following conditions
713394Swpaul * are met:
813394Swpaul * 1. Redistributions of source code must retain the above copyright
913394Swpaul *    notice, this list of conditions and the following disclaimer.
1013394Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1113394Swpaul *    notice, this list of conditions and the following disclaimer in the
1213394Swpaul *    documentation and/or other materials provided with the distribution.
1313394Swpaul * 3. All advertising materials mentioning features or use of this software
1413394Swpaul *    must display the following acknowledgement:
1513394Swpaul *	This product includes software developed by Bill Paul.
1613394Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1713394Swpaul *    may be used to endorse or promote products derived from this software
1813394Swpaul *    without specific prior written permission.
1913394Swpaul *
2013394Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2113394Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213394Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2313394Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2413394Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513394Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613394Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713394Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813394Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913394Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013394Swpaul * SUCH DAMAGE.
3113394Swpaul */
3213394Swpaul
33114601Sobrien#include <sys/cdefs.h>
34114601Sobrien__FBSDID("$FreeBSD$");
3530911Scharnier
3630911Scharnier#include <errno.h>
3730911Scharnier#include <signal.h>
3813394Swpaul#include <stdio.h>
3913394Swpaul#include <stdlib.h>
4013394Swpaul#include <string.h>
41161262Sru#include <strings.h>
4213394Swpaul#include <time.h>
4330911Scharnier#include <unistd.h>
4413394Swpaul#include <sys/socket.h>
4513394Swpaul#include <sys/fcntl.h>
4613394Swpaul#include <sys/wait.h>
4713394Swpaul#include <sys/param.h>
4813394Swpaul#include <rpc/rpc.h>
4913394Swpaul#include <rpc/clnt.h>
5013394Swpaul#include <rpc/pmap_clnt.h>
5113394Swpaul#include <rpcsvc/yp.h>
5213394Swpaul#include <rpcsvc/ypclnt.h>
5313394Swpaul#include "ypxfr_extern.h"
5413394Swpaul#include "yppush_extern.h"
5513394Swpaul
5613394Swpaulchar *progname = "yppush";
5713394Swpaulint debug = 1;
5813394Swpaulint _rpcpmstart = 0;
5913394Swpaulchar *yp_dir = _PATH_YP;
6013394Swpaul
6113394Swpaulchar *yppush_mapname = NULL;	/* Map to transfer. */
6213394Swpaulchar *yppush_domain = NULL;	/* Domain in which map resides. */
6313394Swpaulchar *yppush_master = NULL;	/* Master NIS server for said domain. */
64161262Sruint skip_master = 0;		/* Do not attempt to push map to master. */
6513394Swpaulint verbose = 0;		/* Toggle verbose mode. */
6613394Swpaulunsigned long yppush_transid = 0;
6713394Swpaulint yppush_timeout = 80;	/* Default timeout. */
68161359Sthomasint yppush_jobs = 1;		/* Number of allowed concurrent jobs. */
6913394Swpaulint yppush_running_jobs = 0;	/* Number of currently running jobs. */
7013394Swpaul
7113394Swpaul/* Structure for holding information about a running job. */
7213394Swpaulstruct jobs {
7313394Swpaul	unsigned long tid;
7413394Swpaul	int port;
7513394Swpaul	ypxfrstat stat;
7613394Swpaul	unsigned long prognum;
7713394Swpaul	char *server;
7813394Swpaul	char *map;
7913394Swpaul	int polled;
8013394Swpaul	struct jobs *next;
8113394Swpaul};
8213394Swpaul
8313394Swpaulstruct jobs *yppush_joblist;	/* Linked list of running jobs. */
8413394Swpaul
85161359Sthomasstatic int yppush_svc_run(int);
86161359Sthomas
8713394Swpaul/*
8813394Swpaul * Local error messages.
8913394Swpaul */
9094887Sdesstatic const char *
9190298Sdesyppusherr_string(int err)
9213394Swpaul{
9390297Sdes	switch (err) {
9494887Sdes	case YPPUSH_TIMEDOUT:
9594887Sdes		return("transfer or callback timed out");
9694887Sdes	case YPPUSH_YPSERV:
9794887Sdes		return("failed to contact ypserv");
9894887Sdes	case YPPUSH_NOHOST:
9994887Sdes		return("no such host");
10094887Sdes	case YPPUSH_PMAP:
10194887Sdes		return("portmapper failure");
10294887Sdes	default:
10394887Sdes		return("unknown error code");
10413394Swpaul	}
10513394Swpaul}
10613394Swpaul
10713394Swpaul/*
10813394Swpaul * Report state of a job.
10913394Swpaul */
11090298Sdesstatic int
11190298Sdesyppush_show_status(ypxfrstat status, unsigned long tid)
11213394Swpaul{
11313394Swpaul	struct jobs *job;
11413394Swpaul
11513394Swpaul	job = yppush_joblist;
11613394Swpaul
117161359Sthomas	while (job != NULL) {
11813394Swpaul		if (job->tid == tid)
11913394Swpaul			break;
12013394Swpaul		job = job->next;
12113394Swpaul	}
12213394Swpaul
123161359Sthomas	if (job == NULL) {
124161359Sthomas		yp_error("warning: received callback with invalid transaction ID: %lu",
125161359Sthomas			 tid);
126161359Sthomas		return (0);
127161359Sthomas	}
128161359Sthomas
12913394Swpaul	if (job->polled) {
130161359Sthomas		yp_error("warning: received callback with duplicate transaction ID: %lu",
131161359Sthomas			 tid);
132161359Sthomas		return (0);
13313394Swpaul	}
13413394Swpaul
135161359Sthomas	if (verbose > 1) {
13630911Scharnier		yp_error("checking return status: transaction ID: %lu",
13713394Swpaul								job->tid);
138161359Sthomas	}
139161359Sthomas
14013394Swpaul	if (status != YPPUSH_SUCC || verbose) {
14130911Scharnier		yp_error("transfer of map %s to server %s %s",
14213394Swpaul		 	job->map, job->server, status == YPPUSH_SUCC ?
14313394Swpaul		 	"succeeded" : "failed");
14413394Swpaul		yp_error("status returned by ypxfr: %s", status > YPPUSH_AGE ?
14590297Sdes			yppusherr_string(status) :
14613394Swpaul			ypxfrerr_string(status));
14713394Swpaul	}
14813394Swpaul
14913394Swpaul	job->polled = 1;
15013394Swpaul
15113394Swpaul	svc_unregister(job->prognum, 1);
15290297Sdes
15313394Swpaul	yppush_running_jobs--;
15413394Swpaul	return(0);
15513394Swpaul}
15613394Swpaul
15713394Swpaul/* Exit routine. */
15890298Sdesstatic void
15990298Sdesyppush_exit(int now)
16013394Swpaul{
16113394Swpaul	struct jobs *jptr;
16213799Swpaul	int still_pending = 1;
16313394Swpaul
16413394Swpaul	/* Let all the information trickle in. */
16590297Sdes	while (!now && still_pending) {
16613394Swpaul		jptr = yppush_joblist;
16713394Swpaul		still_pending = 0;
16813394Swpaul		while (jptr) {
16913394Swpaul			if (jptr->polled == 0) {
17013394Swpaul				still_pending++;
17113394Swpaul				if (verbose > 1)
17213394Swpaul					yp_error("%s has not responded",
17313394Swpaul						  jptr->server);
17413394Swpaul			} else {
17513394Swpaul				if (verbose > 1)
17613394Swpaul					yp_error("%s has responded",
17713394Swpaul						  jptr->server);
17813394Swpaul			}
17913394Swpaul			jptr = jptr->next;
18013394Swpaul		}
18113394Swpaul		if (still_pending) {
18213394Swpaul			if (verbose > 1)
18313394Swpaul				yp_error("%d transfer%sstill pending",
18413394Swpaul					still_pending,
18513394Swpaul					still_pending > 1 ? "s " : " ");
186161359Sthomas			if (yppush_svc_run (YPPUSH_RESPONSE_TIMEOUT) == 0) {
18713799Swpaul				yp_error("timed out");
18813799Swpaul				now = 1;
18913799Swpaul			}
19013394Swpaul		} else {
19113394Swpaul			if (verbose)
19213394Swpaul				yp_error("all transfers complete");
19313394Swpaul			break;
19413394Swpaul		}
19513394Swpaul	}
19613394Swpaul
19713394Swpaul
19813394Swpaul	/* All stats collected and reported -- kill all the stragglers. */
19913394Swpaul	jptr = yppush_joblist;
20090297Sdes	while (jptr) {
20113394Swpaul		if (!jptr->polled)
20213394Swpaul			yp_error("warning: exiting with transfer \
20330911Scharnierto %s (transid = %lu) still pending", jptr->server, jptr->tid);
20413394Swpaul		svc_unregister(jptr->prognum, 1);
20513394Swpaul		jptr = jptr->next;
20613394Swpaul	}
20713394Swpaul
20813394Swpaul	exit(0);
20913394Swpaul}
21013394Swpaul
21113394Swpaul/*
21213394Swpaul * Handler for 'normal' signals.
21313394Swpaul */
21413394Swpaul
21590298Sdesstatic void
21690298Sdeshandler(int sig)
21713394Swpaul{
218161359Sthomas	yppush_exit (1);
21913394Swpaul	return;
22013394Swpaul}
22113394Swpaul
22213394Swpaul/*
22313394Swpaul * Dispatch loop for callback RPC services.
224161359Sthomas * Return value:
225161359Sthomas *   -1 error
226161359Sthomas *    0 timeout
227161359Sthomas *   >0 request serviced
22813394Swpaul */
229161359Sthomasstatic int
230161359Sthomasyppush_svc_run(int timeout_secs)
23113394Swpaul{
232161359Sthomas	int rc;
23313394Swpaul	fd_set readfds;
23413394Swpaul	struct timeval timeout;
23513394Swpaul
23613394Swpaul	timeout.tv_usec = 0;
237161359Sthomas	timeout.tv_sec = timeout_secs;
23813394Swpaul
23913394Swpaulretry:
24013394Swpaul	readfds = svc_fdset;
241161359Sthomas	rc = select(svc_maxfd + 1, &readfds, NULL, NULL, &timeout);
242161359Sthomas	switch (rc) {
24313394Swpaul	case -1:
24413394Swpaul		if (errno == EINTR)
24513394Swpaul			goto retry;
24613394Swpaul		yp_error("select failed: %s", strerror(errno));
24713394Swpaul		break;
24813394Swpaul	case 0:
24913394Swpaul		yp_error("select() timed out");
25013394Swpaul		break;
25113394Swpaul	default:
25213394Swpaul		svc_getreqset(&readfds);
25313394Swpaul		break;
25413394Swpaul	}
255161359Sthomas	return rc;
25613394Swpaul}
25713394Swpaul
25813394Swpaul/*
25913799Swpaul * RPC service routines for callbacks.
26013394Swpaul */
26113394Swpaulvoid *
26213394Swpaulyppushproc_null_1_svc(void *argp, struct svc_req *rqstp)
26313394Swpaul{
26413394Swpaul	static char * result;
26513394Swpaul	/* Do nothing -- RPC conventions call for all a null proc. */
26613394Swpaul	return((void *) &result);
26713394Swpaul}
26813394Swpaul
26913394Swpaulvoid *
27013394Swpaulyppushproc_xfrresp_1_svc(yppushresp_xfr *argp, struct svc_req *rqstp)
27113394Swpaul{
27213394Swpaul	static char * result;
27313394Swpaul	yppush_show_status(argp->status, argp->transid);
27413394Swpaul	return((void *) &result);
27513394Swpaul}
27613394Swpaul
27713394Swpaul/*
27813394Swpaul * Transmit a YPPROC_XFR request to ypserv.
27990297Sdes */
28090298Sdesstatic int
28190298Sdesyppush_send_xfr(struct jobs *job)
28213394Swpaul{
28313394Swpaul	ypreq_xfr req;
28413394Swpaul/*	ypresp_xfr *resp; */
28513394Swpaul	DBT key, data;
28613394Swpaul	CLIENT *clnt;
28713394Swpaul	struct rpc_err err;
28813394Swpaul	struct timeval timeout;
28913394Swpaul
29013394Swpaul	timeout.tv_usec = 0;
29113394Swpaul	timeout.tv_sec = 0;
29213394Swpaul
29313394Swpaul	/*
29413394Swpaul	 * The ypreq_xfr structure has a member of type map_parms,
29513394Swpaul	 * which seems to require the order number of the map.
29613394Swpaul	 * It isn't actually used at the other end (at least the
29713394Swpaul	 * FreeBSD ypserv doesn't use it) but we fill it in here
29813394Swpaul	 * for the sake of completeness.
29913394Swpaul	 */
30013394Swpaul	key.data = "YP_LAST_MODIFIED";
30113394Swpaul	key.size = sizeof ("YP_LAST_MODIFIED") - 1;
30213394Swpaul
30313394Swpaul	if (yp_get_record(yppush_domain, yppush_mapname, &key, &data,
30413394Swpaul			  1) != YP_TRUE) {
30513394Swpaul		yp_error("failed to read order number from %s: %s: %s",
30613394Swpaul			  yppush_mapname, yperr_string(yp_errno),
30713394Swpaul			  strerror(errno));
30813394Swpaul		return(1);
30913394Swpaul	}
31013394Swpaul
31113394Swpaul	/* Fill in the request arguments */
31213394Swpaul	req.map_parms.ordernum = atoi(data.data);
31313394Swpaul	req.map_parms.domain = yppush_domain;
31413394Swpaul	req.map_parms.peer = yppush_master;
31513394Swpaul	req.map_parms.map = job->map;
31613394Swpaul	req.transid = job->tid;
31713394Swpaul	req.prog = job->prognum;
31813394Swpaul	req.port = job->port;
31913394Swpaul
32013394Swpaul	/* Get a handle to the remote ypserv. */
32113394Swpaul	if ((clnt = clnt_create(job->server, YPPROG, YPVERS, "udp")) == NULL) {
32213394Swpaul		yp_error("%s: %s",job->server,clnt_spcreateerror("couldn't \
32313394Swpaulcreate udp handle to NIS server"));
32490297Sdes		switch (rpc_createerr.cf_stat) {
32513394Swpaul			case RPC_UNKNOWNHOST:
32613394Swpaul				job->stat = YPPUSH_NOHOST;
32713394Swpaul				break;
32813394Swpaul			case RPC_PMAPFAILURE:
32913394Swpaul				job->stat = YPPUSH_PMAP;
33013394Swpaul				break;
33113394Swpaul			default:
33213394Swpaul				job->stat = YPPUSH_RPC;
33313394Swpaul				break;
33413394Swpaul			}
33513394Swpaul		return(1);
33613394Swpaul	}
33713394Swpaul
33813394Swpaul	/*
33913394Swpaul	 * Reduce timeout to nothing since we may not
34013394Swpaul	 * get a response from ypserv and we don't want to block.
34113394Swpaul	 */
34213394Swpaul	if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE)
34313394Swpaul		yp_error("failed to set timeout on ypproc_xfr call");
34413394Swpaul
34513394Swpaul	/* Invoke the ypproc_xfr service. */
34613394Swpaul	if (ypproc_xfr_2(&req, clnt) == NULL) {
34713394Swpaul		clnt_geterr(clnt, &err);
34813394Swpaul		if (err.re_status != RPC_SUCCESS &&
34913394Swpaul		    err.re_status != RPC_TIMEDOUT) {
35013394Swpaul			yp_error("%s: %s", job->server, clnt_sperror(clnt,
35113394Swpaul							"yp_xfr failed"));
35213394Swpaul			job->stat = YPPUSH_YPSERV;
35313394Swpaul			clnt_destroy(clnt);
35413394Swpaul			return(1);
35513394Swpaul		}
35613394Swpaul	}
35713394Swpaul
35813394Swpaul	clnt_destroy(clnt);
35913394Swpaul
36013394Swpaul	return(0);
36113394Swpaul}
36213394Swpaul
36313394Swpaul/*
36413394Swpaul * Main driver function. Register the callback service, add the transfer
36513394Swpaul * request to the internal list, send the YPPROC_XFR request to ypserv
36613394Swpaul * do other magic things.
36713394Swpaul */
36890298Sdesint
36990298Sdesyp_push(char *server, char *map, unsigned long tid)
37013394Swpaul{
37113394Swpaul	unsigned long prognum;
37213394Swpaul	int sock = RPC_ANYSOCK;
37313394Swpaul	SVCXPRT *xprt;
37413394Swpaul	struct jobs *job;
37513394Swpaul
376161359Sthomas	/* Register the job in our linked list of jobs. */
377161359Sthomas
378161359Sthomas	/* First allocate job structure */
379161359Sthomas	if ((job = (struct jobs *)malloc(sizeof (struct jobs))) == NULL) {
380161359Sthomas		yp_error("malloc failed");
381161359Sthomas		yppush_exit (1);
382161359Sthomas	}
383161359Sthomas
38413394Swpaul	/*
385161359Sthomas	 * Register the callback service on the first free transient
386161359Sthomas	 * program number.
38713394Swpaul	 */
38813394Swpaul	xprt = svcudp_create(sock);
38915443Swpaul	for (prognum = 0x40000000; prognum < 0x5FFFFFFF; prognum++) {
39013394Swpaul		if (svc_register(xprt, prognum, 1,
39113394Swpaul		    yppush_xfrrespprog_1, IPPROTO_UDP) == TRUE)
39213394Swpaul			break;
39313394Swpaul	}
394161359Sthomas	if (prognum == 0x5FFFFFFF) {
395161359Sthomas		yp_error ("can't register yppush_xfrrespprog_1");
396161359Sthomas		yppush_exit (1);
39713394Swpaul	}
39813394Swpaul
39913394Swpaul	/* Initialize the info for this job. */
40013394Swpaul	job->stat = 0;
40113394Swpaul	job->tid = tid;
40213394Swpaul	job->port = xprt->xp_port;
40313394Swpaul	job->server = strdup(server);
40413394Swpaul	job->map = strdup(map);
40513394Swpaul	job->prognum = prognum;
40613394Swpaul	job->polled = 0;
40713394Swpaul	job->next = yppush_joblist;
40813394Swpaul	yppush_joblist = job;
40913394Swpaul
41013394Swpaul	if (verbose) {
41113394Swpaul		yp_error("initiating transfer: %s -> %s (transid = %lu)",
41213394Swpaul			yppush_mapname, server, tid);
41313394Swpaul	}
41413394Swpaul
41513394Swpaul	/*
41613394Swpaul	 * Send the XFR request to ypserv. We don't have to wait for
417161359Sthomas	 * a response here since we handle them asynchronously.
41813394Swpaul	 */
41913394Swpaul
42013394Swpaul	if (yppush_send_xfr(job)){
42113394Swpaul		/* Transfer request blew up. */
42213394Swpaul		yppush_show_status(job->stat ? job->stat :
42313394Swpaul			YPPUSH_YPSERV,job->tid);
42413394Swpaul	} else {
42513394Swpaul		if (verbose > 1)
42613394Swpaul			yp_error("%s has been called", server);
42713394Swpaul	}
42813394Swpaul
42913394Swpaul	return(0);
43013394Swpaul}
43113394Swpaul
43213394Swpaul/*
43313394Swpaul * Called for each entry in the ypservers map from yp_get_map(), which
43413394Swpaul * is our private yp_all() routine.
43513394Swpaul */
43690298Sdesint
43790298Sdesyppush_foreach(int status, char *key, int keylen, char *val, int vallen,
43890298Sdes    char *data)
43913394Swpaul{
44013394Swpaul	char server[YPMAXRECORD + 2];
44113394Swpaul
44213394Swpaul	if (status != YP_TRUE)
44313394Swpaul		return (status);
44413394Swpaul
44513394Swpaul	snprintf(server, sizeof(server), "%.*s", vallen, val);
446161262Sru	if (skip_master && strcasecmp(server, yppush_master) == 0)
447161262Sru		return (0);
44813394Swpaul
44913394Swpaul	/*
450161359Sthomas	 * Restrict the number of concurrent jobs: if yppush_jobs number
45113394Swpaul	 * of jobs have already been dispatched and are still pending,
45213394Swpaul	 * wait for one of them to finish so we can reuse its slot.
45313394Swpaul	 */
454161359Sthomas	while (yppush_running_jobs >= yppush_jobs && (yppush_svc_run (yppush_timeout) > 0))
455161359Sthomas		;
45613394Swpaul
45713394Swpaul	/* Cleared for takeoff: set everything in motion. */
45895658Sdes	if (yp_push(server, yppush_mapname, yppush_transid))
45913394Swpaul		return(yp_errno);
46013394Swpaul
46113394Swpaul	/* Bump the job counter and transaction ID. */
46213394Swpaul	yppush_running_jobs++;
46313394Swpaul	yppush_transid++;
46413394Swpaul	return (0);
46513394Swpaul}
46613394Swpaul
46713394Swpaulstatic void usage()
46813394Swpaul{
46930911Scharnier	fprintf (stderr, "%s\n%s\n",
47030911Scharnier	"usage: yppush [-d domain] [-t timeout] [-j #parallel jobs] [-h host]",
47130911Scharnier	"              [-p path] mapname");
47213394Swpaul	exit(1);
47313394Swpaul}
47413394Swpaul
47513394Swpaul/*
47613394Swpaul * Entry point. (About time!)
47713394Swpaul */
47830911Scharnierint
47990298Sdesmain(int argc, char *argv[])
48013394Swpaul{
48113394Swpaul	int ch;
48213394Swpaul	DBT key, data;
48313394Swpaul	char myname[MAXHOSTNAMELEN];
48413394Swpaul	struct hostlist {
48513394Swpaul		char *name;
48613394Swpaul		struct hostlist *next;
48713394Swpaul	};
48813394Swpaul	struct hostlist *yppush_hostlist = NULL;
48913394Swpaul	struct hostlist *tmp;
49013394Swpaul
49124428Simp	while ((ch = getopt(argc, argv, "d:j:p:h:t:v")) != -1) {
49290297Sdes		switch (ch) {
49313394Swpaul		case 'd':
49413394Swpaul			yppush_domain = optarg;
49513394Swpaul			break;
49613394Swpaul		case 'j':
49713394Swpaul			yppush_jobs = atoi(optarg);
49813394Swpaul			if (yppush_jobs <= 0)
49913394Swpaul				yppush_jobs = 1;
50013394Swpaul			break;
50113394Swpaul		case 'p':
50213394Swpaul			yp_dir = optarg;
50313394Swpaul			break;
50413394Swpaul		case 'h': /* we can handle multiple hosts */
50513394Swpaul			if ((tmp = (struct hostlist *)malloc(sizeof(struct hostlist))) == NULL) {
50630911Scharnier				yp_error("malloc failed");
50713394Swpaul				yppush_exit(1);
50813394Swpaul			}
50913394Swpaul			tmp->name = strdup(optarg);
51013394Swpaul			tmp->next = yppush_hostlist;
51113394Swpaul			yppush_hostlist = tmp;
51213394Swpaul			break;
51313394Swpaul		case 't':
51413394Swpaul			yppush_timeout = atoi(optarg);
51513394Swpaul			break;
51613394Swpaul		case 'v':
51713394Swpaul			verbose++;
51813394Swpaul			break;
51913394Swpaul		default:
52013394Swpaul			usage();
52113394Swpaul			break;
52213394Swpaul		}
52313394Swpaul	}
52413394Swpaul
52513394Swpaul	argc -= optind;
52613394Swpaul	argv += optind;
52713394Swpaul
52813394Swpaul	yppush_mapname = argv[0];
52913394Swpaul
53013394Swpaul	if (yppush_mapname == NULL) {
53113394Swpaul	/* "No guts, no glory." */
53213394Swpaul		usage();
53313394Swpaul	}
53413394Swpaul
53513394Swpaul	/*
53613394Swpaul	 * If no domain was specified, try to find the default
53713394Swpaul	 * domain. If we can't find that, we're doomed and must bail.
53813394Swpaul	 */
53913394Swpaul	if (yppush_domain == NULL) {
54013394Swpaul		char *yppush_check_domain;
54113394Swpaul		if (!yp_get_default_domain(&yppush_check_domain) &&
54213394Swpaul			!_yp_check(&yppush_check_domain)) {
54313394Swpaul			yp_error("no domain specified and NIS not running");
54413394Swpaul			usage();
54513394Swpaul		} else
54613394Swpaul			yp_get_default_domain(&yppush_domain);
54713394Swpaul	}
54813394Swpaul
54913394Swpaul	/* Check to see that we are the master for this map. */
55013394Swpaul
55113394Swpaul	if (gethostname ((char *)&myname, sizeof(myname))) {
55213394Swpaul		yp_error("failed to get name of local host: %s",
55313394Swpaul			strerror(errno));
55413394Swpaul		yppush_exit(1);
55513394Swpaul	}
55613394Swpaul
55713394Swpaul	key.data = "YP_MASTER_NAME";
55813394Swpaul	key.size = sizeof("YP_MASTER_NAME") - 1;
55913394Swpaul
56013394Swpaul	if (yp_get_record(yppush_domain, yppush_mapname,
56113394Swpaul			  &key, &data, 1) != YP_TRUE) {
56213394Swpaul		yp_error("couldn't open %s map: %s", yppush_mapname,
56313394Swpaul			 strerror(errno));
56413394Swpaul		yppush_exit(1);
56513394Swpaul	}
56613394Swpaul
567161262Sru	if (strncasecmp(myname, data.data, data.size) == 0) {
568161262Sru		/* I am master server, and no explicit host list was
569161262Sru		   specified: do not push map to myself -- this will
570161262Sru		   fail with YPPUSH_AGE anyway. */
571161262Sru		if (yppush_hostlist == NULL)
572161262Sru			skip_master = 1;
573161262Sru	} else {
57415016Swpaul		yp_error("warning: this host is not the master for %s",
57515016Swpaul							yppush_mapname);
57615016Swpaul#ifdef NITPICKY
57713394Swpaul		yppush_exit(1);
57815016Swpaul#endif
57913394Swpaul	}
58013394Swpaul
58116242Speter	yppush_master = malloc(data.size + 1);
58216242Speter	strncpy(yppush_master, data.data, data.size);
58313394Swpaul	yppush_master[data.size] = '\0';
58413394Swpaul
58513394Swpaul	/* Install some handy handlers. */
58613394Swpaul	signal(SIGTERM, handler);
58713394Swpaul	signal(SIGINT, handler);
58813394Swpaul
58913394Swpaul	/* set initial transaction ID */
59037269Sbde	yppush_transid = time((time_t *)NULL);
59113394Swpaul
59213394Swpaul	if (yppush_hostlist) {
59313394Swpaul	/*
59413394Swpaul	 * Host list was specified on the command line:
59513394Swpaul	 * kick off the transfers by hand.
59613394Swpaul	 */
59713394Swpaul		tmp = yppush_hostlist;
59890297Sdes		while (tmp) {
59913394Swpaul			yppush_foreach(YP_TRUE, NULL, 0, tmp->name,
60090298Sdes			    strlen(tmp->name), NULL);
60113394Swpaul			tmp = tmp->next;
60213394Swpaul		}
60313394Swpaul	} else {
60413394Swpaul	/*
60513394Swpaul	 * Do a yp_all() on the ypservers map and initiate a ypxfr
60613394Swpaul	 * for each one.
60713394Swpaul	 */
60813394Swpaul		ypxfr_get_map("ypservers", yppush_domain,
60913394Swpaul			      "localhost", yppush_foreach);
61013394Swpaul	}
61113394Swpaul
61213394Swpaul	if (verbose > 1)
61313394Swpaul		yp_error("all jobs dispatched");
61413394Swpaul
61513394Swpaul	/* All done -- normal exit. */
61613394Swpaul	yppush_exit(0);
61713394Swpaul
61813394Swpaul	/* Just in case. */
61913394Swpaul	exit(0);
62013394Swpaul}
621