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