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

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-fix-backwards-ifndef-INET6.patch/modules/replicated.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
 
 *  repl_list.h - routines for replicated mount server selection
4
 
 *
5
 
 *   Copyright 2004 Jeff Moyer <jmoyer@redaht.com> - All Rights Reserved
6
 
 *   Copyright 2004-2006 Ian Kent <raven@themaw.net> - 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
 
 * A priority ordered list of hosts is created by using the following
15
 
 * selection rules.
16
 
 *
17
 
 *   1) Highest priority in selection is proximity.
18
 
 *      Proximity, in order of precedence is:
19
 
 *        - PROXIMITY_LOCAL, host corresponds to a local interface.
20
 
 *        - PROXIMITY_SUBNET, host is located in a subnet reachable
21
 
 *          through a local interface.
22
 
 *        - PROXIMITY_NETWORK, host is located in a network reachable
23
 
 *          through a local interface.
24
 
 *        - PROXIMITY_OTHER, host is on a network not directlty
25
 
 *          reachable through a local interface.
26
 
 *
27
 
 *   2) NFS version and protocol is selected by caclculating the largest
28
 
 *      number of hosts supporting an NFS version and protocol that
29
 
 *      have the closest proximity. These hosts are added to the list
30
 
 *      in response time order. Hosts may have a corresponding weight
31
 
 *      which essentially increaes response time and so influences the
32
 
 *      host order.
33
 
 *
34
 
 *   3) Hosts at further proximity that support the selected NFS version
35
 
 *      and protocol are also added to the list in response time order as
36
 
 *      in 2 above.
37
 
 *
38
 
 * ----------------------------------------------------------------------- */
39
 
 
40
 
#ifndef _GNU_SOURCE
41
 
#define _GNU_SOURCE
42
 
#endif
43
 
 
44
 
#include <string.h>
45
 
#include <stdlib.h>
46
 
#include <sys/errno.h>
47
 
#include <sys/types.h>
48
 
#include <stdint.h>
49
 
#include <sys/ioctl.h>
50
 
#include <sys/socket.h>
51
 
#include <arpa/inet.h>
52
 
#include <net/if.h>
53
 
#include <netinet/in.h>
54
 
#include <netdb.h>
55
 
 
56
 
#include "rpc_subs.h"
57
 
#include "replicated.h"
58
 
#include "automount.h"
59
 
 
60
 
#ifndef MAX_ERR_BUF
61
 
#define MAX_ERR_BUF             512
62
 
#endif
63
 
 
64
 
#define MAX_IFC_BUF             2048
65
 
static int volatile ifc_buf_len = MAX_IFC_BUF;
66
 
static int volatile ifc_last_len = 0;
67
 
 
68
 
#define MASK_A  0x7F000000
69
 
#define MASK_B  0xBFFF0000
70
 
#define MASK_C  0xDFFFFF00
71
 
 
72
 
/* Get numeric value of the n bits starting at position p */
73
 
#define getbits(x, p, n)        ((x >> (p + 1 - n)) & ~(~0 << n))
74
 
 
75
 
#define max(x, y)       (x >= y ? x : y)
76
 
#define mmax(x, y, z)   (max(x, y) == x ? max(x, z) : max(y, z))
77
 
 
78
 
unsigned int ipv6_mask_cmp(uint32_t *host, uint32_t *iface, uint32_t *mask)
79
 
{
80
 
        unsigned int ret = 1;
81
 
        unsigned int i;
82
 
 
83
 
        for (i = 0; i < 4; i++) {
84
 
                if ((host[i] & mask[i]) != (iface[i] & mask[i])) {
85
 
                        ret = 0;
86
 
                        break;
87
 
                }
88
 
        }
89
 
        return ret;
90
 
}
91
 
 
92
 
void seed_random(void)
93
 
{
94
 
        int fd;
95
 
        unsigned int seed;
96
 
 
97
 
        fd = open_fd("/dev/urandom", O_RDONLY);
98
 
        if (fd < 0) {
99
 
                srandom(time(NULL));
100
 
                return;
101
 
        }
102
 
 
103
 
        if (read(fd, &seed, sizeof(seed)) != -1)
104
 
                srandom(seed);
105
 
        else
106
 
                srandom(time(NULL));
107
 
 
108
 
        close(fd);
109
 
 
110
 
        return;
111
 
}
112
 
 
113
 
static int alloc_ifreq(struct ifconf *ifc, int sock)
114
 
{
115
 
        int ret, lastlen = ifc_last_len, len = ifc_buf_len;
116
 
        char err_buf[MAX_ERR_BUF], *buf;
117
 
 
118
 
        while (1) {
119
 
                buf = malloc(len);
120
 
                if (!buf) {
121
 
                        char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF);
122
 
                        logerr("malloc: %s", estr);
123
 
                        return 0;
124
 
                }
125
 
 
126
 
                ifc->ifc_len = len;
127
 
                ifc->ifc_req = (struct ifreq *) buf;
128
 
 
129
 
                ret = ioctl(sock, SIOCGIFCONF, ifc);
130
 
                if (ret == -1) {
131
 
                        char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF);
132
 
                        logerr("ioctl: %s", estr);
133
 
                        free(buf);
134
 
                        return 0;
135
 
                }
136
 
 
137
 
                if (ifc->ifc_len <= lastlen)
138
 
                        break;
139
 
 
140
 
                lastlen = ifc->ifc_len;
141
 
                len += MAX_IFC_BUF;
142
 
                free(buf);
143
 
        }
144
 
 
145
 
        if (lastlen != ifc_last_len) {
146
 
                ifc_last_len = lastlen;
147
 
                ifc_buf_len = len;
148
 
        }
149
 
 
150
 
        return 1;
151
 
}
152
 
 
153
 
static unsigned int get_proximity(struct sockaddr *host_addr)
154
 
