~ubuntu-branches/ubuntu/precise/autofs5/precise

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-fix-rpc-large-export-list.patch/lib/rpc_subs.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2011-07-03 14:35:46 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110703143546-nej26krjij0rf792
Tags: 5.0.6-0ubuntu1
* New upstream release:
  - Dropped upstream patches 
  - Refreshed debian/patches/17ld.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ----------------------------------------------------------------------- *
2
 
 *   
3
 
 *  rpc_subs.c - routines for rpc discovery
4
 
 *
5
 
 *   Copyright 2004 Ian Kent <raven@themaw.net> - All Rights Reserved
6
 
 *   Copyright 2004 Jeff Moyer <jmoyer@redaht.com> - All Rights Reserved
7
 
 *
8
 
 *   This program is free software; you can redistribute it and/or modify
9
 
 *   it under the terms of the GNU General Public License as published by
10
 
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
11
 
 *   USA; either version 2 of the License, or (at your option) any later
12
 
 *   version; incorporated herein by reference.
13
 
 *
14
 
 * ----------------------------------------------------------------------- */
15
 
 
16
 
#ifndef _GNU_SOURCE
17
 
#define _GNU_SOURCE
18
 
#endif
19
 
 
20
 
#include "config.h"
21
 
 
22
 
#include <rpc/types.h>
23
 
#include <rpc/rpc.h>
24
 
#include <rpc/pmap_prot.h>
25
 
#include <sys/socket.h>
26
 
#include <netdb.h>
27
 
#include <net/if.h>
28
 
#include <netinet/in.h>
29
 
#include <arpa/inet.h>
30
 
#include <rpcsvc/ypclnt.h>
31
 
#include <errno.h>
32
 
#include <sys/ioctl.h>
33
 
#include <ctype.h>
34
 
#include <pthread.h>
35
 
#include <poll.h>
36
 
 
37
 
#include "mount.h"
38
 
#include "rpc_subs.h"
39
 
#include "automount.h"
40
 
 
41
 
/* #define STANDALONE */
42
 
#ifdef STANDALONE
43
 
#define error(logopt, msg, args...)     fprintf(stderr, msg "\n", ##args)
44
 
#else
45
 
#include "log.h"
46
 
#endif
47
 
 
48
 
#define MAX_IFC_BUF     1024
49
 
#define MAX_ERR_BUF     128
50
 
 
51
 
#define MAX_NETWORK_LEN         255
52
 
 
53
 
/* Get numeric value of the n bits starting at position p */
54
 
#define getbits(x, p, n)      ((x >> (p + 1 - n)) & ~(~0 << n))
55
 
 
56
 
inline void dump_core(void);
57
 
 
58
 
static CLIENT *rpc_clntudp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
59
 
{
60
 
        struct sockaddr_in *in4_raddr;
61
 
        struct sockaddr_in6 *in6_raddr;
62
 
        CLIENT *client = NULL;
63
 
 
64
 
        switch (addr->sa_family) {
65
 
        case AF_INET:
66
 
                in4_raddr = (struct sockaddr_in *) addr;
67
 
                in4_raddr->sin_port = htons(info->port);
68
 
                client = clntudp_bufcreate(in4_raddr,
69
 
                                           info->program, info->version,
70
 
                                           info->timeout, fd,
71
 
                                           info->send_sz, info->recv_sz);
72
 
                break;
73
 
 
74
 
        case AF_INET6:
75
 
#ifndef INET6
76
 
                /* Quiet compile warning */
77
 
                in6_raddr = NULL;
78
 
#else
79
 
                in6_raddr = (struct sockaddr_in6 *) addr;
80
 
                in6_raddr->sin6_port = htons(info->port);
81
 
                client = clntudp6_bufcreate(in6_raddr,
82
 
                                            info->program, info->version,
83
 
                                            info->timeout, fd,
84
 
                                            info->send_sz, info->recv_sz);
85
 
#endif
86
 
                break;
87
 
 
88
 
        default:
89
 
                break;
90
 
        }
91
 
 
92
 
        return client;
93
 
}
94
 
 
95
 
static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
96
 
{
97
 
        struct sockaddr_in *in4_raddr;
98
 
        struct sockaddr_in6 *in6_raddr;
99
 
        CLIENT *client = NULL;
100
 
 
101
 
        switch (addr->sa_family) {
102
 
        case AF_INET:
103
 
                in4_raddr = (struct sockaddr_in *) addr;
104
 
                in4_raddr->sin_port = htons(info->port);
105
 
                client = clnttcp_create(in4_raddr,
106
 
                                        info->program, info->version, fd,
107
 
                                        info->send_sz, info->recv_sz);
108
 
                break;
109
 
 
110
 
        case AF_INET6:
111
 
#ifndef INET6
112
 
                /* Quiet compile warning */
113
 
                in6_raddr = NULL;
114
 
#else
115
 
                in6_raddr = (struct sockaddr_in6 *) addr;
116
 
                in6_raddr->sin6_port = htons(info->port);
117
 
                client = clnttcp6_create(in6_raddr,
118
 
                                         info->program, info->version, fd,
119
 
                                         info->send_sz, info->recv_sz);
120
 
#endif
121
 
                break;
122
 
 
123
 
        default:
124
 
                break;
125
 
        }
126
 
 
127
 
        return client;
128
 
}
129
 
 
130
 
