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

« back to all changes in this revision

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