#define CONFFILE2 "/etc/mdadm/mdadm.conf"
#endif
char DefaultConfFile[] = CONFFILE;
+char DefaultConfDir[] = CONFFILE ".d";
char DefaultAltConfFile[] = CONFFILE2;
+char DefaultAltConfDir[] = CONFFILE2 ".d";
enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev,
Homehost, AutoMode, Policy, PartPolicy, LTEnd };
return -1;
}
-/*
- * conf_line reads one logical line from the conffile.
- * It skips comments and continues until it finds a line that starts
- * with a non blank/comment. This character is pushed back for the next call
- * A doubly linked list of words is returned.
- * the first word will be a keyword. Other words will have had quotes removed.
- */
-
-char *conf_line(FILE *file)
-{
- char *w;
- char *list;
-
- w = conf_word(file, 1);
- if (w == NULL) return NULL;
-
- list = dl_strdup(w);
- free(w);
- dl_init(list);
-
- while ((w = conf_word(file,0))){
- char *w2 = dl_strdup(w);
- free(w);
- dl_add(list, w2);
- }
-/* printf("got a line\n");*/
- return list;
-}
-
-void free_line(char *line)
-{
- char *w;
- for (w=dl_next(line); w != line; w=dl_next(line)) {
- dl_del(w);
- dl_free(w);
- }
- dl_free(line);
-}
-
-
struct conf_dev {
- struct conf_dev *next;
- char *name;
+ struct conf_dev *next;
+ char *name;
} *cdevlist = NULL;
struct mddev_dev *load_partitions(void)
if (!name)
continue;
d = xmalloc(sizeof(*d));
+ memset(d, 0, sizeof(*d));
d->devname = xstrdup(name);
d->next = rv;
- d->used = 0;
rv = d;
}
fclose(f);
struct mddev_dev *load_containers(void)
{
- struct mdstat_ent *mdstat = mdstat_read(1, 0);
+ struct mdstat_ent *mdstat = mdstat_read(0, 0);
struct mdstat_ent *ent;
struct mddev_dev *d;
struct mddev_dev *rv = NULL;
+ struct map_ent *map = NULL, *me;
if (!mdstat)
return NULL;
strncmp(ent->metadata_version, "external:", 9) == 0 &&
!is_subarray(&ent->metadata_version[9])) {
d = xmalloc(sizeof(*d));
- if (asprintf(&d->devname, "/dev/%s", ent->dev) < 0) {
+ memset(d, 0, sizeof(*d));
+ me = map_by_devnm(&map, ent->dev);
+ if (me)
+ d->devname = xstrdup(me->path);
+ else if (asprintf(&d->devname, "/dev/%s", ent->dev) < 0) {
free(d);
continue;
}
d->next = rv;
- d->used = 0;
rv = d;
}
free_mdstat(mdstat);
+ map_free(map);
return rv;
}
struct createinfo createinfo = {
.autof = 2, /* by default, create devices with standard names */
.symlinks = 1,
+ .names = 0, /* By default, stick with numbered md devices. */
#ifdef DEBIAN
.gid = 6, /* disk */
.mode = 0660,
createinfo.symlinks = 1;
else if (strncasecmp(w, "symlinks=no", 11) == 0)
createinfo.symlinks = 0;
+ else if (strncasecmp(w, "names=yes", 12) == 0)
+ createinfo.names = 1;
+ else if (strncasecmp(w, "names=no", 11) == 0)
+ createinfo.names = 0;
else {
pr_err("unrecognised word on CREATE line: %s\n",
w);
if (strcasecmp(w, "<ignore>") == 0 ||
strncmp(w, "/dev/md/", 8) == 0 ||
(w[0] != '/' && w[0] != '<') ||
- (strncmp(w, "/dev/md", 7) == 0 &&
+ (strncmp(w, "/dev/md", 7) == 0 &&
is_number(w+7)) ||
(strncmp(w, "/dev/md_d", 9) == 0 &&
is_number(w+9))
{
char *w;
- for (w=dl_next(line); w != line ; w=dl_next(w)) {
+ for (w=dl_next(line); w != line ; w=dl_next(w))
if (alert_email == NULL)
alert_email = xstrdup(w);
- else
- pr_err("excess address on MAIL line: %s - ignored\n",
- w);
- }
}
static char *alert_mail_from = NULL;
}
}
-
static char *alert_program = NULL;
void programline(char *line)
{
char *w;
- for (w=dl_next(line); w != line ; w=dl_next(w)) {
+ for (w=dl_next(line); w != line ; w=dl_next(w))
if (alert_program == NULL)
alert_program = xstrdup(w);
- else
- pr_err("excess program on PROGRAM line: %s - ignored\n",
- w);
- }
}
static char *home_host = NULL;
home_host = xstrdup("");
else
home_host = xstrdup(w);
- }else
- pr_err("excess host name on HOMEHOST line: %s - ignored\n",
- w);
+ }
}
}
int homehost = 0;
int i;
- if (auto_seen) {
- pr_err("AUTO line may only be give once."
- " Subsequent lines ignored\n");
+ if (auto_seen)
return;
- }
+ auto_seen = 1;
+
/* Parse the 'auto' line creating policy statements for the 'auto' policy.
*
* The default is 'yes' but the 'auto' line might over-ride that.
* been seen gets an appropriate auto= entry.
*/
+ /* If environment variable MDADM_CONF_AUTO is defined, then
+ * it is prepended to the auto line. This allow a script
+ * to easily disable some metadata types.
+ */
+ w = getenv("MDADM_CONF_AUTO");
+ if (w && *w) {
+ char *l = xstrdup(w);
+ char *head = line;
+ w = strtok(l, " \t");
+ while (w) {
+ char *nw = dl_strdup(w);
+ dl_insert(head, nw);
+ head = nw;
+ w = strtok(NULL, " \t");
+ }
+ free(l);
+ }
+
for (super_cnt = 0; superlist[super_cnt]; super_cnt++)
;
seen = xcalloc(super_cnt, 1);
conffile = file;
}
-void load_conffile(void)
+void conf_file(FILE *f)
{
- FILE *f;
char *line;
-
- if (loaded) return;
- if (conffile == NULL)
- conffile = DefaultConfFile;
-
- if (strcmp(conffile, "none") == 0) {
- loaded = 1;
- return;
- }
- if (strcmp(conffile, "partitions")==0) {
- char *list = dl_strdup("DEV");
- dl_init(list);
- dl_add(list, dl_strdup("partitions"));
- devline(list);
- free_line(list);
- loaded = 1;
- return;
- }
- f = fopen(conffile, "r");
- /* Debian chose to relocate mdadm.conf into /etc/mdadm/.
- * To allow Debian users to compile from clean source and still
- * have a working mdadm, we read /etc/mdadm/mdadm.conf
- * if /etc/mdadm.conf doesn't exist
- */
- if (f == NULL &&
- conffile == DefaultConfFile) {
- f = fopen(DefaultAltConfFile, "r");
- if (f)
- conffile = DefaultAltConfFile;
- }
- if (f == NULL)
- return;
-
- loaded = 1;
while ((line=conf_line(f))) {
switch(match_keyword(line)) {
case Devices:
}
free_line(line);
}
+}
- fclose(f);
+struct fname {
+ struct fname *next;
+ char name[];
+};
-/* printf("got file\n"); */
+void conf_file_or_dir(FILE *f)
+{
+ struct stat st;
+ DIR *dir;
+ struct dirent *dp;
+ struct fname *list = NULL;
+
+ fstat(fileno(f), &st);
+ if (S_ISREG(st.st_mode))
+ conf_file(f);
+ else if (!S_ISDIR(st.st_mode))
+ return;
+#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
+ dir = fdopendir(fileno(f));
+ if (!dir)
+ return;
+ while ((dp = readdir(dir)) != NULL) {
+ int l;
+ struct fname *fn, **p;
+ if (dp->d_ino == 0)
+ continue;
+ if (dp->d_name[0] == '.')
+ continue;
+ l = strlen(dp->d_name);
+ if (l < 6 || strcmp(dp->d_name+l-5, ".conf") != 0)
+ continue;
+ fn = xmalloc(sizeof(*fn)+l+1);
+ strcpy(fn->name, dp->d_name);
+ for (p = &list;
+ *p && strcmp((*p)->name, fn->name) < 0;
+ p = & (*p)->next)
+ ;
+ fn->next = *p;
+ *p = fn;
+ }
+ while (list) {
+ int fd;
+ FILE *f2;
+ struct fname *fn = list;
+ list = list->next;
+ fd = openat(fileno(f), fn->name, O_RDONLY);
+ free(fn);
+ if (fd < 0)
+ continue;
+ f2 = fdopen(fd, "r");
+ if (!f2) {
+ close(fd);
+ continue;
+ }
+ conf_file(f2);
+ fclose(f2);
+ }
+ closedir(dir);
+#endif
+}
+
+void load_conffile(void)
+{
+ FILE *f;
+ char *confdir = NULL;
+ char *head;
+
+ if (loaded)
+ return;
+ if (conffile == NULL) {
+ conffile = DefaultConfFile;
+ confdir = DefaultConfDir;
+ }
+
+ if (strcmp(conffile, "partitions")==0) {
+ char *list = dl_strdup("DEV");
+ dl_init(list);
+ dl_add(list, dl_strdup("partitions"));
+ devline(list);
+ free_line(list);
+ } else if (strcmp(conffile, "none") != 0) {
+ f = fopen(conffile, "r");
+ /* Debian chose to relocate mdadm.conf into /etc/mdadm/.
+ * To allow Debian users to compile from clean source and still
+ * have a working mdadm, we read /etc/mdadm/mdadm.conf
+ * if /etc/mdadm.conf doesn't exist
+ */
+ if (f == NULL &&
+ conffile == DefaultConfFile) {
+ f = fopen(DefaultAltConfFile, "r");
+ if (f) {
+ conffile = DefaultAltConfFile;
+ confdir = DefaultAltConfDir;
+ }
+ }
+ if (f) {
+ conf_file_or_dir(f);
+ fclose(f);
+ }
+ if (confdir) {
+ f = fopen(confdir, "r");
+ if (f) {
+ conf_file_or_dir(f);
+ fclose(f);
+ }
+ }
+ }
+ /* If there was no AUTO line, process an empty line
+ * now so that the MDADM_CONF_AUTO env var gets processed.
+ */
+ head = dl_strdup("AUTO");
+ dl_init(head);
+ autoline(head);
+ free_line(head);
+
+ loaded = 1;
}
char *conf_get_mailaddr(void)
if (flags & GLOB_APPEND) {
for (i=0; i<globbuf.gl_pathc; i++) {
struct mddev_dev *t = xmalloc(sizeof(*t));
+ memset(t, 0, sizeof(*t));
t->devname = xstrdup(globbuf.gl_pathv[i]);
t->next = dlist;
- t->used = 0;
dlist = t;
/* printf("one dev is %s\n", t->devname);*/
}
int match_oneof(char *devices, char *devname)
{
- /* check if one of the comma separated patterns in devices
- * matches devname
- */
-
- while (devices && *devices) {
- char patn[1024];
- char *p = devices;
- devices = strchr(devices, ',');
- if (!devices)
- devices = p + strlen(p);
- if (devices-p < 1024) {
- strncpy(patn, p, devices-p);
- patn[devices-p] = 0;
- if (fnmatch(patn, devname, FNM_PATHNAME)==0)
- return 1;
+ /* check if one of the comma separated patterns in devices
+ * matches devname
+ */
+
+ while (devices && *devices) {
+ char patn[1024];
+ char *p = devices;
+ devices = strchr(devices, ',');
+ if (!devices)
+ devices = p + strlen(p);
+ if (devices-p < 1024) {
+ strncpy(patn, p, devices-p);
+ patn[devices-p] = 0;
+ if (fnmatch(patn, devname, FNM_PATHNAME)==0)
+ return 1;
+ }
+ if (*devices == ',')
+ devices++;
}
- if (*devices == ',')
- devices++;
- }
- return 0;
+ return 0;
}
int devname_matches(char *name, char *match)
else if (strncmp(match, "/dev/", 5) == 0)
match += 5;
-
if (strncmp(name, "md", 2) == 0 &&
isdigit(name[2]))
name += 2;
int conf_name_is_free(char *name)
{
- /* Check if this name is already take by an ARRAY entry in
+ /* Check if this name is already taken by an ARRAY entry in
* the config file.
* It can be taken either by a match on devname, name, or
* even super-minor.
for (a1 = array_list; a1; a1 = a1->next) {
if (!a1->devname)
continue;
+ if (strcmp(a1->devname, "<ignore>") == 0)
+ continue;
for (a2 = a1->next; a2; a2 = a2->next) {
if (!a2->devname)
continue;