{
155
 
        struct sockaddr_in *addr, *msk_addr, *if_addr;
156
 
        struct sockaddr_in6 *addr6, *msk6_addr, *if6_addr;
157
 
        struct in_addr *hst_addr;
158
 
        struct in6_addr *hst6_addr;
159
 
        int addr_len;
160
 
        char buf[MAX_ERR_BUF], *ptr;
161
 
        struct ifconf ifc;
162
 
        struct ifreq *ifr, nmptr;
163
 
        int sock, ret, i;
164
 
        uint32_t mask, ha, ia, *mask6, *ha6, *ia6;
165
 
 
166
 
        addr = NULL;
167
 
        addr6 = NULL;
168
 
        hst_addr = NULL;
169
 
        hst6_addr = NULL;
170
 
        mask6 = NULL;
171
 
        ha6 = NULL;
172
 
        ia6 = NULL;
173
 
 
174
 
        switch (host_addr->sa_family) {
175
 
        case AF_INET:
176
 
                addr = (struct sockaddr_in *) host_addr;
177
 
                hst_addr = (struct in_addr *) &addr->sin_addr;
178
 
                ha = ntohl((uint32_t) hst_addr->s_addr);
179
 
                addr_len = sizeof(hst_addr);
180
 
                break;
181
 
 
182
 
        case AF_INET6:
183
 
#ifndef INET6
184
 
                return PROXIMITY_UNSUPPORTED;
185
 
#else
186
 
                addr6 = (struct sockaddr_in6 *) host_addr;
187
 
                hst6_addr = (struct in6_addr *) &addr6->sin6_addr;
188
 
                ha6 = &hst6_addr->s6_addr32[0];
189
 
                addr_len = sizeof(hst6_addr);
190
 
                break;
191
 
#endif
192
 
 
193
 
        default:
194
 
                return PROXIMITY_ERROR;
195
 
        }
196
 
 
197
 
        sock = open_sock(AF_INET, SOCK_DGRAM, 0);
198
 
        if (sock < 0) {
199
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
200
 
                logerr("socket creation failed: %s", estr);
201
 
                return PROXIMITY_ERROR;
202
 
        }
203
 
 
204
 
        if (!alloc_ifreq(&ifc, sock)) {
205
 
                close(sock);
206
 
                return PROXIMITY_ERROR;
207
 
        }
208
 
 
209
 
        /* For each interface */
210
 
 
211
 
        /* Is the address a local interface */
212
 
        i = 0;
213
 
        ptr = (char *) &ifc.ifc_buf[0];
214
 
 
215
 
        while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) {
216
 
                ifr = (struct ifreq *) ptr;
217
 
 
218
 
                switch (ifr->ifr_addr.sa_family) {
219
 
                case AF_INET:
220
 
#ifndef INET6
221
 
                        if (host_addr->sa_family == AF_INET6)
222
 
                                break;
223
 
#endif
224
 
                        if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
225
 
                        ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len);
226
 
                        if (!ret) {
227
 
                                close(sock);
228
 
                                free(ifc.ifc_req);
229
 
                                return PROXIMITY_LOCAL;
230
 
                        }
231
 
                        break;
232
 
 
233
 
                case AF_INET6:
234
 
#ifndef INET6
235
 
                        if (host_addr->sa_family == AF_INET)
236
 
                                break;
237
 
 
238
 
                        if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr;
239
 
                        ret = memcmp(&if6_addr->sin6_addr, hst6_addr, addr_len);
240
 
                        if (!ret) {
241
 
                                close(sock);
242
 
                                free(ifc.ifc_req);
243
 
                                return PROXIMITY_LOCAL;
244
 
                        }
245
 
#endif
246
 
 
247
 
                default:
248
 
                        break;
249
 
                }
250
 
 
251
 
                i++;
252
 
                ptr = (char *) &ifc.ifc_req[i];
253
 
        }
254
 
 
255
 
        i = 0;
256
 
        ptr = (char *) &ifc.ifc_buf[0];
257
 
 
258
 
        while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) {
259
 
                ifr = (struct ifreq *) ptr;
260
 
 
261
 
                nmptr = *ifr;
262
 
                ret = ioctl(sock, SIOCGIFNETMASK, &nmptr);
263
 
                if (ret == -1) {
264
 
                        char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
265
 
                        logerr("ioctl: %s", estr);
266
 
                        close(sock);
267
 
                        free(ifc.ifc_req);
268
 
                        return PROXIMITY_ERROR;
269
 
                }
270
 
 
271
 
                switch (ifr->ifr_addr.sa_family) {
272
 
                case AF_INET:
273
 
#ifndef INET6
274
 
                        if (host_addr->sa_family == AF_INET6)
275
 
                                break;
276
 
#endif
277
 
                        if_addr = (struct sockaddr_in *) &ifr->ifr_addr;
278
 
                        ia =  ntohl((uint32_t) if_addr->sin_addr.s_addr);
279
 
 
280
 
                        /* Is the address within a localiy attached subnet */
281
 
 
282
 
                        msk_addr = (struct sockaddr_in *) &nmptr.ifr_netmask;
283
 
                        mask = ntohl((uint32_t) msk_addr->sin_addr.s_addr);
284
 
 
285
 
                        if ((ia & mask) == (ha & mask)) {
286
 
                                close(sock);
287
 
                                free(ifc.ifc_req);
288
 
                                return PROXIMITY_SUBNET;
289
 
                        }
290
 
 
291
 
                        /*
292
 
                         * Is the address within a local ipv4 network.
293
 
                         *
294
 
                         * Bit position 31 == 0 => class A.
295
 
                         * Bit position 30 == 0 => class B.
296
 
                         * Bit position 29 == 0 => class C.
297
 
                         */
298
 
 
299
 
                        if (!getbits(ia, 31, 1))
300
 
                                mask = MASK_A;
301
 
                        else if (!getbits(ia, 30, 1))
302
 
                                mask = MASK_B;
303
 
                        else if (!getbits(ia, 29, 1))
304
 
                                mask = MASK_C;
305
 
                        else
306
 
                                break;
307
 
 
308
 
                        if ((ia & mask) == (ha & mask)) {
309
 
                                close(sock);
310
 
                                free(ifc.ifc_req);
311
 
                                return PROXIMITY_NET;
312
 
                        }
313
 
                        break;
314
 
 
315
 
                case AF_INET6:
316
 
#ifndef INET6
317
 
                        if (host_addr->sa_family == AF_INET)
318
 
                                break;
319
 
 
320
 
                        if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr;
321
 
                        ia6 = &if6_addr->sin6_addr.s6_addr32[0];
322
 
 
323
 
                        /* Is the address within the network of the interface */
324
 
 
325
 
                        msk6_addr = (struct sockaddr_in6 *) &nmptr.ifr_netmask;
326
 
                        mask6 = &msk6_addr->sin6_addr.s6_addr32[0];
327
 
 
328
 
                        if (ipv6_mask_cmp(ha6, ia6, mask6)) {
329
 
                                close(sock);
330
 
                                free(ifc.ifc_req);
331
 
                                return PROXIMITY_SUBNET;
332
 
                        }
333
 
 
334
 
                        /* How do we define "local network" in ipv6? */
335
 
#endif
336
 
                        break;
337
 
 
338
 
                default:
339
 
                        break;
340
 
                }
341
 
 
342
 
                i++;
343
 
                ptr = (char *) &ifc.ifc_req[i];
344
 
        }
