]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
mount.nfs: getport() should avoid modifying passed-in arguments
[nfs-utils.git] / utils / mount / network.c
1 /*
2  * network.c -- Provide common network functions for NFS mount/umount
3  *
4  * Copyright (C) 2007 Oracle.  All rights reserved.
5  * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 021110-1307, USA.
21  *
22  */
23
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <time.h>
32 #include <rpc/rpc.h>
33 #include <rpc/pmap_prot.h>
34 #include <rpc/pmap_clnt.h>
35 #include <sys/socket.h>
36
37 #include "xcommon.h"
38 #include "mount.h"
39 #include "nls.h"
40 #include "nfs_mount.h"
41 #include "mount_constants.h"
42 #include "network.h"
43
44 #ifdef HAVE_RPCSVC_NFS_PROT_H
45 #include <rpcsvc/nfs_prot.h>
46 #else
47 #include <linux/nfs.h>
48 #define nfsstat nfs_stat
49 #endif
50
51 #ifndef NFS_PORT
52 #define NFS_PORT 2049
53 #endif
54
55 #define PMAP_TIMEOUT    (10)
56 #define CONNECT_TIMEOUT (20)
57 #define MOUNT_TIMEOUT   (30)
58
59 #if SIZEOF_SOCKLEN_T - 0 == 0
60 #define socklen_t unsigned int
61 #endif
62
63 extern int nfs_mount_data_version;
64 extern char *progname;
65 extern int verbose;
66
67 static const unsigned long nfs_to_mnt[] = {
68         0,
69         0,
70         1,
71         3,
72 };
73
74 static const unsigned long mnt_to_nfs[] = {
75         0,
76         2,
77         2,
78         3,
79 };
80
81 /*
82  * Map an NFS version into the corresponding Mountd version
83  */
84 unsigned long nfsvers_to_mnt(const unsigned long vers)
85 {
86         if (vers <= 3)
87                 return nfs_to_mnt[vers];
88         return 0;
89 }
90
91 /*
92  * Map a Mountd version into the corresponding NFS version
93  */
94 static unsigned long mntvers_to_nfs(const unsigned long vers)
95 {
96         if (vers <= 3)
97                 return mnt_to_nfs[vers];
98         return 0;
99 }
100
101 static const unsigned int probe_udp_only[] = {
102         IPPROTO_UDP,
103         0,
104 };
105
106 static const unsigned int probe_udp_first[] = {
107         IPPROTO_UDP,
108         IPPROTO_TCP,
109         0,
110 };
111
112 static const unsigned int probe_tcp_first[] = {
113         IPPROTO_TCP,
114         IPPROTO_UDP,
115         0,
116 };
117
118 static const unsigned long probe_nfs2_only[] = {
119         2,
120         0,
121 };
122
123 static const unsigned long probe_nfs3_first[] = {
124         3,
125         2,
126         0,
127 };
128
129 static const unsigned long probe_mnt1_first[] = {
130         1,
131         2,
132         0,
133 };
134
135 static const unsigned long probe_mnt3_first[] = {
136         3,
137         1,
138         2,
139         0,
140 };
141
142 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
143 {
144         struct hostent *hp;
145
146         saddr->sin_family = AF_INET;
147         if (!inet_aton(hostname, &saddr->sin_addr)) {
148                 if ((hp = gethostbyname(hostname)) == NULL) {
149                         nfs_error(_("%s: can't get address for %s\n"),
150                                         progname, hostname);
151                         return 0;
152                 } else {
153                         if (hp->h_length > sizeof(*saddr)) {
154                                 nfs_error(_("%s: got bad hp->h_length\n"),
155                                                 progname);
156                                 hp->h_length = sizeof(*saddr);
157                         }
158                         memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
159                 }
160         }
161         return 1;
162 }
163
164 /*
165  * Attempt to connect a socket, but time out after "timeout" seconds.
166  *
167  * On error return, caller closes the socket.
168  */
169 static int connect_to(int fd, struct sockaddr *addr,
170                         socklen_t addrlen, int timeout)
171 {
172         int ret, saved;
173         fd_set rset, wset;
174         struct timeval tv = {
175                 .tv_sec = timeout,
176         };
177
178         saved = fcntl(fd, F_GETFL, 0);
179         fcntl(fd, F_SETFL, saved | O_NONBLOCK);
180
181         ret = connect(fd, addr, addrlen);
182         if (ret < 0 && errno != EINPROGRESS)
183                 return -1;
184         if (ret == 0)
185                 goto out;
186
187         FD_ZERO(&rset);
188         FD_SET(fd, &rset);
189         wset = rset;
190         ret = select(fd + 1, &rset, &wset, NULL, &tv);
191         if (ret == 0) {
192                 errno = ETIMEDOUT;
193                 return -1;
194         }
195         if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
196                 int error;
197                 socklen_t len = sizeof(error);
198                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
199                         return -1;
200                 if (error) {
201                         errno = error;
202                         return -1;
203                 }
204         } else
205                 return -1;
206
207 out:
208         fcntl(fd, F_SETFL, saved);
209         return 0;
210 }
211
212 /*
213  * Create a socket that is locally bound to a reserved or non-reserved port.
214  *
215  * The caller should check rpc_createerr to determine the cause of any error.
216  */
217 static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot,
218                         unsigned int timeout, int resvp, int conn)
219 {
220         int so, cc, type;
221         struct sockaddr_in laddr;
222         socklen_t namelen = sizeof(laddr);
223
224         type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
225         if ((so = socket (AF_INET, type, p_prot)) < 0)
226                 goto err_socket;
227
228         laddr.sin_family = AF_INET;
229         laddr.sin_port = 0;
230         laddr.sin_addr.s_addr = htonl(INADDR_ANY);
231         if (resvp) {
232                 if (bindresvport(so, &laddr) < 0)
233                         goto err_bindresvport;
234         } else {
235                 cc = bind(so, (struct sockaddr *)&laddr, namelen);
236                 if (cc < 0)
237                         goto err_bind;
238         }
239         if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
240                 cc = connect_to(so, (struct sockaddr *)saddr, namelen,
241                                 timeout);
242                 if (cc < 0)
243                         goto err_connect;
244         }
245         return so;
246
247 err_socket:
248         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
249         rpc_createerr.cf_error.re_errno = errno;
250         if (verbose) {
251                 nfs_error(_("%s: Unable to create %s socket: errno %d (%s)\n"),
252                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
253                         errno, strerror(errno));
254         }
255         return RPC_ANYSOCK;
256
257 err_bindresvport:
258         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
259         rpc_createerr.cf_error.re_errno = errno;
260         if (verbose) {
261                 nfs_error(_("%s: Unable to bindresvport %s socket: errno %d"
262                                 " (%s)\n"),
263                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
264                         errno, strerror(errno));
265         }
266         close(so);
267         return RPC_ANYSOCK;
268
269 err_bind:
270         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
271         rpc_createerr.cf_error.re_errno = errno;
272         if (verbose) {
273                 nfs_error(_("%s: Unable to bind to %s socket: errno %d (%s)\n"),
274                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
275                         errno, strerror(errno));
276         }
277         close(so);
278         return RPC_ANYSOCK;
279
280 err_connect:
281         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
282         rpc_createerr.cf_error.re_errno = errno;
283         if (verbose) {
284                 nfs_error(_("%s: Unable to connect to %s:%d, errno %d (%s)\n"),
285                         progname, inet_ntoa(saddr->sin_addr),
286                         ntohs(saddr->sin_port), errno, strerror(errno));
287         }
288         close(so);
289         return RPC_ANYSOCK;
290 }
291
292 /*
293  * getport() is very similar to pmap_getport() with the exception that
294  * this version tries to use an ephemeral port, since reserved ports are
295  * not needed for GETPORT queries.  This conserves the very limited
296  * reserved port space, which helps reduce failed socket binds
297  * during mount storms.
298  *
299  * A side effect of calling this function is that rpccreateerr is set.
300  */
301 static unsigned short getport(struct sockaddr_in *saddr,
302                                 unsigned long program,
303                                 unsigned long version,
304                                 unsigned int proto)
305 {
306         struct sockaddr_in bind_saddr;
307         unsigned short port = 0;
308         int socket;
309         CLIENT *clnt = NULL;
310         enum clnt_stat stat;
311  
312         bind_saddr = *saddr;
313         bind_saddr.sin_port = htons(PMAPPORT);
314
315         socket = get_socket(&bind_saddr, proto, PMAP_TIMEOUT, FALSE, FALSE);
316         if (socket == RPC_ANYSOCK) {
317                 if (proto == IPPROTO_TCP &&
318                     rpc_createerr.cf_error.re_errno == ETIMEDOUT)
319                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
320                 return 0;
321         }
322
323         switch (proto) {
324         case IPPROTO_UDP:
325                 clnt = clntudp_bufcreate(&bind_saddr,
326                                          PMAPPROG, PMAPVERS,
327                                          RETRY_TIMEOUT, &socket,
328                                          RPCSMALLMSGSIZE,
329                                          RPCSMALLMSGSIZE);
330                 break;
331         case IPPROTO_TCP:
332                 clnt = clnttcp_create(&bind_saddr,
333                                       PMAPPROG, PMAPVERS,
334                                       &socket,
335                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
336                 break;
337         }
338         if (clnt != NULL) {
339                 struct pmap parms = {
340                         .pm_prog        = program,
341                         .pm_vers        = version,
342                         .pm_prot        = proto,
343                 };
344
345                 stat = clnt_call(clnt, PMAPPROC_GETPORT,
346                                  (xdrproc_t)xdr_pmap, (caddr_t)&parms,
347                                  (xdrproc_t)xdr_u_short, (caddr_t)&port,
348                                  TIMEOUT);
349                 if (stat) {
350                         clnt_geterr(clnt, &rpc_createerr.cf_error);
351                         rpc_createerr.cf_stat = stat;
352                 }
353                 clnt_destroy(clnt);
354                 if (stat != RPC_SUCCESS)
355                         port = 0;
356                 else if (port == 0)
357                         rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
358         }
359         close(socket);
360
361         return port;
362 }
363
364 /*
365  * Use the portmapper to discover whether or not the service we want is
366  * available. The lists 'versions' and 'protos' define ordered sequences
367  * of service versions and udp/tcp protocols to probe for.
368  */
369 static int probe_port(clnt_addr_t *server, const unsigned long *versions,
370                         const unsigned int *protos)
371 {
372         struct sockaddr_in *saddr = &server->saddr;
373         struct pmap *pmap = &server->pmap;
374         const unsigned long prog = pmap->pm_prog, *p_vers;
375         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
376         const u_short port = (u_short) pmap->pm_port;
377         unsigned long vers = pmap->pm_vers;
378         unsigned short p_port;
379
380         p_prot = prot ? &prot : protos;
381         p_vers = vers ? &vers : versions;
382         rpc_createerr.cf_stat = 0;
383         for (;;) {
384                 p_port = getport(saddr, prog, *p_vers, *p_prot);
385                 if (p_port) {
386                         if (!port || port == p_port) {
387                                 saddr->sin_port = htons(p_port);
388                                 if (verbose) {
389                                         printf(_("%s: trying %s prog %ld vers "
390                                                 "%ld prot %s port %d\n"),
391                                                 progname,
392                                                 inet_ntoa(saddr->sin_addr),
393                                                 prog, *p_vers,
394                                                 *p_prot == IPPROTO_UDP ?
395                                                         _("UDP") : _("TCP"),
396                                                 p_port);
397                                 }
398                                 if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
399                                         goto out_ok;
400                                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
401                                         goto out_bad;
402                         }
403                 }
404                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
405                         goto out_bad;
406
407                 if (!prot) {
408                         if (*++p_prot)
409                                 continue;
410                         p_prot = protos;
411                 }
412                 if (vers == pmap->pm_vers) {
413                         p_vers = versions;
414                         vers = 0;
415                 }
416                 if (vers || !*++p_vers)
417                         break;
418         }
419
420 out_bad:
421         return 0;
422
423 out_ok:
424         if (!vers)
425                 pmap->pm_vers = *p_vers;
426         if (!prot)
427                 pmap->pm_prot = *p_prot;
428         if (!port)
429                 pmap->pm_port = p_port;
430         rpc_createerr.cf_stat = 0;
431         return 1;
432 }
433
434 static int probe_nfsport(clnt_addr_t *nfs_server)
435 {
436         struct pmap *pmap = &nfs_server->pmap;
437
438         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
439                 return 1;
440
441         if (nfs_mount_data_version >= 4)
442                 return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
443         else
444                 return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
445 }
446
447 static int probe_mntport(clnt_addr_t *mnt_server)
448 {
449         struct pmap *pmap = &mnt_server->pmap;
450
451         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
452                 return 1;
453
454         if (nfs_mount_data_version >= 4)
455                 return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
456         else
457                 return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
458 }
459
460 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
461 {
462         struct pmap *nfs_pmap = &nfs_server->pmap;
463         struct pmap *mnt_pmap = &mnt_server->pmap;
464         struct pmap save_nfs, save_mnt;
465         int res;
466         const unsigned long *probe_vers;
467
468         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
469                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
470         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
471                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
472         if (nfs_pmap->pm_vers)
473                 goto version_fixed;
474
475         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
476         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
477         probe_vers = (nfs_mount_data_version >= 4) ?
478                         probe_mnt3_first : probe_mnt1_first;
479
480         for (; *probe_vers; probe_vers++) {
481                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
482                 if ((res = probe_nfsport(nfs_server) != 0)) {
483                         mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
484                         if ((res = probe_mntport(mnt_server)) != 0)
485                                 return 1;
486                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
487                 }
488                 switch (rpc_createerr.cf_stat) {
489                 case RPC_PROGVERSMISMATCH:
490                 case RPC_PROGNOTREGISTERED:
491                         break;
492                 default:
493                         goto out_bad;
494                 }
495                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
496         }
497
498 out_bad:
499         return 0;
500
501 version_fixed:
502         if (!probe_nfsport(nfs_server))
503                 goto out_bad;
504         return probe_mntport(mnt_server);
505 }
506
507 static int probe_statd(void)
508 {
509         struct sockaddr_in addr;
510         unsigned short port;
511
512         memset(&addr, 0, sizeof(addr));
513         addr.sin_family = AF_INET;
514         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
515         port = getport(&addr, 100024, 1, IPPROTO_UDP);
516
517         if (port == 0)
518                 return 0;
519         addr.sin_port = htons(port);
520
521         if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
522                 return 0;
523
524         return 1;
525 }
526
527 /*
528  * Attempt to start rpc.statd
529  */
530 int start_statd(void)
531 {
532 #ifdef START_STATD
533         struct stat stb;
534 #endif
535
536         if (probe_statd())
537                 return 1;
538
539 #ifdef START_STATD
540         if (stat(START_STATD, &stb) == 0) {
541                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
542                         system(START_STATD);
543                         if (probe_statd())
544                                 return 1;
545                 }
546         }
547 #endif
548
549         return 0;
550 }
551
552 /*
553  * nfs_call_umount - ask the server to remove a share from it's rmtab
554  * @mnt_server: address of RPC MNT program server
555  * @argp: directory path of share to "unmount"
556  *
557  * Returns one if the unmount call succeeded; zero if the unmount
558  * failed for any reason.
559  *
560  * Note that a side effect of calling this function is that rpccreateerr
561  * is set.
562  */
563 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
564 {
565         CLIENT *clnt;
566         enum clnt_stat res = 0;
567         int msock;
568
569         switch (mnt_server->pmap.pm_vers) {
570         case 3:
571         case 2:
572         case 1:
573                 if (!probe_mntport(mnt_server))
574                         return 0;
575                 clnt = mnt_openclnt(mnt_server, &msock);
576                 if (!clnt)
577                         return 0;
578                 res = clnt_call(clnt, MOUNTPROC_UMNT,
579                                 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
580                                 (xdrproc_t)xdr_void, NULL,
581                                 TIMEOUT);
582                 mnt_closeclnt(clnt, msock);
583                 if (res == RPC_SUCCESS)
584                         return 1;
585                 break;
586         default:
587                 res = RPC_SUCCESS;
588                 break;
589         }
590
591         if (res == RPC_SUCCESS)
592                 return 1;
593         return 0;
594 }
595
596 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
597 {
598         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
599         struct pmap *mnt_pmap = &mnt_server->pmap;
600         CLIENT *clnt = NULL;
601
602         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
603         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
604                                 TRUE, FALSE);
605         if (*msock == RPC_ANYSOCK) {
606                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
607                         /*
608                          * Probably in-use by a TIME_WAIT connection,
609                          * It is worth waiting a while and trying again.
610                          */
611                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
612                 return NULL;
613         }
614
615         switch (mnt_pmap->pm_prot) {
616         case IPPROTO_UDP:
617                 clnt = clntudp_bufcreate(mnt_saddr,
618                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
619                                          RETRY_TIMEOUT, msock,
620                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
621                 break;
622         case IPPROTO_TCP:
623                 clnt = clnttcp_create(mnt_saddr,
624                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
625                                       msock,
626                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
627                 break;
628         }
629         if (clnt) {
630                 /* try to mount hostname:dirname */
631                 clnt->cl_auth = authunix_create_default();
632                 return clnt;
633         }
634         return NULL;
635 }
636
637 void mnt_closeclnt(CLIENT *clnt, int msock)
638 {
639         auth_destroy(clnt->cl_auth);
640         clnt_destroy(clnt);
641         close(msock);
642 }
643
644 /*
645  * Sigh... getport() doesn't actually check the version number.
646  * In order to make sure that the server actually supports the service
647  * we're requesting, we open and RPC client, and fire off a NULL
648  * RPC call.
649  */
650 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
651                 const unsigned long vers, const unsigned int prot,
652                 struct sockaddr_in *caddr)
653 {
654         CLIENT *clnt = NULL;
655         int sock, stat;
656         static char clnt_res;
657         struct sockaddr dissolve;
658
659         rpc_createerr.cf_stat = stat = 0;
660         sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
661         if (sock == RPC_ANYSOCK) {
662                 if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) {
663                         /*
664                          * TCP timeout. Bubble up the error to see 
665                          * how it should be handled.
666                          */
667                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
668                 }
669                 return 0;
670         }
671
672         if (caddr) {
673                 /* Get the address of our end of this connection */
674                 socklen_t len = sizeof(*caddr);
675                 if (getsockname(sock, caddr, &len) != 0)
676                         caddr->sin_family = 0;
677         }
678
679         switch(prot) {
680         case IPPROTO_UDP:
681                 /* The socket is connected (so we could getsockname successfully),
682                  * but some servers on multi-homed hosts reply from
683                  * the wrong address, so if we stay connected, we lose the reply.
684                  */
685                 dissolve.sa_family = AF_UNSPEC;
686                 connect(sock, &dissolve, sizeof(dissolve));
687
688                 clnt = clntudp_bufcreate(saddr, prog, vers,
689                                          RETRY_TIMEOUT, &sock,
690                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
691                 break;
692         case IPPROTO_TCP:
693                 clnt = clnttcp_create(saddr, prog, vers, &sock,
694                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
695                 break;
696         }
697         if (!clnt) {
698                 close(sock);
699                 return 0;
700         }
701         memset(&clnt_res, 0, sizeof(clnt_res));
702         stat = clnt_call(clnt, NULLPROC,
703                          (xdrproc_t)xdr_void, (caddr_t)NULL,
704                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
705                          TIMEOUT);
706         if (stat) {
707                 clnt_geterr(clnt, &rpc_createerr.cf_error);
708                 rpc_createerr.cf_stat = stat;
709         }
710         clnt_destroy(clnt);
711         close(sock);
712
713         if (stat == RPC_SUCCESS)
714                 return 1;
715         else
716                 return 0;
717 }