ypxfr_main.c revision 16132
113007Swpaul/*
213007Swpaul * Copyright (c) 1995
313007Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
413007Swpaul *
513007Swpaul * Redistribution and use in source and binary forms, with or without
613007Swpaul * modification, are permitted provided that the following conditions
713007Swpaul * are met:
813007Swpaul * 1. Redistributions of source code must retain the above copyright
913007Swpaul *    notice, this list of conditions and the following disclaimer.
1013007Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1113007Swpaul *    notice, this list of conditions and the following disclaimer in the
1213007Swpaul *    documentation and/or other materials provided with the distribution.
1313007Swpaul * 3. All advertising materials mentioning features or use of this software
1413007Swpaul *    must display the following acknowledgement:
1513007Swpaul *	This product includes software developed by Bill Paul.
1613007Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1713007Swpaul *    may be used to endorse or promote products derived from this software
1813007Swpaul *    without specific prior written permission.
1913007Swpaul *
2013007Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2113007Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213007Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2313007Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2413007Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513007Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613007Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713007Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813007Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913007Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013007Swpaul * SUCH DAMAGE.
3113007Swpaul *
3216132Swpaul *	$Id: ypxfr_main.c,v 1.17 1996/06/03 03:11:39 wpaul Exp $
3313007Swpaul */
3413007Swpaul#include <stdio.h>
3513007Swpaul#include <stdlib.h>
3613007Swpaul#include <unistd.h>
3713007Swpaul#include <string.h>
3813007Swpaul#include <syslog.h>
3913007Swpaul#include <errno.h>
4013007Swpaul#include <sys/types.h>
4113007Swpaul#include <sys/param.h>
4213007Swpaul#include <sys/socket.h>
4313007Swpaul#include <netinet/in.h>
4413007Swpaul#include <arpa/inet.h>
4513007Swpaul#include <rpc/rpc.h>
4613376Swpaul#include <rpc/clnt.h>
4713007Swpaul#include <rpcsvc/yp.h>
4813007Swpaulstruct dom_binding {};
4913007Swpaul#include <rpcsvc/ypclnt.h>
5016132Swpaul#include <rpcsvc/ypxfrd.h>
5113007Swpaul#include "ypxfr_extern.h"
5213007Swpaul
5313007Swpaul#ifndef lint
5416132Swpaulstatic const char rcsid[] = "$Id: ypxfr_main.c,v 1.17 1996/06/03 03:11:39 wpaul Exp $";
5513007Swpaul#endif
5613007Swpaul
5713007Swpaulchar *progname = "ypxfr";
5813007Swpaulchar *yp_dir = _PATH_YP;
5913007Swpaulint _rpcpmstart = 0;
6013007Swpaulint ypxfr_use_yplib = 0; /* Assume the worst. */
6113007Swpaulint ypxfr_clear = 1;
6213007Swpaulint ypxfr_prognum = 0;
6313007Swpaulstruct sockaddr_in ypxfr_callback_addr;
6413007Swpaulstruct yppushresp_xfr ypxfr_resp;
6513007SwpaulDB *dbp;
6613007Swpaul
6713007Swpaulstatic void ypxfr_exit(retval, temp)
6813007Swpaul	ypxfrstat retval;
6913007Swpaul	char *temp;
7013007Swpaul{
7113007Swpaul	CLIENT *clnt;
7213007Swpaul	int sock = RPC_ANYSOCK;
7313007Swpaul	struct timeval timeout;
7413007Swpaul
7513007Swpaul	/* Clean up no matter what happened previously. */
7613007Swpaul	if (temp != NULL) {
7713276Swpaul		if (dbp != NULL)
7813276Swpaul			(void)(dbp->close)(dbp);
7913007Swpaul		if (unlink(temp) == -1) {
8013007Swpaul			yp_error("failed to unlink %s",strerror(errno));
8113007Swpaul		}
8213007Swpaul	}
8313007Swpaul
8413007Swpaul	if (_rpcpmstart) {
8513007Swpaul		timeout.tv_sec = 20;
8613007Swpaul		timeout.tv_usec = 0;
8713007Swpaul
8813007Swpaul		if ((clnt = clntudp_create(&ypxfr_callback_addr, ypxfr_prognum,
8913007Swpaul					1, timeout, &sock)) == NULL) {
9016132Swpaul			yp_error("%s", clnt_spcreateerror("failed to \
9116132Swpaulestablish callback handle"));
9213007Swpaul			exit(1);
9313007Swpaul		}
9413007Swpaul
9513007Swpaul		ypxfr_resp.status = retval;
9613007Swpaul
9713007Swpaul		if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
9813007Swpaul			yp_error("%s", clnt_sperror(clnt, "callback failed"));
9913007Swpaul			clnt_destroy(clnt);
10013007Swpaul			exit(1);
10113007Swpaul		}
10213007Swpaul		clnt_destroy(clnt);
10313007Swpaul	} else {
10413007Swpaul		yp_error("Exiting: %s", ypxfrerr_string(retval));
10513007Swpaul	}
10613007Swpaul
10713007Swpaul	exit(0);
10813007Swpaul}
10913007Swpaul
11013007Swpaulstatic void usage()
11113007Swpaul{
11213007Swpaul	if (_rpcpmstart) {
11313007Swpaul		ypxfr_exit(YPXFR_BADARGS,NULL);
11413007Swpaul	} else {
11513007Swpaul		fprintf(stderr,"usage: %s [-f] [-c] [-d target domain] \
11613007Swpaul[-h source host] [-s source domain]\n", progname);
11713007Swpaul		fprintf(stderr,"\t     [-p path] [-C taskid program-number \
11813007Swpaulipaddr port] mapname\n");
11913007Swpaul		exit(1);
12013007Swpaul	}
12113007Swpaul}
12213007Swpaul
12313007Swpaulint ypxfr_foreach(status, key, keylen, val, vallen, data)
12413007Swpaul	int status;
12513007Swpaul	char *key;
12613007Swpaul	int keylen;
12713007Swpaul	char *val;
12813007Swpaul	int vallen;
12913007Swpaul	char *data;
13013007Swpaul{
13113007Swpaul	DBT dbkey, dbval;
13213007Swpaul
13313007Swpaul	if (status != YP_TRUE)
13413007Swpaul		return (status);
13513007Swpaul
13613007Swpaul	dbkey.data = key;
13713007Swpaul	dbkey.size = keylen;
13813007Swpaul	dbval.data = val;
13913007Swpaul	dbval.size = vallen;
14013007Swpaul
14116132Swpaul	if (yp_put_record(dbp, &dbkey, &dbval, 0) != YP_TRUE)
14213007Swpaul		return(yp_errno);
14313007Swpaul
14413007Swpaul	return (0);
14513007Swpaul}
14613007Swpaul
14713007Swpaulmain(argc,argv)
14813007Swpaul	int argc;
14913007Swpaul	char *argv[];
15013007Swpaul{
15113007Swpaul	int ch;
15213007Swpaul	int ypxfr_force = 0;
15313007Swpaul	char *ypxfr_dest_domain = NULL;
15413007Swpaul	char *ypxfr_source_host = NULL;
15513007Swpaul	char *ypxfr_source_domain = NULL;
15613007Swpaul	char *ypxfr_local_domain = NULL;
15713007Swpaul	char *ypxfr_master = NULL;
15813007Swpaul	unsigned long ypxfr_order = -1, ypxfr_skew_check = -1;
15913007Swpaul	char *ypxfr_mapname = NULL;
16013007Swpaul	int ypxfr_args = 0;
16113007Swpaul	char ypxfr_temp_map[MAXPATHLEN + 2];
16213007Swpaul	char tempmap[MAXPATHLEN + 2];
16313007Swpaul	char buf[MAXPATHLEN + 2];
16413007Swpaul	DBT key, data;
16513007Swpaul
16613007Swpaul	debug = 1;
16713007Swpaul
16813007Swpaul	if (!isatty(fileno(stderr))) {
16913007Swpaul		openlog(progname, LOG_PID, LOG_DAEMON);
17013007Swpaul		_rpcpmstart = 1;
17113007Swpaul	}
17213007Swpaul
17313007Swpaul	if (argc < 2)
17413007Swpaul		usage();
17513007Swpaul
17613007Swpaul	while ((ch = getopt(argc, argv, "fcd:h:s:p:C:")) != EOF) {
17713007Swpaul		int my_optind;
17813007Swpaul		switch(ch) {
17913007Swpaul		case 'f':
18013007Swpaul			ypxfr_force++;
18113007Swpaul			ypxfr_args++;
18213007Swpaul			break;
18313007Swpaul		case 'c':
18413007Swpaul			ypxfr_clear = 0;
18513007Swpaul			ypxfr_args++;
18613007Swpaul			break;
18713007Swpaul		case 'd':
18813007Swpaul			ypxfr_dest_domain = optarg;
18913007Swpaul			ypxfr_args += 2;
19013007Swpaul			break;
19113007Swpaul		case 'h':
19213007Swpaul			ypxfr_source_host = optarg;
19313007Swpaul			ypxfr_args += 2;
19413007Swpaul			break;
19513007Swpaul		case 's':
19613007Swpaul			ypxfr_source_domain = optarg;
19713007Swpaul			ypxfr_args += 2;
19813007Swpaul			break;
19913007Swpaul		case 'p':
20013007Swpaul			yp_dir = optarg;
20113007Swpaul			ypxfr_args += 2;
20213007Swpaul			break;
20313007Swpaul		case 'C':
20413007Swpaul			/*
20513007Swpaul			 * Whoever decided that the -C flag should take
20613007Swpaul			 * four arguments is a twit.
20713007Swpaul			 */
20813007Swpaul			my_optind = optind - 1;
20913007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
21013007Swpaul				yp_error("transaction ID not specified");
21113007Swpaul				usage();
21213007Swpaul			}
21313007Swpaul			ypxfr_resp.transid = atol(argv[my_optind]);
21413007Swpaul			my_optind++;
21513007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
21613007Swpaul				yp_error("RPC program number not specified");
21713007Swpaul				usage();
21813007Swpaul			}
21913007Swpaul			ypxfr_prognum = atol(argv[my_optind]);
22013007Swpaul			my_optind++;
22113007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
22213007Swpaul				yp_error("address not specified");
22313007Swpaul				usage();
22413007Swpaul			}
22513007Swpaul			if (!inet_aton(argv[my_optind], &ypxfr_callback_addr.sin_addr)) {
22613007Swpaul				yp_error("failed to convert '%s' to IP addr",
22713007Swpaul					argv[my_optind]);
22813007Swpaul				exit(1);
22913007Swpaul			}
23013007Swpaul			my_optind++;
23113007Swpaul			if (argv[my_optind] == NULL || !strlen(argv[my_optind])) {
23213007Swpaul				yp_error("port not specified");
23313007Swpaul				usage();
23413007Swpaul			}
23513007Swpaul			ypxfr_callback_addr.sin_port = htons((u_short)atoi(argv[my_optind]));
23613007Swpaul			ypxfr_args += 5;
23713007Swpaul			break;
23813007Swpaul		default:
23913007Swpaul			usage();
24013007Swpaul			break;
24113007Swpaul		}
24213007Swpaul	}
24313007Swpaul
24413007Swpaul	ypxfr_mapname = argv[ypxfr_args + 1];
24513007Swpaul
24613007Swpaul	if (ypxfr_mapname == NULL) {
24713007Swpaul		yp_error("no map name specified");
24813007Swpaul		usage();
24913007Swpaul	}
25013007Swpaul
25113007Swpaul	/* Always the case. */
25213007Swpaul	ypxfr_callback_addr.sin_family = AF_INET;
25313007Swpaul
25413007Swpaul	/* Determine if local NIS client facilities are turned on. */
25513007Swpaul	if (!yp_get_default_domain(&ypxfr_local_domain) &&
25613007Swpaul	    _yp_check(&ypxfr_local_domain))
25713007Swpaul		ypxfr_use_yplib = 1;
25813007Swpaul
25913007Swpaul	/*
26013007Swpaul	 * If no destination domain is specified, assume that the
26113007Swpaul	 * local default domain is to be used and try to obtain it.
26213007Swpaul	 * Fails if NIS client facilities are turned off.
26313007Swpaul	 */
26413007Swpaul	if (ypxfr_dest_domain == NULL) {
26513007Swpaul		if (ypxfr_use_yplib) {
26613007Swpaul			yp_get_default_domain(&ypxfr_dest_domain);
26713007Swpaul		} else {
26813007Swpaul			yp_error("no destination domain specified and \
26913007Swpaulthe local domain name isn't set");
27013007Swpaul			ypxfr_exit(YPXFR_BADARGS,NULL);
27113007Swpaul		}
27213007Swpaul	}
27313007Swpaul
27413007Swpaul	/*
27513007Swpaul	 * If a source domain is not specified, assume it to
27613007Swpaul	 * be the same as the destination domain.
27713007Swpaul	 */
27813007Swpaul	if (ypxfr_source_domain == NULL) {
27913007Swpaul		ypxfr_source_domain = ypxfr_dest_domain;
28013007Swpaul	}
28113007Swpaul
28213007Swpaul	/*
28313007Swpaul	 * If the source host is not specified, assume it to be the
28413007Swpaul	 * master for the specified map. If local NIS client facilities
28513007Swpaul	 * are turned on, we can figure this out using yp_master().
28613007Swpaul	 * If not, we have to see if a local copy of the map exists
28713007Swpaul	 * and extract its YP_MASTER_NAME record. If _that_ fails,
28813007Swpaul	 * we are stuck and must ask the user for more information.
28913007Swpaul	 */
29013007Swpaul	if (ypxfr_source_host == NULL) {
29113007Swpaul		if (!ypxfr_use_yplib) {
29213007Swpaul		/*
29313007Swpaul		 * Double whammy: NIS isn't turned on and the user
29413007Swpaul		 * didn't specify a source host.
29513007Swpaul		 */
29613007Swpaul			char *dptr;
29713007Swpaul			key.data = "YP_MASTER_NAME";
29813007Swpaul			key.size = sizeof("YP_MASTER_NAME") - 1;
29913007Swpaul
30013007Swpaul			if (yp_get_record(ypxfr_dest_domain, ypxfr_mapname,
30113007Swpaul					 &key, &data, 1) != YP_TRUE) {
30213007Swpaul				yp_error("no source host specified");
30313007Swpaul				ypxfr_exit(YPXFR_BADARGS,NULL);
30413007Swpaul			}
30513007Swpaul			dptr = data.data;
30613007Swpaul			dptr[data.size] = '\0';
30713007Swpaul			ypxfr_master = ypxfr_source_host = strdup(dptr);
30813007Swpaul		}
30913007Swpaul	} else {
31013007Swpaul		if (ypxfr_use_yplib)
31113007Swpaul			ypxfr_use_yplib = 0;
31213007Swpaul	}
31313007Swpaul
31413007Swpaul	if (ypxfr_master == NULL) {
31513007Swpaul		if ((ypxfr_master = ypxfr_get_master(ypxfr_source_domain,
31613007Swpaul					    	 ypxfr_mapname,
31713007Swpaul					     	ypxfr_source_host,
31813007Swpaul					     	ypxfr_use_yplib)) == NULL) {
31913276Swpaul			yp_error("failed to find master of %s in domain %s: %s",
32013276Swpaul				  ypxfr_mapname, ypxfr_source_domain,
32113276Swpaul				  ypxfrerr_string(yp_errno));
32213007Swpaul			ypxfr_exit(YPXFR_MADDR,NULL);
32313007Swpaul		}
32413007Swpaul	}
32513007Swpaul
32613007Swpaul	/*
32713007Swpaul	 * If we got here and ypxfr_source_host is still undefined,
32813007Swpaul	 * it means we had to resort to using yp_master() to find the
32913007Swpaul	 * master server for the map. The source host and master should
33013007Swpaul	 * be identical.
33113007Swpaul	 */
33213007Swpaul	if (ypxfr_source_host == NULL)
33313007Swpaul		ypxfr_source_host = ypxfr_master;
33413007Swpaul
33513007Swpaul	if ((ypxfr_order = ypxfr_get_order(ypxfr_source_domain,
33613007Swpaul					     ypxfr_mapname,
33713007Swpaul					     ypxfr_master, 0)) == 0) {
33813276Swpaul		yp_error("failed to get order number of %s: %s",
33913376Swpaul				ypxfr_mapname, yp_errno == YPXFR_SUCC ?
34013376Swpaul				"map has order 0" : ypxfrerr_string(yp_errno));
34113007Swpaul		ypxfr_exit(YPXFR_YPERR,NULL);
34213007Swpaul	}
34313007Swpaul
34413007Swpaul	key.data = "YP_LAST_MODIFIED";
34513007Swpaul	key.size = sizeof("YP_LAST_MODIFIED") - 1;
34613007Swpaul
34713007Swpaul	/* The order number is immaterial when the 'force' flag is set. */
34813007Swpaul
34913007Swpaul	if (!ypxfr_force) {
35013007Swpaul		int ignore = 0;
35113007Swpaul		if (yp_get_record(ypxfr_dest_domain,ypxfr_mapname,&key,&data,1) != YP_TRUE) {
35213007Swpaul			switch(yp_errno) {
35313007Swpaul			case YP_NOKEY:
35413007Swpaul				ypxfr_exit(YPXFR_FORCE,NULL);
35513007Swpaul				break;
35613007Swpaul			case YP_NOMAP:
35713007Swpaul				/*
35813007Swpaul				 * If the map doesn't exist, we're
35913007Swpaul				 * creating it. Ignore the error.
36013007Swpaul				 */
36113007Swpaul				ignore++;
36213007Swpaul				break;
36313007Swpaul			case YP_BADDB:
36413007Swpaul			default:
36513007Swpaul				ypxfr_exit(YPXFR_DBM,NULL);
36613007Swpaul				break;
36713007Swpaul			}
36813007Swpaul		}
36913007Swpaul		if (!ignore && ypxfr_order <= atoi(data.data))
37013007Swpaul			ypxfr_exit(YPXFR_AGE, NULL);
37113007Swpaul
37213007Swpaul	}
37313007Swpaul
37413007Swpaul	/* Construct a temporary map file name */
37513007Swpaul	snprintf(tempmap, sizeof(tempmap), "%s.%d",ypxfr_mapname, getpid());
37613007Swpaul	snprintf(ypxfr_temp_map, sizeof(ypxfr_temp_map), "%s/%s/%s", yp_dir,
37713007Swpaul		 ypxfr_dest_domain, tempmap);
37813007Swpaul
37916132Swpaul	if (getrpcport(ypxfr_master, YPXFRD_FREEBSD_PROG,
38016132Swpaul					YPXFRD_FREEBSD_VERS, IPPROTO_TCP)) {
38116132Swpaul		/* Try to send using ypxfrd. If it fails, use old method. */
38216132Swpaul		if (!ypxfrd_get_map(ypxfr_master, ypxfr_mapname,
38316132Swpaul					ypxfr_source_domain, ypxfr_temp_map))
38416132Swpaul			goto leave;
38516132Swpaul	}
38616132Swpaul
38713007Swpaul	/* Open the temporary map read/write. */
38816132Swpaul	if ((dbp = yp_open_db_rw(ypxfr_dest_domain, tempmap, 0)) == NULL) {
38913007Swpaul		yp_error("failed to open temporary map file");
39013007Swpaul		ypxfr_exit(YPXFR_DBM,NULL);
39113007Swpaul	}
39213007Swpaul
39313007Swpaul	/*
39413007Swpaul	 * Fill in the keys we already know, such as the order number,
39513007Swpaul	 * master name, input file name (we actually make up a bogus
39613007Swpaul	 * name for that) and output file name.
39713007Swpaul	 */
39813007Swpaul	snprintf(buf, sizeof(buf), "%d", ypxfr_order);
39913007Swpaul	data.data = buf;
40013007Swpaul	data.size = strlen(buf);
40113007Swpaul
40216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
40313007Swpaul		yp_error("failed to write order number to database");
40413007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
40513007Swpaul	}
40613007Swpaul
40713007Swpaul	key.data = "YP_MASTER_NAME";
40813007Swpaul	key.size = sizeof("YP_MASTER_NAME") - 1;
40913007Swpaul	data.data = ypxfr_master;
41013007Swpaul	data.size = strlen(ypxfr_master);
41113007Swpaul
41216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
41313007Swpaul		yp_error("failed to write master name to database");
41413007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
41513007Swpaul	}
41613007Swpaul
41713007Swpaul	key.data = "YP_DOMAIN_NAME";
41813007Swpaul	key.size = sizeof("YP_DOMAIN_NAME") - 1;
41913007Swpaul	data.data = ypxfr_dest_domain;
42013007Swpaul	data.size = strlen(ypxfr_dest_domain);
42113007Swpaul
42216132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
42313007Swpaul		yp_error("failed to write domain name to database");
42413007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
42513007Swpaul	}
42613007Swpaul
42713007Swpaul	snprintf (buf, sizeof(buf), "%s:%s", ypxfr_source_host, ypxfr_mapname);
42813007Swpaul
42913007Swpaul	key.data = "YP_INPUT_NAME";
43013007Swpaul	key.size = sizeof("YP_INPUT_NAME") - 1;
43113007Swpaul	data.data = &buf;
43213007Swpaul	data.size = strlen(buf);
43313007Swpaul
43416132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
43513007Swpaul		yp_error("failed to write input name to database");
43613007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
43713007Swpaul
43813007Swpaul	}
43913007Swpaul
44013007Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
44113007Swpaul							ypxfr_mapname);
44213007Swpaul
44313007Swpaul	key.data = "YP_OUTPUT_NAME";
44413007Swpaul	key.size = sizeof("YP_OUTPUT_NAME") - 1;
44513007Swpaul	data.data = &buf;
44613007Swpaul	data.size = strlen(buf);
44713007Swpaul
44816132Swpaul	if (yp_put_record(dbp, &key, &data, 0) != YP_TRUE) {
44913007Swpaul		yp_error("failed to write output name to database");
45013007Swpaul		ypxfr_exit(YPXFR_DBM,&ypxfr_temp_map);
45113007Swpaul	}
45213007Swpaul
45313007Swpaul	/* Now suck over the contents of the map from the master. */
45413007Swpaul
45513007Swpaul	if (ypxfr_get_map(ypxfr_mapname,ypxfr_source_domain,
45613007Swpaul			  ypxfr_source_host, ypxfr_foreach)){
45713007Swpaul		yp_error("failed to retrieve map from source host");
45813007Swpaul		ypxfr_exit(YPXFR_YPERR,&ypxfr_temp_map);
45913007Swpaul	}
46013007Swpaul
46113007Swpaul	(void)(dbp->close)(dbp);
46213276Swpaul	dbp = NULL; /* <- yes, it seems this is necessary. */
46313007Swpaul
46416132Swpaulleave:
46516132Swpaul
46616132Swpaul	snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, ypxfr_dest_domain,
46716132Swpaul							ypxfr_mapname);
46816132Swpaul
46913007Swpaul	/* Peek at the order number again and check for skew. */
47013007Swpaul	if ((ypxfr_skew_check = ypxfr_get_order(ypxfr_source_domain,
47113007Swpaul					     ypxfr_mapname,
47213007Swpaul					     ypxfr_master, 0)) == 0) {
47313276Swpaul		yp_error("failed to get order number of %s: %s",
47413376Swpaul				ypxfr_mapname, yp_errno == YPXFR_SUCC ?
47513376Swpaul				"map has order 0" : ypxfrerr_string(yp_errno));
47613007Swpaul		ypxfr_exit(YPXFR_YPERR,&ypxfr_temp_map);
47713007Swpaul	}
47813007Swpaul
47913007Swpaul	if (ypxfr_order != ypxfr_skew_check)
48013007Swpaul		ypxfr_exit(YPXFR_SKEW,&ypxfr_temp_map);
48113007Swpaul
48213007Swpaul	/*
48313007Swpaul	 * Send a YPPROC_CLEAR to the local ypserv.
48413007Swpaul	 */
48513376Swpaul	if (ypxfr_clear) {
48613007Swpaul		char in = 0;
48713007Swpaul		char *out = NULL;
48813376Swpaul		int stat;
48913376Swpaul		if ((stat = callrpc("localhost",YPPROG,YPVERS,YPPROC_CLEAR,
49013376Swpaul			xdr_void, (void *)&in,
49113376Swpaul			xdr_void, (void *)out)) != RPC_SUCCESS) {
49213376Swpaul			yp_error("failed to send 'clear' to local ypserv: %s",
49313376Swpaul				 clnt_sperrno((enum clnt_stat) stat));
49413376Swpaul			ypxfr_exit(YPXFR_CLEAR, &ypxfr_temp_map);
49513007Swpaul		}
49613007Swpaul	}
49713007Swpaul
49813376Swpaul	/*
49913376Swpaul	 * Put the new map in place immediately. I'm not sure if the
50013376Swpaul	 * kernel does an unlink() and rename() atomically in the event
50113376Swpaul	 * that we move a new copy of a map over the top of an existing
50213376Swpaul	 * one, but there's less chance of a race condition happening
50313376Swpaul	 * than if we were to do the unlink() ourselves.
50413376Swpaul	 */
50513007Swpaul	if (rename(ypxfr_temp_map, buf) == -1) {
50613007Swpaul		yp_error("rename(%s,%s) failed: %s", ypxfr_temp_map, buf,
50713007Swpaul							strerror(errno));
50813007Swpaul		ypxfr_exit(YPXFR_FILE,NULL);
50913007Swpaul	}
51013007Swpaul
51113007Swpaul	ypxfr_exit(YPXFR_SUCC,NULL);
51213007Swpaul
51313007Swpaul	return(1);
51413007Swpaul}
515