345
 
 
346
 
        close(sock);
347
 
        free(ifc.ifc_req);
348
 
 
349
 
        return PROXIMITY_OTHER;
350
 
}
351
 
 
352
 
static struct host *new_host(const char *name,
353
 
                             struct sockaddr *addr, size_t addr_len,
354
 
                             unsigned int proximity, unsigned int weight)
355
 
{
356
 
        struct host *new;
357
 
        struct sockaddr *tmp2;
358
 
        char *tmp1;
359
 
 
360
 
        if (!name || !addr)
361
 
                return NULL;
362
 
 
363
 
        tmp1 = strdup(name);
364
 
        if (!tmp1)
365
 
                return NULL;
366
 
 
367
 
        tmp2 = malloc(addr_len);
368
 
        if (!tmp2) {
369
 
                free(tmp1);
370
 
                return NULL;
371
 
        }
372
 
        memcpy(tmp2, addr, addr_len);
373
 
 
374
 
        new = malloc(sizeof(struct host));
375
 
        if (!new) {
376
 
                free(tmp1);
377
 
                free(tmp2);
378
 
                return NULL;
379
 
        }
380
 
 
381
 
        memset(new, 0, sizeof(struct host));
382
 
 
383
 
        new->name = tmp1;
384
 
        new->addr_len = addr_len;
385
 
        new->addr = tmp2;
386
 
        new->proximity = proximity;
387
 
        new->weight = weight;
388
 
 
389
 
        return new;
390
 
}
391
 
 
392
 
static int add_host(struct host **list, struct host *host)
393
 
{
394
 
        struct host *this, *last;
395
 
 
396
 
        if (!*list) {
397
 
                *list = host;
398
 
                return 1;
399
 
        }
400
 
 
401
 
        this = *list;
402
 
        last = this;
403
 
        while (this) {
404
 
                if (this->proximity >= host->proximity)
405
 
                        break;
406
 
                last = this;
407
 
                this = this->next;
408
 
        }
409
 
 
410
 
        if (host->cost) {
411
 
                while (this) {
412
 
                        if (this->proximity != host->proximity)
413
 
                                break;
414
 
                        if (this->cost >= host->cost)
415
 
                                break;
416
 
                        last = this;
417
 
                        this = this->next;
418
 
                }
419
 
        }
420
 
 
421
 
        if (last == this) {
422
 
                host->next = last;
423
 
                *list = host;
424
 
                return 1;
425
 
        }
426
 
 
427
 
        last->next = host;
428
 
        host->next = this;
429
 
 
430
 
        return 1;
431
 
}
432
 
 
433
 
static void free_host(struct host *host)
434
 
{
435
 
        free(host->name);
436
 
        free(host->addr);
437
 
        free(host->path);
438
 
        free(host);
439
 
}
440
 
 
441
 
static void remove_host(struct host **hosts, struct host *host)
442
 
{
443
 
        struct host *last, *this;
444
 
 
445
 
        if (host == *hosts) {
446
 
                *hosts = (*hosts)->next;
447
 
                host->next = NULL;
448
 
                return;
449
 
        }
450
 
 
451
 
        this = *hosts;
452
 
        last = NULL;
453
 
        while (this) {
454
 
                if (this == host)
455
 
                        break;
456
 
                last = this;
457
 
                this = this->next;
458
 
        }
459
 
 
460
 
        if (!last || !this)
461
 
                return;
462
 
 
463
 
        last->next = this->next;
464
 
        host->next = NULL;
465
 
 
466
 
        return;
467
 
}
468
 
 
469
 
static void delete_host(struct host **hosts, struct host *host)
470
 
{
471
 
        remove_host(hosts, host);
472
 
        free_host(host);
473
 
        return;
474
 
}
475
 
 
476
 
void free_host_list(struct host **list)
477
 
{
478
 
        struct host *this;
479
 
 
480
 
        this = *list;
481
 
        while (this) {
482
 
                struct host *next = this->next;
483
 
                free_host(this);
484
 
                this = next;
485
 
        }
486
 
        *list = NULL;
487
 
}
488
 
 
489
 
static unsigned short get_port_option(const char *options)
490
 
{
491
 
        const char *start;
492
 
        long port = 0;
493
 
 
494
 
        if (!options)
495
 
                return NFS_PORT;
496
 
 
497
 
        start = strstr(options, "port=");
498
 
        if (!start)
499
 
                port = NFS_PORT;
500
 
        else {
501
 
                char optport[30], *opteq, *end;
502
 
                int len;
503
 
 
504
 
                end = strchr(start, ',');
505
 
                len = end ? end - start : strlen(start);
506
 
                strncpy(optport, start, len);
507
 
                optport[len] = '\0';
508
 
                opteq = strchr(optport, '=');
509
 
                if (opteq)
510
 
                        port = atoi(opteq + 1);
511
 
        }
512
 
 
513
 
        if (port < 0)
514
 
                port = 0;
515
 
 
516
 
        return (unsigned short) port;
517
 
}
518
 
 
519
 
static unsigned int get_nfs_info(unsigned logopt, struct host *host,
520
 
                         struct conn_info *pm_info, struct conn_info *rpc_info,
521
 
                         const char *proto, unsigned int version,
522
 
                         const char *options, unsigned int random_selection)
523
 
