Home | History | Annotate | Line # | Download | only in yppush
yppush.c revision 1.21.10.1
      1  1.21.10.1      jym /*	$NetBSD: yppush.c,v 1.21.10.1 2009/05/13 19:20:45 jym Exp $	*/
      2        1.1  thorpej 
      3        1.1  thorpej /*
      4        1.8    lukem  *
      5        1.8    lukem  * Copyright (c) 1997 Charles D. Cranor
      6        1.1  thorpej  * All rights reserved.
      7        1.1  thorpej  *
      8        1.1  thorpej  * Redistribution and use in source and binary forms, with or without
      9        1.1  thorpej  * modification, are permitted provided that the following conditions
     10        1.1  thorpej  * are met:
     11        1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     12        1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     13        1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     14        1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     15        1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     16        1.8    lukem  * 3. The name of the author may not be used to endorse or promote products
     17        1.1  thorpej  *    derived from this software without specific prior written permission.
     18        1.1  thorpej  *
     19        1.8    lukem  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20        1.8    lukem  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21        1.8    lukem  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22        1.8    lukem  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23        1.8    lukem  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24        1.8    lukem  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25        1.8    lukem  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26        1.8    lukem  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27        1.8    lukem  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28        1.8    lukem  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29        1.8    lukem  */
     30        1.1  thorpej 
     31        1.8    lukem /*
     32        1.8    lukem  * yppush
     33        1.8    lukem  * author: Chuck Cranor <chuck (at) ccrc.wustl.edu>
     34        1.8    lukem  * date: 05-Nov-97
     35        1.8    lukem  *
     36        1.8    lukem  * notes: this is a full rewrite of Mats O Jansson <moj (at) stacken.kth.se>'s
     37        1.8    lukem  * yppush.c.   i have restructured and cleaned up the entire file.
     38        1.8    lukem  */
     39        1.1  thorpej #include <sys/types.h>
     40        1.8    lukem #include <sys/param.h>
     41        1.1  thorpej #include <sys/stat.h>
     42        1.8    lukem #include <sys/time.h>
     43        1.4  thorpej #include <sys/wait.h>
     44        1.1  thorpej 
     45        1.4  thorpej #include <ctype.h>
     46        1.1  thorpej #include <err.h>
     47       1.10   kleink #include <errno.h>
     48        1.8    lukem #include <signal.h>
     49        1.1  thorpej #include <stdio.h>
     50       1.13     matt #include <stdlib.h>
     51        1.9  thorpej #include <string.h>
     52       1.16    lukem #include <syslog.h>
     53        1.1  thorpej #include <unistd.h>
     54        1.1  thorpej 
     55        1.1  thorpej #include <rpc/rpc.h>
     56        1.1  thorpej #include <rpcsvc/yp_prot.h>
     57        1.1  thorpej #include <rpcsvc/ypclnt.h>
     58        1.1  thorpej 
     59        1.8    lukem #include "ypdb.h"
     60        1.8    lukem #include "ypdef.h"
     61        1.1  thorpej #include "yplib_host.h"
     62        1.1  thorpej #include "yppush.h"
     63        1.1  thorpej 
     64        1.8    lukem /*
     65        1.8    lukem  * yppush: push a new YP map out YP servers
     66        1.8    lukem  *
     67        1.8    lukem  * usage:
     68        1.8    lukem  *   yppush [-d domain] [-h host] [-v] mapname
     69        1.8    lukem  *
     70        1.8    lukem  *   -d: the domainname the map lives in [if different from default]
     71        1.8    lukem  *   -h: push only to this host [otherwise, push to all hosts]
     72        1.8    lukem  *   -v: verbose
     73        1.8    lukem  */
     74        1.8    lukem 
     75        1.8    lukem /*
     76        1.8    lukem  * structures
     77        1.8    lukem  */
     78        1.8    lukem 
     79        1.8    lukem struct yppush_info {
     80        1.8    lukem 	char   *ourdomain;	/* domain of interest */
     81        1.8    lukem 	char   *map;		/* map we are pushing */
     82        1.8    lukem 	char   *owner;		/* owner of map */
     83        1.8    lukem 	int     order;		/* order number of map (version) */
     84        1.8    lukem };
     85        1.8    lukem /*
     86        1.8    lukem  * global vars
     87        1.8    lukem  */
     88        1.8    lukem 
     89        1.8    lukem int     verbo = 0;		/* verbose */
     90        1.8    lukem 
     91        1.8    lukem /*
     92        1.8    lukem  * prototypes
     93        1.8    lukem  */
     94        1.1  thorpej 
     95       1.18      wiz int	main(int, char *[]);
     96       1.18      wiz int	pushit(int, char *, int, char *, int, char *);
     97       1.18      wiz void	push(char *, int, struct yppush_info *);
     98       1.18      wiz void	_svc_run(void);
     99       1.18      wiz void	usage(void);
    100        1.1  thorpej 
    101        1.1  thorpej 
    102        1.8    lukem /*
    103        1.8    lukem  * main
    104        1.8    lukem  */
    105        1.1  thorpej 
    106        1.1  thorpej int
    107       1.18      wiz main(int argc, char *argv[])
    108        1.8    lukem 
    109        1.1  thorpej {
    110        1.8    lukem 	char   *targhost = NULL;
    111        1.8    lukem 	struct yppush_info ypi = {NULL, NULL, NULL, 0};
    112        1.8    lukem 	int     c, rv;
    113        1.8    lukem 	const char *cp;
    114        1.8    lukem 	char   *master;
    115        1.8    lukem 	DBM    *ypdb;
    116  1.21.10.1      jym 	datum   dat;
    117        1.8    lukem 	CLIENT *ypserv;
    118        1.8    lukem 	struct timeval tv;
    119        1.8    lukem 	enum clnt_stat retval;
    120        1.8    lukem 	struct ypall_callback ypallcb;
    121        1.1  thorpej 
    122        1.8    lukem 	/*
    123        1.8    lukem          * parse command line
    124        1.8    lukem          */
    125        1.1  thorpej 	while ((c = getopt(argc, argv, "d:h:v")) != -1) {
    126        1.8    lukem 		switch (c) {
    127        1.1  thorpej 		case 'd':
    128        1.8    lukem 			ypi.ourdomain = optarg;
    129        1.1  thorpej 			break;
    130        1.1  thorpej 		case 'h':
    131        1.8    lukem 			targhost = optarg;
    132        1.1  thorpej 			break;
    133        1.8    lukem 		case 'v':
    134        1.8    lukem 			verbo = 1;
    135        1.1  thorpej 			break;
    136        1.1  thorpej 		default:
    137        1.8    lukem 			usage();
    138        1.8    lukem 			/* NOTREACHED */
    139        1.1  thorpej 		}
    140        1.1  thorpej 	}
    141        1.8    lukem 	argc -= optind;
    142        1.8    lukem 	argv += optind;
    143        1.1  thorpej 	if (argc != 1)
    144        1.1  thorpej 		usage();
    145       1.15    lukem 	openlog("yppush", LOG_PID, LOG_DAEMON);
    146        1.8    lukem 	ypi.map = argv[0];
    147        1.8    lukem 	if (strlen(ypi.map) > YPMAXMAP)
    148        1.8    lukem 		errx(1, "%s: map name too long (limit %d)", ypi.map, YPMAXMAP);
    149        1.8    lukem 
    150        1.8    lukem 	/*
    151        1.8    lukem          * ensure we have a domain
    152        1.8    lukem          */
    153        1.8    lukem 	if (ypi.ourdomain == NULL) {
    154        1.8    lukem 		c = yp_get_default_domain(&ypi.ourdomain);
    155        1.8    lukem 		if (ypi.ourdomain == NULL)
    156        1.8    lukem 			errx(1, "unable to get default domain: %s",
    157        1.3  thorpej 			    yperr_string(c));
    158        1.8    lukem 	}
    159        1.8    lukem 	/*
    160        1.8    lukem          * verify that the domain and specified database exsists
    161        1.8    lukem          *
    162        1.8    lukem          * XXXCDC: this effectively prevents us from pushing from any
    163        1.8    lukem          * host but the master.   an alternate plan is to find the master
    164        1.8    lukem          * host for a map, clear it, ask for the order number, and then
    165        1.8    lukem          * send xfr requests.   if that was used we would not need local
    166        1.8    lukem          * file access.
    167        1.8    lukem          */
    168        1.8    lukem 	if (chdir(YP_DB_PATH) < 0)
    169        1.8    lukem 		err(1, "%s", YP_DB_PATH);
    170        1.8    lukem 	if (chdir(ypi.ourdomain) < 0)
    171        1.8    lukem 		err(1, "%s/%s", YP_DB_PATH, ypi.ourdomain);
    172        1.8    lukem 
    173        1.8    lukem 	/*
    174        1.8    lukem          * now open the database so we can extract "order number"
    175        1.8    lukem          * (i.e. timestamp) of the map.
    176        1.8    lukem          */
    177       1.21    lukem 	ypdb = ypdb_open(ypi.map);
    178        1.8    lukem 	if (ypdb == NULL)
    179        1.8    lukem 		err(1, "ypdb_open %s/%s/%s", YP_DB_PATH, ypi.ourdomain,
    180        1.8    lukem 		    ypi.map);
    181  1.21.10.1      jym 	dat.dptr = YP_LAST_KEY;
    182  1.21.10.1      jym 	dat.dsize = YP_LAST_LEN;
    183  1.21.10.1      jym 	dat = ypdb_fetch(ypdb, dat);
    184  1.21.10.1      jym 	if (dat.dptr == NULL)
    185        1.8    lukem 		errx(1,
    186        1.8    lukem 		    "unable to fetch %s key: check database with 'makedbm -u'",
    187        1.8    lukem 		    YP_LAST_KEY);
    188        1.8    lukem 	ypi.order = 0;
    189  1.21.10.1      jym 	cp = dat.dptr;
    190  1.21.10.1      jym 	while (cp < dat.dptr + dat.dsize) {
    191       1.19      dsl 		if (!isdigit((unsigned char)*cp))
    192        1.8    lukem 			errx(1,
    193        1.8    lukem 		    "invalid order number: check database with 'makedbm -u'");
    194        1.8    lukem 		ypi.order = (ypi.order * 10) + *cp - '0';
    195        1.8    lukem 		cp++;
    196        1.8    lukem 	}
    197       1.11    lukem 	ypdb_close(ypdb);
    198        1.1  thorpej 
    199        1.8    lukem 	if (verbo)
    200        1.8    lukem 		printf("pushing %s [order=%d] in domain %s\n", ypi.map,
    201        1.8    lukem 		    ypi.order, ypi.ourdomain);
    202        1.8    lukem 
    203        1.8    lukem 	/*
    204        1.8    lukem          * ok, we are ready to do it.   first we send a clear_2 request
    205        1.8    lukem          * to the local server [should be the master] to make sure it has
    206        1.8    lukem          * the correct database open.
    207        1.8    lukem          *
    208        1.8    lukem          * XXXCDC: note that yp_bind_local exits on failure so ypserv can't
    209        1.8    lukem          * be null.   this makes it difficult to print a useful error message.
    210        1.8    lukem          * [it will print "clntudp_create: no contact with localhost"]
    211        1.8    lukem          */
    212        1.8    lukem 	tv.tv_sec = 10;
    213        1.8    lukem 	tv.tv_usec = 0;
    214        1.8    lukem 	ypserv = yp_bind_local(YPPROG, YPVERS);
    215        1.8    lukem 	retval = clnt_call(ypserv, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
    216        1.8    lukem 	if (retval != RPC_SUCCESS)
    217        1.8    lukem 		errx(1, "clnt_call CLEAR to local ypserv: %s",
    218        1.8    lukem 		    clnt_sperrno(retval));
    219        1.8    lukem 	clnt_destroy(ypserv);
    220        1.8    lukem 
    221        1.8    lukem 	/*
    222        1.8    lukem          * now use normal yplib functions to bind to the domain.
    223        1.8    lukem          */
    224        1.8    lukem 	rv = yp_bind(ypi.ourdomain);
    225        1.8    lukem 	if (rv)
    226        1.8    lukem 		errx(1, "error binding to %s: %s", ypi.ourdomain,
    227        1.8    lukem 		    yperr_string(rv));
    228        1.8    lukem 
    229        1.8    lukem 	/*
    230        1.8    lukem          * find 'owner' of the map (see pushit for usage)
    231        1.8    lukem          */
    232        1.8    lukem 	rv = yp_master(ypi.ourdomain, ypi.map, &ypi.owner);
    233        1.8    lukem 	if (rv)
    234        1.8    lukem 		errx(1, "error finding master for %s in %s: %s", ypi.map,
    235        1.8    lukem 		    ypi.ourdomain, yperr_string(rv));
    236        1.8    lukem 
    237        1.8    lukem 	/*
    238        1.8    lukem          * inform user of our progress
    239        1.8    lukem          */
    240        1.8    lukem 	if (verbo) {
    241        1.8    lukem 		printf("pushing map %s in %s: order=%d, owner=%s\n", ypi.map,
    242        1.8    lukem 		    ypi.ourdomain, ypi.order, ypi.owner);
    243        1.8    lukem 		printf("pushing to %s\n",
    244        1.8    lukem 		    (targhost) ? targhost : "<all ypservs>");
    245        1.8    lukem 	}
    246        1.1  thorpej 
    247        1.8    lukem 	/*
    248        1.8    lukem          * finally, do it.
    249        1.8    lukem          */
    250        1.8    lukem 	if (targhost) {
    251        1.8    lukem 		push(targhost, strlen(targhost), &ypi);
    252        1.8    lukem 	} else {
    253        1.8    lukem 
    254        1.8    lukem 		/*
    255        1.8    lukem 	         * no host specified, do all hosts the master knows about via
    256        1.8    lukem 	         * the ypservers map.
    257        1.8    lukem 	         */
    258        1.8    lukem 		rv = yp_master(ypi.ourdomain, "ypservers", &master);
    259        1.8    lukem 		if (rv)
    260        1.8    lukem 			errx(1, "error finding master for ypservers in %s: %s",
    261        1.8    lukem 			    ypi.ourdomain, yperr_string(rv));
    262        1.8    lukem 
    263        1.8    lukem 		if (verbo)
    264        1.8    lukem 			printf(
    265        1.8    lukem 		"contacting ypservers %s master on %s for list of ypservs...\n",
    266        1.8    lukem 			    ypi.ourdomain, master);
    267        1.8    lukem 
    268        1.8    lukem 		ypserv = yp_bind_host(master, YPPROG, YPVERS, 0, 1);
    269        1.8    lukem 
    270        1.8    lukem 		ypallcb.foreach = pushit;	/* callback function */
    271        1.8    lukem 		ypallcb.data = (char *) &ypi;	/* data to pass into callback */
    272        1.8    lukem 
    273        1.8    lukem 		rv = yp_all_host(ypserv, ypi.ourdomain, "ypservers", &ypallcb);
    274        1.8    lukem 		if (rv)
    275        1.8    lukem 			errx(1, "pushing %s in %s failed: %s", ypi.map,
    276        1.8    lukem 			    ypi.ourdomain, yperr_string(rv));
    277        1.1  thorpej 	}
    278        1.8    lukem 	exit(0);
    279        1.1  thorpej }
    280        1.1  thorpej 
    281        1.8    lukem /*
    282        1.8    lukem  * usage: print usage and exit
    283        1.8    lukem  */
    284        1.1  thorpej void
    285       1.18      wiz usage(void)
    286        1.1  thorpej {
    287        1.8    lukem 	fprintf(stderr, "usage: %s [-d domain] [-h host] [-v] map\n",
    288       1.17      cgd 	    getprogname());
    289        1.1  thorpej 	exit(1);
    290        1.1  thorpej }
    291        1.1  thorpej 
    292        1.8    lukem /*
    293        1.8    lukem  * pushit: called from yp_all_host to push a specific host.
    294        1.8    lukem  * the key/value pairs are from the ypservers map.
    295        1.8    lukem  */
    296        1.8    lukem int
    297       1.18      wiz pushit(int instatus, char *inkey, int inkeylen, char *inval,
    298       1.18      wiz        int invallen, char *indata)
    299        1.1  thorpej {
    300        1.8    lukem 	struct yppush_info *ypi = (struct yppush_info *) indata;
    301        1.1  thorpej 
    302        1.8    lukem 	push(inkey, inkeylen, ypi);		/* do it! */
    303        1.8    lukem 	return (0);
    304        1.1  thorpej }
    305        1.1  thorpej 
    306        1.8    lukem /*
    307        1.8    lukem  * push: push a specific map on a specific host
    308        1.8    lukem  */
    309        1.1  thorpej void
    310       1.18      wiz push(char *host, int hostlen, struct yppush_info *ypi)
    311        1.8    lukem {
    312        1.8    lukem 	char    target[YPMAXPEER];
    313        1.8    lukem 	CLIENT *ypserv;
    314        1.1  thorpej 	SVCXPRT *transp;
    315        1.8    lukem 	int     prog, pid, rv;
    316        1.1  thorpej 	struct timeval tv;
    317        1.8    lukem 	struct ypreq_xfr req;
    318        1.1  thorpej 
    319        1.8    lukem 	/*
    320        1.8    lukem          * get our target host in a null terminated string
    321        1.8    lukem          */
    322        1.8    lukem 	snprintf(target, sizeof(target), "%*.*s", hostlen, hostlen, host);
    323        1.8    lukem 
    324        1.8    lukem 	/*
    325        1.8    lukem          * XXXCDC: arg!  we would like to use yp_bind_host here, except that
    326        1.8    lukem          * it exits on failure and we don't want to give up just because
    327        1.8    lukem          * one host fails.  thus, we have to do it the hard way.
    328        1.8    lukem          */
    329        1.8    lukem 	ypserv = clnt_create(target, YPPROG, YPVERS, "tcp");
    330        1.8    lukem 	if (ypserv == NULL) {
    331        1.8    lukem 		clnt_pcreateerror(target);
    332        1.1  thorpej 		return;
    333        1.1  thorpej 	}
    334        1.1  thorpej 
    335        1.8    lukem 	/*
    336        1.8    lukem          * our XFR rpc request to the client just starts the transfer.
    337        1.8    lukem          * when the client is done, it wants to call a procedure that
    338        1.8    lukem          * we are serving to tell us that it is done.   so we must create
    339        1.8    lukem          * and register a procedure for us for it to call.
    340        1.8    lukem          */
    341        1.8    lukem 	transp = svcudp_create(RPC_ANYSOCK);
    342        1.1  thorpej 	if (transp == NULL) {
    343        1.8    lukem 		warnx("callback svcudp_create failed");
    344        1.8    lukem 		goto error;
    345        1.1  thorpej 	}
    346        1.1  thorpej 
    347        1.8    lukem 	/* register it with portmap */
    348        1.1  thorpej 	for (prog = 0x40000000; prog < 0x5fffffff; prog++) {
    349        1.8    lukem 		if (svc_register(transp, prog, 1, yppush_xfrrespprog_1,
    350        1.8    lukem 		    IPPROTO_UDP))
    351        1.1  thorpej 			break;
    352        1.1  thorpej 	}
    353        1.8    lukem 	if (prog >= 0x5fffffff) {
    354        1.8    lukem 		warnx("unable to register callback");
    355        1.8    lukem 		goto error;
    356        1.8    lukem 	}
    357        1.1  thorpej 
    358        1.8    lukem 	/*
    359        1.8    lukem          * now fork off a server to catch our reply
    360        1.8    lukem          */
    361        1.8    lukem 	pid = fork();
    362        1.8    lukem 	if (pid == -1) {
    363        1.8    lukem 		svc_unregister(prog, 1);	/* drop our mapping with
    364        1.8    lukem 						 * portmap */
    365        1.8    lukem 		warn("fork failed");
    366        1.8    lukem 		goto error;
    367        1.1  thorpej 	}
    368        1.1  thorpej 
    369        1.8    lukem 	/*
    370        1.8    lukem          * child process becomes the server
    371        1.8    lukem          */
    372        1.8    lukem 	if (pid == 0) {
    373        1.1  thorpej 		_svc_run();
    374        1.1  thorpej 		exit(0);
    375        1.8    lukem 	}
    376        1.8    lukem 
    377        1.8    lukem 	/*
    378        1.8    lukem          * we are the parent process: send XFR request to server.
    379        1.8    lukem          * the "owner" field isn't used by ypserv (and shouldn't be, since
    380        1.8    lukem          * the ypserv has no idea if we are a legitimate yppush or not).
    381        1.8    lukem          * instead, the owner of the map is determined by the master value
    382        1.8    lukem          * currently cached on the slave server.
    383        1.8    lukem          */
    384       1.12     fvdl 	close(transp->xp_fd);	/* close child's socket, we don't need it */
    385        1.8    lukem 	/* don't wait for anything here, we will wait for child's exit */
    386        1.8    lukem 	tv.tv_sec = 0;
    387        1.8    lukem 	tv.tv_usec = 0;
    388        1.8    lukem 	req.map_parms.domain = ypi->ourdomain;
    389        1.8    lukem 	req.map_parms.map = ypi->map;
    390        1.8    lukem 	req.map_parms.owner = ypi->owner;	/* NOT USED */
    391        1.8    lukem 	req.map_parms.ordernum = ypi->order;
    392        1.8    lukem 	req.transid = (u_int) pid;
    393        1.8    lukem 	req.proto = prog;
    394        1.8    lukem 	req.port = transp->xp_port;
    395        1.8    lukem 
    396        1.8    lukem 	if (verbo)
    397        1.8    lukem 		printf("asking host %s to transfer map (xid=%d)\n", target,
    398        1.8    lukem 		    req.transid);
    399        1.8    lukem 
    400        1.8    lukem 	rv = clnt_call(ypserv, YPPROC_XFR, xdr_ypreq_xfr, &req,
    401        1.8    lukem 	    		xdr_void, NULL, tv);			/* do it! */
    402        1.1  thorpej 
    403        1.8    lukem 	if (rv != RPC_SUCCESS && rv != RPC_TIMEDOUT) {
    404        1.8    lukem 		warnx("unable to xfr to host %s: %s", target, clnt_sperrno(rv));
    405        1.8    lukem 		kill(pid, SIGTERM);
    406        1.1  thorpej 	}
    407        1.8    lukem 
    408        1.8    lukem 	/*
    409        1.8    lukem          * now wait for child to get the reply and exit
    410        1.8    lukem          */
    411        1.8    lukem 	wait4(pid, NULL, 0, NULL);
    412        1.8    lukem 	svc_unregister(prog, 1);
    413        1.8    lukem 
    414        1.8    lukem 	/*
    415        1.8    lukem          * ... and we are done.   fall through
    416        1.8    lukem          */
    417        1.8    lukem 
    418        1.8    lukem error:
    419        1.8    lukem 	if (transp)
    420        1.8    lukem 		svc_destroy(transp);
    421        1.8    lukem 	clnt_destroy(ypserv);
    422        1.8    lukem 	return;
    423        1.1  thorpej }
    424        1.1  thorpej 
    425        1.8    lukem /*
    426        1.8    lukem  * _svc_run: this is the main loop for the RPC server that we fork off
    427        1.8    lukem  * to await the reply from ypxfr.
    428        1.8    lukem  */
    429        1.8    lukem void
    430       1.18      wiz _svc_run(void)
    431        1.1  thorpej {
    432        1.8    lukem 	fd_set  readfds;
    433        1.8    lukem 	struct timeval tv;
    434        1.8    lukem 	int     rv, nfds;
    435        1.1  thorpej 
    436        1.8    lukem 	nfds = sysconf(_SC_OPEN_MAX);
    437        1.8    lukem 	while (1) {
    438        1.1  thorpej 
    439        1.8    lukem 		readfds = svc_fdset;	/* structure copy from global var */
    440        1.8    lukem 		tv.tv_sec = 60;
    441        1.8    lukem 		tv.tv_usec = 0;
    442        1.8    lukem 
    443        1.8    lukem 		rv = select(nfds, &readfds, NULL, NULL, &tv);
    444        1.8    lukem 
    445        1.8    lukem 		if (rv < 0) {
    446        1.8    lukem 			if (errno == EINTR)
    447        1.8    lukem 				continue;
    448        1.8    lukem 			warn("_svc_run: select failed");
    449        1.8    lukem 			return;
    450        1.8    lukem 		}
    451        1.8    lukem 		if (rv == 0)
    452        1.8    lukem 			errx(0, "_svc_run: callback timed out");
    453        1.1  thorpej 
    454        1.8    lukem 		/*
    455        1.8    lukem 	         * got something
    456        1.8    lukem 	         */
    457        1.8    lukem 		svc_getreqset(&readfds);
    458        1.1  thorpej 
    459        1.8    lukem 	}
    460        1.1  thorpej }
    461