/*
131
 
 *  Perform a non-blocking connect on the socket fd.
132
 
 *
133
 
 *  The input struct timeval always has tv_nsec set to zero,
134
 
 *  we only ever use tv_sec for timeouts.
135
 
 */
136
 
static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, struct timeval *tout)
137
 
{
138
 
        struct pollfd pfd[1];
139
 
        int timeout = tout->tv_sec;
140
 
        int flags, ret;
141
 
 
142
 
        flags = fcntl(fd, F_GETFL, 0);
143
 
        if (flags < 0)
144
 
                return -1;
145
 
 
146
 
        ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
147
 
        if (ret < 0)
148
 
                return -1;
149
 
 
150
 
        /* 
151
 
         * From here on subsequent sys calls could change errno so
152
 
         * we set ret = -errno to capture it in case we decide to
153
 
         * use it later.
154
 
         */
155
 
        ret = connect(fd, addr, len);
156
 
        if (ret < 0 && errno != EINPROGRESS) {
157
 
                ret = -errno;
158
 
                goto done;
159
 
        }
160
 
 
161
 
        if (ret == 0)
162
 
                goto done;
163
 
 
164
 
        if (timeout != -1) {
165
 
                if (timeout >= (INT_MAX - 1)/1000)
166
 
                        timeout = INT_MAX - 1;
167
 
                else
168
 
                        timeout = timeout * 1000;
169
 
        }
170
 
 
171
 
        pfd[0].fd = fd;
172
 
        pfd[0].events = POLLOUT;
173
 
 
174
 
        ret = poll(pfd, 1, timeout);
175
 
        if (ret <= 0) {
176
 
                if (ret == 0)
177
 
                        ret = -ETIMEDOUT;
178
 
                else
179
 
                        ret = -errno;
180
 
                goto done;
181
 
        }
182
 
 
183
 
        if (pfd[0].revents) {
184
 
                int status;
185
 
 
186
 
                len = sizeof(ret);
187
 
                status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
188
 
                if (status < 0) {
189
 
                        char buf[MAX_ERR_BUF + 1];
190
 
                        char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
191
 
 
192
 
                        /*
193
 
                         * We assume getsockopt amounts to a read on the
194
 
                         * descriptor and gives us the errno we need for
195
 
                         * the POLLERR revent case.
196
 
                         */
197
 
                        ret = -errno;
198
 
 
199
 
                        /* Unexpected case, log it so we know we got caught */
200
 
                        if (pfd[0].revents & POLLNVAL)
201
 
                                logerr("unexpected poll(2) error on connect:"
202
 
                                       " %s", estr);
203
 
 
204
 
                        goto done;
205
 
                }
206
 
 
207
 
                /* Oops - something wrong with connect */
208
 
                if (ret)
209
 
                        ret = -ret;
210
 
        }
211
 
 
212
 
done:
213
 
        fcntl(fd, F_SETFL, flags);
214
 
        return ret;
215
 
}
216
 
 
217
 
static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd)
218
 