{
524
 
        char *have_port_opt = options ? strstr(options, "port=") : NULL;
525
 
        struct pmap parms;
526
 
        struct timeval start, end;
527
 
        struct timezone tz;
528
 
        unsigned int supported = 0;
529
 
        double taken = 0;
530
 
        int status, count = 0;
531
 
 
532
 
        debug(logopt,
533
 
              "called for host %s proto %s version 0x%x",
534
 
              host->name, proto, version);
535
 
 
536
 
        memset(&parms, 0, sizeof(struct pmap));
537
 
 
538
 
        parms.pm_prog = NFS_PROGRAM;
539
 
 
540
 
        /* Try to prode UDP first to conserve socket space */
541
 
        rpc_info->proto = getprotobyname(proto);
542
 
        if (!rpc_info->proto)
543
 
                return 0;
544
 
 
545
 
        if (!(version & NFS4_REQUESTED))
546
 
                goto v3_ver;
547
 
 
548
 
        if (!(rpc_info->port = get_port_option(options)))
549
 
                goto v3_ver;
550
 
 
551
 
        if (rpc_info->proto->p_proto == IPPROTO_UDP)
552
 
                status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS4_VERSION);
553
 
        else
554
 
                status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS4_VERSION);
555
 
        if (status) {
556
 
                gettimeofday(&start, &tz);
557
 
                status = rpc_ping_proto(rpc_info);
558
 
                gettimeofday(&end, &tz);
559
 
                if (status) {
560
 
                        double reply;
561
 
                        if (random_selection) {
562
 
                                /* Random value between 0 and 1 */
563
 
                                reply = ((float) random())/((float) RAND_MAX+1);
564
 
                                debug(logopt,
565
 
                                      "nfs v4 random selection time: %f", reply);
566
 
                        } else {
567
 
                                reply = elapsed(start, end);
568
 
                                debug(logopt, "nfs v4 rpc ping time: %f", reply);
569
 
                        }
570
 
                        taken += reply;
571
 
                        count++;
572
 
                        supported = NFS4_SUPPORTED;
573
 
                }
574
 
        }
575
 
 
576
 
v3_ver:
577
 
        if (!have_port_opt) {
578
 
                status = rpc_portmap_getclient(pm_info,
579
 
                                host->name, host->addr, host->addr_len,
580
 
                                proto, RPC_CLOSE_DEFAULT);
581
 
                if (!status)
582
 
                        goto done_ver;
583
 
        }
584
 
 
585
 
        if (!(version & NFS3_REQUESTED))
586
 
                goto v2_ver;
587
 
 
588
 
        if (have_port_opt) {
589
 
                if (!(rpc_info->port = get_port_option(options)))
590
 
                        goto done_ver;
591
 
        } else {
592
 
                parms.pm_prot = rpc_info->proto->p_proto;
593
 
                parms.pm_vers = NFS3_VERSION;
594
 
                rpc_info->port = rpc_portmap_getport(pm_info, &parms);
595
 
                if (!rpc_info->port)
596
 
                        goto v2_ver;
597
 
        }
598
 
 
599
 
        if (rpc_info->proto->p_proto == IPPROTO_UDP)
600
 
                status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS3_VERSION);
601
 
        else
602
 
                status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS3_VERSION);
603
 
        if (status) {
604
 
                gettimeofday(&start, &tz);
605
 
                status = rpc_ping_proto(rpc_info);
606
 
                gettimeofday(&end, &tz);
607
 
                if (status) {
608
 
                        double reply;
609
 
                        if (random_selection) {
610
 
                                /* Random value between 0 and 1 */
611
 
                                reply = ((float) random())/((float) RAND_MAX+1);
612
 
                                debug(logopt,
613
 
                                      "nfs v3 random selection time: %f", reply);
614
 
                        } else {
615
 
                                reply = elapsed(start, end);
616
 
                                debug(logopt, "nfs v3 rpc ping time: %f", reply);
617
 
                        }
618
 
                        taken += reply;
619
 
                        count++;
620
 
                        supported |= NFS3_SUPPORTED;
621
 
                }
622
 
        }
623
 
 
624
 
v2_ver:
625
 
        if (!(version & NFS2_REQUESTED))
626
 
                goto done_ver;
627
 
 
628
 
        if (have_port_opt) {
629
 
                if (!(rpc_info->port = get_port_option(options)))
630
 
                        goto done_ver;
631
 
        } else {
632
 
                parms.pm_prot = rpc_info->proto->p_proto;
633
 
                parms.pm_vers = NFS2_VERSION;
634
 
                rpc_info->port = rpc_portmap_getport(pm_info, &parms);
635
 
                if (!rpc_info->port)
636
 
                        goto done_ver;
637
 
        }
638
 
 
639
 
        if (rpc_info->proto->p_proto == IPPROTO_UDP)
640
 
                status = rpc_udp_getclient(rpc_info, NFS_PROGRAM, NFS2_VERSION);
641
 
        else
642
 
                status = rpc_tcp_getclient(rpc_info, NFS_PROGRAM, NFS2_VERSION);
643
 
        if (status) {
644
 
                gettimeofday(&start, &tz);
645
 
                status = rpc_ping_proto(rpc_info);
646
 
                gettimeofday(&end, &tz);
647
 
                if (status) {
648
 
                        double reply;
649
 
                        if (random_selection) {
650
 
                                /* Random value between 0 and 1 */
651
 
                                reply = ((float) random())/((float) RAND_MAX+1);
652
 
                                debug(logopt,
653
 
                                      "nfs v2 random selection time: %f", reply);
654
 
                        } else {
655
 
                                reply = elapsed(start, end);;
656
 
                                debug(logopt, "nfs v2 rpc ping time: %f", reply);
657
 
                        }
658
 
                        taken += reply;
659
 
                        count++;
660
 
                        supported |= NFS2_SUPPORTED;
661
 
                }
662
 
        }
663
 
 
664
 
done_ver:
665
 
        if (rpc_info->proto->p_proto == IPPROTO_UDP) {
666
 
                rpc_destroy_udp_client(rpc_info);
667
 
                rpc_destroy_udp_client(pm_info);
668
 
        } else {
669
 
                rpc_destroy_tcp_client(rpc_info);
670
 
                rpc_destroy_tcp_client(pm_info);
671
 
        }
