Whamcloud - gitweb
LU-13048 mdd: allow release after a non-blocking migrate
[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  * Copyright (c) 2014, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/utils/nidlist.c
32  *
33  * Author: Jim Garlick <garlick@llnl.gov>
34  */
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <netdb.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43
44 #include "nidlist.h"
45
46 struct nl_struct {
47         char **nids;
48         int len;
49         int count;
50 };
51 #define NL_CHUNK        64
52
53 static void nl_oom(void)
54 {
55         fprintf(stderr, "%s: out of memory\n", prog);
56         exit(1);
57 }
58
59 NIDList nl_create(void)
60 {
61         struct nl_struct *nl;
62
63         nl = malloc(sizeof(struct nl_struct));
64         if (!nl)
65                 nl_oom();
66         nl->len = NL_CHUNK;
67         nl->nids = malloc(nl->len * sizeof(char *));
68         if (!nl->nids)
69                 nl_oom();
70         nl->count = 0;
71
72         return nl;
73 }
74
75 void nl_destroy(NIDList nl)
76 {
77         int i;
78
79         for (i = 0; i < nl->count; i++)
80                 free(nl->nids[i]);
81         free(nl->nids);
82         free(nl);
83 }
84
85 static void nl_grow(NIDList nl, int n)
86 {
87         nl->len += n;
88         nl->nids = realloc(nl->nids, nl->len * sizeof(char *));
89         if (!nl->nids)
90                 nl_oom();
91 }
92
93 void nl_add(NIDList nl, char *nid)
94 {
95         char *cp;
96
97         cp = strdup(nid);
98         if (!cp)
99                 nl_oom();
100         if (nl->count == nl->len)
101                 nl_grow(nl, NL_CHUNK);
102         nl->nids[nl->count++] = cp;
103 }
104
105 int nl_count(NIDList nl)
106 {
107         return nl->count;
108 }
109
110 static char *nl_nid_addr(char *nid)
111 {
112         char *addr, *p;
113
114         addr = strdup(nid);
115         if (!addr)
116                 nl_oom();
117         p = strchr(addr, '@');
118         if (p)
119                 *p = '\0';
120
121         return addr;
122 }
123
124 static int nl_nid_parse_addr(char *addr)
125 {
126         int o;
127
128         for (o = strlen(addr); o > 0; o--)
129                 if (!isdigit(addr[o - 1]))
130                         break;
131
132         return o;
133 }
134
135 static int nl_cmp_addr(char *nid1, char *nid2, int *cflagp)
136 {
137         char *p1 = nl_nid_addr(nid1);
138         char *p2 = nl_nid_addr(nid2);
139         int res, o1, o2, cflag = 0;
140
141         o1 = nl_nid_parse_addr(p1);
142         o2 = nl_nid_parse_addr(p2);
143
144         res = strncmp(p1, p2, o1);
145         if (o1 == o2 && res == 0) {
146                 res = strtoul(&p1[o1], NULL, 10) - strtoul(&p2[o2], NULL, 10);
147                 if (cflagp && strlen(&p1[o1]) > 0 && strlen(&p2[o2]) > 0)
148                         cflag = 1;
149         } else
150                 res = strcmp(p1, p2);
151         free(p1);
152         free(p2);
153         if (cflagp)
154                 *cflagp = cflag;
155         return res;
156 }
157
158 static int nl_cmp_lnet(char *nid1, char *nid2)
159 {
160         char *s1 = strchr(nid1, '@');
161         char *s2 = strchr(nid2, '@');
162
163         return strcmp(s1 ? s1 + 1 : "", s2 ? s2 + 1 : "");
164 }
165
166 static int nl_cmp(const void *p1, const void *p2)
167 {
168         int res;
169
170         res = nl_cmp_lnet(*(char **)p1, *(char **)p2);
171         if (res == 0)
172                 res = nl_cmp_addr(*(char **)p1, *(char **)p2, NULL);
173         return res;
174 }
175
176 void nl_sort(NIDList nl)
177 {
178         qsort(nl->nids, nl->count, sizeof(char *), nl_cmp);
179 }
180
181 void nl_uniq(NIDList nl)
182 {
183         int i, j;
184
185         for (i = 1; i < nl->count; i++) {
186                 if (!strcmp(nl->nids[i], nl->nids[i - 1])) {
187                         free(nl->nids[i]);
188                         for (j = i; j < nl->count - 1; j++)
189                                 nl->nids[j] = nl->nids[j + 1];
190                         nl->count--;
191                         i--;
192                 }
193         }
194 }
195
196 static char *nl_nid_lookup_ipaddr(char *nid)
197 {
198         struct addrinfo *ai, *aip;
199         char name[NI_MAXHOST] = "";
200         char *p, *addr, *lnet = NULL, *res = NULL;
201         struct addrinfo hints;
202         int len, x;
203
204         addr = nl_nid_addr(nid);
205         if (sscanf(addr, "%d.%d.%d.%d", &x, &x, &x, &x) == 4) {
206                 p = strchr(nid, '@');
207                 if (p)
208                         lnet = p + 1;
209                 memset(&hints, 0, sizeof(struct addrinfo));
210                 hints.ai_family = AF_INET;
211                 if (getaddrinfo(addr, NULL, &hints, &ai) == 0) {
212                         for (aip = ai; aip != NULL; aip = aip->ai_next) {
213                                 if (getnameinfo(aip->ai_addr, aip->ai_addrlen,
214                                     name, sizeof(name), NULL, 0,
215                                     NI_NAMEREQD | NI_NOFQDN) == 0) {
216                                         p = strchr(name, '.');
217                                         if (p)
218                                                 *p = '\0';
219                                         len = strlen(name) + 2;
220                                         if (lnet != NULL)
221                                                 len += strlen(lnet);
222                                         res = malloc(len);
223                                         if (!res)
224                                                 nl_oom();
225                                         if (lnet != NULL)
226                                                 snprintf(res, len, "%s@%s",
227                                                          name, lnet);
228                                         else
229                                                 snprintf(res, len, "%s", name);
230                                         break;
231                                 }
232                         }
233                         freeaddrinfo(ai);
234                 }
235         }
236         free(addr);
237
238         return res;
239 }
240
241 void nl_lookup_ip(NIDList nl)
242 {
243         int i;
244         char *new;
245
246         for (i = 0; i < nl->count; i++) {
247                 new = nl_nid_lookup_ipaddr(nl->nids[i]);
248                 if (new) {
249                         free(nl->nids[i]);
250                         nl->nids[i] = new;
251                 }
252         }
253 }
254
255 char *nl_string(NIDList nl, char *sep)
256 {
257         int seplen = strlen(sep);
258         int i, len = 1;
259         char *s;
260
261         for (i = 0; i < nl->count; i++)
262                 len += strlen(nl->nids[i]) + seplen;
263         s = malloc(len);
264         if (!s)
265                 nl_oom();
266         s[0] = '\0';
267         for (i = 0; i < nl->count; i++) {
268                 int cur = strlen(s);
269                 snprintf(s + cur, len - cur, "%s%s",
270                          i > 0 ? sep : "", nl->nids[i]);
271         }
272         return s;
273 }
274
275 static void nl_strxcat(char *s, char **nids, int len, const int max_len)
276 {
277         int i, o, lastn = 0;
278         char *base, *p, *lnet = NULL, *savedn = NULL;
279
280         p = strchr(nids[0], '@');
281         if (p)
282                 lnet = p + 1;
283         base = nl_nid_addr(nids[0]);
284         o = nl_nid_parse_addr(base);
285         base[o] = '\0';
286         for (i = 0; i < len; i++) {
287                 char *addr = nl_nid_addr(nids[i]);
288                 int n = strtoul(&addr[o], NULL, 10);
289
290                 if (i == 0)
291                         snprintf(s + strlen(s), max_len, "%s[%s", base,
292                                  &addr[o]);
293                 else if (i < len) {
294                         if (n == lastn + 1) {
295                                 if (savedn)
296                                         free(savedn);
297                                 savedn = strdup(&addr[o]);
298                                 if (!savedn)
299                                         nl_oom();
300                         } else {
301                                 if (savedn) {
302                                         snprintf(s + strlen(s),
303                                                  max_len - strlen(s),
304                                                  "-%s", savedn);
305                                         free(savedn);
306                                         savedn = NULL;
307                                 }
308                                 snprintf(s + strlen(s), max_len - strlen(s),
309                                          ",%s", &addr[o]);
310                         }
311                 }
312                 if (i == len - 1) {
313                         if (savedn) {
314                                 snprintf(s + strlen(s), max_len - strlen(s),
315                                          "-%s", savedn);
316                                 free(savedn);
317                         }
318                         strncat(s, "]", max_len - strlen(s));
319                         if (lnet)
320                                 snprintf(s + strlen(s), max_len - strlen(s),
321                                          "@%s", lnet);
322                 }
323                 free(addr);
324                 lastn = n;
325         }
326         free(base);
327 }
328
329 char *nl_xstring(NIDList nl, char *sep)
330 {
331         int seplen = strlen(sep);
332         int cflag, i, j, len = 1;
333         char *s;
334
335         for (i = 0; i < nl->count; i++)
336                 len += strlen(nl->nids[i]) + seplen;
337         s = malloc(len);
338         if (!s)
339                 nl_oom();
340         s[0] = '\0';
341         for (i = 0; i < nl->count; i++) {
342                 if (i > 0)
343                         strncat(s, sep, len);
344                 for (j = i + 1; j < nl->count; j++) {
345                         if (nl_cmp_lnet(nl->nids[i], nl->nids[j]) != 0)
346                                 break;
347                         (void)nl_cmp_addr(nl->nids[i], nl->nids[j], &cflag);
348                         if (!cflag)
349                                 break;
350                 }
351                 if (j - i > 1)
352                         nl_strxcat(s, &nl->nids[i], j - i, len);
353                 else
354                         strncat(s, nl->nids[i], len);
355                 i += j - i - 1;
356         }
357         return s;
358 }