{
219
 
        CLIENT *client = NULL;
220
 
        struct sockaddr *laddr;
221
 
        struct sockaddr_in in4_laddr;
222
 
        struct sockaddr_in6 in6_laddr;
223
 
        int type, proto;
224
 
        socklen_t slen;
225
 
 
226
 
        proto = info->proto->p_proto;
227
 
        if (proto == IPPROTO_UDP)
228
 
                type = SOCK_DGRAM;
229
 
        else
230
 
                type = SOCK_STREAM;
231
 
 
232
 
        /*
233
 
         * bind to any unused port.  If we left this up to the rpc
234
 
         * layer, it would bind to a reserved port, which has been shown
235
 
         * to exhaust the reserved port range in some situations.
236
 
         */
237
 
        switch (addr->sa_family) {
238
 
        case AF_INET:
239
 
                in4_laddr.sin_family = AF_INET;
240
 
                in4_laddr.sin_port = htons(0);
241
 
                in4_laddr.sin_addr.s_addr = htonl(INADDR_ANY);
242
 
                slen = sizeof(struct sockaddr_in);
243
 
                laddr = (struct sockaddr *) &in4_laddr;
244
 
                break;
245
 
 
246
 
        case AF_INET6:
247
 
#ifndef INET6
248
 
                /* Quiet compiler */
249
 
                in6_laddr.sin6_family = AF_INET6;
250
 
                return NULL;
251
 
#else
252
 
                in6_laddr.sin6_family = AF_INET6;
253
 
                in6_laddr.sin6_port = htons(0);
254
 
                in6_laddr.sin6_addr = in6addr_any;
255
 
                slen = sizeof(struct sockaddr_in6);
256
 
                laddr = (struct sockaddr *) &in6_laddr;
257
 
                break;
258
 
#endif
259
 
        default:
260
 
                return NULL;
261
 
        }
262
 
 
263
 
        switch (info->proto->p_proto) {
264
 
        case IPPROTO_UDP:
265
 
                if (!info->client) {
266
 
                        *fd = open_sock(addr->sa_family, type, proto);
267
 
                        if (*fd < 0)
268
 
                                return NULL;
269
 
 
270
 
                        if (bind(*fd, laddr, slen) < 0) {
271
 
                                close(*fd);
272
 
                                return NULL;
273
 
                        }
274
 
                }
275
 
                client = rpc_clntudp_create(addr, info, fd);
276
 
                break;
277
 
 
278
 
        case IPPROTO_TCP:
279
 
                if (!info->client) {
280
 
                        *fd = open_sock(addr->sa_family, type, proto);
281
 
                        if (*fd < 0)
282
 
                                return NULL;
283
 
 
284
 
                        if (connect_nb(*fd, laddr, slen, &info->timeout) < 0) {
285
 
                                close(*fd);
286
 
                                return NULL;
287
 
                        }
288
 
                }
289
 
                client = rpc_clnttcp_create(addr, info, fd);
290
 
                break;
291
 
 
292
 
        default:
293
 
                break;
294
 
        }
295
 
 
296
 
        return client;
297
 
}
298
 
 
299
 
/*
300
 
 * Create a UDP RPC client
301
 
 */
302
 
static CLIENT *create_udp_client(struct conn_info *info)
303
 
{
304
 
        CLIENT *client = NULL;
305
 
        struct addrinfo *ai, *haddr;
306
 
        struct addrinfo hints;
307
 
        int fd, ret;
308
 
 
309
 
        if (info->proto->p_proto != IPPROTO_UDP)
310
 
                return NULL;
311
 
 
312
 
        fd = RPC_ANYSOCK;
313
 
 
314
 
        if (info->client) {
315
 
                if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
316
 
                        fd = RPC_ANYSOCK;
317
 
                        clnt_destroy(info->client);
318
 
                        info->client = NULL;
319
 
                } else {
320
 
                        clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
321
 
                        clnt_destroy(info->client);
322
 
                }
323
 
        }
324
 
 
325
 
        if (info->addr) {
326
 
                client = rpc_do_create_client(info->addr, info, &fd);
327
 
                if (client)
328
 
                        goto done;
329
 
 
330
 
                if (!info->client) {
331
 
                        close(fd);
332
 
                        fd = RPC_ANYSOCK;
333
 
                }
334
 
        }
335
 
 
336
 
        memset(&hints, 0, sizeof(hints));
337
 
        hints.ai_flags = AI_ADDRCONFIG;
338
 
        hints.ai_family = AF_UNSPEC;
339
 
        hints.ai_socktype = SOCK_DGRAM;
340
 
 
341
 
        ret = getaddrinfo(info->host, NULL, &hints, &ai);
342
 
        if (ret) {
343
 
                error(LOGOPT_ANY,
344
 
                      "hostname lookup failed: %s", gai_strerror(ret));
345
 
                info->client = NULL;
346
 
                goto out_close;
347
 
        }
348
 
 
349
 
        haddr = ai;
350
 
        while (haddr) {
351
 
                client = rpc_do_create_client(haddr->ai_addr, info, &fd);
352
 
                if (client)
353
 
                        break;
354
 
 
355
 
                if (!info->client) {
356
 
                        close(fd);
357
 
                        fd = RPC_ANYSOCK;
358
 
                }
359
 
 
360
 
                haddr = haddr->ai_next;
361
 
        }
362
 
 
363
 
        freeaddrinfo(ai);
364
 
 
365
 
        if (!client) {
366
 
                info->client = NULL;
367
 
                goto out_close;
368
 
        }
369
 
done:
370
 
        /* Close socket fd on destroy, as is default for rpcowned fds */
371
 
        if  (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
372
 
                clnt_destroy(client);
373
 
                info->client = NULL;
374
 
                goto out_close;
375
 
        }
376
 
 
377
 
        return client;
378
 
 
379
 
out_close:
380
 
        if (fd != -1)
381
 
                close(fd);
382
 
        return NULL;
383
 
}
384
 
 
385
 
int rpc_udp_getclient(struct conn_info *info,
386
 
                      unsigned int program, unsigned int version)
387
 