672
 
 
673
 
        if (count) {
674
 
                /*
675
 
                 * Average response time to 7 significant places as
676
 
                 * integral type.
677
 
                 */
678
 
                host->cost = (unsigned long) ((taken * 1000000) / count);
679
 
 
680
 
                /* Allow for user bias */
681
 
                if (host->weight)
682
 
                        host->cost *= (host->weight + 1);
683
 
 
684
 
                debug(logopt, "host %s cost %ld weight %d",
685
 
                      host->name, host->cost, host->weight);
686
 
        }
687
 
 
688
 
        return supported;
689
 
}
690
 
 
691
 
static int get_vers_and_cost(unsigned logopt, struct host *host,
692
 
                             unsigned int version, const char *options,
693
 
                             unsigned int random_selection)
694
 
{
695
 
        struct conn_info pm_info, rpc_info;
696
 
        time_t timeout = RPC_TIMEOUT;
697
 
        unsigned int supported, vers = (NFS_VERS_MASK | NFS4_VERS_MASK);
698
 
        int ret = 0;
699
 
 
700
 
        memset(&pm_info, 0, sizeof(struct conn_info));
701
 
        memset(&rpc_info, 0, sizeof(struct conn_info));
702
 
 
703
 
        if (host->proximity == PROXIMITY_NET)
704
 
                timeout = RPC_TIMEOUT * 2;
705
 
        else if (host->proximity == PROXIMITY_OTHER)
706
 
                timeout = RPC_TIMEOUT * 8;
707
 
 
708
 
        rpc_info.host = host->name;
709
 
        rpc_info.addr = host->addr;
710
 
        rpc_info.addr_len = host->addr_len;
711
 
        rpc_info.program = NFS_PROGRAM;
712
 
        rpc_info.timeout.tv_sec = timeout;
713
 
        rpc_info.close_option = RPC_CLOSE_DEFAULT;
714
 
        rpc_info.client = NULL;
715
 
 
716
 
        vers &= version;
717
 
 
718
 
        if (version & UDP_REQUESTED) {
719
 
                supported = get_nfs_info(logopt, host,
720
 
                                        &pm_info, &rpc_info, "udp", vers,
721
 
                                        options, random_selection);
722
 
                if (supported) {
723
 
                        ret = 1;
724
 
                        host->version |= (supported << 8);
725
 
                }
726
 
        }
727
 
 
728
 
        if (version & TCP_REQUESTED) {
729
 
                supported = get_nfs_info(logopt, host,
730
 
                                         &pm_info, &rpc_info, "tcp", vers,
731
 
                                         options, random_selection);
732
 
                if (supported) {
733
 
                        ret = 1;
734
 
                        host->version |= supported;
735
 
                }
736
 
        }
737
 
 
738
 
        return ret;
739
 
}
740
 
 
741
 
static int get_supported_ver_and_cost(unsigned logopt, struct host *host,
742
 
                                      unsigned int version, const char *options,
743
 
                                      unsigned int random_selection)
744
 
{
745
 
        char *have_port_opt = options ? strstr(options, "port=") : NULL;
746
 
        struct conn_info pm_info, rpc_info;
747
 
        struct pmap parms;
748
 
        const char *proto;
749
 
        unsigned int vers;
750
 
        struct timeval start, end;
751
 
        struct timezone tz;
752
 
        double taken = 0;
753
 
        time_t timeout = RPC_TIMEOUT;
754
 
        int status;
755
 
 
756
 
        debug(logopt,
757
 
              "called with host %s version 0x%x", host->name, version);
758
 
 
759
 
        memset(&pm_info, 0, sizeof(struct conn_info));
760
 
        memset(&rpc_info, 0, sizeof(struct conn_info));
761
 
        memset(&parms, 0, sizeof(struct pmap));
762
 
 
763
 
        if (host->proximity == PROXIMITY_NET)
764
 
                timeout = RPC_TIMEOUT * 2;
765
 
        else if (host->proximity == PROXIMITY_OTHER)
766
 
                timeout = RPC_TIMEOUT * 8;
767
 
 
768
 
        rpc_info.host = host->name;
769
 
        rpc_info.addr = host->addr;
770
 
        rpc_info.addr_len = host->addr_len;
771
 
        rpc_info.program = NFS_PROGRAM;
772
 
        rpc_info.timeout.tv_sec = timeout;
773
 
        rpc_info.close_option = RPC_CLOSE_DEFAULT;
774
 
        rpc_info.client = NULL;
775
 
 
776
 
        parms.pm_prog = NFS_PROGRAM;
777
 
 
778
 
        /*
779
 
         *  The version passed in is the version as defined in
780
 
         *  include/replicated.h.  However, the version we want to send
781
 
         *  off to the rpc calls should match the program version of NFS.
782
 
         *  So, we do the conversion here.
783
 
         */
784
 
        if (version & UDP_SELECTED_MASK) {
785
 
                proto = "udp";
786
 
                version >>= 8;
787
 
        } else
788
 
                proto = "tcp";
789
 
 
790
 
        switch (version) {
791
 
        case NFS2_SUPPORTED:
792
 
                vers = NFS2_VERSION;
793
 
                break;
794
 
        case NFS3_SUPPORTED:
795
 
                vers = NFS3_VERSION;
796
 
                break;
797
 
        case NFS4_SUPPORTED:
798
 
                vers = NFS4_VERSION;
799
 
                break;
800
 
        default:
801
 
                crit(logopt, "called with invalid version: 0x%x\n", version);
802
 
                return 0;
803
 
        }
804
 
 
805
 
        rpc_info.proto = getprotobyname(proto);
806
 
        if (!rpc_info.proto)
807
 
                return 0;
808
 
 
809
 
        status = 0;
810
 
 
811
 
        parms.pm_vers = vers;
812
 
        if (have_port_opt || (vers & NFS4_VERSION)) {
813
 
                if (!(rpc_info.port = get_port_option(options)))
814
 
                        return 0;
815
 
        } else {
816
 
                int ret = rpc_portmap_getclient(&pm_info,
817
 
                                host->name, host->addr, host->addr_len,
818
 
                                proto, RPC_CLOSE_DEFAULT);
819
 
                if (!ret)
820
 
                        return 0;
821
 
 
822
 
                parms.pm_prot = rpc_info.proto->p_proto;
823
 
                rpc_info.port = rpc_portmap_getport(&pm_info, &parms);
824
 
                if (!rpc_info.port)
825
 
                        goto done;
826
 
        }
827
 
 
828
 
        if (rpc_info.proto->p_proto == IPPROTO_UDP)
829
 
                status = rpc_udp_getclient(&rpc_info, NFS_PROGRAM, parms.pm_vers);
830
 
        else
831
 
                status = rpc_tcp_getclient(&rpc_info, NFS_PROGRAM, parms.pm_vers);
832
 
        if (status) {
833
 
                gettimeofday(&start, &tz);
834
 
                status = rpc_ping_proto(&rpc_info);
835
 
                gettimeofday(&end, &tz);
836
 
                if (status) {
837
 
                        if (random_selection) {
838
 
                                /* Random value between 0 and 1 */
839
 
                                taken = ((float) random())/((float) RAND_MAX+1);
840
 
                                debug(logopt, "random selection time %f", taken);
841
 
                        } else {
842
 
                                taken = elapsed(start, end);
843
 
                                debug(logopt, "rpc ping time %f", taken);
844
 
                        }
845
 
                }
846
 
        }
847
 
done:
848
 
        if (rpc_info.proto->p_proto == IPPROTO_UDP) {
849
 
                rpc_destroy_udp_client(&rpc_info);
850
 
                rpc_destroy_udp_client(&pm_info);
851
 
        } else {
852
 
                rpc_destroy_tcp_client(&rpc_info);
853
 
                rpc_destroy_tcp_client(&pm_info);
854
 
        }
855
 
 
856
 
        if (status) {
857
 
                /* Response time to 7 significant places as integral type. */
858
 
                host->cost = (unsigned long) (taken * 1000000);
859
 
 
860
 
                /* Allow for user bias */
861
 
                if (host->weight)
862
 
                        host->cost *= (host->weight + 1);
863
 
 
864
 
                debug(logopt, "cost %ld weight %d", host->cost, host->weight);
865
 
 
866
 
                return 1;
867
 
        }
868
 
 
869
 
        return 0;
870
 
}
871
 
 
872
 
