18360efbdSAlfred Perlstein /* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */ 28360efbdSAlfred Perlstein 399064799SGarrett Wollman /* 499064799SGarrett Wollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 599064799SGarrett Wollman * unrestricted use provided that this legend is included on all tape 699064799SGarrett Wollman * media and as a part of the software program in whole or part. Users 799064799SGarrett Wollman * may copy or modify Sun RPC without charge, but are not authorized 899064799SGarrett Wollman * to license or distribute it to anyone else except as part of a product or 999064799SGarrett Wollman * program developed by the user. 1099064799SGarrett Wollman * 1199064799SGarrett Wollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1299064799SGarrett Wollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1399064799SGarrett Wollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1499064799SGarrett Wollman * 1599064799SGarrett Wollman * Sun RPC is provided with no support and without any obligation on the 1699064799SGarrett Wollman * part of Sun Microsystems, Inc. to assist in its use, correction, 1799064799SGarrett Wollman * modification or enhancement. 1899064799SGarrett Wollman * 1999064799SGarrett Wollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2099064799SGarrett Wollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2199064799SGarrett Wollman * OR ANY PART THEREOF. 2299064799SGarrett Wollman * 2399064799SGarrett Wollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2499064799SGarrett Wollman * or profits or other special, indirect and consequential damages, even if 2599064799SGarrett Wollman * Sun has been advised of the possibility of such damages. 2699064799SGarrett Wollman * 2799064799SGarrett Wollman * Sun Microsystems, Inc. 2899064799SGarrett Wollman * 2550 Garcia Avenue 2999064799SGarrett Wollman * Mountain View, California 94043 3099064799SGarrett Wollman */ 3199064799SGarrett Wollman 328360efbdSAlfred Perlstein /* #ident "@(#)clnt_generic.c 1.20 94/05/03 SMI" */ 338360efbdSAlfred Perlstein 3499064799SGarrett Wollman #if defined(LIBC_SCCS) && !defined(lint) 3599064799SGarrett Wollman /*static char *sccsid = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";*/ 3699064799SGarrett Wollman /*static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";*/ 377f3dea24SPeter Wemm static char *rcsid = "$FreeBSD$"; 3899064799SGarrett Wollman #endif 3999064799SGarrett Wollman 4099064799SGarrett Wollman /* 418360efbdSAlfred Perlstein * Copyright (c) 1986-1991 by Sun Microsystems Inc. 4299064799SGarrett Wollman */ 438360efbdSAlfred Perlstein #include "reentrant.h" 448360efbdSAlfred Perlstein #include "namespace.h" 458360efbdSAlfred Perlstein #include <sys/types.h> 4699064799SGarrett Wollman #include <sys/socket.h> 478360efbdSAlfred Perlstein #include <netinet/in.h> 488360efbdSAlfred Perlstein #include <netinet/tcp.h> 498360efbdSAlfred Perlstein #include <stdio.h> 50d201fe46SDaniel Eischen #include <errno.h> 5199064799SGarrett Wollman #include <netdb.h> 528360efbdSAlfred Perlstein #include <rpc/rpc.h> 538360efbdSAlfred Perlstein #include <rpc/nettype.h> 544c3af266SPoul-Henning Kamp #include <string.h> 558360efbdSAlfred Perlstein #include <stdlib.h> 568360efbdSAlfred Perlstein #include <unistd.h> 578360efbdSAlfred Perlstein #include "un-namespace.h" 588360efbdSAlfred Perlstein #include "rpc_com.h" 5999064799SGarrett Wollman 6099064799SGarrett Wollman /* 618360efbdSAlfred Perlstein * Generic client creation with version checking the value of 628360efbdSAlfred Perlstein * vers_out is set to the highest server supported value 638360efbdSAlfred Perlstein * vers_low <= vers_out <= vers_high AND an error results 648360efbdSAlfred Perlstein * if this can not be done. 6599064799SGarrett Wollman */ 6699064799SGarrett Wollman CLIENT * 678360efbdSAlfred Perlstein clnt_create_vers(hostname, prog, vers_out, vers_low, vers_high, nettype) 688360efbdSAlfred Perlstein const char *hostname; 698360efbdSAlfred Perlstein rpcprog_t prog; 708360efbdSAlfred Perlstein rpcvers_t *vers_out; 718360efbdSAlfred Perlstein rpcvers_t vers_low; 728360efbdSAlfred Perlstein rpcvers_t vers_high; 738360efbdSAlfred Perlstein const char *nettype; 7499064799SGarrett Wollman { 758360efbdSAlfred Perlstein CLIENT *clnt; 768360efbdSAlfred Perlstein struct timeval to; 778360efbdSAlfred Perlstein enum clnt_stat rpc_stat; 788360efbdSAlfred Perlstein struct rpc_err rpcerr; 7999064799SGarrett Wollman 808360efbdSAlfred Perlstein clnt = clnt_create(hostname, prog, vers_high, nettype); 818360efbdSAlfred Perlstein if (clnt == NULL) { 8299064799SGarrett Wollman return (NULL); 8399064799SGarrett Wollman } 848360efbdSAlfred Perlstein to.tv_sec = 10; 858360efbdSAlfred Perlstein to.tv_usec = 0; 868360efbdSAlfred Perlstein rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, 878360efbdSAlfred Perlstein (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL, to); 888360efbdSAlfred Perlstein if (rpc_stat == RPC_SUCCESS) { 898360efbdSAlfred Perlstein *vers_out = vers_high; 908360efbdSAlfred Perlstein return (clnt); 918360efbdSAlfred Perlstein } 928360efbdSAlfred Perlstein if (rpc_stat == RPC_PROGVERSMISMATCH) { 938360efbdSAlfred Perlstein unsigned long minvers, maxvers; 948360efbdSAlfred Perlstein 958360efbdSAlfred Perlstein clnt_geterr(clnt, &rpcerr); 968360efbdSAlfred Perlstein minvers = rpcerr.re_vers.low; 978360efbdSAlfred Perlstein maxvers = rpcerr.re_vers.high; 988360efbdSAlfred Perlstein if (maxvers < vers_high) 998360efbdSAlfred Perlstein vers_high = (rpcvers_t)maxvers; 1008360efbdSAlfred Perlstein if (minvers > vers_low) 1018360efbdSAlfred Perlstein vers_low = (rpcvers_t)minvers; 1028360efbdSAlfred Perlstein if (vers_low > vers_high) { 1038360efbdSAlfred Perlstein goto error; 1048360efbdSAlfred Perlstein } 1058360efbdSAlfred Perlstein CLNT_CONTROL(clnt, CLSET_VERS, (char *)(void *)&vers_high); 1068360efbdSAlfred Perlstein rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, 1078360efbdSAlfred Perlstein (char *) NULL, (xdrproc_t) xdr_void, 1088360efbdSAlfred Perlstein (char *) NULL, to); 1098360efbdSAlfred Perlstein if (rpc_stat == RPC_SUCCESS) { 1108360efbdSAlfred Perlstein *vers_out = vers_high; 1118360efbdSAlfred Perlstein return (clnt); 1128360efbdSAlfred Perlstein } 1138360efbdSAlfred Perlstein } 1148360efbdSAlfred Perlstein clnt_geterr(clnt, &rpcerr); 1158360efbdSAlfred Perlstein 1168360efbdSAlfred Perlstein error: 1178360efbdSAlfred Perlstein rpc_createerr.cf_stat = rpc_stat; 1188360efbdSAlfred Perlstein rpc_createerr.cf_error = rpcerr; 1198360efbdSAlfred Perlstein clnt_destroy(clnt); 1208360efbdSAlfred Perlstein return (NULL); 1218360efbdSAlfred Perlstein } 1228360efbdSAlfred Perlstein 12399064799SGarrett Wollman /* 1248360efbdSAlfred Perlstein * Top level client creation routine. 1258360efbdSAlfred Perlstein * Generic client creation: takes (servers name, program-number, nettype) and 1268360efbdSAlfred Perlstein * returns client handle. Default options are set, which the user can 1278360efbdSAlfred Perlstein * change using the rpc equivalent of _ioctl()'s. 1288360efbdSAlfred Perlstein * 1298360efbdSAlfred Perlstein * It tries for all the netids in that particular class of netid until 1308360efbdSAlfred Perlstein * it succeeds. 1318360efbdSAlfred Perlstein * XXX The error message in the case of failure will be the one 1328360efbdSAlfred Perlstein * pertaining to the last create error. 1338360efbdSAlfred Perlstein * 1348360efbdSAlfred Perlstein * It calls clnt_tp_create(); 13599064799SGarrett Wollman */ 1368360efbdSAlfred Perlstein CLIENT * 1378360efbdSAlfred Perlstein clnt_create(hostname, prog, vers, nettype) 1388360efbdSAlfred Perlstein const char *hostname; /* server name */ 1398360efbdSAlfred Perlstein rpcprog_t prog; /* program number */ 1408360efbdSAlfred Perlstein rpcvers_t vers; /* version number */ 1418360efbdSAlfred Perlstein const char *nettype; /* net type */ 1428360efbdSAlfred Perlstein { 1438360efbdSAlfred Perlstein struct netconfig *nconf; 1448360efbdSAlfred Perlstein CLIENT *clnt = NULL; 1458360efbdSAlfred Perlstein void *handle; 1468360efbdSAlfred Perlstein enum clnt_stat save_cf_stat = RPC_SUCCESS; 1478360efbdSAlfred Perlstein struct rpc_err save_cf_error; 1488360efbdSAlfred Perlstein 1498360efbdSAlfred Perlstein 1508360efbdSAlfred Perlstein if ((handle = __rpc_setconf(nettype)) == NULL) { 15199064799SGarrett Wollman rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 15299064799SGarrett Wollman return (NULL); 15399064799SGarrett Wollman } 1548360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_SUCCESS; 1558360efbdSAlfred Perlstein while (clnt == NULL) { 1568360efbdSAlfred Perlstein if ((nconf = __rpc_getconf(handle)) == NULL) { 1578360efbdSAlfred Perlstein if (rpc_createerr.cf_stat == RPC_SUCCESS) 1588360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 15999064799SGarrett Wollman break; 1608360efbdSAlfred Perlstein } 1618360efbdSAlfred Perlstein #ifdef CLNT_DEBUG 1628360efbdSAlfred Perlstein printf("trying netid %s\n", nconf->nc_netid); 1638360efbdSAlfred Perlstein #endif 1648360efbdSAlfred Perlstein clnt = clnt_tp_create(hostname, prog, vers, nconf); 1658360efbdSAlfred Perlstein if (clnt) 1668360efbdSAlfred Perlstein break; 1678360efbdSAlfred Perlstein else 1688360efbdSAlfred Perlstein /* 1698360efbdSAlfred Perlstein * Since we didn't get a name-to-address 1708360efbdSAlfred Perlstein * translation failure here, we remember 1718360efbdSAlfred Perlstein * this particular error. The object of 1728360efbdSAlfred Perlstein * this is to enable us to return to the 1738360efbdSAlfred Perlstein * caller a more-specific error than the 1748360efbdSAlfred Perlstein * unhelpful ``Name to address translation 1758360efbdSAlfred Perlstein * failed'' which might well occur if we 1768360efbdSAlfred Perlstein * merely returned the last error (because 1778360efbdSAlfred Perlstein * the local loopbacks are typically the 1788360efbdSAlfred Perlstein * last ones in /etc/netconfig and the most 1798360efbdSAlfred Perlstein * likely to be unable to translate a host 1808360efbdSAlfred Perlstein * name). 1818360efbdSAlfred Perlstein */ 1828360efbdSAlfred Perlstein if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE) { 1838360efbdSAlfred Perlstein save_cf_stat = rpc_createerr.cf_stat; 1848360efbdSAlfred Perlstein save_cf_error = rpc_createerr.cf_error; 1858360efbdSAlfred Perlstein } 1868360efbdSAlfred Perlstein } 1878360efbdSAlfred Perlstein 1888360efbdSAlfred Perlstein /* 1898360efbdSAlfred Perlstein * Attempt to return an error more specific than ``Name to address 1908360efbdSAlfred Perlstein * translation failed'' 1918360efbdSAlfred Perlstein */ 1928360efbdSAlfred Perlstein if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE) && 1938360efbdSAlfred Perlstein (save_cf_stat != RPC_SUCCESS)) { 1948360efbdSAlfred Perlstein rpc_createerr.cf_stat = save_cf_stat; 1958360efbdSAlfred Perlstein rpc_createerr.cf_error = save_cf_error; 1968360efbdSAlfred Perlstein } 1978360efbdSAlfred Perlstein __rpc_endconf(handle); 1988360efbdSAlfred Perlstein return (clnt); 1998360efbdSAlfred Perlstein } 2008360efbdSAlfred Perlstein 2018360efbdSAlfred Perlstein /* 2028360efbdSAlfred Perlstein * Generic client creation: takes (servers name, program-number, netconf) and 2038360efbdSAlfred Perlstein * returns client handle. Default options are set, which the user can 2048360efbdSAlfred Perlstein * change using the rpc equivalent of _ioctl()'s : clnt_control() 2058360efbdSAlfred Perlstein * It finds out the server address from rpcbind and calls clnt_tli_create() 2068360efbdSAlfred Perlstein */ 2078360efbdSAlfred Perlstein CLIENT * 2088360efbdSAlfred Perlstein clnt_tp_create(hostname, prog, vers, nconf) 2098360efbdSAlfred Perlstein const char *hostname; /* server name */ 2108360efbdSAlfred Perlstein rpcprog_t prog; /* program number */ 2118360efbdSAlfred Perlstein rpcvers_t vers; /* version number */ 2128360efbdSAlfred Perlstein const struct netconfig *nconf; /* net config struct */ 2138360efbdSAlfred Perlstein { 2148360efbdSAlfred Perlstein struct netbuf *svcaddr; /* servers address */ 2158360efbdSAlfred Perlstein CLIENT *cl = NULL; /* client handle */ 2168360efbdSAlfred Perlstein 2178360efbdSAlfred Perlstein if (nconf == NULL) { 2188360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 21999064799SGarrett Wollman return (NULL); 22099064799SGarrett Wollman } 2218360efbdSAlfred Perlstein 2228360efbdSAlfred Perlstein /* 2238360efbdSAlfred Perlstein * Get the address of the server 2248360efbdSAlfred Perlstein */ 2258360efbdSAlfred Perlstein if ((svcaddr = __rpcb_findaddr(prog, vers, nconf, hostname, 2268360efbdSAlfred Perlstein &cl)) == NULL) { 2278360efbdSAlfred Perlstein /* appropriate error number is set by rpcbind libraries */ 2288360efbdSAlfred Perlstein return (NULL); 2298360efbdSAlfred Perlstein } 2308360efbdSAlfred Perlstein if (cl == NULL) { 2318360efbdSAlfred Perlstein cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 2328360efbdSAlfred Perlstein prog, vers, 0, 0); 2338360efbdSAlfred Perlstein } else { 2348360efbdSAlfred Perlstein /* Reuse the CLIENT handle and change the appropriate fields */ 2358360efbdSAlfred Perlstein if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { 2368360efbdSAlfred Perlstein if (cl->cl_netid == NULL) 2378360efbdSAlfred Perlstein cl->cl_netid = strdup(nconf->nc_netid); 2388360efbdSAlfred Perlstein if (cl->cl_tp == NULL) 2398360efbdSAlfred Perlstein cl->cl_tp = strdup(nconf->nc_device); 2408360efbdSAlfred Perlstein (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); 2418360efbdSAlfred Perlstein (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); 2428360efbdSAlfred Perlstein } else { 2438360efbdSAlfred Perlstein CLNT_DESTROY(cl); 2448360efbdSAlfred Perlstein cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, 2458360efbdSAlfred Perlstein prog, vers, 0, 0); 2468360efbdSAlfred Perlstein } 2478360efbdSAlfred Perlstein } 2488360efbdSAlfred Perlstein free(svcaddr->buf); 2498360efbdSAlfred Perlstein free(svcaddr); 2508360efbdSAlfred Perlstein return (cl); 2518360efbdSAlfred Perlstein } 2528360efbdSAlfred Perlstein 2538360efbdSAlfred Perlstein /* 2548360efbdSAlfred Perlstein * Generic client creation: returns client handle. 2558360efbdSAlfred Perlstein * Default options are set, which the user can 2568360efbdSAlfred Perlstein * change using the rpc equivalent of _ioctl()'s : clnt_control(). 2578360efbdSAlfred Perlstein * If fd is RPC_ANYFD, it will be opened using nconf. 2588360efbdSAlfred Perlstein * It will be bound if not so. 2598360efbdSAlfred Perlstein * If sizes are 0; appropriate defaults will be chosen. 2608360efbdSAlfred Perlstein */ 2618360efbdSAlfred Perlstein CLIENT * 2628360efbdSAlfred Perlstein clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) 2638360efbdSAlfred Perlstein int fd; /* fd */ 2648360efbdSAlfred Perlstein const struct netconfig *nconf; /* netconfig structure */ 2658360efbdSAlfred Perlstein const struct netbuf *svcaddr; /* servers address */ 2668360efbdSAlfred Perlstein rpcprog_t prog; /* program number */ 2678360efbdSAlfred Perlstein rpcvers_t vers; /* version number */ 2688360efbdSAlfred Perlstein u_int sendsz; /* send size */ 2698360efbdSAlfred Perlstein u_int recvsz; /* recv size */ 2708360efbdSAlfred Perlstein { 2718360efbdSAlfred Perlstein CLIENT *cl; /* client handle */ 2728360efbdSAlfred Perlstein bool_t madefd = FALSE; /* whether fd opened here */ 2738360efbdSAlfred Perlstein long servtype; 2748360efbdSAlfred Perlstein int one = 1; 2758360efbdSAlfred Perlstein struct __rpc_sockinfo si; 2768360efbdSAlfred Perlstein 2778360efbdSAlfred Perlstein if (fd == RPC_ANYFD) { 2788360efbdSAlfred Perlstein if (nconf == NULL) { 2798360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 2808360efbdSAlfred Perlstein return (NULL); 2818360efbdSAlfred Perlstein } 2828360efbdSAlfred Perlstein 2838360efbdSAlfred Perlstein fd = __rpc_nconf2fd(nconf); 2848360efbdSAlfred Perlstein 2858360efbdSAlfred Perlstein if (fd == -1) 2868360efbdSAlfred Perlstein goto err; 2878360efbdSAlfred Perlstein 2888360efbdSAlfred Perlstein madefd = TRUE; 2898360efbdSAlfred Perlstein servtype = nconf->nc_semantics; 2908360efbdSAlfred Perlstein if (!__rpc_fd2sockinfo(fd, &si)) 2918360efbdSAlfred Perlstein goto err; 2928360efbdSAlfred Perlstein 2938360efbdSAlfred Perlstein bindresvport(fd, NULL); 2948360efbdSAlfred Perlstein } else { 2958360efbdSAlfred Perlstein if (!__rpc_fd2sockinfo(fd, &si)) 2968360efbdSAlfred Perlstein goto err; 2978360efbdSAlfred Perlstein servtype = __rpc_socktype2seman(si.si_socktype); 2988360efbdSAlfred Perlstein if (servtype == -1) { 2998360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; 3008360efbdSAlfred Perlstein return NULL; 3018360efbdSAlfred Perlstein } 3028360efbdSAlfred Perlstein 3038360efbdSAlfred Perlstein } 3048360efbdSAlfred Perlstein 3058360efbdSAlfred Perlstein if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { 3068360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ 3078360efbdSAlfred Perlstein goto err1; 3088360efbdSAlfred Perlstein } 3098360efbdSAlfred Perlstein 3108360efbdSAlfred Perlstein switch (servtype) { 3118360efbdSAlfred Perlstein case NC_TPI_COTS_ORD: 3128360efbdSAlfred Perlstein cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); 3138360efbdSAlfred Perlstein if (!nconf || !cl) 3148360efbdSAlfred Perlstein break; 3158360efbdSAlfred Perlstein /* XXX fvdl - is this useful? */ 3168360efbdSAlfred Perlstein if (strncmp(nconf->nc_protofmly, "inet", 4) == 0) 3178360efbdSAlfred Perlstein _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, 3188360efbdSAlfred Perlstein sizeof (one)); 3198360efbdSAlfred Perlstein break; 3208360efbdSAlfred Perlstein case NC_TPI_CLTS: 3218360efbdSAlfred Perlstein cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); 32299064799SGarrett Wollman break; 32399064799SGarrett Wollman default: 3248360efbdSAlfred Perlstein goto err; 32599064799SGarrett Wollman } 3268360efbdSAlfred Perlstein 3278360efbdSAlfred Perlstein if (cl == NULL) 3288360efbdSAlfred Perlstein goto err1; /* borrow errors from clnt_dg/vc creates */ 3298360efbdSAlfred Perlstein if (nconf) { 3308360efbdSAlfred Perlstein cl->cl_netid = strdup(nconf->nc_netid); 3318360efbdSAlfred Perlstein cl->cl_tp = strdup(nconf->nc_device); 3328360efbdSAlfred Perlstein } else { 3338360efbdSAlfred Perlstein cl->cl_netid = ""; 3348360efbdSAlfred Perlstein cl->cl_tp = ""; 3358360efbdSAlfred Perlstein } 3368360efbdSAlfred Perlstein if (madefd) { 3378360efbdSAlfred Perlstein (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); 3388360efbdSAlfred Perlstein /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, (char *) NULL); */ 3398360efbdSAlfred Perlstein }; 3408360efbdSAlfred Perlstein 3418360efbdSAlfred Perlstein return (cl); 3428360efbdSAlfred Perlstein 3438360efbdSAlfred Perlstein err: 3448360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_SYSTEMERROR; 3458360efbdSAlfred Perlstein rpc_createerr.cf_error.re_errno = errno; 3468360efbdSAlfred Perlstein err1: if (madefd) 3478360efbdSAlfred Perlstein (void)_close(fd); 3488360efbdSAlfred Perlstein return (NULL); 34999064799SGarrett Wollman } 350