{
388
 
        struct protoent *pe_proto;
389
 
        CLIENT *client;
390
 
 
391
 
        if (!info->client) {
392
 
                pe_proto = getprotobyname("udp");
393
 
                if (!pe_proto)
394
 
                        return 0;
395
 
 
396
 
                info->proto = pe_proto;
397
 
                info->send_sz = UDPMSGSIZE;
398
 
                info->recv_sz = UDPMSGSIZE;
399
 
        }
400
 
 
401
 
        info->program = program;
402
 
        info->version = version;
403
 
 
404
 
        client = create_udp_client(info);
405
 
 
406
 
        if (!client)
407
 
                return 0;
408
 
 
409
 
        info->client = client;
410
 
 
411
 
        return 1;
412
 
}
413
 
 
414
 
void rpc_destroy_udp_client(struct conn_info *info)
415
 
{
416
 
        if (!info->client)
417
 
                return;
418
 
 
419
 
        clnt_destroy(info->client);
420
 
        info->client = NULL;
421
 
        return;
422
 
}
423
 
 
424
 
/*
425
 
 * Create a TCP RPC client using non-blocking connect
426
 
 */
427
 
static CLIENT *create_tcp_client(struct conn_info *info)
428
 
{
429
 
        CLIENT *client = NULL;
430
 
        struct addrinfo *ai, *haddr;
431
 
        struct addrinfo hints;
432
 
        int fd, ret;
433
 
 
434
 
        if (info->proto->p_proto != IPPROTO_TCP)
435
 
                return NULL;
436
 
 
437
 
        fd = RPC_ANYSOCK;
438
 
 
439
 
        if (info->client) {
440
 
                if (!clnt_control(info->client, CLGET_FD, (char *) &fd)) {
441
 
                        fd = RPC_ANYSOCK;
442
 
                        clnt_destroy(info->client);
443
 
                        info->client = NULL;
444
 
                } else {
445
 
                        clnt_control(info->client, CLSET_FD_NCLOSE, NULL);
446
 
                        clnt_destroy(info->client);
447
 
                }
448
 
        }
449
 
 
450
 
        if (info->addr) {
451
 
                client = rpc_do_create_client(info->addr, info, &fd);
452
 
                if (client)
453
 
                        goto done;
454
 
 
455
 
                if (!info->client) {
456
 
                        close(fd);
457
 
                        fd = RPC_ANYSOCK;
458
 
                }
459
 
        }
460
 
 
461
 
        memset(&hints, 0, sizeof(hints));
462
 
        hints.ai_flags = AI_ADDRCONFIG;
463
 
        hints.ai_family = AF_UNSPEC;
464
 
        hints.ai_socktype = SOCK_STREAM;
465
 
 
466
 
        ret = getaddrinfo(info->host, NULL, &hints, &ai);
467
 
        if (ret) {
468
 
                error(LOGOPT_ANY,
469
 
                      "hostname lookup failed: %s", gai_strerror(ret));
470
 
                info->client = NULL;
471
 
                goto out_close;
472
 
        }
473
 
 
474
 
        haddr = ai;
475
 
        while (haddr) {
476
 
                client = rpc_do_create_client(haddr->ai_addr, info, &fd);
477
 
                if (client)
478
 
                        break;
479
 
 
480
 
                if (!info->client) {
481
 
                        close(fd);
482
 
                        fd = RPC_ANYSOCK;
483
 
                }
484
 
 
485
 
                haddr = haddr->ai_next;
486
 
        }
487
 
 
488
 
        freeaddrinfo(ai);
489
 
 
490
 
        if (!client) {
491
 
                info->client = NULL;
492
 
                goto out_close;
493
 
        }
494
 
done:
495
 
        /* Close socket fd on destroy, as is default for rpcowned fds */
496
 
        if  (!clnt_control(client, CLSET_FD_CLOSE, NULL)) {
497
 
                clnt_destroy(client);
498
 
                info->client = NULL;
499
 
                goto out_close;
500
 
        }
501
 
 
502
 
        return client;
503
 
 
504
 
out_close:
505
 
        if (fd != -1)
506
 
                close(fd);
507
 
        return NULL;
508
 
}
509
 
 
510
 
int rpc_tcp_getclient(struct conn_info *info,
511
 
                      unsigned int program, unsigned int version)
512
 
{
513
 
        struct protoent *pe_proto;
514
 
        CLIENT *client;
515
 
 
516
 
        if (!info->client) {
517
 
                pe_proto = getprotobyname("tcp");
518
 
                if (!pe_proto)
519
 
                        return 0;
520
 
 
521
 
                info->proto = pe_proto;
522
 
                info->send_sz = 0;
523
 
                info->recv_sz = 0;
524
 
        }
525
 
 
526
 
        info->program = program;
527
 
        info->version = version;
528
 
 
529
 
        client = create_tcp_client(info);
530
 
 
531
 
        if (!client)
532
 
                return 0;
533
 
 
534
 
        info->client = client;
535
 
 
536
 
        return 1;
537
 
}
538
 
 
539
 
void rpc_destroy_tcp_client(struct conn_info *info)
540
 