int prune_host_list(unsigned logopt, struct host **list,
873
 
                    unsigned int vers, const char *options,
874
 
                    unsigned int random_selection)
875
 
{
876
 
        struct host *this, *last, *first;
877
 
        struct host *new = NULL;
878
 
        unsigned int proximity, selected_version = 0;
879
 
        unsigned int v2_tcp_count, v3_tcp_count, v4_tcp_count;
880
 
        unsigned int v2_udp_count, v3_udp_count, v4_udp_count;
881
 
        unsigned int max_udp_count, max_tcp_count, max_count;
882
 
        int status;
883
 
 
884
 
        if (!*list)
885
 
                return 0;
886
 
 
887
 
        /* Use closest hosts to choose NFS version */
888
 
 
889
 
        first = *list;
890
 
 
891
 
        /* Get proximity of first entry after local entries */
892
 
        this = first;
893
 
        while (this && this->proximity == PROXIMITY_LOCAL)
894
 
                this = this->next;
895
 
 
896
 
        /*
897
 
         * Check for either a list containing only proximity local hosts
898
 
         * or a single host entry whose proximity isn't local. If so
899
 
         * return immediately as we don't want to add probe latency for
900
 
         * the common case of a single filesystem mount request.
901
 
         */
902
 
        if (!this || !this->next)
903
 
                return 1;
904
 
 
905
 
        proximity = this->proximity;
906
 
        first = this;
907
 
        this = first;
908
 
        while (this) {
909
 
                struct host *next = this->next;
910
 
 
911
 
                if (this->proximity != proximity)
912
 
                        break;
913
 
 
914
 
                if (this->name) {
915
 
                        status = get_vers_and_cost(logopt, this, vers,
916
 
                                                   options, random_selection);
917
 
                        if (!status) {
918
 
                                if (this == first) {
919
 
                                        first = next;
920
 
                                        if (next)
921
 
                                                proximity = next->proximity;
922
 
                                }
923
 
                                delete_host(list, this);
924
 
                        }
925
 
                }
926
 
                this = next;
927
 
        }
928
 
 
929
 
        /*
930
 
         * The list of hosts that aren't proximity local may now
931
 
         * be empty if we haven't been able probe any so we need
932
 
         * to check again for a list containing only proximity
933
 
         * local hosts.
934
 
         */
935
 
        if (!first)
936
 
                return 1;
937
 
 
938
 
        last = this;
939
 
 
940
 
        /* Select NFS version of highest number of closest servers */
941
 
 
942
 
        v4_tcp_count = v3_tcp_count = v2_tcp_count = 0;
943
 
        v4_udp_count = v3_udp_count = v2_udp_count = 0;
944
 
 
945
 
        this = first;
946
 
        do {
947
 
                if (this->version & NFS4_TCP_SUPPORTED)
948
 
                        v4_tcp_count++;
949
 
 
950
 
                if (this->version & NFS3_TCP_SUPPORTED)
951
 
                        v3_tcp_count++;
952
 
 
953
 
                if (this->version & NFS2_TCP_SUPPORTED)
954
 
                        v2_tcp_count++;
955
 
 
956
 
                if (this->version & NFS4_UDP_SUPPORTED)
957
 
                        v4_udp_count++;
958
 
 
959
 
                if (this->version & NFS3_UDP_SUPPORTED)
960
 
                        v3_udp_count++;
961
 
 
962
 
                if (this->version & NFS2_UDP_SUPPORTED)
963
 
                        v2_udp_count++;
964
 
 
965
 
                this = this->next; 
966
 
        } while (this && this != last);
967
 
 
968
 
        max_tcp_count = mmax(v4_tcp_count, v3_tcp_count, v2_tcp_count);
969
 
        max_udp_count = mmax(v4_udp_count, v3_udp_count, v2_udp_count);
970
 
        max_count = max(max_tcp_count, max_udp_count);
971
 
 
972
 
        if (max_count == v4_tcp_count) {
973
 
                selected_version = NFS4_TCP_SUPPORTED;
974
 
                debug(logopt,
975
 
                      "selected subset of hosts that support NFS4 over TCP");
976
 
        } else if (max_count == v3_tcp_count) {
977
 
                selected_version = NFS3_TCP_SUPPORTED;
978
 
                debug(logopt,
979
 
                      "selected subset of hosts that support NFS3 over TCP");
980
 
        } else if (max_count == v2_tcp_count) {
981
 
                selected_version = NFS2_TCP_SUPPORTED;
982
 
                debug(logopt,
983
 
                      "selected subset of hosts that support NFS2 over TCP");
984
 
        } else if (max_count == v4_udp_count) {
985
 
                selected_version = NFS4_UDP_SUPPORTED;
986
 
                debug(logopt,
987
 
                      "selected subset of hosts that support NFS4 over UDP");
988
 
        } else if (max_count == v3_udp_count) {
989
 
                selected_version = NFS3_UDP_SUPPORTED;
990
 
                debug(logopt,
991
 
                      "selected subset of hosts that support NFS3 over UDP");
992
 
        } else if (max_count == v2_udp_count) {
993
 
                selected_version = NFS2_UDP_SUPPORTED;
994
 
                debug(logopt,
995
 
                      "selected subset of hosts that support NFS2 over UDP");
996
 
        }
997
 
 
998
 
        /* Add local and hosts with selected version to new list */
999
 
        this = *list;
1000
 
        do {
1001
 
                struct host *next = this->next;
1002
 
                if (this->version & selected_version ||
1003
 
                    this->proximity == PROXIMITY_LOCAL) {
1004
 
                        this->version = selected_version;
1005
 
                        remove_host(list, this);
1006
 
                        add_host(&new, this);
1007
 
                }
1008
 
                this = next;
1009
 
        } while (this && this != last);
1010
 
 
1011
 
        /*
1012
 
         * Now go through rest of list and check for chosen version
1013
 
         * and add to new list if selected version is supported.
1014
 
         */ 
1015
 
 
1016
 
        first = last;
1017
 
        this = first;
1018
 
        while (this) {
1019
 
                struct host *next = this->next;
1020
 
                if (!this->name) {
1021
 
                        remove_host(list, this);
1022
 
                        add_host(&new, this);
1023
 
                } else {
1024
 
                        status = get_supported_ver_and_cost(logopt, this,
1025
 
                                                selected_version, options,
1026
 
                                                random_selection);
1027
 
                        if (status) {
1028
 
                                this->version = selected_version;
1029
 
                                remove_host(list, this);
1030
 
                                add_host(&new, this);
1031
 
                        }
1032
 
                }
1033
 
                this = next;
1034
 
        }
1035
 
 
1036
 
        free_host_list(list);
1037
 
        *list = new;
1038
 
 
1039
 
        return 1;
1040
 
}
1041
 
 
1042
 
