Imported Upstream version 0.5.0
[platform/upstream/multipath-tools.git] / libmultipath / structs.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  * Copyright (c) 2004 Stefan Bader, IBM
4  */
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <libdevmapper.h>
8 #include <libudev.h>
9
10 #include "checkers.h"
11 #include "memory.h"
12 #include "vector.h"
13 #include "util.h"
14 #include "structs.h"
15 #include "config.h"
16 #include "debug.h"
17 #include "structs_vec.h"
18 #include "blacklist.h"
19 #include "prio.h"
20
21 struct path *
22 alloc_path (void)
23 {
24         struct path * pp;
25
26         pp = (struct path *)MALLOC(sizeof(struct path));
27
28         if (pp) {
29                 pp->sg_id.host_no = -1;
30                 pp->sg_id.channel = -1;
31                 pp->sg_id.scsi_id = -1;
32                 pp->sg_id.lun = -1;
33                 pp->fd = -1;
34                 pp->priority = PRIO_UNDEF;
35         }
36         return pp;
37 }
38
39 void
40 free_path (struct path * pp)
41 {
42         if (!pp)
43                 return;
44
45         if (checker_selected(&pp->checker))
46                 checker_put(&pp->checker);
47
48         if (prio_selected(&pp->prio))
49                 prio_put(&pp->prio);
50
51         if (pp->fd >= 0)
52                 close(pp->fd);
53
54         if (pp->udev) {
55                 udev_device_unref(pp->udev);
56                 pp->udev = NULL;
57         }
58
59         FREE(pp);
60 }
61
62 void
63 free_pathvec (vector vec, enum free_path_mode free_paths)
64 {
65         int i;
66         struct path * pp;
67
68         if (!vec)
69                 return;
70
71         if (free_paths == FREE_PATHS)
72                 vector_foreach_slot(vec, pp, i)
73                         free_path(pp);
74
75         vector_free(vec);
76 }
77
78 struct pathgroup *
79 alloc_pathgroup (void)
80 {
81         struct pathgroup * pgp;
82
83         pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
84
85         if (!pgp)
86                 return NULL;
87
88         pgp->paths = vector_alloc();
89
90         if (!pgp->paths) {
91                 FREE(pgp);
92                 pgp = NULL;
93         }
94
95         return pgp;
96 }
97
98 void
99 free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
100 {
101         if (!pgp)
102                 return;
103
104         free_pathvec(pgp->paths, free_paths);
105         FREE(pgp);
106 }
107
108 void
109 free_pgvec (vector pgvec, enum free_path_mode free_paths)
110 {
111         int i;
112         struct pathgroup * pgp;
113
114         if (!pgvec)
115                 return;
116
117         vector_foreach_slot(pgvec, pgp, i)
118                 free_pathgroup(pgp, free_paths);
119
120         vector_free(pgvec);
121 }
122
123 struct multipath *
124 alloc_multipath (void)
125 {
126         struct multipath * mpp;
127
128         mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
129
130         if (mpp) {
131                 mpp->bestpg = 1;
132                 mpp->mpcontext = NULL;
133                 mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
134                 mpp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
135         }
136         return mpp;
137 }
138
139 extern void
140 free_multipath_attributes (struct multipath * mpp)
141 {
142         if (!mpp)
143                 return;
144
145         if (mpp->selector &&
146             mpp->selector != conf->selector &&
147             (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
148             (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
149                 FREE(mpp->selector);
150                 mpp->selector = NULL;
151         }
152
153         if (mpp->features) {
154                 FREE(mpp->features);
155                 mpp->features = NULL;
156         }
157
158         if (mpp->hwhandler &&
159             mpp->hwhandler != conf->hwhandler &&
160             (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
161                 FREE(mpp->hwhandler);
162                 mpp->hwhandler = NULL;
163         }
164 }
165
166 void
167 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
168 {
169         if (!mpp)
170                 return;
171
172         free_multipath_attributes(mpp);
173
174         if (mpp->alias) {
175                 FREE(mpp->alias);
176                 mpp->alias = NULL;
177         }
178
179         if (mpp->dmi) {
180                 FREE(mpp->dmi);
181                 mpp->dmi = NULL;
182         }
183
184         free_pathvec(mpp->paths, free_paths);
185         free_pgvec(mpp->pg, free_paths);
186         FREE_PTR(mpp->mpcontext);
187         FREE(mpp);
188 }
189
190 void
191 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
192 {
193         int i;
194         struct multipath * mpp;
195
196         if (!mpvec)
197                 return;
198
199         vector_foreach_slot (mpvec, mpp, i) {
200                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
201                         free_multipath(mpp, free_paths);
202                         vector_del_slot(mpvec, i);
203                         return;
204                 }
205         }
206 }
207
208 void
209 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
210 {
211         int i;
212         struct multipath * mpp;
213
214         if (!mpvec)
215                 return;
216
217         vector_foreach_slot (mpvec, mpp, i)
218                 free_multipath(mpp, free_paths);
219
220         vector_free(mpvec);
221 }
222
223 int
224 store_path (vector pathvec, struct path * pp)
225 {
226         if (!vector_alloc_slot(pathvec))
227                 return 1;
228
229         vector_set_slot(pathvec, pp);
230
231         return 0;
232 }
233
234 int
235 store_pathgroup (vector pgvec, struct pathgroup * pgp)
236 {
237         if (!vector_alloc_slot(pgvec))
238                 return 1;
239
240         vector_set_slot(pgvec, pgp);
241
242         return 0;
243 }
244
245 struct multipath *
246 find_mp_by_minor (vector mpvec, int minor)
247 {
248         int i;
249         struct multipath * mpp;
250
251         if (!mpvec)
252                 return NULL;
253
254         vector_foreach_slot (mpvec, mpp, i) {
255                 if (!mpp->dmi)
256                         continue;
257
258                 if (mpp->dmi->minor == minor)
259                         return mpp;
260         }
261         return NULL;
262 }
263
264 struct multipath *
265 find_mp_by_wwid (vector mpvec, char * wwid)
266 {
267         int i;
268         struct multipath * mpp;
269
270         if (!mpvec)
271                 return NULL;
272
273         vector_foreach_slot (mpvec, mpp, i)
274                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE))
275                         return mpp;
276
277         return NULL;
278 }
279
280 struct multipath *
281 find_mp_by_alias (vector mpvec, char * alias)
282 {
283         int i;
284         int len;
285         struct multipath * mpp;
286
287         if (!mpvec)
288                 return NULL;
289
290         len = strlen(alias);
291
292         if (!len)
293                 return NULL;
294
295         vector_foreach_slot (mpvec, mpp, i) {
296                 if (strlen(mpp->alias) == len &&
297                     !strncmp(mpp->alias, alias, len))
298                         return mpp;
299         }
300         return NULL;
301 }
302
303 struct multipath *
304 find_mp_by_str (vector mpvec, char * str)
305 {
306         int minor;
307
308         if (sscanf(str, "dm-%d", &minor) == 1)
309                 return find_mp_by_minor(mpvec, minor);
310         else
311                 return find_mp_by_alias(mpvec, str);
312 }
313
314 struct path *
315 find_path_by_dev (vector pathvec, char * dev)
316 {
317         int i;
318         struct path * pp;
319
320         if (!pathvec)
321                 return NULL;
322
323         vector_foreach_slot (pathvec, pp, i)
324                 if (!strcmp(pp->dev, dev))
325                         return pp;
326
327         condlog(3, "%s: not found in pathvec", dev);
328         return NULL;
329 }
330
331 struct path *
332 find_path_by_devt (vector pathvec, char * dev_t)
333 {
334         int i;
335         struct path * pp;
336
337         if (!pathvec)
338                 return NULL;
339
340         vector_foreach_slot (pathvec, pp, i)
341                 if (!strcmp(pp->dev_t, dev_t))
342                         return pp;
343
344         condlog(3, "%s: not found in pathvec", dev_t);
345         return NULL;
346 }
347
348 extern int
349 pathcountgr (struct pathgroup * pgp, int state)
350 {
351         struct path *pp;
352         int count = 0;
353         int i;
354
355         vector_foreach_slot (pgp->paths, pp, i)
356                 if ((pp->state == state) || (state == PATH_WILD))
357                         count++;
358
359         return count;
360 }
361
362 extern int
363 pathcount (struct multipath * mpp, int state)
364 {
365         struct pathgroup *pgp;
366         int count = 0;
367         int i;
368
369         if (mpp->pg) {
370                 vector_foreach_slot (mpp->pg, pgp, i)
371                         count += pathcountgr(pgp, state);
372         }
373         return count;
374 }
375
376 extern int
377 pathcmp (struct pathgroup *pgp, struct pathgroup *cpgp)
378 {
379         int i, j;
380         struct path *pp, *cpp;
381         int pnum = 0, found = 0;
382
383         vector_foreach_slot(pgp->paths, pp, i) {
384                 pnum++;
385                 vector_foreach_slot(cpgp->paths, cpp, j) {
386                         if ((long)pp == (long)cpp) {
387                                 found++;
388                                 break;
389                         }
390                 }
391         }
392
393         return pnum - found;
394 }
395
396 struct path *
397 first_path (struct multipath * mpp)
398 {
399         struct pathgroup * pgp;
400         if (!mpp->pg)
401                 return NULL;
402         pgp = VECTOR_SLOT(mpp->pg, 0);
403
404         return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
405 }
406
407 extern void
408 setup_feature(struct multipath * mpp, char *feature)
409 {
410         if (!strncmp(feature, "queue_if_no_path", 16)) {
411                 if (mpp->no_path_retry <= NO_PATH_RETRY_UNDEF)
412                         mpp->no_path_retry = NO_PATH_RETRY_QUEUE;
413         }
414 }
415
416 extern int
417 add_feature (char **f, char *n)
418 {
419         int c = 0, d, l;
420         char *e, *p, *t;
421
422         if (!f)
423                 return 1;
424
425         /* Nothing to do */
426         if (!n || *n == '0')
427                 return 0;
428
429         /* Check if feature is already present */
430         if (strstr(*f, n))
431                 return 0;
432
433         /* Get feature count */
434         c = strtoul(*f, &e, 10);
435         if (*f == e)
436                 /* parse error */
437                 return 1;
438
439         /* Check if we need to increase feature count space */
440         l = strlen(*f) + strlen(n) + 1;
441
442         /* Count new features */
443         if ((c % 10) == 9)
444                 l++;
445         c++;
446         p = n;
447         while (*p != '\0') {
448                 if (*p == ' ' && p[1] != '\0' && p[1] != ' ') {
449                         if ((c % 10) == 9)
450                                 l++;
451                         c++;
452                 }
453                 p++;
454         }
455
456         t = MALLOC(l + 1);
457         if (!t)
458                 return 1;
459
460         memset(t, 0, l + 1);
461
462         /* Update feature count */
463         d = c;
464         l = 1;
465         while (d > 9) {
466                 d /= 10;
467                 l++;
468         }
469         p = t;
470         snprintf(p, l + 2, "%0d ", c);
471
472         /* Copy the feature string */
473         p = strchr(*f, ' ');
474         if (p) {
475                 while (*p == ' ')
476                         p++;
477                 strcat(t, p);
478                 strcat(t, " ");
479         } else {
480                 p = t + strlen(t);
481         }
482         strcat(t, n);
483
484         FREE(*f);
485         *f = t;
486
487         return 0;
488 }
489
490 extern int
491 remove_feature(char **f, char *o)
492 {
493         int c = 0, d, l;
494         char *e, *p, *n;
495
496         if (!f || !*f)
497                 return 1;
498
499         /* Nothing to do */
500         if (!o || *o == '\0')
501                 return 0;
502
503         /* Check if not present */
504         if (!strstr(*f, o))
505                 return 0;
506
507         /* Get feature count */
508         c = strtoul(*f, &e, 10);
509         if (*f == e)
510                 /* parse error */
511                 return 1;
512
513         /* Normalize features */
514         while (*o == ' ') {
515                 o++;
516         }
517         /* Just spaces, return */
518         if (*o == '\0')
519                 return 0;
520         e = o + strlen(o);
521         while (*e == ' ')
522                 e--;
523         d = (int)(e - o);
524
525         /* Update feature count */
526         c--;
527         p = o;
528         while (p[0] != '\0') {
529                 if (p[0] == ' ' && p[1] != ' ' && p[1] != '\0')
530                         c--;
531                 p++;
532         }
533
534         /* Quick exit if all features have been removed */
535         if (c == 0) {
536                 n = MALLOC(2);
537                 if (!n)
538                         return 1;
539                 strcpy(n, "0");
540                 goto out;
541         }
542
543         /* Search feature to be removed */
544         e = strstr(*f, o);
545         if (!e)
546                 /* Not found, return */
547                 return 0;
548
549         /* Update feature count space */
550         l = strlen(*f) - d;
551         n =  MALLOC(l + 1);
552         if (!n)
553                 return 1;
554
555         /* Copy the feature count */
556         sprintf(n, "%0d", c);
557         /*
558          * Copy existing features up to the feature
559          * about to be removed
560          */
561         p = strchr(*f, ' ');
562         if (!p)
563                 /* Internal error, feature string inconsistent */
564                 return 1;
565         while (*p == ' ')
566                 p++;
567         p--;
568         if (e != p) {
569                 do {
570                         e--;
571                         d++;
572                 } while (*e == ' ');
573                 e++; d--;
574                 strncat(n, p, (size_t)(e - p));
575                 p += (size_t)(e - p);
576         }
577         /* Skip feature to be removed */
578         p += d;
579
580         /* Copy remaining features */
581         if (strlen(p)) {
582                 while (*p == ' ')
583                         p++;
584                 if (strlen(p)) {
585                         p--;
586                         strcat(n, p);
587                 }
588         }
589
590 out:
591         FREE(*f);
592         *f = n;
593
594         return 0;
595 }
596