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