+int dm_status_device(struct crypt_device *cd, const char *name)
+{
+ int r;
+ struct dm_info dmi;
+ struct stat st;
+
+ /* libdevmapper is too clever and handles
+ * path argument differenly with error.
+ * Fail early here if parameter is non-existent path.
+ */
+ if (strchr(name, '/') && stat(name, &st) < 0)
+ return -ENODEV;
+
+ if (dm_init_context(cd))
+ return -ENOTSUP;
+ r = dm_status_dmi(name, &dmi, NULL, NULL);
+ dm_exit_context();
+ if (r < 0)
+ return r;
+
+ return (dmi.open_count > 0);
+}
+
+int dm_status_suspended(struct crypt_device *cd, const char *name)
+{
+ int r;
+ struct dm_info dmi;
+
+ if (dm_init_context(cd))
+ return -ENOTSUP;
+ r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL);
+ dm_exit_context();
+ if (r < 0)
+ return r;
+
+ return dmi.suspended ? 1 : 0;
+}
+
+static int _dm_status_verity_ok(const char *name)
+{
+ int r;
+ struct dm_info dmi;
+ char *status_line = NULL;
+
+ r = dm_status_dmi(name, &dmi, DM_VERITY_TARGET, &status_line);
+ if (r < 0 || !status_line) {
+ free(status_line);
+ return r;
+ }
+
+ log_dbg("Verity volume %s status is %s.", name, status_line ?: "");
+ r = status_line[0] == 'V' ? 1 : 0;
+ free(status_line);
+
+ return r;
+}
+
+int dm_status_verity_ok(struct crypt_device *cd, const char *name)
+{
+ int r;
+
+ if (dm_init_context(cd))
+ return -ENOTSUP;
+ r = _dm_status_verity_ok(name);
+ dm_exit_context();
+ return r;
+}
+
+/* FIXME use hex wrapper, user val wrappers for line parsing */
+static int _dm_query_crypt(uint32_t get_flags,
+ struct dm_info *dmi,
+ char *params,
+ struct crypt_dm_active_device *dmd)
+{
+ uint64_t val64;
+ char *rcipher, *key_, *rdevice, *endp, buffer[3], *arg;
+ unsigned int i;
+ int r;
+
+ memset(dmd, 0, sizeof(*dmd));
+ dmd->target = DM_CRYPT;
+
+ rcipher = strsep(¶ms, " ");
+ /* cipher */
+ if (get_flags & DM_ACTIVE_CRYPT_CIPHER)
+ dmd->u.crypt.cipher = strdup(rcipher);
+
+ /* skip */
+ key_ = strsep(¶ms, " ");
+ if (!params)
+ return -EINVAL;
+ val64 = strtoull(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ params++;
+
+ dmd->u.crypt.iv_offset = val64;
+
+ /* device */
+ rdevice = strsep(¶ms, " ");
+ if (get_flags & DM_ACTIVE_DEVICE) {
+ arg = crypt_lookup_dev(rdevice);
+ r = device_alloc(&dmd->data_device, arg);
+ free(arg);
+ if (r < 0 && r != -ENOTBLK)
+ return r;
+ }
+
+ /*offset */
+ if (!params)
+ return -EINVAL;
+ val64 = strtoull(params, ¶ms, 10);
+ dmd->u.crypt.offset = val64;
+
+ /* Features section, available since crypt target version 1.11 */
+ if (*params) {
+ if (*params != ' ')
+ return -EINVAL;
+ params++;
+
+ /* Number of arguments */
+ val64 = strtoull(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ params++;
+
+ for (i = 0; i < val64; i++) {
+ if (!params)
+ return -EINVAL;
+ arg = strsep(¶ms, " ");
+ if (!strcasecmp(arg, "allow_discards"))
+ dmd->flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+ else if (!strcasecmp(arg, "same_cpu_crypt"))
+ dmd->flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT;
+ else if (!strcasecmp(arg, "submit_from_crypt_cpus"))
+ dmd->flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
+ else /* unknown option */
+ return -EINVAL;
+ }
+
+ /* All parameters shold be processed */
+ if (params)
+ return -EINVAL;
+ }
+
+ /* Never allow to return empty key */
+ if ((get_flags & DM_ACTIVE_CRYPT_KEY) && dmi->suspended) {
+ log_dbg("Cannot read volume key while suspended.");
+ return -EINVAL;
+ }
+
+ if (get_flags & DM_ACTIVE_CRYPT_KEYSIZE) {
+ dmd->u.crypt.vk = crypt_alloc_volume_key(strlen(key_) / 2, NULL);
+ if (!dmd->u.crypt.vk)
+ return -ENOMEM;
+
+ if (get_flags & DM_ACTIVE_CRYPT_KEY) {
+ buffer[2] = '\0';
+ for(i = 0; i < dmd->u.crypt.vk->keylength; i++) {
+ memcpy(buffer, &key_[i * 2], 2);
+ dmd->u.crypt.vk->key[i] = strtoul(buffer, &endp, 16);
+ if (endp != &buffer[2]) {
+ crypt_free_volume_key(dmd->u.crypt.vk);
+ dmd->u.crypt.vk = NULL;
+ return -EINVAL;
+ }
+ }
+ }
+ }
+ memset(key_, 0, strlen(key_));
+
+ return 0;
+}
+
+static int _dm_query_verity(uint32_t get_flags,
+ struct dm_info *dmi,
+ char *params,
+ struct crypt_dm_active_device *dmd)
+{
+ struct crypt_params_verity *vp = NULL;
+ uint32_t val32;
+ uint64_t val64;
+ ssize_t len;
+ char *str, *str2;
+ int r;
+
+ if (get_flags & DM_ACTIVE_VERITY_PARAMS)
+ vp = dmd->u.verity.vp;
+
+ memset(dmd, 0, sizeof(*dmd));
+
+ dmd->target = DM_VERITY;
+ dmd->u.verity.vp = vp;
+
+ /* version */
+ val32 = strtoul(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ if (vp)
+ vp->hash_type = val32;
+ params++;
+
+ /* data device */
+ str = strsep(¶ms, " ");
+ if (!params)
+ return -EINVAL;
+ if (get_flags & DM_ACTIVE_DEVICE) {
+ str2 = crypt_lookup_dev(str);
+ r = device_alloc(&dmd->data_device, str2);
+ free(str2);
+ if (r < 0 && r != -ENOTBLK)
+ return r;
+ }
+
+ /* hash device */
+ str = strsep(¶ms, " ");
+ if (!params)
+ return -EINVAL;
+ if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE) {
+ str2 = crypt_lookup_dev(str);
+ r = device_alloc(&dmd->u.verity.hash_device, str2);
+ free(str2);
+ if (r < 0 && r != -ENOTBLK)
+ return r;
+ }
+
+ /* data block size*/
+ val32 = strtoul(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ if (vp)
+ vp->data_block_size = val32;
+ params++;
+
+ /* hash block size */
+ val32 = strtoul(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ if (vp)
+ vp->hash_block_size = val32;
+ params++;
+
+ /* data blocks */
+ val64 = strtoull(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ if (vp)
+ vp->data_size = val64;
+ params++;
+
+ /* hash start */
+ val64 = strtoull(params, ¶ms, 10);
+ if (*params != ' ')
+ return -EINVAL;
+ dmd->u.verity.hash_offset = val64;
+ params++;
+
+ /* hash algorithm */
+ str = strsep(¶ms, " ");
+ if (!params)
+ return -EINVAL;
+ if (vp)
+ vp->hash_name = strdup(str);
+
+ /* root digest */
+ str = strsep(¶ms, " ");
+ if (!params)
+ return -EINVAL;
+ len = crypt_hex_to_bytes(str, &str2, 0);
+ if (len < 0)
+ return len;
+ dmd->u.verity.root_hash_size = len;
+ if (get_flags & DM_ACTIVE_VERITY_ROOT_HASH)
+ dmd->u.verity.root_hash = str2;
+ else
+ free(str2);
+
+ /* salt */
+ str = strsep(¶ms, " ");
+ if (params)
+ return -EINVAL;
+ if (vp) {
+ if (!strcmp(str, "-")) {
+ vp->salt_size = 0;
+ vp->salt = NULL;
+ } else {
+ len = crypt_hex_to_bytes(str, &str2, 0);
+ if (len < 0)
+ return len;
+ vp->salt_size = len;
+ vp->salt = str2;
+ }
+ }
+
+ return 0;
+}
+
+int dm_query_device(struct crypt_device *cd, const char *name,
+ uint32_t get_flags, struct crypt_dm_active_device *dmd)