Whamcloud - gitweb
LU-8599 utils: restore lshowmount utility
[fs/lustre-release.git] / lustre / utils / nidlist.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  *
29  * lustre/utils/nidlist.c
30  *
31  * Author: Jim Garlick <garlick@llnl.gov>
32  */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <netdb.h>
39 #include <netinet/in.h>
40 #include <sys/socket.h>
41
42 #include "nidlist.h"
43
44 struct nl_struct {
45         char **nids;
46         int len;
47         int count;
48 };
49 #define NL_CHUNK        64
50
51 static void nl_oom(void)
52 {
53         fprintf(stderr, "%s: out of memory\n", prog);
54         exit(1);
55 }
56
57 NIDList nl_create(void)
58 {
59         struct nl_struct *nl;
60
61         nl = malloc(sizeof(struct nl_struct));
62         if (!nl)
63                 nl_oom();
64         nl->len = NL_CHUNK;
65         nl->nids = malloc(nl->len * sizeof(char *));
66         if (!nl->nids)
67                 nl_oom();
68         nl->count = 0;
69
70         return nl;
71 }
72
73 void nl_destroy(NIDList nl)
74 {
75         int i;
76
77         for (i = 0; i < nl->count; i++)
78                 free(nl->nids[i]);
79         free(nl->nids);
80         free(nl);
81 }
82
83 static void nl_grow(NIDList nl, int n)
84 {
85         nl->len += n;
86         nl->nids = realloc(nl->nids, nl->len * sizeof(char *));
87         if (!nl->nids)
88                 nl_oom();
89 }
90
91 void nl_add(NIDList nl, char *nid)
92 {
93         char *cp;
94
95         cp = strdup(nid);
96         if (!cp)
97                 nl_oom();
98         if (nl->count == nl->len)
99                 nl_grow(nl, NL_CHUNK);
100         nl->nids[nl->count++] = cp;
101 }
102
103 int nl_count(NIDList nl)
104 {
105         return nl->count;
106 }
107
108 static char *nl_nid_addr(char *nid)
109 {
110         char *addr, *p;
111
112         addr = strdup(nid);
113         if (!addr)
114                 nl_oom();
115         p = strchr(addr, '@');
116         if (p)
117                 *p = '\0';
118
119         return addr;
120 }
121
122 static int nl_nid_parse_addr(char *addr)
123 {
124         int o;
125
126         for (o = strlen(addr); o > 0; o--)
127                 if (!isdigit(addr[o - 1]))
128                         break;
129
130         return o;
131 }
132
133 static int nl_cmp_addr(char *nid1, char *nid2, int *cflagp)
134 {
135         char *p1 = nl_nid_addr(nid1);
136         char *p2 = nl_nid_addr(nid2);
137         int res, o1, o2, cflag = 0;
138
139         o1 = nl_nid_parse_addr(p1);
140         o2 = nl_nid_parse_addr(p2);
141
142         res = strncmp(p1, p2, o1);
143         if (o1 == o2 && res == 0) {
144                 res = strtoul(&p1[o1], NULL, 10) - strtoul(&p2[o2], NULL, 10);
145                 if (cflagp && strlen(&p1[o1]) > 0 && strlen(&p2[o2]) > 0)
146                         cflag = 1;
147         } else
148                 res = strcmp(p1, p2);
149         free(p1);
150         free(p2);
151         if (cflagp)
152                 *cflagp = cflag;
153         return res;
154 }
155
156 static int nl_cmp_lnet(char *nid1, char *nid2)
157 {
158         char *s1 = strchr(nid1, '@');
159         char *s2 = strchr(nid2, '@');
160
161         return strcmp(s1 ? s1 + 1 : "", s2 ? s2 + 1 : "");
162 }
163
164 static int nl_cmp(const void *p1, const void *p2)
165 {
166         int res;
167
168         res = nl_cmp_lnet(*(char **)p1, *(char **)p2);
169         if (res == 0)
170                 res = nl_cmp_addr(*(char **)p1, *(char **)p2, NULL);
171         return res;
172 }
173
174 void nl_sort(NIDList nl)
175 {
176         qsort(nl->nids, nl->count, sizeof(char *), nl_cmp);
177 }
178
179 void nl_uniq(NIDList nl)
180 {
181         int i, j;
182
183         for (i = 1; i < nl->count; i++) {
184                 if (!strcmp(nl->nids[i], nl->nids[i - 1])) {
185                         free(nl->nids[i]);
186                         for (j = i; j < nl->count - 1; j++)
187                                 nl->nids[j] = nl->nids[j + 1];
188                         nl->count--;
189                         i--;
190                 }
191         }
192 }
193
194 static char *nl_nid_lookup_ipaddr(char *nid)
195 {
196         struct addrinfo *ai, *aip;
197         char name[NI_MAXHOST] = "";
198         char *p, *addr, *lnet = NULL, *res = NULL;
199         int len, x;
200
201         addr = nl_nid_addr(nid);
202         if (sscanf(addr, "%d.%d.%d.%d", &x, &x, &x, &x) == 4) {
203                 p = strchr(nid, '@');
204                 if (p)
205                         lnet = p + 1;
206                 if (getaddrinfo(addr, NULL, NULL, &ai) == 0) {
207                         for (aip = ai; aip != NULL; aip = aip->ai_next) {
208                                 if (getnameinfo(aip->ai_addr, aip->ai_addrlen,
209                                     name, sizeof(name), NULL, 0,
210                                     NI_NAMEREQD | NI_NOFQDN) == 0) {
211                                         p = strchr(name, '.');
212                                         if (p)
213                                                 *p = '\0';
214                                         len = strlen(name) + 2;
215                                         if (lnet != NULL)
216                                                 len += strlen(lnet);
217                                         res = malloc(len);
218                                         if (!res)
219                                                 nl_oom();
220                                         if (lnet != NULL)
221                                                 snprintf(res, len, "%s@%s",
222                                                          name, lnet);
223                                         else
224                                                 snprintf(res, len, "%s", name);
225                                         break;
226                                 }
227                         }
228                         freeaddrinfo(ai);
229                 }
230         }
231         free(addr);
232
233         return res;
234 }
235
236 void nl_lookup_ip(NIDList nl)
237 {
238         int i;
239         char *new;
240
241         for (i = 0; i < nl->count; i++) {
242                 new = nl_nid_lookup_ipaddr(nl->nids[i]);
243                 if (new) {
244                         free(nl->nids[i]);
245                         nl->nids[i] = new;
246                 }
247         }
248 }
249
250 char *nl_string(NIDList nl, char *sep)
251 {
252         int seplen = strlen(sep);
253         int i, len = 1;
254         char *s;
255
256         for (i = 0; i < nl->count; i++)
257                 len += strlen(nl->nids[i]) + seplen;
258         s = malloc(len);
259         if (!s)
260                 nl_oom();
261         s[0] = '\0';
262         for (i = 0; i < nl->count; i++) {
263                 if (i > 0)
264                         strncat(s, sep, len);
265                 strncat(s, nl->nids[i], len);
266         }
267         return s;
268 }
269
270 static void nl_strxcat(char *s, char **nids, int len, const int max_len)
271 {
272         int i, o, lastn = 0;
273         char *base, *p, *lnet = NULL, *savedn = NULL;
274
275         p = strchr(nids[0], '@');
276         if (p)
277                 lnet = p + 1;
278         base = nl_nid_addr(nids[0]);
279         o = nl_nid_parse_addr(base);
280         base[o] = '\0';
281         for (i = 0; i < len; i++) {
282                 char *addr = nl_nid_addr(nids[i]);
283                 int n = strtoul(&addr[o], NULL, 10);
284
285                 if (i == 0)
286                         snprintf(s + strlen(s), max_len, "%s[%s", base,
287                                  &addr[o]);
288                 else if (i < len) {
289                         if (n == lastn + 1) {
290                                 if (savedn)
291                                         free(savedn);
292                                 savedn = strdup(&addr[o]);
293                                 if (!savedn)
294                                         nl_oom();
295                         } else {
296                                 if (savedn) {
297                                         snprintf(s + strlen(s),
298                                                  max_len - strlen(s),
299                                                  "-%s", savedn);
300                                         free(savedn);
301                                         savedn = NULL;
302                                 }
303                                 snprintf(s + strlen(s), max_len - strlen(s),
304                                          ",%s", &addr[o]);
305                         }
306                 }
307                 if (i == len - 1) {
308                         if (savedn) {
309                                 snprintf(s + strlen(s), max_len - strlen(s),
310                                          "-%s", savedn);
311                                 free(savedn);
312                         }
313                         strncat(s, "]", 1);
314                         if (lnet)
315                                 snprintf(s + strlen(s), max_len - strlen(s),
316                                          "@%s", lnet);
317                 }
318                 free(addr);
319                 lastn = n;
320         }
321         free(base);
322 }
323
324 char *nl_xstring(NIDList nl, char *sep)
325 {
326         int seplen = strlen(sep);
327         int cflag, i, j, len = 1;
328         char *s;
329
330         for (i = 0; i < nl->count; i++)
331                 len += strlen(nl->nids[i]) + seplen;
332         s = malloc(len);
333         if (!s)
334                 nl_oom();
335         s[0] = '\0';
336         for (i = 0; i < nl->count; i++) {
337                 if (i > 0)
338                         strncat(s, sep, len);
339                 for (j = i + 1; j < nl->count; j++) {
340                         if (nl_cmp_lnet(nl->nids[i], nl->nids[j]) != 0)
341                                 break;
342                         (void)nl_cmp_addr(nl->nids[i], nl->nids[j], &cflag);
343                         if (!cflag)
344                                 break;
345                 }
346                 if (j - i > 1)
347                         nl_strxcat(s, &nl->nids[i], j - i, len);
348                 else
349                         strncat(s, nl->nids[i], len);
350                 i += j - i - 1;
351         }
352         return s;
353 }