static int add_new_host(struct host **list,
1043
 
                        const char *host, unsigned int weight,
1044
 
                        struct addrinfo *host_addr)
1045
 
{
1046
 
        struct host *new;
1047
 
        unsigned int prx;
1048
 
        int addr_len;
1049
 
 
1050
 
        prx = get_proximity(host_addr->ai_addr);
1051
 
        /*
1052
 
         * If we tried to add an IPv6 address and we don't have IPv6
1053
 
         * support return success in the hope of getting an IPv4
1054
 
         * address later.
1055
 
         */
1056
 
        if (prx == PROXIMITY_UNSUPPORTED)
1057
 
                return 1;
1058
 
        if (prx == PROXIMITY_ERROR)
1059
 
                return 0;
1060
 
 
1061
 
        addr_len = sizeof(struct sockaddr);
1062
 
        new = new_host(host, host_addr->ai_addr, addr_len, prx, weight);
1063
 
        if (!new)
1064
 
                return 0;
1065
 
 
1066
 
        if (!add_host(list, new)) {
1067
 
                free_host(new);
1068
 
                return 0;
1069
 
        }
1070
 
 
1071
 
        return 1;
1072
 
}
1073
 
 
1074
 
static int add_host_addrs(struct host **list, const char *host, unsigned int weight)
1075
 
{
1076
 
        struct addrinfo hints, *ni, *this;
1077
 
        int ret;
1078
 
 
1079
 
        memset(&hints, 0, sizeof(hints));
1080
 
        hints.ai_flags = AI_NUMERICHOST;
1081
 
        hints.ai_family = AF_UNSPEC;
1082
 
        hints.ai_socktype = SOCK_DGRAM;
1083
 
 
1084
 
        ret = getaddrinfo(host, NULL, &hints, &ni);
1085
 
        if (ret)
1086
 
                goto try_name;
1087
 
 
1088
 
        this = ni;
1089
 
        while (this) {
1090
 
                ret = add_new_host(list, host, weight, this);
1091
 
                if (!ret)
1092
 
                        break;
1093
 
                this = this->ai_next;
1094
 
        }
1095
 
        freeaddrinfo(ni);
1096
 
        goto done;
1097
 
 
1098
 
try_name:
1099
 
        memset(&hints, 0, sizeof(hints));
1100
 
        hints.ai_flags = AI_ADDRCONFIG;
1101
 
        hints.ai_family = AF_UNSPEC;
1102
 
        hints.ai_socktype = SOCK_DGRAM;
1103
 
 
1104
 
        ret = getaddrinfo(host, NULL, &hints, &ni);
1105
 
        if (ret) {
1106
 
                error(LOGOPT_ANY, "hostname lookup failed: %s",
1107
 
                      gai_strerror(ret));
1108
 
                return 0;
1109
 
        }
1110
 
 
1111
 
        this = ni;
1112
 
        while (this) {
1113
 
                ret = add_new_host(list, host, weight, this);
1114
 
                if (!ret)
1115
 
                        break;
1116
 
                this = this->ai_next;
1117
 
        }
1118
 
        freeaddrinfo(ni);
1119
 
done:
1120
 
        return ret;
1121
 
}
1122
 
 
1123
 
static int add_path(struct host *hosts, const char *path, int len)
1124
 
