void RebuildMap(void) { struct mdstat_ent *mdstat = mdstat_read(0, 0); struct mdstat_ent *md; struct map_ent *map = NULL; int require_homehost; char sys_hostname[256]; char *homehost = conf_get_homehost(&require_homehost); if (homehost == NULL || strcmp(homehost, "<system>")==0) { if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { sys_hostname[sizeof(sys_hostname)-1] = 0; homehost = sys_hostname; } } for (md = mdstat ; md ; md = md->next) { struct mdinfo *sra = sysfs_read(-1, md->devnm, GET_DEVS); struct mdinfo *sd; if (!sra) continue; for (sd = sra->devs ; sd ; sd = sd->next) { char namebuf[100]; char dn[30]; int dfd; int ok; int devid; struct supertype *st; char *subarray = NULL; char *path; struct mdinfo *info; sprintf(dn, "%d:%d", sd->disk.major, sd->disk.minor); dfd = dev_open(dn, O_RDONLY); if (dfd < 0) continue; st = guess_super(dfd); if ( st == NULL) ok = -1; else { subarray = get_member_info(md); ok = st->ss->load_super(st, dfd, NULL); } close(dfd); if (ok != 0) continue; if (subarray) info = st->ss->container_content(st, subarray); else { info = xmalloc(sizeof(*info)); st->ss->getinfo_super(st, info, NULL); } if (!info) continue; devid = devnm2devid(md->devnm); path = map_dev(major(devid), minor(devid), 0); if (path == NULL || strncmp(path, "/dev/md/", 8) != 0) { /* We would really like a name that provides * an MD_DEVNAME for udev. * The name needs to be unique both in /dev/md/ * and in this mapfile. * It needs to match what -I or -As would come * up with. * That means: * Check if array is in mdadm.conf * - if so use that. * determine trustworthy from homehost etc * find a unique name based on metadata name. * */ struct mddev_ident *match = conf_match(st, info, NULL, 0, NULL); struct stat stb; if (match && match->devname && match->devname[0] == '/') { path = match->devname; if (path[0] != '/') { strcpy(namebuf, "/dev/md/"); strcat(namebuf, path); path = namebuf; } } else { int unum = 0; char *sep = "_"; const char *name; int conflict = 1; if ((homehost == NULL || st->ss->match_home(st, homehost) != 1) && st->ss->match_home(st, "any") != 1 && (require_homehost || ! conf_name_is_free(info->name))) /* require a numeric suffix */ unum = 0; else /* allow name to be used as-is if no conflict */ unum = -1; name = info->name; if (!*name) { name = st->ss->name; if (!isdigit(name[strlen(name)-1]) && unum == -1) { unum = 0; sep = ""; } } if (strchr(name, ':')) { /* Probably a uniquifying * hostname prefix. Allow * without a suffix, and strip * hostname if it is us. */ if (homehost && unum == -1 && strncmp(name, homehost, strlen(homehost)) == 0 && name[strlen(homehost)] == ':') name += strlen(homehost)+1; unum = -1; } while (conflict) { if (unum >= 0) sprintf(namebuf, "/dev/md/%s%s%d", name, sep, unum); else sprintf(namebuf, "/dev/md/%s", name); unum++; if (lstat(namebuf, &stb) != 0 && (map == NULL || !map_by_name(&map, namebuf+8))) conflict = 0; } path = namebuf; } } map_add(&map, md->devnm, info->text_version, info->uuid, path); st->ss->free_super(st); free(info); break; } sysfs_free(sra); } /* Only trigger a change if we wrote a new map file */ if (map_write(map)) for (md = mdstat ; md ; md = md->next) { struct mdinfo *sra = sysfs_read(-1, md->devnm, GET_VERSION); if (sra) sysfs_uevent(sra, "change"); sysfs_free(sra); } map_free(map); free_mdstat(mdstat); }
int main(int argc, char *argv[]) { char *container_name = NULL; char *devnm = NULL; int status = 0; int opt; int all = 0; int takeover = 0; int dofork = 1; static struct option options[] = { {"all", 0, NULL, 'a'}, {"takeover", 0, NULL, 't'}, {"help", 0, NULL, 'h'}, {"offroot", 0, NULL, OffRootOpt}, {"foreground", 0, NULL, 'F'}, {NULL, 0, NULL, 0} }; if (in_initrd()) { /* * set first char of argv[0] to @. This is used by * systemd to signal that the task was launched from * initrd/initramfs and should be preserved during shutdown */ argv[0][0] = '@'; } while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) { switch (opt) { case 'a': container_name = argv[optind-1]; all = 1; break; case 't': takeover = 1; break; case 'F': dofork = 0; break; case OffRootOpt: argv[0][0] = '@'; break; case 'h': default: usage(); break; } } if (all == 0 && container_name == NULL) { if (argv[optind]) container_name = argv[optind]; } if (container_name == NULL) usage(); if (argc - optind > 1) usage(); if (strcmp(container_name, "/proc/mdstat") == 0) all = 1; if (all) { struct mdstat_ent *mdstat, *e; int container_len = strlen(container_name); /* launch an mdmon instance for each container found */ mdstat = mdstat_read(0, 0); for (e = mdstat; e; e = e->next) { if (e->metadata_version && strncmp(e->metadata_version, "external:", 9) == 0 && !is_subarray(&e->metadata_version[9])) { /* update cmdline so this mdmon instance can be * distinguished from others in a call to ps(1) */ if (strlen(e->devnm) <= (unsigned)container_len) { memset(container_name, 0, container_len); sprintf(container_name, "%s", e->devnm); } status |= mdmon(e->devnm, 1, takeover); } } free_mdstat(mdstat); return status; } else if (strncmp(container_name, "md", 2) == 0) { int id = devnm2devid(container_name); if (id) devnm = container_name; } else { struct stat st; if (stat(container_name, &st) == 0) devnm = xstrdup(stat2devnm(&st)); } if (!devnm) { pr_err("%s is not a valid md device name\n", container_name); exit(1); } return mdmon(devnm, dofork && do_fork(), takeover); }