+
+static char *container2devname(char *devname)
+{
+ int fd = open(devname, O_RDONLY);
+ char *mdname = NULL;
+
+ if (fd >= 0) {
+ mdname = devnum2devname(fd2devnum(fd));
+ close(fd);
+ }
+
+ return mdname;
+}
+
+int Incremental_container(struct supertype *st, char *devname, int verbose,
+ int runstop, int autof)
+{
+ /* Collect the contents of this container and for each
+ * array, choose a device name and assemble the array.
+ */
+
+ struct mdinfo *list = st->ss->container_content(st);
+ struct mdinfo *ra;
+ char *mdname = container2devname(devname);
+
+ if (!mdname) {
+ fprintf(stderr, Name": failed to determine device name\n");
+ return 2;
+ }
+
+ for (ra = list ; ra ; ra = ra->next) {
+ struct mdinfo *dev, *sra;
+ int devnum = -1;
+ int mdfd;
+ char chosen_name[1024];
+ int usepart = 1;
+ char *n;
+ int working = 0, preexist = 0;
+ struct map_ent *mp, *map = NULL;
+ char nbuf[64];
+ char *name_to_use;
+ struct mddev_ident_s *match = NULL;
+
+ if ((autof&7) == 3 || (autof&7) == 5)
+ usepart = 0;
+
+ mp = map_by_uuid(&map, ra->uuid);
+
+ name_to_use = ra->name;
+ if (! name_to_use ||
+ ! *name_to_use ||
+ (*devname != '/' || strncmp("UUID-", strrchr(devname,'/')+1,5) == 0)
+ )
+ name_to_use = fname_from_uuid(st, ra, nbuf, '-');
+
+ if (!mp) {
+
+ /* Check in mdadm.conf for devices == devname and
+ * member == ra->text_version after second slash.
+ */
+ char *sub = strchr(ra->text_version+1, '/');
+ struct mddev_ident_s *array_list;
+ if (sub) {
+ sub++;
+ array_list = conf_get_ident(NULL);
+ } else
+ array_list = NULL;
+ for(; array_list ; array_list = array_list->next) {
+ int fd;
+ char *dn;
+ if (array_list->member == NULL ||
+ array_list->container == NULL)
+ continue;
+ if (strcmp(array_list->member, sub) != 0)
+ continue;
+ if (array_list->uuid_set &&
+ !same_uuid(ra->uuid, array_list->uuid, st->ss->swapuuid))
+ continue;
+ fd = open(array_list->container, O_RDONLY);
+ if (fd < 0)
+ continue;
+ dn = devnum2devname(fd2devnum(fd));
+ close(fd);
+ if (strncmp(dn, ra->text_version+1,
+ strlen(dn)) != 0 ||
+ ra->text_version[strlen(dn)+1] != '/') {
+ free(dn);
+ continue;
+ }
+ free(dn);
+ /* we have a match */
+ match = array_list;
+ if (verbose>0)
+ fprintf(stderr, Name ": match found for member %s\n",
+ array_list->member);
+ break;
+ }
+ }
+
+ if (match && is_standard(match->devname, &devnum))
+ /* we have devnum now */;
+ else if (mp)
+ devnum = mp->devnum;
+ else if (is_standard(name_to_use, &devnum))
+ /* have devnum */;
+ else {
+ n = name_to_use;
+ if (*n == 'd')
+ n++;
+ if (*n && devnum < 0) {
+ devnum = strtoul(n, &n, 10);
+ if (devnum >= 0 && (*n == 0 || *n == ' ')) {
+ /* Use this devnum */
+ usepart = (name_to_use[0] == 'd');
+ if (mddev_busy(usepart ? (-1-devnum) : devnum))
+ devnum = -1;
+ } else
+ devnum = -1;
+ }
+
+ if (devnum < 0) {
+ char *nm = name_to_use;
+ char nbuf[1024];
+ struct stat stb;
+ if (strchr(nm, ':'))
+ nm = strchr(nm, ':')+1;
+ sprintf(nbuf, "/dev/md/%s", nm);
+
+ if (stat(nbuf, &stb) == 0 &&
+ S_ISBLK(stb.st_mode) &&
+ major(stb.st_rdev) == (usepart ?
+ get_mdp_major() : MD_MAJOR)){
+ if (usepart)
+ devnum = minor(stb.st_rdev)
+ >> MdpMinorShift;
+ else
+ devnum = minor(stb.st_rdev);
+ if (mddev_busy(usepart ? (-1-devnum) : devnum))
+ devnum = -1;
+ }
+ }
+
+ if (devnum >= 0)
+ devnum = usepart ? (-1-devnum) : devnum;
+ else
+ devnum = find_free_devnum(usepart);
+ }
+ mdfd = open_mddev_devnum(mp ? mp->path : match ? match->devname : NULL,
+ devnum, name_to_use,
+ chosen_name, autof>>3);
+
+ if (mdfd < 0) {
+ fprintf(stderr, Name ": failed to open %s: %s.\n",
+ chosen_name, strerror(errno));
+ return 2;
+ }
+
+
+ sysfs_init(ra, mdfd, 0);
+
+ sra = sysfs_read(mdfd, 0, GET_VERSION);
+ if (sra == NULL || strcmp(sra->text_version, ra->text_version) != 0)
+ if (sysfs_set_array(ra, md_get_version(mdfd)) != 0)
+ return 1;
+ if (sra)
+ sysfs_free(sra);
+
+ for (dev = ra->devs; dev; dev = dev->next)
+ if (sysfs_add_disk(ra, dev) == 0)
+ working++;
+ else if (errno == EEXIST)
+ preexist++;
+ if (working == 0)
+ /* Nothing new, don't try to start */ ;
+ else if (runstop > 0 ||
+ (working + preexist) >= ra->array.working_disks) {
+ switch(ra->array.level) {
+ case LEVEL_LINEAR:
+ case LEVEL_MULTIPATH:
+ case 0:
+ sysfs_set_str(ra, NULL, "array_state",
+ "active");
+ break;
+ default:
+ sysfs_set_str(ra, NULL, "array_state",
+ "readonly");
+ /* start mdmon if needed. */
+ if (!mdmon_running(st->container_dev))
+ start_mdmon(st->container_dev);
+ ping_monitor(devnum2devname(st->container_dev));
+ break;
+ }
+ sysfs_set_safemode(ra, ra->safe_mode_delay);
+ if (verbose >= 0) {
+ fprintf(stderr, Name
+ ": Started %s with %d devices",
+ chosen_name, working + preexist);
+ if (preexist)
+ fprintf(stderr, " (%d new)", working);
+ fprintf(stderr, "\n");
+ }
+ /* FIXME should have an O_EXCL and wait for read-auto */
+ } else
+ if (verbose >= 0)
+ fprintf(stderr, Name
+ ": %s assembled with %d devices but "
+ "not started\n",
+ chosen_name, working);
+ close(mdfd);
+ map_update(&map, devnum,
+ ra->text_version,
+ ra->uuid, chosen_name);
+ }
+ return 0;
+}