The file ypclnt.c in the glibc-2.1 distribution has a file descriptor leak. In particular, if ypbind is called prior to any other NIS calls (except ypunbind), each subsequent call will leave a UDP connection open. This is because ypbind caches the connection, but the subsequent calls overwrite it with a new one each time. If you don't call ypbind first, there is no problem. A patch which fixes the trouble is at the end of this message. The problem also exists in RedHat 6.0, and probably other versions. (note that this bug was also submitted by email. Sorry if I created a duplicate) The following C program demonstrates the problem. /*****************************************************************/ #include <errno.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <rpc/rpc.h> #include <rpcsvc/nis.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> #include <rpcsvc/ypupd.h> #include <sys/stat.h> #include <sys/uio.h> #include <bits/libc-lock.h> main () { char domain[YPMAXDOMAIN]; unsigned int order; int yp_order_result; int i; #define NUMCHECKS 10 char *master; char *mapname = "services.byname"; unsigned char openfile[5*NUMCHECKS]; int fd; struct stat fdstat; char **mapkey; int mapkeylen[NUMCHECKS]; char *mapval; int mapvallen; mapkey = (char **)malloc(NUMCHECKS*(sizeof(char *))); for (fd=0; fd<5*NUMCHECKS; fd++) { if (fstat(fd, &fdstat) == 0) { openfile[fd] = 1; } else { openfile[fd] = 0; } } if (getdomainname(domain, sizeof(domain)) < 0) { fprintf(stderr,"NIS not running\n"); exit(1); } if ( yp_bind(domain) ) { fprintf(stderr,"cant bind to domain %s\n"); exit(1); } for (fd=0; fd<5*NUMCHECKS; fd++) { if (!openfile[fd] && fstat(fd, &fdstat) == 0) { printf("fd %d left open by ypbind (this is to be expected)\n",fd); openfile[fd] = 1; } } yp_order(domain, mapname, &order); for (fd=0; fd<5*NUMCHECKS; fd++) { if (!openfile[fd] && fstat(fd, &fdstat) == 0) { printf("fd %d left open by yp_order\n", fd); openfile[fd] = 1; } } yp_first(domain, mapname, mapkey, mapkeylen, &mapval, &mapvallen); for (fd=0; fd<5*NUMCHECKS; fd++) { if (!openfile[fd] && fstat(fd, &fdstat) == 0) { printf("fd %d left open by yp_first\n",fd); openfile[fd] = 1; } } for (i=1; i<NUMCHECKS; i++) { if (YPERR_NOMORE == yp_next(domain, mapname, mapkey[i-1], mapkeylen[i-1], &(mapkey[i]), &(mapkeylen[i]), &mapval, &mapvallen)) break; } for (fd=0; fd<5*NUMCHECKS; fd++) { if (!openfile[fd] && fstat(fd, &fdstat) == 0) { printf("fd %d left open by yp_next\n",fd); openfile[fd] = 1; } } } /*****************************************************************/ Solution: A patch which remedies the problem is below. It also fixes a typo in a comment (exits was written as exists, which was worse than no comment!) nesconset <nis> diff -c2 ypclnt.c.orig ypclnt.c *** glibc-2.1/nis/ypclnt.c.orig Wed Jun 30 11:59:21 1999 --- glibc-2.1/nis/ypclnt.c Wed Dec 8 10:12:32 1999 *************** *** 202,208 **** } ! ysd->dom_socket = RPC_ANYSOCK; ! ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS, ! UDPTIMEOUT, &ysd->dom_socket); if (ysd->dom_client == NULL) ysd->dom_vers = -1; --- 202,212 ---- } ! /* if we don't already have a socket from a previous call, get one */ ! if ( ysd->dom_socket < 1 ) { ! ysd->dom_socket = RPC_ANYSOCK; ! ysd->dom_client = clntudp_create (&ysd->dom_server_addr, ! YPPROG, YPVERS, UDPTIMEOUT, ! &ysd->dom_socket); ! } if (ysd->dom_client == NULL) ysd->dom_vers = -1; *************** *** 211,215 **** while (ysd->dom_client == NULL); ! /* If the program exists, close the socket */ if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1) perror ("fcntl: F_SETFD"); --- 215,219 ---- while (ysd->dom_client == NULL); ! /* If the program exits, close the socket */ if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1) perror ("fcntl: F_SETFD");
This problem appears to be resolved (ypc.c is the test program above, run on ultrasparc): bash$ cc ypc.c -o ypc -lnsl bash$ ./ypc fd 4 left open by ypbind (this is to be expected) bash$ rpm -qf /usr/lib/libnsl.a glibc-devel-2.1.3-15