{
541
 
        struct linger lin = { 1, 0 };
542
 
        socklen_t lin_len = sizeof(struct linger);
543
 
        int fd;
544
 
 
545
 
        if (!info->client)
546
 
                return;
547
 
 
548
 
        if (!clnt_control(info->client, CLGET_FD, (char *) &fd))
549
 
                fd = -1;
550
 
 
551
 
        switch (info->close_option) {
552
 
        case RPC_CLOSE_NOLINGER:
553
 
                if (fd >= 0)
554
 
                        setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
555
 
                break;
556
 
        }
557
 
 
558
 
        clnt_destroy(info->client);
559
 
        info->client = NULL;
560
 
 
561
 
        return;
562
 
}
563
 
 
564
 
int rpc_portmap_getclient(struct conn_info *info,
565
 
                          const char *host, struct sockaddr *addr, size_t addr_len,
566
 
                          const char *proto, unsigned int option)
567
 
{
568
 
        struct protoent *pe_proto;
569
 
        CLIENT *client;
570
 
 
571
 
        pe_proto = getprotobyname(proto);
572
 
        if (!pe_proto)
573
 
                return 0;
574
 
 
575
 
        info->host = host;
576
 
        info->addr = addr;
577
 
        info->addr_len = addr_len;
578
 
        info->program = PMAPPROG;
579
 
        info->port = PMAPPORT;
580
 
        info->version = PMAPVERS;
581
 
        info->proto = pe_proto;
582
 
        info->send_sz = RPCSMALLMSGSIZE;
583
 
        info->recv_sz = RPCSMALLMSGSIZE;
584
 
        info->timeout.tv_sec = PMAP_TOUT_UDP;
585
 
        info->timeout.tv_usec = 0;
586
 
        info->close_option = option;
587
 
        info->client = NULL;
588
 
 
589
 
        if (pe_proto->p_proto == IPPROTO_TCP) {
590
 
                info->timeout.tv_sec = PMAP_TOUT_TCP;
591
 
                client = create_tcp_client(info);
592
 
        } else
593
 
                client = create_udp_client(info);
594
 
 
595
 
        if (!client)
596
 
                return 0;
597
 
 
598
 
        info->client = client;
599
 
 
600
 
        return 1;
601
 
}
602
 
 
603
 
unsigned short rpc_portmap_getport(struct conn_info *info, struct pmap *parms)
604
 
