Whamcloud - gitweb
Land b1_8_gate onto b1_8 (20081218_1708)
[fs/lustre-release.git] / lustre / utils / lshowmount.c
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <getopt.h>
9 #include <dirent.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <arpa/inet.h>
14 #include <netdb.h>
15 #include <errno.h>
16 #include "lshowmount.h"
17 #include "hash.h"
18 #include "hostlist.h"
19
20 #define PROGNAME "lshowmount"
21
22 extern int errno;
23 static int enumerate = 0;
24 static int lookup    = 0;
25 static int verbose   = 0;
26
27 static int totalexports = 0;
28 static int totalfailures = 0;
29
30 static struct option long_options[] = {
31     {"enumerate", 0, 0, 'e'},
32     {"help",      0, 0, 'h'},
33     {"lookup",    0, 0, 'l'},
34     {"verbose",   0, 0, 'v'},
35     {0, 0, 0, 0}
36 };
37
38 inline int
39 lshowmount_hash_strcmp(const void *key1, const void *key2)
40 {
41     return strcmp((char *) key1, (char *) key2);
42 }
43
44 inline void
45 lshowmount_hash_hostlist_freeitem(void *data)
46 {
47     hostlist_t hl = NULL;
48
49     if (data == NULL) {
50         return;
51     }
52
53     hl = (hostlist_t) data;
54     hostlist_destroy(hl);
55 }
56
57 inline int
58 is_ipaddress(const char *str)
59 {
60     int rc = 0;
61     int quad[4];
62
63     rc = sscanf(str, "%d.%d.%d.%d", &quad[0], &quad[1], &quad[2], &quad[3]);
64     if (rc == 4) {
65         return 1;
66     }
67     return 0;
68 }
69
70 inline void
71 lshowmount_gethostname(const char *src, char *dst, int dstsize)
72 {
73     struct hostent *hostptr = NULL;
74     char tmpsrc[4];
75     int rc = 0;
76
77     memset(dst, 0, sizeof(char) * dstsize);
78     if (lookup && is_ipaddress(src)) {
79         rc = inet_pton(AF_INET, src, tmpsrc);
80
81         if (rc <= 0) {
82             strncpy(dst, src, dstsize);
83             return;
84         }
85         else {
86             hostptr = gethostbyaddr(tmpsrc, 4, AF_INET);
87             if (hostptr == NULL) {
88                 strncpy(dst, src, dstsize);
89                 return;
90             }
91             else {
92                 strncpy(dst, hostptr->h_name, dstsize);
93                 return;
94             }
95         }
96     }
97     strncpy(dst, src, dstsize);
98 }
99
100 void
101 lshowmount_print_hosts(char** network,
102                        hash_t network_hash)
103 {
104     hostlist_t hl = NULL;
105     hostlist_iterator_t itr = NULL;
106     char *hosts = NULL;
107     int numnets = 0, numhosts = 0, i = 0;
108
109     if (network == NULL || network_hash == NULL) {
110         return;
111     }
112
113     numnets = hash_count(network_hash);
114     for (i = 0; i < numnets; i++) {
115         errno = 0;
116         hl = hash_remove(network_hash, network[i]);
117         if (hl == NULL) {
118             continue;
119         }
120         hostlist_uniq(hl);
121         numhosts = hostlist_count(hl);
122
123         if (numhosts > 0) {
124             if (enumerate) {
125                 itr = hostlist_iterator_create(hl);
126
127                 /* setup argument */
128                 while ((hosts = hostlist_next(itr)) != NULL) {
129                     printf("    %s@%s\n", hosts, network[i]);
130                 }
131                 hostlist_iterator_destroy(itr);
132             }
133             else {
134                 hosts = malloc(sizeof(char) * (numhosts) * (NID_MAX+1));
135                 if (hosts == NULL) {
136                     fprintf(stderr, "warning: could not allocate buffer "
137                                     "to print hostrange\n");
138                     return;
139                 }
140                 hostlist_ranged_string(hl, sizeof(char) *
141                                            numhosts *
142                                            (NID_MAX+1), hosts);
143                 printf("    %s@%s\n", hosts, network[i]);
144                 free(hosts);
145                 hosts = NULL;
146             }
147         }
148         memset(network[i], 0, sizeof(char) * (LNET_NETWORK_TYPE_MAX+1));
149         lshowmount_hash_hostlist_freeitem(hl);
150     }
151 }
152
153 void usage(void)
154 {
155         fprintf(stderr, "usage: %s [-e] [-h] [-l] [-v]\n", PROGNAME);
156 }
157
158 int getclients(char*  procpath,
159                char** network,
160                hash_t network_hash)
161 {
162     DIR *dirp, *dirp2;
163     struct dirent *dp, *dp2;
164     char path[PATH_MAX+1];
165     char nid[NID_MAX+1], addr[NID_MAX+1];
166     int size = PATH_MAX+1, sizeleft, sizeleft2;
167     int tmplen, tmplen2, idx, rc = 0;
168     char *tmp, *tmp2;
169     hostlist_t hl;
170
171     if (procpath == NULL) {
172         return -1;
173     }
174
175     /* It is not an error if we cannot open
176      * procpath since we are not sure if this
177      * node is an mgs, mds, and/or oss */
178     errno = 0;
179     dirp = opendir(procpath);
180     if (dirp == NULL) {
181         return 0;
182     }
183
184     do {
185         errno = 0;
186         dp = readdir(dirp);
187         if (dp != NULL) {
188             if (dp->d_type != DT_DIR ||
189                 strncmp(dp->d_name, ".", 2) == 0  ||
190                 strncmp(dp->d_name, "..", 3) == 0) {
191                 continue;
192             }
193
194             sizeleft = size;
195             tmp = path;
196             memset(tmp, 0, sizeof(char) * sizeleft);
197
198             strncpy(tmp, procpath, sizeleft);
199             tmplen = strnlen(tmp, sizeleft);
200             sizeleft -= tmplen;
201             tmp += tmplen;
202
203             strncpy(tmp, "/", sizeleft);
204             tmplen = strnlen(tmp, sizeleft);
205             sizeleft -= tmplen;
206             tmp += tmplen;
207
208             strncpy(tmp, dp->d_name, sizeleft);
209             tmplen = strnlen(tmp, sizeleft);
210             sizeleft -= tmplen;
211             tmp += tmplen;
212
213             strncpy(tmp, "/", sizeleft);
214             tmplen = strnlen(tmp, sizeleft);
215             sizeleft -= tmplen;
216             tmp += tmplen;
217
218             strncpy(tmp, PROC_EXPORTS, sizeleft);
219             tmplen = strnlen(tmp, sizeleft);
220             sizeleft -= tmplen;
221             tmp += tmplen;
222
223             errno = 0;
224             dirp2 = opendir(path);
225             if (dirp2 == NULL) {
226                 fprintf(stderr, "error: could not open: %s\n", path);
227                 rc = errno;
228                 continue;
229             }
230
231             do {
232                 errno = 0;
233                 dp2 = readdir(dirp2);
234                 if (dp2 != NULL) {
235                     if (strncmp(dp2->d_name, ".", 2) == 0  ||
236                         strncmp(dp2->d_name, "..", 3) == 0 ||
237                         dp2->d_type != DT_DIR) {
238                         continue;
239                     }
240                     totalexports++;
241
242                     sizeleft2 = sizeleft;
243                     tmp2 = tmp;
244                     memset(tmp2, 0, sizeof(char) * sizeleft2);
245
246                     strncpy(tmp2, "/", sizeleft2);
247                     tmplen2 = strnlen(tmp2, sizeleft2);
248                     sizeleft2 -= tmplen2;
249                     tmp2 += tmplen2;
250
251                     strncpy(tmp2, dp2->d_name, sizeleft2);
252                     tmplen2 = strnlen(tmp2, sizeleft2);
253                     sizeleft2 -= tmplen2;
254                     tmp2 += tmplen2;
255
256                     memset(nid, 0, sizeof(char) * (NID_MAX+1));
257                     strncpy(nid, basename(path), sizeof(char) * (NID_MAX+1));
258                     tmp2 = strrchr(nid, '@');
259                     if (tmp2 == NULL) {
260                         totalfailures++;
261                         continue;
262                     }
263                     *tmp2 = '\0';
264                     tmp2++;
265                     /* Note that tmp2 should now hold the lnet network */
266
267                     /* Check to see if this lnet network already has a hostset
268                      * associated with it */
269                     errno = 0;
270                     hl = hash_find(network_hash, tmp2);
271                     if (hl == NULL) {
272                         if (hash_count(network_hash) >= NETWORK_MAX) {
273                             (void)closedir(dirp2);
274                             return EINVAL;
275                         }
276
277                         /* Create a new hostset for this hash table and
278                          * insert the first part of the nid into it */
279                         idx = hash_count(network_hash);
280                         strncpy(network[idx], tmp2, LNET_NETWORK_TYPE_MAX);
281                         lshowmount_gethostname(nid, addr, NID_MAX+1);
282                         hl = hostlist_create(addr);
283                         hash_insert(network_hash, network[idx], hl);
284                     }
285                     else {
286                         lshowmount_gethostname(nid, addr, NID_MAX+1);
287                         hostlist_push_host(hl, addr);
288                     }
289                 }
290             } while (dp2 != NULL);
291             (void) closedir(dirp2);
292
293             /* If the verbose option is set we want to print
294              * out the hostlist for each mgs, mds, obdfilter */
295             if (verbose) {
296                 printf("%s:\n", dp->d_name);
297                 if (totalfailures > 0) {
298                     fprintf(stderr, "failures %d of %d exports\n",
299                             totalfailures, totalexports);
300                 }
301
302                 if (!rc && totalfailures > 0) {
303                     rc = 1;
304                 }
305
306                 totalexports = totalfailures = 0;
307                 lshowmount_print_hosts(network, network_hash);
308             }
309         }
310     } while (dp != NULL);
311     (void) closedir(dirp);
312
313     if (!rc && totalfailures > 0) {
314         rc = 1;
315     }
316
317     return rc;
318 }
319
320 int main(int argc, char **argv)
321 {
322     int                 opt = 0;
323     int                 optidx = 0;
324     int                 i = 0, rc = 0, rc2 = 0, rc3 = 0;
325     hash_t              network_hash = NULL;
326     char**              network = NULL;
327
328     while ((opt = getopt_long(argc, argv, "ehlv",long_options, &optidx)) != -1) {
329         switch (opt) {
330             case 'e':
331                 enumerate = 1;
332                 break;
333             case 'h':
334                 usage();
335                 goto finish;
336                 break;
337             case 'l':
338                 lookup = 1;
339                 break;
340             case 'v':
341                 verbose = 1;
342                 break;
343             default:
344                 usage();
345                 rc = -1;
346                 goto finish;
347                 break;
348         }
349     }
350
351     /* Allocate memory for NETWORK_MAX total possible
352      * lnet networks.  Each network will have its own
353      * hash table so that we can possibly create a ranged
354      * string for it */
355     network = malloc(sizeof(char *) * NETWORK_MAX);
356     if (network == NULL) {
357         rc = ENOMEM;
358         goto finish;
359     }
360     memset(network, 0, sizeof(char *) * NETWORK_MAX);
361     for (i = 0; i < NETWORK_MAX; i++) {
362         network[i] = malloc(sizeof(char) * (LNET_NETWORK_TYPE_MAX+1));
363         if (network[i] == NULL) {
364             rc = ENOMEM;
365             goto finish;
366         }
367         memset(network[i], 0, sizeof(char) * (LNET_NETWORK_TYPE_MAX+1));
368     }
369
370     /* Initialize the network_hash.  This hash table will map
371      * a particular network say elan1 or tcp2 to a hostset */
372     network_hash = hash_create(0,
373                                (hash_key_f) hash_key_string,
374                                lshowmount_hash_strcmp,
375                                lshowmount_hash_hostlist_freeitem);
376
377     rc  = getclients(PROC_DIR_MGS, network, network_hash);
378     rc2 = getclients(PROC_DIR_MDS, network, network_hash);
379     rc3 = getclients(PROC_DIR_OST, network, network_hash);
380     if (rc || rc2 || rc3) {
381         rc = rc2 > rc ? rc2 : rc;
382         rc = rc3 > rc ? rc3 : rc;
383     }
384
385     if (!verbose) {
386         if (totalfailures > 0) {
387             fprintf(stderr, "failures %d of %d exports\n",
388                     totalfailures, totalexports);
389         }
390         lshowmount_print_hosts(network, network_hash);
391     }
392
393 finish:
394     hash_destroy(network_hash);
395     if (network != NULL) {
396         for (i = 0; i < NETWORK_MAX; i++) {
397             if (network[i] != NULL) {
398                 free(network[i]);
399                 network[i] = NULL;
400             }
401         }
402         free(network);
403         network = NULL;
404     }
405
406     return rc;
407 }
408
409 /*
410  * vi:tabstop=4 shiftwidth=4 expandtab
411  */