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