{
605
 
        struct conn_info pmap_info;
606
 
        unsigned short port = 0;
607
 
        CLIENT *client;
608
 
        enum clnt_stat status;
609
 
        int proto = info->proto->p_proto;
610
 
 
611
 
        memset(&pmap_info, 0, sizeof(struct conn_info));
612
 
 
613
 
        if (proto == IPPROTO_TCP)
614
 
                pmap_info.timeout.tv_sec = PMAP_TOUT_TCP;
615
 
        else
616
 
                pmap_info.timeout.tv_sec = PMAP_TOUT_UDP;
617
 
 
618
 
        if (info->client)
619
 
                client = info->client;
620
 
        else {
621
 
                pmap_info.host = info->host;
622
 
                pmap_info.addr = info->addr;
623
 
                pmap_info.addr_len = info->addr_len;
624
 
                pmap_info.port = PMAPPORT;
625
 
                pmap_info.program = PMAPPROG;
626
 
                pmap_info.version = PMAPVERS;
627
 
                pmap_info.proto = info->proto;
628
 
                pmap_info.send_sz = RPCSMALLMSGSIZE;
629
 
                pmap_info.recv_sz = RPCSMALLMSGSIZE;
630
 
 
631
 
                if (proto == IPPROTO_TCP)
632
 
                        client = create_tcp_client(&pmap_info);
633
 
                else
634
 
                        client = create_udp_client(&pmap_info);
635
 
 
636
 
                if (!client)
637
 
                        return 0;
638
 
        }
639
 
 
640
 
        /*
641
 
         * Check to see if server is up otherwise a getport will take
642
 
         * forever to timeout.
643
 
         */
644
 
        status = clnt_call(client, PMAPPROC_NULL,
645
 
                         (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
646
 
                         pmap_info.timeout);
647
 
 
648
 
        if (status == RPC_SUCCESS) {
649
 
                status = clnt_call(client, PMAPPROC_GETPORT,
650
 
                                 (xdrproc_t) xdr_pmap, (caddr_t) parms,
651
 
                                 (xdrproc_t) xdr_u_short, (caddr_t) &port,
652
 
                                 pmap_info.timeout);
653
 
        }
654
 
 
655
 
        if (!info->client) {
656
 
                /*
657
 
                 * Only play with the close options if we think it
658
 
                 * completed OK
659
 
                 */
660
 
                if (proto == IPPROTO_TCP && status == RPC_SUCCESS) {
661
 
                        struct linger lin = { 1, 0 };
662
 
                        socklen_t lin_len = sizeof(struct linger);
663
 
                        int fd;
664
 
 
665
 
                        if (!clnt_control(client, CLGET_FD, (char *) &fd))
666
 
                                fd = -1;
667
 
 
668
 
                        switch (info->close_option) {
669
 
                        case RPC_CLOSE_NOLINGER:
670
 
                                if (fd >= 0)
671
 
                                        setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
672
 
                                break;
673
 
                        }
674
 
                }
675
 
                clnt_destroy(client);
676
 
        }
677
 
 
678
 
        if (status != RPC_SUCCESS)
679
 
                return 0;
680
 
 
681
 
        return port;
682
 
}
683
 
 
684
 
int rpc_ping_proto(struct conn_info *info)
685
 
{
686
 
        CLIENT *client;
687
 
        enum clnt_stat status;
688
 
        int proto = info->proto->p_proto;
689
 
 
690
 
        if (info->client)
691
 
                client = info->client;
692
 
        else {
693
 
                if (info->proto->p_proto == IPPROTO_UDP) {
694
 
                        info->send_sz = UDPMSGSIZE;
695
 
                        info->recv_sz = UDPMSGSIZE;
696
 
                        client = create_udp_client(info);
697
 
                } else
698
 
                        client = create_tcp_client(info);
699
 
 
700
 
                if (!client)
701
 
                        return 0;
702
 
        }
703
 
 
704
 
        clnt_control(client, CLSET_TIMEOUT, (char *) &info->timeout);
705
 
        clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info->timeout);
706
 
 
707
 
        status = clnt_call(client, NFSPROC_NULL,
708
 
                         (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
709
 
                         info->timeout);
710
 
 
711
 
        if (!info->client) {
712
 
                /*
713
 
                 * Only play with the close options if we think it
714
 
                 * completed OK
715
 
                 */
716
 
                if (proto == IPPROTO_TCP && status == RPC_SUCCESS) {
717
 
                        struct linger lin = { 1, 0 };
718
 
                        socklen_t lin_len = sizeof(struct linger);
719
 
                        int fd;
720
 
 
721
 
                        if (!clnt_control(client, CLGET_FD, (char *) &fd))
722
 
                                fd = -1;
723
 
 
724
 
                        switch (info->close_option) {
725
 
                        case RPC_CLOSE_NOLINGER:
726
 
                                if (fd >= 0)
727
 
                                        setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
728
 
                                break;
729
 
                        }
730
 
                }
731
 
                clnt_destroy(client);
732
 
        }
733
 
 
734
 
        if (status != RPC_SUCCESS)
735
 
                return 0;
736
 
 
737
 
        return 1;
738
 
}
739
 
 
740
 
static unsigned int __rpc_ping(const char *host,
741
 
                                unsigned long version,
742
 
                                char *proto,
743
 
                                long seconds, long micros,
744
 
                                unsigned int option)
745
 
{
746
 
        unsigned int status;
747
 
        struct conn_info info;
748
 
        struct pmap parms;
749
 
 
750
 
        info.host = host;
751
 
        info.addr = NULL;
752
 
        info.addr_len = 0;
753
 
        info.program = NFS_PROGRAM;
754
 
        info.version = version;
755
 
        info.send_sz = 0;
756
 
        info.recv_sz = 0;
757
 
        info.timeout.tv_sec = seconds;
758
 
        info.timeout.tv_usec = micros;
759
 
        info.close_option = option;
760
 
        info.client = NULL;
761
 
 
762
 
        status = RPC_PING_FAIL;
763
 
 
764
 
        info.proto = getprotobyname(proto);
765
 
        if (!info.proto)
766
 
                return status;
767
 
 
768
 
        parms.pm_prog = NFS_PROGRAM;
769
 
        parms.pm_vers = version;
770
 
        parms.pm_prot = info.proto->p_proto;
771
 
        parms.pm_port = 0;
772
 
 
773
 
        info.port = rpc_portmap_getport(&info, &parms);
774
 
        if (!info.port)
775
 
                return status;
776
 
 
777
 
        status = rpc_ping_proto(&info);
778
 
 
779
 
        return status;
780
 
}
781
 
 
782
 
int rpc_ping(const char *host, long seconds, long micros, unsigned int option)
783
 
{
784
 
        unsigned long vers3 = NFS3_VERSION;
785
 
        unsigned long vers2 = NFS2_VERSION;
786
 
        unsigned int status;
787
 
 
788
 
        status = __rpc_ping(host, vers2, "udp", seconds, micros, option);
789
 
        if (status)
790
 
                return RPC_PING_V2 | RPC_PING_UDP;
791
 
 
792
 
        status = __rpc_ping(host, vers3, "udp", seconds, micros, option);
793
 
        if (status)
794
 
                return RPC_PING_V3 | RPC_PING_UDP;
795
 
 
796
 
        status = __rpc_ping(host, vers2, "tcp", seconds, micros, option);
797
 
        if (status)
798
 
                return RPC_PING_V2 | RPC_PING_TCP;
799
 
 
800
 
        status = __rpc_ping(host, vers3, "tcp", seconds, micros, option);
801
 
        if (status)
802
 
                return RPC_PING_V3 | RPC_PING_TCP;
803
 
 
804
 
        return status;
805
 
}
806
 
 
807
 
double elapsed(struct timeval start, struct timeval end)
808
 
{
809
 
        double t1, t2;
810
 
        t1 =  (double)start.tv_sec + (double)start.tv_usec/(1000*1000);
811
 
        t2 =  (double)end.tv_sec + (double)end.tv_usec/(1000*1000);
812
 
        return t2-t1;
813
 
}
814
 
 
815
 
int rpc_time(const char *host,
816
 
             unsigned int ping_vers, unsigned int ping_proto,
817
 
             long seconds, long micros, unsigned int option, double *result)
818
 
{
819
 
        int status;
820
 
        double taken;
821
 
        struct timeval start, end;
822
 
        struct timezone tz;
823
 
        char *proto = (ping_proto & RPC_PING_UDP) ? "udp" : "tcp";
824
 
        unsigned long vers = ping_vers;
825
 
 
826
 
        gettimeofday(&start, &tz);
827
 
        status = __rpc_ping(host, vers, proto, seconds, micros, option);
828
 
        gettimeofday(&end, &tz);
829
 
 
830
 
        if (!status) {
831
 
                return 0;
832
 
        }
833
 
 
834
 
        taken = elapsed(start, end);
835
 
 
836
 
        if (result != NULL)
837
 
                *result = taken;
838
 
 
839
 
        return status;
840
 
}
841
 
 
842
 
static int rpc_get_exports_proto(struct conn_info *info, exports *exp)
843
 
{
844
 
        CLIENT *client;
845
 
        enum clnt_stat status;
846
 
        int proto = info->proto->p_proto;
847
 
        unsigned int option = info->close_option;
848
 
 
849
 
        if (info->proto->p_proto == IPPROTO_UDP) {
850
 
                info->send_sz = UDPMSGSIZE;
851
 
                info->recv_sz = UDPMSGSIZE;
852
 
                client = create_udp_client(info);
853
 
        } else
854
 
                client = create_tcp_client(info);
855
 
 
856
 
        if (!client)
857
 
                return 0;
858
 
 
859
 
        clnt_control(client, CLSET_TIMEOUT, (char *) &info->timeout);
860
 
        clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info->timeout);
861
 
 
862
 
        client->cl_auth = authunix_create_default();
863
 
 
864
 
        status = clnt_call(client, MOUNTPROC_EXPORT,
865
 
                         (xdrproc_t) xdr_void, NULL,
866
 
                         (xdrproc_t) xdr_exports, (caddr_t) exp,
867
 
                         info->timeout);
868
 
 
869
 
        /* Only play with the close options if we think it completed OK */
870
 
        if (proto == IPPROTO_TCP && status == RPC_SUCCESS) {
871
 
                struct linger lin = { 1, 0 };
872
 
                socklen_t lin_len = sizeof(struct linger);
873
 
                int fd;
874
 
 
875
 
                if (!clnt_control(client, CLGET_FD, (char *) &fd))
876
 
                        fd = -1;
877
 
 
878
 
                switch (option) {
879
 
                case RPC_CLOSE_NOLINGER:
880
 
                        if (fd >= 0)
881
 
                                setsockopt(fd, SOL_SOCKET, SO_LINGER, &lin, lin_len);
882
 
                        break;
883
 
                }
884
 
        }
885
 
        auth_destroy(client->cl_auth);
886
 
        clnt_destroy(client);
887
 
 
888
 
        if (status != RPC_SUCCESS)
889
 
                return 0;
890
 
 
891
 
        return 1;
892
 
}
893
 
 
894
 
