static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
{
	bool found = false;
	char **dep, *cipher_spec = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN], deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = {};
	const char *dev, *namei;
	int key_nums, r;
	struct crypt_dm_active_device dmd, dmdi = {}, dmdep = {};
	struct dm_target *tgt = &dmd.segment, *tgti = &dmdi.segment;

	r = dm_query_device(cd, name,
			DM_ACTIVE_DEVICE |
			DM_ACTIVE_UUID |
			DM_ACTIVE_CRYPT_CIPHER |
			DM_ACTIVE_CRYPT_KEYSIZE, &dmd);
	if (r < 0)
		return r;

	if (tgt->type != DM_CRYPT && tgt->type != DM_LINEAR) {
		log_dbg(cd, "Unsupported device table detected in %s.", name);
		r = -EINVAL;
		goto out;
	}

	r = -EINVAL;

	if (dmd.uuid) {
		r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), CRYPT_SUBDEV "-%.32s", dmd.uuid + 6);
		if (r < 0 || (size_t)r != (sizeof(deps_uuid_prefix) - 1))
			r = -EINVAL;
	}

	if (r >= 0) {
		r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
		if (r)
			goto out;
	}

	r = crypt_parse_name_and_mode(tgt->type == DM_LINEAR ? "null" : tgt->u.crypt.cipher, cipher,
				      &key_nums, cipher_mode);
	if (r < 0) {
		log_dbg(cd, "Cannot parse cipher and mode from active device.");
		goto out;
	}

	dep = deps;

	if (tgt->type == DM_CRYPT && tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
		r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi);
		if (r < 0)
			goto out;
		if (!single_segment(&dmdi) || tgti->type != DM_INTEGRITY) {
			log_dbg(cd, "Unsupported device table detected in %s.", namei);
			r = -EINVAL;
			goto out;
		}
		if (!cd->metadata_device) {
			device_free(cd, cd->device);
			MOVE_REF(cd->device, tgti->data_device);
		}
	}

	/* do not try to lookup LUKS2 header in detached header mode */
	if (dmd.uuid && !cd->metadata_device && !found) {
		while (*dep && !found) {
			r = dm_query_device(cd, *dep, DM_ACTIVE_DEVICE, &dmdep);
			if (r < 0)
				goto out;

			tgt = &dmdep.segment;

			while (tgt && !found) {
				dev = device_path(tgt->data_device);
				if (!dev) {
					tgt = tgt->next;
					continue;
				}
				if (!strstr(dev, dm_get_dir()) ||
				    !crypt_string_in(dev + strlen(dm_get_dir()) + 1, deps, ARRAY_SIZE(deps))) {
					device_free(cd, cd->device);
					MOVE_REF(cd->device, tgt->data_device);
					found = true;
				}
				tgt = tgt->next;
			}
			dep++;
			dm_targets_free(cd, &dmdep);
		}
	}

	if (asprintf(&cipher_spec, "%s-%s", cipher, cipher_mode) < 0) {
		cipher_spec = NULL;
		r = -ENOMEM;
		goto out;
	}

	tgt = &dmd.segment;
	r = 0;

	if (isPLAIN(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT) {
		cd->u.plain.hdr.hash = NULL; /* no way to get this */
		cd->u.plain.hdr.offset = tgt->u.crypt.offset;
		cd->u.plain.hdr.skip = tgt->u.crypt.iv_offset;
		cd->u.plain.hdr.sector_size = tgt->u.crypt.sector_size;
		cd->u.plain.key_size = tgt->u.crypt.vk->keylength;
		cd->u.plain.cipher = strdup(cipher);
		MOVE_REF(cd->u.plain.cipher_spec, cipher_spec);
		cd->u.plain.cipher_mode = cd->u.plain.cipher_spec + strlen(cipher) + 1;
	} else if (isLOOPAES(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT) {
		cd->u.loopaes.hdr.offset = tgt->u.crypt.offset;
		cd->u.loopaes.cipher = strdup(cipher);
		MOVE_REF(cd->u.loopaes.cipher_spec, cipher_spec);
		cd->u.loopaes.cipher_mode = cd->u.loopaes.cipher_spec + strlen(cipher) + 1;
		/* version 3 uses last key for IV */
		if (tgt->u.crypt.vk->keylength % key_nums)
			key_nums++;
		cd->u.loopaes.key_size = tgt->u.crypt.vk->keylength / key_nums;
	} else if (isLUKS1(cd->type) || isLUKS2(cd->type)) {
		if (crypt_metadata_device(cd)) {
			r = _crypt_load_luks(cd, cd->type, 0, 0);
			if (r < 0) {
				log_dbg(cd, "LUKS device header does not match active device.");
				crypt_set_null_type(cd);
				device_close(cd, cd->metadata_device);
				device_close(cd, cd->device);
				r = 0;
				goto out;
			}
			/* check whether UUIDs match each other */
			r = crypt_uuid_cmp(dmd.uuid, LUKS_UUID(cd));
			if (r < 0) {
				log_dbg(cd, "LUKS device header uuid: %s mismatches DM returned uuid %s",
					LUKS_UUID(cd), dmd.uuid);
				crypt_free_type(cd);
				r = 0;
				goto out;
			}
		} else {
			log_dbg(cd, "LUKS device header not available.");
			crypt_set_null_type(cd);
			r = 0;
		}
	} else if (isTCRYPT(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT) {
		r = TCRYPT_init_by_name(cd, name, dmd.uuid, tgt, &cd->device,
					&cd->u.tcrypt.params, &cd->u.tcrypt.hdr);
	} else if (isBITLK(cd->type)) {
		r = _crypt_load_bitlk(cd, NULL);
		if (r < 0) {
			log_dbg(cd, "BITLK device header not available.");
			crypt_set_null_type(cd);
			r = 0;
		}
	}
out:
	dm_targets_free(cd, &dmd);
	dm_targets_free(cd, &dmdi);
	dm_targets_free(cd, &dmdep);
	free(CONST_CAST(void*)dmd.uuid);
	free(cipher_spec);
	dep = deps;
	while (*dep)
		free(*dep++);
	return r;
}
static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
{
	bool found = false;
	char **dep, *cipher_spec = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN], deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = {};
	const char *dev, *namei;
	int key_nums, r;
	struct crypt_dm_active_device dmd, dmdi = {}, dmdep = {};
	struct dm_target *tgt = &dmd.segment, *tgti = &dmdi.segment;

	r = dm_query_device(cd, name,
			DM_ACTIVE_DEVICE |
			DM_ACTIVE_UUID |
			DM_ACTIVE_CRYPT_CIPHER |
			DM_ACTIVE_CRYPT_KEYSIZE, &dmd);
	if (r < 0)
		return r;

	if (tgt->type != DM_CRYPT && tgt->type != DM_LINEAR) {
		log_dbg(cd, "Unsupported device table detected in %s.", name);
		r = -EINVAL;
		goto out;
	}

	r = -EINVAL;

	if (dmd.uuid) {
		r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), CRYPT_SUBDEV "-%.32s", dmd.uuid + 6);
		if (r < 0 || (size_t)r != (sizeof(deps_uuid_prefix) - 1))
			r = -EINVAL;
	}

	if (r >= 0) {
		r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
		if (r)
			goto out;
	}

	r = crypt_parse_name_and_mode(tgt->type == DM_LINEAR ? "null" : tgt->u.crypt.cipher, cipher,
				      &key_nums, cipher_mode);
	if (r < 0) {
		log_dbg(cd, "Cannot parse cipher and mode from active device.");
		goto out;
	}

	dep = deps;

	if (tgt->type == DM_CRYPT && tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
		r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi);
		if (r < 0)
			goto out;
		if (!single_segment(&dmdi) || tgti->type != DM_INTEGRITY) {
			log_dbg(cd, "Unsupported device table detected in %s.", namei);
			r = -EINVAL;
			goto out;
		}
		if (!cd->metadata_device) {
			device_free(cd, cd->device);
			MOVE_REF(cd->device, tgti->data_device);
		}
	}

	 
	if (dmd.uuid && !cd->metadata_device && !found) {
		while (*dep && !found) {
			r = dm_query_device(cd, *dep, DM_ACTIVE_DEVICE, &dmdep);
			if (r < 0)
				goto out;

			tgt = &dmdep.segment;

			while (tgt && !found) {
				dev = device_path(tgt->data_device);
				if (!dev) {
					tgt = tgt->next;
					continue;
				}
				if (!strstr(dev, dm_get_dir()) ||
				    !crypt_string_in(dev + strlen(dm_get_dir()) + 1, deps, ARRAY_SIZE(deps))) {
					device_free(cd, cd->device);
					MOVE_REF(cd->device, tgt->data_device);
					found = true;
				}
				tgt = tgt->next;
			}
			dep++;
			dm_targets_free(cd, &dmdep);
		}
	}

	if (asprintf(&cipher_spec, "%s-%s", cipher, cipher_mode) < 0) {
		cipher_spec = NULL;
		r = -ENOMEM;
		goto out;
	}

	tgt = &dmd.segment;
	r = 0;

	if (isPLAIN(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT) {
		cd->u.plain.hdr.hash = NULL;  
		cd->u.plain.hdr.offset = tgt->u.crypt.offset;
		cd->u.plain.hdr.skip = tgt->u.crypt.iv_offset;
		cd->u.plain.hdr.sector_size = tgt->u.crypt.sector_size;
		cd->u.plain.key_size = tgt->u.crypt.vk->keylength;
		cd->u.plain.cipher = strdup(cipher);
		MOVE_REF(cd->u.plain.cipher_spec, cipher_spec);
		cd->u.plain.cipher_mode = cd->u.plain.cipher_spec + strlen(cipher) + 1;
	} else if (isLOOPAES(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT) {
		cd->u.loopaes.hdr.offset = tgt->u.crypt.offset;
		cd->u.loopaes.cipher = strdup(cipher);
		MOVE_REF(cd->u.loopaes.cipher_spec, cipher_spec);
		cd->u.loopaes.cipher_mode = cd->u.loopaes.cipher_spec + strlen(cipher) + 1;
		 
		if (tgt->u.crypt.vk->keylength % key_nums)
			key_nums++;
		cd->u.loopaes.key_size = tgt->u.crypt.vk->keylength / key_nums;
	} else if (isLUKS1(cd->type) || isLUKS2(cd->type)) {
		if (crypt_metadata_device(cd)) {
			r = _crypt_load_luks(cd, cd->type, 0, 0);
			if (r < 0) {
				log_dbg(cd, "LUKS device header does not match active device.");
				crypt_set_null_type(cd);
				device_close(cd, cd->metadata_device);
				device_close(cd, cd->device);
				r = 0;
				goto out;
			}
			 
			r = crypt_uuid_cmp(dmd.uuid, LUKS_UUID(cd));
			if (r < 0) {
				log_dbg(cd, "LUKS device header uuid: %s mismatches DM returned uuid %s",
					LUKS_UUID(cd), dmd.uuid);
				crypt_free_type(cd);
				r = 0;
				goto out;
			}
		} else {
			log_dbg(cd, "LUKS device header not available.");
			crypt_set_null_type(cd);
			r = 0;
		}
	} else if (isTCRYPT(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT) {
		r = TCRYPT_init_by_name(cd, name, dmd.uuid, tgt, &cd->device,
					&cd->u.tcrypt.params, &cd->u.tcrypt.hdr);
	} else if (isBITLK(cd->type)) {
		r = _crypt_load_bitlk(cd, NULL);
		if (r < 0) {
			log_dbg(cd, "BITLK device header not available.");
			crypt_set_null_type(cd);
			r = 0;
		}
	}
out:
	dm_targets_free(cd, &dmd);
	dm_targets_free(cd, &dmdi);
	dm_targets_free(cd, &dmdep);
	free(CONST_CAST(void*)dmd.uuid);
	free(cipher_spec);
	dep = deps;
	while (*dep)
		free(*dep++);
	return r;
}