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