static void rpc_export_free(exports item)
895
 
{
896
 
        groups grp;
897
 
        groups tmp;
898
 
 
899
 
        if (item->ex_dir)
900
 
                free(item->ex_dir);
901
 
 
902
 
        grp = item->ex_groups;
903
 
        while (grp) {
904
 
                if (grp->gr_name)
905
 
                        free(grp->gr_name);
906
 
                tmp = grp;
907
 
                grp = grp->gr_next;
908
 
                free(tmp);
909
 
        }
910
 
        free(item);
911
 
}
912
 
 
913
 
void rpc_exports_free(exports list)
914
 
{
915
 
        exports tmp;
916
 
 
917
 
        while (list) {
918
 
                tmp = list;
919
 
                list = list->ex_next;
920
 
                rpc_export_free(tmp);
921
 
        }
922
 
        return;
923
 
}
924
 
 
925
 
exports rpc_get_exports(const char *host, long seconds, long micros, unsigned int option)
926
 
{
927
 
        struct conn_info info;
928
 
        exports exportlist;
929
 
        struct pmap parms;
930
 
        int status;
931
 
 
932
 
        info.host = host;
933
 
        info.addr = NULL;
934
 
        info.addr_len = 0;
935
 
        info.program = MOUNTPROG;
936
 
        info.version = MOUNTVERS;
937
 
        info.send_sz = 0;
938
 
        info.recv_sz = 0;
939
 
        info.timeout.tv_sec = seconds;
940
 
        info.timeout.tv_usec = micros;
941
 
        info.close_option = option;
942
 
        info.client = NULL;
943
 
 
944
 
        parms.pm_prog = info.program;
945
 
        parms.pm_vers = info.version;
946
 
        parms.pm_port = 0;
947
 
 
948
 
        /* Try UDP first */
949
 
        info.proto = getprotobyname("udp");
950
 
        if (!info.proto)
951
 
                goto try_tcp;
952
 
 
953
 
        parms.pm_prot = info.proto->p_proto;
954
 
 
955
 
        info.port = rpc_portmap_getport(&info, &parms);
956
 
        if (!info.port)
957
 
                goto try_tcp;
958
 
 
959
 
        memset(&exportlist, '\0', sizeof(exportlist));
960
 
 
961
 
        status = rpc_get_exports_proto(&info, &exportlist);
962
 
        if (status)
963
 
                return exportlist;
964
 
 
965
 
try_tcp:
966
 
        info.proto = getprotobyname("tcp");
967
 
        if (!info.proto)
968
 
                return NULL;
969
 
 
970
 
        parms.pm_prot = info.proto->p_proto;
971
 
 
972
 
        info.port = rpc_portmap_getport(&info, &parms);
973
 
        if (!info.port)
974
 
                return NULL;
975
 
 
976
 
        memset(&exportlist, '\0', sizeof(exportlist));
977
 
 
978
 
        status = rpc_get_exports_proto(&info, &exportlist);
979
 
        if (!status)
980
 
                return NULL;
981
 
 
982
 
        return exportlist;
983
 
}
984
 
 
985
 
