Beispiel #1
0
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);
}
Beispiel #2
0
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);
}