Imported Upstream version 0.7.5
[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                 checker_clear(&pp->checker);
104                 dm_path_to_gen(pp)->ops = &dm_gen_path_ops;
105         }
106         return pp;
107 }
108
109 void
110 free_path (struct path * pp)
111 {
112         if (!pp)
113                 return;
114
115         if (checker_selected(&pp->checker))
116                 checker_put(&pp->checker);
117
118         if (prio_selected(&pp->prio))
119                 prio_put(&pp->prio);
120
121         if (pp->fd >= 0)
122                 close(pp->fd);
123
124         if (pp->udev) {
125                 udev_device_unref(pp->udev);
126                 pp->udev = NULL;
127         }
128
129         FREE(pp);
130 }
131
132 void
133 free_pathvec (vector vec, enum free_path_mode free_paths)
134 {
135         int i;
136         struct path * pp;
137
138         if (!vec)
139                 return;
140
141         if (free_paths == FREE_PATHS)
142                 vector_foreach_slot(vec, pp, i)
143                         free_path(pp);
144
145         vector_free(vec);
146 }
147
148 struct pathgroup *
149 alloc_pathgroup (void)
150 {
151         struct pathgroup * pgp;
152
153         pgp = (struct pathgroup *)MALLOC(sizeof(struct pathgroup));
154
155         if (!pgp)
156                 return NULL;
157
158         pgp->paths = vector_alloc();
159
160         if (!pgp->paths) {
161                 FREE(pgp);
162                 pgp = NULL;
163         }
164
165         dm_pathgroup_to_gen(pgp)->ops = &dm_gen_pathgroup_ops;
166         return pgp;
167 }
168
169 void
170 free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths)
171 {
172         if (!pgp)
173                 return;
174
175         free_pathvec(pgp->paths, free_paths);
176         FREE(pgp);
177 }
178
179 void
180 free_pgvec (vector pgvec, enum free_path_mode free_paths)
181 {
182         int i;
183         struct pathgroup * pgp;
184
185         if (!pgvec)
186                 return;
187
188         vector_foreach_slot(pgvec, pgp, i)
189                 free_pathgroup(pgp, free_paths);
190
191         vector_free(pgvec);
192 }
193
194 struct multipath *
195 alloc_multipath (void)
196 {
197         struct multipath * mpp;
198
199         mpp = (struct multipath *)MALLOC(sizeof(struct multipath));
200
201         if (mpp) {
202                 mpp->bestpg = 1;
203                 mpp->mpcontext = NULL;
204                 mpp->no_path_retry = NO_PATH_RETRY_UNDEF;
205                 mpp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
206                 dm_multipath_to_gen(mpp)->ops = &dm_gen_multipath_ops;
207         }
208         return mpp;
209 }
210
211 void free_multipath_attributes(struct multipath *mpp)
212 {
213         if (!mpp)
214                 return;
215
216         if (mpp->selector) {
217                 FREE(mpp->selector);
218                 mpp->selector = NULL;
219         }
220
221         if (mpp->features) {
222                 FREE(mpp->features);
223                 mpp->features = NULL;
224         }
225
226         if (mpp->hwhandler) {
227                 FREE(mpp->hwhandler);
228                 mpp->hwhandler = NULL;
229         }
230 }
231
232 void
233 free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
234 {
235         if (!mpp)
236                 return;
237
238         free_multipath_attributes(mpp);
239
240         if (mpp->alias) {
241                 FREE(mpp->alias);
242                 mpp->alias = NULL;
243         }
244
245         if (mpp->dmi) {
246                 FREE(mpp->dmi);
247                 mpp->dmi = NULL;
248         }
249
250         free_pathvec(mpp->paths, free_paths);
251         free_pgvec(mpp->pg, free_paths);
252         FREE_PTR(mpp->mpcontext);
253         FREE(mpp);
254 }
255
256 void
257 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
258 {
259         int i;
260         struct multipath * mpp;
261
262         if (!mpvec)
263                 return;
264
265         vector_foreach_slot (mpvec, mpp, i) {
266                 if (!strncmp(mpp->wwid, wwid, WWID_SIZE)) {
267                         free_multipath(mpp, free_paths);
268                         vector_del_slot(mpvec, i);
269                         return;
270                 }
271         }
272 }
273
274 void
275 free_multipathvec (vector mpvec, enum free_path_mode free_paths)
276 {
277         int i;
278         struct multipath * mpp;
279
280         if (!mpvec)
281                 return;
282
283         vector_foreach_slot (mpvec, mpp, i)
284                 free_multipath(mpp, free_paths);
285
286         vector_free(mpvec);
287 }
288
289 int
290 store_path (vector pathvec, struct path * pp)
291 {
292         int err = 0;
293
294         if (!strlen(pp->dev_t)) {
295                 condlog(2, "%s: Empty device number", pp->dev);
296                 err++;
297         }
298         if (!strlen(pp->dev)) {
299                 condlog(2, "%s: Empty device name", pp->dev_t);
300                 err++;
301         }
302
303         if (err > 1)
304                 return 1;
305
306         if (!vector_alloc_slot(pathvec))
307                 return 1;
308
309         vector_set_slot(pathvec, pp);
310
311         return 0;
312 }
313
314 int
315 store_pathgroup (vector pgvec, struct pathgroup * pgp)
316 {
317         if (!vector_alloc_slot(pgvec))
318                 return 1;
319
320         vector_set_slot(pgvec, pgp);
321
322         return 0;
323 }
324
325 int add_pathgroup(struct multipath *mpp, struct pathgroup *pgp)
326 {
327         int ret = store_pathgroup(mpp->pg, pgp);
328
329         if (ret)
330                 return ret;
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 (vector mpvec, 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 (vector mpvec, 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 (vector mpvec, const char * alias)
392 {
393         int i;
394         int 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 (vector mpvec, 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 (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 (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(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(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(struct pathgroup *pgp, 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 (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 }