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