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