#if 0
986
 
#include <stdio.h>
987
 
 
988
 
int main(int argc, char **argv)
989
 
{
990
 
        int ret;
991
 
        double res = 0.0;
992
 
        exports exportlist, tmp;
993
 
        groups grouplist;
994
 
        int n, maxlen;
995
 
 
996
 
/*
997
 
        ret = rpc_ping("budgie", 10, 0, RPC_CLOSE_DEFAULT);
998
 
        printf("ret = %d\n", ret);
999
 
 
1000
 
        res = 0.0;
1001
 
        ret = rpc_time("budgie", NFS2_VERSION, RPC_PING_TCP, 10, 0, RPC_CLOSE_DEFAULT, &res);
1002
 
        printf("v2 tcp ret = %d, res = %f\n", ret, res);
1003
 
 
1004
 
        res = 0.0;
1005
 
        ret = rpc_time("budgie", NFS3_VERSION, RPC_PING_TCP, 10, 0, RPC_CLOSE_DEFAULT, &res);
1006
 
        printf("v3 tcp ret = %d, res = %f\n", ret, res);
1007
 
 
1008
 
        res = 0.0;
1009
 
        ret = rpc_time("budgie", NFS2_VERSION, RPC_PING_UDP, 10, 0, RPC_CLOSE_DEFAULT, &res);
1010
 
        printf("v2 udp ret = %d, res = %f\n", ret, res);
1011
 
 
1012
 
        res = 0.0;
1013
 
        ret = rpc_time("budgie", NFS3_VERSION, RPC_PING_UDP, 10, 0, RPC_CLOSE_DEFAULT, &res);
1014
 
        printf("v3 udp ret = %d, res = %f\n", ret, res);
1015
 
*/
1016
 
        exportlist = rpc_get_exports("budgie", 10, 0, RPC_CLOSE_NOLINGER);
1017
 
        exportlist = rpc_exports_prune(exportlist);
1018
 
 
1019
 
        maxlen = 0;
1020
 
        for (tmp = exportlist; tmp; tmp = tmp->ex_next) {
1021
 
                if ((n = strlen(tmp->ex_dir)) > maxlen)
1022
 
                        maxlen = n;
1023
 
        }
1024
 
 
1025
 
        if (exportlist) {
1026
 
                while (exportlist) {
1027
 
                        printf("%-*s ", maxlen, exportlist->ex_dir);
1028
 
                        grouplist = exportlist->ex_groups;
1029
 
                        if (grouplist) {
1030
 
                                while (grouplist) {
1031
 
                                        printf("%s%s", grouplist->gr_name,
1032
 
                                                grouplist->gr_next ? "," : "");
1033
 
                                        grouplist = grouplist->gr_next;
1034
 
                                }
1035
 
                        }
1036
 
                        printf("\n");
1037
 
                        exportlist = exportlist->ex_next;
1038
 
                }
1039
 
        }
1040
 
        rpc_exports_free(exportlist);
1041
 
 
1042
 
        exit(0);
1043
 
}
1044
 
#endif