{
1125
 
        struct host *this;
1126
 
        char *tmp, *tmp2;
1127
 
 
1128
 
        tmp = alloca(len + 1);
1129
 
        if (!tmp)
1130
 
                return 0;
1131
 
 
1132
 
        strncpy(tmp, path, len);
1133
 
        tmp[len] = '\0';
1134
 
 
1135
 
        this = hosts;
1136
 
        while (this) {
1137
 
                if (!this->path) {
1138
 
                        tmp2 = strdup(tmp);
1139
 
                        if (!tmp2)
1140
 
                                return 0;
1141
 
                        this->path = tmp2;
1142
 
                }
1143
 
                this = this->next;
1144
 
        }
1145
 
 
1146
 
        return 1;
1147
 
}
1148
 
 
1149
 
static int add_local_path(struct host **hosts, const char *path)
1150
 
{
1151
 
        struct host *new;
1152
 
        char *tmp;
1153
 
 
1154
 
        tmp = strdup(path);
1155
 
        if (!tmp)
1156
 
                return 0;
1157
 
 
1158
 
        new = malloc(sizeof(struct host));
1159
 
        if (!new) {
1160
 
                free(tmp);
1161
 
                return 0;
1162
 
        }
1163
 
 
1164
 
        memset(new, 0, sizeof(struct host));
1165
 
 
1166
 
        new->path = tmp;
1167
 
        new->proximity = PROXIMITY_LOCAL;
1168
 
        new->version = NFS_VERS_MASK;
1169
 
        new->name = NULL;
1170
 
        new->addr = NULL;
1171
 
        new->weight = new->cost = 0;
1172
 
 
1173
 
        add_host(hosts, new);
1174
 
 
1175
 
        return 1;
1176
 
}
1177
 
 
1178
 
static char *seek_delim(const char *s)
1179
 
{
1180
 
        const char *p = s;
1181
 
        char *delim;
1182
 
 
1183
 
        delim = strpbrk(p, "(, \t:");
1184
 
        if (delim && *delim != ':')
1185
 
                return delim;
1186
 
 
1187
 
        while (*p) {
1188
 
                if (*p != ':') {
1189
 
                        p++;
1190
 
                        continue;
1191
 
                }
1192
 
                if (!strncmp(p, ":/", 2))
1193
 
                        return (char *) p;
1194
 
                p++;
1195
 
        }
1196
 
 
1197
 
        return NULL;
1198
 
}
1199
 
 
1200
 
int parse_location(unsigned logopt, struct host **hosts, const char *list)
1201
 
{
1202
 
        char *str, *p, *delim;
1203
 
        unsigned int empty = 1;
1204
 
 
1205
 
        if (!list)
1206
 
                return 0;
1207
 
 
1208
 
        str = strdup(list);
1209
 
        if (!str)
1210
 
                return 0;
1211
 
 
1212
 
        p = str;
1213
 
 
1214
 
        while (p && *p) {
1215
 
                char *next = NULL;
1216
 
                int weight = 0;
1217
 
 
1218
 
                p += strspn(p, " \t,");
1219
 
                delim = seek_delim(p);
1220
 
 
1221
 
                if (delim) {
1222
 
                        if (*delim == '(') {
1223
 
                                char *w = delim + 1;
1224
 
 
1225
 
                                *delim = '\0';
1226
 
 
1227
 
                                delim = strchr(w, ')');
1228
 
                                if (delim) {
1229
 
                                        *delim = '\0';
1230
 
                                        weight = atoi(w);
1231
 
                                }
1232
 
                                delim++;
1233
 
                        }
1234
 
 
1235
 
                        if (*delim == ':') {
1236
 
                                char *path;
1237
 
 
1238
 
                                *delim = '\0';
1239
 
                                path = delim + 1;
1240
 
 
1241
 
                                /* Oh boy - might have spaces in the path */
1242
 
                                next = path;
1243
 
                                while (*next && strncmp(next, ":/", 2))
1244
 
                                        next++;
1245
 
 
1246
 
                                /* No spaces in host names at least */
1247
 
                                if (*next == ':') {
1248
 
                                        while (*next &&
1249
 
                                              (*next != ' ' && *next != '\t'))
1250
 
                                                next--;
1251
 
                                        *next++ = '\0';
1252
 
                                }
1253
 
 
1254
 
                                if (p != delim) {
1255
 
                                        if (!add_host_addrs(hosts, p, weight)) {
1256
 
                                                if (empty) {
1257
 
                                                        p = next;
1258
 
                                                        continue;
1259
 
                                                }
1260
 
                                        }
1261
 
 
1262
 
                                        if (!add_path(*hosts, path, strlen(path))) {
1263
 
                                                free_host_list(hosts);
1264
 
                                                free(str);
1265
 
                                                return 0;
1266
 
                                        }
1267
 
                                } else {
1268
 
                                        if (!add_local_path(hosts, path)) {
1269
 
                                                p = next;
1270
 
                                                continue;
1271
 
                                        }
1272
 
                                }
1273
 
                        } else if (*delim != '\0') {
1274
 
                                *delim = '\0';
1275
 
                                next = delim + 1;
1276
 
 
1277
 
                                if (!add_host_addrs(hosts, p, weight)) {
1278
 
                                        p = next;
1279
 
                                        continue;
1280
 
                                }
1281
 
 
1282
 
                                empty = 0;
1283
 
                        }
1284
 
                } else {
1285
 
                        /* syntax error - no mount path */
1286
 
                        free_host_list(hosts);
1287
 
                        free(str);
1288
 
                        return 0;
1289
 
                }
1290
 
 
1291
 
                p = next;
1292
 
        }
1293
 
 
1294
 
        free(str);
1295
 
        return 1;
1296
 
}
1297
 
 
1298
 
void dump_host_list(struct host *hosts)
1299
 
{
1300
 
        struct host *this;
1301
 
 
1302
 
        if (!hosts)
1303
 
                return;
1304
 
 
1305
 
        this = hosts;
1306
 
        while (this) {
1307
 
                logmsg("name %s path %s version %x proximity %u weight %u cost %u",
1308
 
                      this->name, this->path, this->version,
1309
 
                      this->proximity, this->weight, this->cost);
1310
 
                this = this->next;
1311
 
        }
1312
 
        return;
1313
 
}
1314