]> git.ipfire.org Git - thirdparty/mdadm.git/blob - policy.c
mdmonitor: use MAILFROM to set sendmail envelope sender address
[thirdparty/mdadm.git] / policy.c
1 /*
2 * mdadm - manage Linux "md" devices aka RAID arrays.
3 *
4 * Copyright (C) 2001-2009 Neil Brown <neilb@suse.de>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * Author: Neil Brown
22 * Email: <neilb@suse.de>
23 */
24
25 #include "mdadm.h"
26 #include "xmalloc.h"
27
28 #include <dirent.h>
29 #include <fnmatch.h>
30 #include <ctype.h>
31 #include "dlink.h"
32 /*
33 * Policy module for mdadm.
34 * A policy statement about a device lists a set of values for each
35 * of a set of names. Each value can have a metadata type as context.
36 *
37 * names include:
38 * action - the actions that can be taken on hot-plug
39 * domain - the domain(s) that the device is part of
40 *
41 * Policy information is extracted from various sources, but
42 * particularly from a set of policy rules in mdadm.conf
43 */
44
45 static void pol_new(struct dev_policy **pol, char *name, const char *val,
46 const char *metadata)
47 {
48 struct dev_policy *n = xmalloc(sizeof(*n));
49 const char *real_metadata = NULL;
50 int i;
51
52 n->name = name;
53 n->value = val;
54
55 /* We need to normalise the metadata name */
56 if (metadata) {
57 for (i = 0; superlist[i] ; i++)
58 if (strcmp(metadata, superlist[i]->name) == 0) {
59 real_metadata = superlist[i]->name;
60 break;
61 }
62 if (!real_metadata) {
63 if (strcmp(metadata, "1") == 0 ||
64 strcmp(metadata, "1.0") == 0 ||
65 strcmp(metadata, "1.1") == 0 ||
66 strcmp(metadata, "1.2") == 0)
67 real_metadata = super1.name;
68 }
69 if (!real_metadata) {
70 static const char *prev = NULL;
71 if (prev != metadata) {
72 pr_err("metadata=%s unrecognised - ignoring rule\n",
73 metadata);
74 prev = metadata;
75 }
76 real_metadata = "unknown";
77 }
78 }
79
80 n->metadata = real_metadata;
81 n->next = *pol;
82 *pol = n;
83 }
84
85 static int pol_lesseq(struct dev_policy *a, struct dev_policy *b)
86 {
87 int cmp;
88
89 if (a->name < b->name)
90 return 1;
91 if (a->name > b->name)
92 return 0;
93
94 cmp = strcmp(a->value, b->value);
95 if (cmp < 0)
96 return 1;
97 if (cmp > 0)
98 return 0;
99
100 return (a->metadata <= b->metadata);
101 }
102
103 static void pol_sort(struct dev_policy **pol)
104 {
105 /* sort policy list in *pol by name/metadata/value
106 * using merge sort
107 */
108
109 struct dev_policy *pl[2];
110 pl[0] = *pol;
111 pl[1] = NULL;
112
113 do {
114 struct dev_policy **plp[2], *p[2];
115 int curr = 0;
116 struct dev_policy nul = { NULL, NULL, NULL, NULL };
117 struct dev_policy *prev = &nul;
118 int next = 0;
119
120 /* p[] are the two lists that we are merging.
121 * plp[] are the ends of the two lists we create
122 * from the merge.
123 * 'curr' is which of plp[] that we are currently
124 * adding items to.
125 * 'next' is which if p[] we will take the next
126 * item from.
127 * 'prev' is that last value, which was placed in
128 * plp[curr].
129 */
130 plp[0] = &pl[0];
131 plp[1] = &pl[1];
132 p[0] = pl[0];
133 p[1] = pl[1];
134
135 /* take least of p[0] and p[1]
136 * if it is larger than prev, add to
137 * plp[curr], else swap curr then add
138 */
139 while (p[0] || p[1]) {
140 if (p[next] == NULL ||
141 (p[1-next] != NULL &&
142 !(pol_lesseq(prev, p[1-next])
143 ^pol_lesseq(prev, p[next])
144 ^pol_lesseq(p[next], p[1-next])))
145 )
146 next = 1 - next;
147
148 if (!pol_lesseq(prev, p[next]))
149 curr = 1 - curr;
150
151 *plp[curr] = prev = p[next];
152 plp[curr] = &p[next]->next;
153 p[next] = p[next]->next;
154 }
155 *plp[0] = NULL;
156 *plp[1] = NULL;
157 } while (pl[0] && pl[1]);
158 if (pl[0])
159 *pol = pl[0];
160 else
161 *pol = pl[1];
162 }
163
164 static void pol_dedup(struct dev_policy *pol)
165 {
166 /* This is a sorted list - remove duplicates. */
167 while (pol && pol->next) {
168 if (pol_lesseq(pol->next, pol)) {
169 struct dev_policy *tmp = pol->next;
170 pol->next = tmp->next;
171 free(tmp);
172 } else
173 pol = pol->next;
174 }
175 }
176
177 /*
178 * pol_find finds the first entry in the policy
179 * list to match name.
180 * If it returns non-NULL there is at least one
181 * value, but how many can only be found by
182 * iterating through the list.
183 */
184 struct dev_policy *pol_find(struct dev_policy *pol, char *name)
185 {
186 while (pol && pol->name < name)
187 pol = pol->next;
188
189 if (!pol || pol->name != name)
190 return NULL;
191 return pol;
192 }
193
194 static char **disk_paths(struct mdinfo *disk)
195 {
196 struct stat stb;
197 int prefix_len;
198 DIR *by_path;
199 char symlink[PATH_MAX] = "/dev/disk/by-path/";
200 char **paths;
201 int cnt = 0;
202 struct dirent *ent;
203
204 paths = xmalloc(sizeof(*paths) * (cnt+1));
205
206 by_path = opendir(symlink);
207 if (by_path) {
208 prefix_len = strlen(symlink);
209 while ((ent = readdir(by_path)) != NULL) {
210 if (ent->d_type != DT_LNK)
211 continue;
212 strncpy(symlink + prefix_len,
213 ent->d_name,
214 sizeof(symlink) - prefix_len);
215 if (stat(symlink, &stb) < 0)
216 continue;
217 if ((stb.st_mode & S_IFMT) != S_IFBLK)
218 continue;
219 if (stb.st_rdev != makedev(disk->disk.major, disk->disk.minor))
220 continue;
221 paths[cnt++] = xstrdup(ent->d_name);
222 paths = xrealloc(paths, sizeof(*paths) * (cnt+1));
223 }
224 closedir(by_path);
225 }
226 paths[cnt] = NULL;
227 return paths;
228 }
229
230 char type_part[] = "part";
231 char type_disk[] = "disk";
232 static char *disk_type(struct mdinfo *disk)
233 {
234 char buf[30+20+20];
235 struct stat stb;
236 sprintf(buf, "/sys/dev/block/%d:%d/partition",
237 disk->disk.major, disk->disk.minor);
238 if (stat(buf, &stb) == 0)
239 return type_part;
240 else
241 return type_disk;
242 }
243
244 static int path_has_part(char *path, char **part)
245 {
246 /* check if path ends with "-partNN" and
247 * if it does, place a pointer to "-pathNN"
248 * in 'part'.
249 */
250 int l;
251 if (!path)
252 return 0;
253 l = strlen(path);
254 while (l > 1 && isdigit(path[l-1]))
255 l--;
256 if (l < 5 || strncmp(path+l-5, "-part", 5) != 0)
257 return 0;
258 *part = path+l-5;
259 return 1;
260 }
261
262 static int pol_match(struct rule *rule, char **paths, char *type, char **part)
263 {
264 /* Check if this rule matches on any path and type.
265 * If 'part' is not NULL, then 'path' must end in -partN, which
266 * we ignore for matching, and return in *part on success.
267 */
268 int pathok = 0; /* 0 == no path, 1 == match, -1 == no match yet */
269 int typeok = 0;
270
271 for (; rule; rule = rule->next) {
272 if (rule->name == rule_path) {
273 char *p = NULL;
274 int i;
275 if (pathok == 0)
276 pathok = -1;
277 if (!paths)
278 continue;
279 for (i = 0; paths[i]; i++) {
280 if (part) {
281 if (!path_has_part(paths[i], &p))
282 continue;
283 *p = '\0';
284 *part = p+1;
285 }
286 if (fnmatch(rule->value, paths[i], 0) == 0)
287 pathok = 1;
288 if (part)
289 *p = '-';
290 }
291 }
292 if (rule->name == rule_type) {
293 if (typeok == 0)
294 typeok = -1;
295 if (type && strcmp(rule->value, type) == 0)
296 typeok = 1;
297 }
298 }
299 return pathok >= 0 && typeok >= 0;
300 }
301
302 static void pol_merge(struct dev_policy **pol, struct rule *rule)
303 {
304 /* copy any name assignments from rule into pol */
305 struct rule *r;
306 char *metadata = NULL;
307 for (r = rule; r ; r = r->next)
308 if (r->name == pol_metadata)
309 metadata = r->value;
310
311 for (r = rule; r ; r = r->next)
312 if (r->name == pol_act ||
313 r->name == pol_domain ||
314 r->name == pol_auto)
315 pol_new(pol, r->name, r->value, metadata);
316 }
317
318 static void pol_merge_part(struct dev_policy **pol, struct rule *rule, char *part)
319 {
320 /* copy any name assignments from rule into pol, appending
321 * -part to any domain. The string with -part appended is
322 * stored with the rule so it has a lifetime to match
323 * the rule.
324 */
325 struct rule *r;
326 char *metadata = NULL;
327 for (r = rule; r ; r = r->next)
328 if (r->name == pol_metadata)
329 metadata = r->value;
330
331 for (r = rule; r ; r = r->next) {
332 if (r->name == pol_act)
333 pol_new(pol, r->name, r->value, metadata);
334 else if (r->name == pol_domain) {
335 char *dom;
336 int len;
337 if (r->dups == NULL)
338 r->dups = dl_head();
339 len = strlen(r->value);
340 for (dom = dl_next(r->dups); dom != r->dups;
341 dom = dl_next(dom))
342 if (strcmp(dom+len+1, part)== 0)
343 break;
344 if (dom == r->dups) {
345 char *newdom = dl_strndup(
346 r->value, len + 1 + strlen(part));
347 strcat(strcat(newdom, "-"), part);
348 dl_add(r->dups, newdom);
349 dom = newdom;
350 }
351 pol_new(pol, r->name, dom, metadata);
352 }
353 }
354 }
355
356 static struct pol_rule *config_rules = NULL;
357 static struct pol_rule **config_rules_end = NULL;
358 static int config_rules_has_path = 0;
359
360 /*
361 * most policy comes from a set policy rules that are
362 * read from the config file.
363 * path_policy() gathers policy information for the
364 * disk described in the given a 'path' and a 'type'.
365 */
366 struct dev_policy *path_policy(char **paths, char *type)
367 {
368 struct pol_rule *rules;
369 struct dev_policy *pol = NULL;
370
371 rules = config_rules;
372
373 while (rules) {
374 char *part = NULL;
375 if (rules->type == rule_policy)
376 if (pol_match(rules->rule, paths, type, NULL))
377 pol_merge(&pol, rules->rule);
378 if (rules->type == rule_part && strcmp(type, type_part) == 0)
379 if (pol_match(rules->rule, paths, type_disk, &part))
380 pol_merge_part(&pol, rules->rule, part);
381 rules = rules->next;
382 }
383
384 pol_sort(&pol);
385 pol_dedup(pol);
386 return pol;
387 }
388
389 /**
390 * drive_test_and_add_policies() - get policies for drive and add them to pols.
391 * @st: supertype.
392 * @pols: pointer to pointer of first list entry, cannot be NULL, may point to NULL.
393 * @fd: device descriptor.
394 * @verbose: verbose flag.
395 *
396 * If supertype doesn't support this functionality return success. Use metadata handler to get
397 * policies.
398 */
399 mdadm_status_t drive_test_and_add_policies(struct supertype *st, dev_policy_t **pols, int fd,
400 const int verbose)
401 {
402 if (!st->ss->test_and_add_drive_policies)
403 return MDADM_STATUS_SUCCESS;
404
405 if (st->ss->test_and_add_drive_policies(pols, fd, verbose) == MDADM_STATUS_SUCCESS) {
406 /* After successful call list cannot be empty */
407 assert(*pols);
408 return MDADM_STATUS_SUCCESS;
409 }
410
411 return MDADM_STATUS_ERROR;
412 }
413
414 /**
415 * sysfs_test_and_add_policies() - get policies for mddev and add them to pols.
416 * @st: supertype.
417 * @pols: pointer to pointer of first list entry, cannot be NULL, may point to NULL.
418 * @mdi: mdinfo describes the MD array, must have GET_DISKS option.
419 * @verbose: verbose flag.
420 *
421 * If supertype doesn't support this functionality return success. To get policies, all disks
422 * connected to mddev are analyzed.
423 */
424 mdadm_status_t sysfs_test_and_add_drive_policies(struct supertype *st, dev_policy_t **pols,
425 struct mdinfo *mdi, const int verbose)
426 {
427 struct mdinfo *sd;
428
429 if (!st->ss->test_and_add_drive_policies)
430 return MDADM_STATUS_SUCCESS;
431
432 for (sd = mdi->devs; sd; sd = sd->next) {
433 char *devpath = map_dev(sd->disk.major, sd->disk.minor, 0);
434 int fd = dev_open(devpath, O_RDONLY);
435 int rv;
436
437 if (!is_fd_valid(fd)) {
438 pr_err("Cannot open fd for %s\n", devpath);
439 return MDADM_STATUS_ERROR;
440 }
441
442 rv = drive_test_and_add_policies(st, pols, fd, verbose);
443 close(fd);
444
445 if (rv)
446 return MDADM_STATUS_ERROR;
447 }
448
449 return MDADM_STATUS_SUCCESS;
450 }
451
452 /**
453 * mddev_test_and_add_policies() - get policies for mddev and add them to pols.
454 * @st: supertype.
455 * @pols: pointer to pointer of first list entry, cannot be NULL, may point to NULL.
456 * @array_fd: MD device descriptor.
457 * @verbose: verbose flag.
458 *
459 * If supertype doesn't support this functionality return success. Use fd to extract disks.
460 */
461 mdadm_status_t mddev_test_and_add_drive_policies(struct supertype *st, dev_policy_t **pols,
462 int array_fd, const int verbose)
463 {
464 struct mdinfo *sra;
465 int ret;
466
467 if (!st->ss->test_and_add_drive_policies)
468 return MDADM_STATUS_SUCCESS;
469
470 sra = sysfs_read(array_fd, NULL, GET_DEVS);
471 if (!sra) {
472 pr_err("Cannot load sysfs for %s\n", fd2devnm(array_fd));
473 return MDADM_STATUS_ERROR;
474 }
475
476 ret = sysfs_test_and_add_drive_policies(st, pols, sra, verbose);
477
478 sysfs_free(sra);
479 return ret;
480 }
481
482 void pol_add(struct dev_policy **pol,
483 char *name, char *val,
484 char *metadata)
485 {
486 pol_new(pol, name, val, metadata);
487 pol_sort(pol);
488 pol_dedup(*pol);
489 }
490
491 static void free_paths(char **paths)
492 {
493 int i;
494
495 if (!paths)
496 return;
497
498 for (i = 0; paths[i]; i++)
499 free(paths[i]);
500 free(paths);
501 }
502
503 /*
504 * disk_policy() gathers policy information for the
505 * disk described in the given mdinfo (disk.{major,minor}).
506 */
507 struct dev_policy *disk_policy(struct mdinfo *disk)
508 {
509 char **paths = NULL;
510 char *type = disk_type(disk);
511 struct dev_policy *pol = NULL;
512
513 if (config_rules_has_path)
514 paths = disk_paths(disk);
515
516 pol = path_policy(paths, type);
517
518 free_paths(paths);
519 return pol;
520 }
521
522 struct dev_policy *devid_policy(int dev)
523 {
524 struct mdinfo disk;
525 disk.disk.major = major(dev);
526 disk.disk.minor = minor(dev);
527 return disk_policy(&disk);
528 }
529
530 /*
531 * process policy rules read from config file.
532 */
533
534 char rule_path[] = "path";
535 char rule_type[] = "type";
536
537 char rule_policy[] = "policy";
538 char rule_part[] = "part-policy";
539
540 char pol_metadata[] = "metadata";
541 char pol_act[] = "action";
542 char pol_domain[] = "domain";
543 char pol_auto[] = "auto";
544
545 static int try_rule(char *w, char *name, struct rule **rp)
546 {
547 struct rule *r;
548 int len = strlen(name);
549 if (strncmp(w, name, len) != 0 ||
550 w[len] != '=')
551 return 0;
552 r = xmalloc(sizeof(*r));
553 r->next = *rp;
554 r->name = name;
555 r->value = xstrdup(w+len+1);
556 r->dups = NULL;
557 *rp = r;
558 return 1;
559 }
560
561 void policyline(char *line, char *type)
562 {
563 struct pol_rule *pr;
564 char *w;
565
566 if (config_rules_end == NULL)
567 config_rules_end = &config_rules;
568
569 pr = xmalloc(sizeof(*pr));
570 pr->type = type;
571 pr->rule = NULL;
572 for (w = dl_next(line); w != line ; w = dl_next(w)) {
573 if (try_rule(w, rule_path, &pr->rule))
574 config_rules_has_path = 1;
575 else if (! try_rule(w, rule_type, &pr->rule) &&
576 ! try_rule(w, pol_metadata, &pr->rule) &&
577 ! try_rule(w, pol_act, &pr->rule) &&
578 ! try_rule(w, pol_domain, &pr->rule) &&
579 ! try_rule(w, pol_auto, &pr->rule))
580 pr_err("policy rule %s unrecognised and ignored\n",
581 w);
582 }
583 pr->next = config_rules;
584 config_rules = pr;
585 }
586
587 void policy_add(char *type, ...)
588 {
589 va_list ap;
590 struct pol_rule *pr;
591 char *name, *val;
592
593 pr = xmalloc(sizeof(*pr));
594 pr->type = type;
595 pr->rule = NULL;
596
597 va_start(ap, type);
598 while ((name = va_arg(ap, char*)) != NULL) {
599 struct rule *r;
600
601 val = va_arg(ap, char*);
602 r = xmalloc(sizeof(*r));
603 r->next = pr->rule;
604 r->name = name;
605 r->value = xstrdup(val);
606 r->dups = NULL;
607 pr->rule = r;
608 }
609 pr->next = config_rules;
610 config_rules = pr;
611 va_end(ap);
612 }
613
614 void policy_free(void)
615 {
616 while (config_rules) {
617 struct pol_rule *pr = config_rules;
618 struct rule *r;
619
620 config_rules = config_rules->next;
621
622 for (r = pr->rule; r; ) {
623 struct rule *next = r->next;
624 free(r->value);
625 if (r->dups)
626 free_line(r->dups);
627 free(r);
628 r = next;
629 }
630 free(pr);
631 }
632 config_rules_end = NULL;
633 config_rules_has_path = 0;
634 }
635
636 void dev_policy_free(struct dev_policy *p)
637 {
638 struct dev_policy *t;
639 while (p) {
640 t = p;
641 p = p->next;
642 free(t);
643 }
644 }
645
646 static enum policy_action map_act(const char *act)
647 {
648 if (strcmp(act, "include") == 0)
649 return act_include;
650 if (strcmp(act, "re-add") == 0)
651 return act_re_add;
652 if (strcmp(act, "spare") == 0)
653 return act_spare;
654 if (strcmp(act, "spare-same-slot") == 0)
655 return act_spare_same_slot;
656 if (strcmp(act, "force-spare") == 0)
657 return act_force_spare;
658 return act_err;
659 }
660
661 static enum policy_action policy_action(struct dev_policy *plist, const char *metadata)
662 {
663 enum policy_action rv = act_default;
664 struct dev_policy *p;
665
666 plist = pol_find(plist, pol_act);
667 pol_for_each(p, plist, metadata) {
668 enum policy_action a = map_act(p->value);
669 if (a > rv)
670 rv = a;
671 }
672 return rv;
673 }
674
675 int policy_action_allows(struct dev_policy *plist, const char *metadata, enum policy_action want)
676 {
677 enum policy_action act = policy_action(plist, metadata);
678
679 if (act == act_err)
680 return 0;
681 return (act >= want);
682 }
683
684 int disk_action_allows(struct mdinfo *disk, const char *metadata, enum policy_action want)
685 {
686 struct dev_policy *pol = disk_policy(disk);
687 int rv = policy_action_allows(pol, metadata, want);
688
689 dev_policy_free(pol);
690 return rv;
691 }
692
693 /* Domain policy:
694 * Any device can have a list of domains asserted by different policy
695 * statements.
696 * An array also has a list of domains comprising all the domains of
697 * all the devices in an array.
698 * Where an array has a spare-group, that becomes an addition domain for
699 * every device in the array and thus for the array.
700 *
701 * We keep the list of domains in a sorted linked list
702 * As dev policies are already sorted, this is fairly easy to manage.
703 */
704
705 static struct domainlist **domain_merge_one(struct domainlist **domp,
706 const char *domain)
707 {
708 /* merge a domain name into a sorted list and return the
709 * location of the insertion or match
710 */
711 struct domainlist *dom = *domp;
712
713 while (dom && strcmp(dom->dom, domain) < 0) {
714 domp = &dom->next;
715 dom = *domp;
716 }
717 if (dom == NULL || strcmp(dom->dom, domain) != 0) {
718 dom = xmalloc(sizeof(*dom));
719 dom->next = *domp;
720 dom->dom = domain;
721 *domp = dom;
722 }
723 return domp;
724 }
725
726 #if (DEBUG)
727 void dump_policy(struct dev_policy *policy)
728 {
729 while (policy) {
730 dprintf("policy: %p name: %s value: %s metadata: %s\n",
731 policy,
732 policy->name,
733 policy->value,
734 policy->metadata);
735 policy = policy->next;
736 }
737 }
738 #endif
739
740 void domain_merge(struct domainlist **domp, struct dev_policy *pollist,
741 const char *metadata)
742 {
743 /* Add to 'domp' all the domains in pol that apply to 'metadata'
744 * which are not already in domp
745 */
746 struct dev_policy *pol;
747 pollist = pol_find(pollist, pol_domain);
748 pol_for_each(pol, pollist, metadata)
749 domain_merge_one(domp, pol->value);
750 }
751
752 int domain_test(struct domainlist *dom, struct dev_policy *pol,
753 const char *metadata)
754 {
755 /* Check that all domains in pol (for metadata) are also in
756 * dom. Both lists are sorted.
757 * If pol has no domains, we don't really know about this device
758 * so we allow caller to choose:
759 * -1: has no domains
760 * 0: has domains, not all match
761 * 1: has domains, all match
762 */
763 int found_any = -1;
764 struct dev_policy *p;
765
766 pol = pol_find(pol, pol_domain);
767 pol_for_each(p, pol, metadata) {
768 found_any = 1;
769 while (dom && strcmp(dom->dom, p->value) < 0)
770 dom = dom->next;
771 if (!dom || strcmp(dom->dom, p->value) != 0)
772 return 0;
773 }
774 return found_any;
775 }
776
777 void domainlist_add_dev(struct domainlist **dom, int devid, const char *metadata)
778 {
779 struct dev_policy *pol = devid_policy(devid);
780 domain_merge(dom, pol, metadata);
781 dev_policy_free(pol);
782 }
783
784 struct domainlist *domain_from_array(struct mdinfo *mdi, const char *metadata)
785 {
786 struct domainlist *domlist = NULL;
787
788 if (!mdi)
789 return NULL;
790 for (mdi = mdi->devs ; mdi ; mdi = mdi->next)
791 domainlist_add_dev(&domlist, makedev(mdi->disk.major,
792 mdi->disk.minor),
793 metadata);
794
795 return domlist;
796 }
797
798 void domain_add(struct domainlist **domp, char *domain)
799 {
800 domain_merge_one(domp, domain);
801 }
802
803 void domain_free(struct domainlist *dl)
804 {
805 while (dl) {
806 struct domainlist *head = dl;
807 dl = dl->next;
808 free(head);
809 }
810 }
811
812 /*
813 * same-path policy.
814 * Some policy decisions are guided by knowledge of which
815 * array previously owned the device at a given physical location (path).
816 * When removing a device from an array we might record the array against
817 * the path, and when finding a new device, we might look for which
818 * array previously used that path.
819 *
820 * The 'array' is described by a map_ent, and the path by a the disk in an
821 * mdinfo, or a string.
822 */
823
824 void policy_save_path(char *id_path, struct map_ent *array)
825 {
826 char path[PATH_MAX];
827 FILE *f = NULL;
828
829 if (mkdir(FAILED_SLOTS_DIR, S_IRWXU) < 0 && errno != EEXIST) {
830 pr_err("can't create file to save path to old disk: %s\n", strerror(errno));
831 return;
832 }
833
834 snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_path);
835 f = fopen(path, "w");
836 if (!f) {
837 pr_err("can't create file to save path to old disk: %s\n",
838 strerror(errno));
839 return;
840 }
841
842 if (fprintf(f, "%20s %08x:%08x:%08x:%08x\n",
843 array->metadata,
844 array->uuid[0], array->uuid[1],
845 array->uuid[2], array->uuid[3]) <= 0)
846 pr_err("Failed to write to <id_path> cookie\n");
847
848 fclose(f);
849 }
850
851 int policy_check_path(struct mdinfo *disk, struct map_ent *array)
852 {
853 char path[PATH_MAX];
854 FILE *f = NULL;
855 char **id_paths = disk_paths(disk);
856 int i;
857 int rv = 0;
858
859 for (i = 0; id_paths[i]; i++) {
860 snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_paths[i]);
861 f = fopen(path, "r");
862 if (!f)
863 continue;
864
865 rv = fscanf(f, " %20s %x:%x:%x:%x\n",
866 array->metadata,
867 array->uuid,
868 array->uuid+1,
869 array->uuid+2,
870 array->uuid+3);
871 fclose(f);
872 break;
873 }
874 free_paths(id_paths);
875 return rv == 5;
876 }
877
878 /* invocation of udev rule file */
879 char udev_template_start[] =
880 "# do not edit this file, it is automatically generated by mdadm\n"
881 "\n";
882
883 /* find rule named rule_type and return its value */
884 char *find_rule(struct rule *rule, char *rule_type)
885 {
886 while (rule) {
887 if (rule->name == rule_type)
888 return rule->value;
889
890 rule = rule->next;
891 }
892 return NULL;
893 }
894
895 #define UDEV_RULE_FORMAT \
896 "ACTION==\"add\", SUBSYSTEM==\"block\", " \
897 "ENV{DEVTYPE}==\"%s\", ENV{ID_PATH}==\"%s\", " \
898 "RUN+=\"" BINDIR "/mdadm --incremental $env{DEVNAME}\"\n"
899
900 #define UDEV_RULE_FORMAT_NOTYPE \
901 "ACTION==\"add\", SUBSYSTEM==\"block\", " \
902 "ENV{ID_PATH}==\"%s\", " \
903 "RUN+=\"" BINDIR "/mdadm --incremental $env{DEVNAME}\"\n"
904
905 /* Write rule in the rule file. Use format from UDEV_RULE_FORMAT */
906 int write_rule(struct rule *rule, int fd, int force_part)
907 {
908 char line[1024];
909 char *pth = find_rule(rule, rule_path);
910 char *typ = find_rule(rule, rule_type);
911 if (!pth)
912 return -1;
913
914 if (force_part)
915 typ = type_part;
916 if (typ)
917 snprintf(line, sizeof(line) - 1, UDEV_RULE_FORMAT, typ, pth);
918 else
919 snprintf(line, sizeof(line) - 1, UDEV_RULE_FORMAT_NOTYPE, pth);
920 return write(fd, line, strlen(line)) == (int)strlen(line);
921 }
922
923 /* Generate single entry in udev rule basing on POLICY line found in config
924 * file. Take only those with paths, only first occurrence if paths are equal
925 * and if actions supports handling of spares (>=act_spare_same_slot)
926 */
927 int generate_entries(int fd)
928 {
929 struct pol_rule *loop, *dup;
930 char *loop_value, *dup_value;
931 int duplicate;
932
933 for (loop = config_rules; loop; loop = loop->next) {
934 if (loop->type != rule_policy && loop->type != rule_part)
935 continue;
936 duplicate = 0;
937
938 /* only policies with paths and with actions supporting
939 * bare disks are considered */
940 loop_value = find_rule(loop->rule, pol_act);
941 if (!loop_value || map_act(loop_value) < act_spare_same_slot)
942 continue;
943 loop_value = find_rule(loop->rule, rule_path);
944 if (!loop_value)
945 continue;
946 for (dup = config_rules; dup != loop; dup = dup->next) {
947 if (dup->type != rule_policy && loop->type != rule_part)
948 continue;
949 dup_value = find_rule(dup->rule, pol_act);
950 if (!dup_value || map_act(dup_value) < act_spare_same_slot)
951 continue;
952 dup_value = find_rule(dup->rule, rule_path);
953 if (!dup_value)
954 continue;
955 if (strcmp(loop_value, dup_value) == 0) {
956 duplicate = 1;
957 break;
958 }
959 }
960
961 /* not a dup or first occurrence */
962 if (!duplicate)
963 if (!write_rule(loop->rule, fd, loop->type == rule_part) )
964 return 0;
965 }
966 return 1;
967 }
968
969 /* Write_rules routine creates dynamic udev rules used to handle
970 * hot-plug events for bare devices (and making them spares)
971 */
972 int Write_rules(char *rule_name)
973 {
974 int fd = fileno(stdout);
975
976 if (rule_name)
977 fd = creat(rule_name, 0644);
978
979 if (!is_fd_valid(fd))
980 return 1;
981
982 /* write static invocation */
983 if (write(fd, udev_template_start, sizeof(udev_template_start) - 1) !=
984 (int)sizeof(udev_template_start) - 1)
985 goto abort;
986
987 /* iterate, if none created or error occurred, remove file */
988 if (generate_entries(fd) < 0)
989 goto abort;
990
991 fsync(fd);
992 if (rule_name)
993 close(fd);
994
995 return 0;
996 abort:
997 if (rule_name) {
998 close(fd);
999 unlink(rule_name);
1000 }
1001 return 1;
1002 }