]>
git.ipfire.org Git - thirdparty/mdadm.git/blob - policy.c
2 * mdadm - manage Linux "md" devices aka RAID arrays.
4 * Copyright (C) 2001-2009 Neil Brown <neilb@suse.de>
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.
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.
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
22 * Email: <neilb@suse.de>
31 * Policy module for mdadm.
32 * A policy statement about a device lists a set of values for each
33 * of a set of names. Each value can have a metadata type as context.
36 * action - the actions that can be taken on hot-plug
37 * domain - the domain(s) that the device is part of
39 * Policy information is extracted from various sources, but
40 * particularly from a set of policy rules in mdadm.conf
43 void pol_new(struct dev_policy
**pol
, char *name
, char *val
, char *metadata
)
45 struct dev_policy
*n
= malloc(sizeof(*n
));
46 const char *real_metadata
= NULL
;
52 /* We need to normalise the metadata name */
54 for (i
= 0; superlist
[i
] ; i
++)
55 if (strcmp(metadata
, superlist
[i
]->name
) == 0) {
56 real_metadata
= superlist
[i
]->name
;
60 if (strcmp(metadata
, "1") == 0 ||
61 strcmp(metadata
, "1.0") == 0 ||
62 strcmp(metadata
, "1.1") == 0 ||
63 strcmp(metadata
, "1.2") == 0)
64 real_metadata
= super1
.name
;
67 static char *prev
= NULL
;
68 if (prev
!= metadata
) {
69 fprintf(stderr
, Name
": metadata=%s unrecognised - ignoring rule\n",
73 real_metadata
= "unknown";
77 n
->metadata
= real_metadata
;
82 static int pol_lesseq(struct dev_policy
*a
, struct dev_policy
*b
)
86 if (a
->name
< b
->name
)
88 if (a
->name
> b
->name
)
91 cmp
= strcmp(a
->value
, b
->value
);
97 return (a
->metadata
<= b
->metadata
);
100 static void pol_sort(struct dev_policy
**pol
)
102 /* sort policy list in *pol by name/metadata/value
106 struct dev_policy
*pl
[2];
111 struct dev_policy
**plp
[2], *p
[2];
113 struct dev_policy nul
= { NULL
, NULL
, NULL
, NULL
};
114 struct dev_policy
*prev
= &nul
;
117 /* p[] are the two lists that we are merging.
118 * plp[] are the ends of the two lists we create
120 * 'curr' is which of plp[] that we are currently
122 * 'next' is which if p[] we will take the next
124 * 'prev' is that last value, which was placed in
132 /* take least of p[0] and p[1]
133 * if it is larger than prev, add to
134 * plp[curr], else swap curr then add
136 while (p
[0] || p
[1]) {
137 if (p
[next
] == NULL
||
138 (p
[1-next
] != NULL
&&
139 !(pol_lesseq(prev
, p
[1-next
])
140 ^pol_lesseq(p
[1-next
], p
[next
])
141 ^pol_lesseq(p
[next
], prev
)))
145 if (!pol_lesseq(prev
, p
[next
]))
148 *plp
[curr
] = prev
= p
[next
];
149 plp
[curr
] = &p
[next
]->next
;
150 p
[next
] = p
[next
]->next
;
154 } while (pl
[0] && pl
[1]);
161 static void pol_dedup(struct dev_policy
*pol
)
163 /* This is a sorted list - remove duplicates. */
164 while (pol
&& pol
->next
) {
165 if (pol_lesseq(pol
->next
, pol
)) {
166 struct dev_policy
*tmp
= pol
->next
;
167 pol
->next
= tmp
->next
;
175 * pol_find finds the first entry in the policy
176 * list to match name.
177 * If it returns non-NULL there is at least one
178 * value, but how many can only be found by
179 * iterating through the list.
181 struct dev_policy
*pol_find(struct dev_policy
*pol
, char *name
)
183 while (pol
&& pol
->name
< name
)
186 if (!pol
|| pol
->name
!= name
)
191 static char *disk_path(struct mdinfo
*disk
)
196 char symlink
[PATH_MAX
] = "/dev/disk/by-path/";
199 by_path
= opendir(symlink
);
202 prefix_len
= strlen(symlink
);
204 while ((ent
= readdir(by_path
)) != NULL
) {
205 if (ent
->d_type
!= DT_LNK
)
207 strncpy(symlink
+ prefix_len
,
209 sizeof(symlink
) - prefix_len
);
210 if (stat(symlink
, &stb
) < 0)
212 if ((stb
.st_mode
& S_IFMT
) != S_IFBLK
)
214 if (stb
.st_rdev
!= makedev(disk
->disk
.major
, disk
->disk
.minor
))
217 return strdup(ent
->d_name
);
223 char type_part
[] = "part";
224 char type_disk
[] = "disk";
225 static char *disk_type(struct mdinfo
*disk
)
229 sprintf(buf
, "/sys/dev/block/%d:%d/partition",
230 disk
->disk
.major
, disk
->disk
.minor
);
231 if (stat(buf
, &stb
) == 0)
237 static int pol_match(struct rule
*rule
, char *path
, char *type
)
239 /* check if this rule matches on path and type */
240 int pathok
= 0; /* 0 == no path, 1 == match, -1 == no match yet */
244 if (rule
->name
== rule_path
) {
247 if (fnmatch(rule
->value
, path
, 0) == 0)
250 if (rule
->name
== rule_type
) {
253 if (strcmp(rule
->value
, type
) == 0)
258 return pathok
>= 0 && typeok
>= 0;
261 static void pol_merge(struct dev_policy
**pol
, struct rule
*rule
)
263 /* copy any name assignments from rule into pol */
265 char *metadata
= NULL
;
266 for (r
= rule
; r
; r
= r
->next
)
267 if (r
->name
== pol_metadata
)
270 for (r
= rule
; r
; r
= r
->next
)
271 if (r
->name
== pol_act
||
272 r
->name
== pol_domain
)
273 pol_new(pol
, r
->name
, r
->value
, metadata
);
276 static int path_has_part(char *path
, char **part
)
278 /* check if path ends with "-partNN" and
279 * if it does, place a pointer to "-pathNN"
282 int l
= strlen(path
);
283 while (l
> 1 && isdigit(path
[l
-1]))
285 if (l
< 5 || strncmp(path
+l
-5, "-part", 5) != 0)
291 static void pol_merge_part(struct dev_policy
**pol
, struct rule
*rule
, char *part
)
293 /* copy any name assignments from rule into pol, appending
294 * -part to any domain. The string with -part appended is
295 * stored with the rule so it has a lifetime to match
299 char *metadata
= NULL
;
300 for (r
= rule
; r
; r
= r
->next
)
301 if (r
->name
== pol_metadata
)
304 for (r
= rule
; r
; r
= r
->next
) {
305 if (r
->name
== pol_act
)
306 pol_new(pol
, r
->name
, r
->value
, metadata
);
307 else if (r
->name
== pol_domain
) {
312 len
= strlen(r
->value
);
313 for (dom
= dl_next(r
->dups
); dom
!= r
->dups
;
315 if (strcmp(dom
+len
+1, part
)== 0)
317 if (dom
== r
->dups
) {
318 char *newdom
= dl_strndup(
319 r
->value
, len
+ 1 + strlen(part
));
320 strcat(strcat(newdom
, "-"), part
);
321 dl_add(r
->dups
, newdom
);
324 pol_new(pol
, r
->name
, dom
, metadata
);
329 static struct pol_rule
*config_rules
= NULL
;
330 static struct pol_rule
**config_rules_end
= NULL
;
331 static int config_rules_has_path
= 0;
334 * most policy comes from a set policy rules that are
335 * read from the config file.
336 * disk_policy() gathers policy information for the
337 * disk described in the given mdinfo (disk.{major,minor}).
339 struct dev_policy
*disk_policy(struct mdinfo
*disk
)
342 char *type
= disk_type(disk
);
343 struct pol_rule
*rules
;
344 struct dev_policy
*pol
= NULL
;
348 if (config_rules_has_path
) {
349 path
= disk_path(disk
);
354 rules
= config_rules
;
358 if (rules
->type
== rule_policy
)
359 if (pol_match(rules
->rule
, path
, type
))
360 pol_merge(&pol
, rules
->rule
);
361 if (rules
->type
== rule_part
&& strcmp(type
, type_part
) == 0)
362 if (path_has_part(path
, &part
)) {
364 if (pol_match(rules
->rule
, path
, type_disk
))
365 pol_merge_part(&pol
, rules
->rule
, part
+1);
377 * process policy rules read from config file.
380 char rule_path
[] = "path";
381 char rule_type
[] = "type";
383 char rule_policy
[] = "policy";
384 char rule_part
[] = "part-policy";
386 char pol_metadata
[] = "metadata";
387 char pol_act
[] = "action";
388 char pol_domain
[] = "domain";
390 static int try_rule(char *w
, char *name
, struct rule
**rp
)
393 int len
= strlen(name
);
394 if (strncmp(w
, name
, len
) != 0 ||
397 r
= malloc(sizeof(*r
));
400 r
->value
= strdup(w
+len
+1);
406 void policyline(char *line
, char *type
)
411 if (config_rules_end
== NULL
)
412 config_rules_end
= &config_rules
;
414 pr
= malloc(sizeof(*pr
));
417 for (w
= dl_next(line
); w
!= line
; w
= dl_next(w
)) {
418 if (try_rule(w
, rule_path
, &pr
->rule
))
419 config_rules_has_path
= 1;
420 else if (! try_rule(w
, rule_type
, &pr
->rule
) &&
421 ! try_rule(w
, pol_metadata
, &pr
->rule
) &&
422 ! try_rule(w
, pol_act
, &pr
->rule
) &&
423 ! try_rule(w
, pol_domain
, &pr
->rule
))
424 fprintf(stderr
, Name
": policy rule %s unrecognised and ignored\n",
427 pr
->next
= config_rules
;
431 void policy_free(void)
433 while (config_rules
) {
434 struct pol_rule
*pr
= config_rules
;
437 config_rules
= config_rules
->next
;
439 for (r
= pr
->rule
; r
; ) {
440 struct rule
*next
= r
->next
;
449 config_rules_end
= NULL
;
450 config_rules_has_path
= 0;
453 void dev_policy_free(struct dev_policy
*p
)
455 struct dev_policy
*t
;