static void test_unhexmem_one(const char *s, size_t l, int retval) { _cleanup_free_ char *hex = NULL; _cleanup_free_ void *mem = NULL; size_t len; assert_se(unhexmem(s, l, &mem, &len) == retval); if (retval == 0) { char *answer; if (l == (size_t) -1) l = strlen(s); assert_se(hex = hexmem(mem, len)); answer = strndupa(strempty(s), l); assert_se(streq(delete_chars(answer, WHITESPACE), hex)); } }
static int determine_devices(void) { _cleanup_free_ void *m = NULL; sd_id128_t root_uuid, verity_uuid; char ids[37]; size_t l; int r; /* Try to automatically derive the root data and hash device paths from the root hash */ if (!arg_root_hash) return 0; if (arg_data_what && arg_hash_what) return 0; r = unhexmem(arg_root_hash, strlen(arg_root_hash), &m, &l); if (r < 0) return log_error_errno(r, "Failed to parse root hash: %s", arg_root_hash); if (l < sizeof(sd_id128_t)) { log_debug("Root hash is shorter than 128 bits (32 characters), ignoring for discovering verity partition."); return 0; } if (!arg_data_what) { memcpy(&root_uuid, m, sizeof(root_uuid)); arg_data_what = strjoin("/dev/disk/by-partuuid/", id128_to_uuid_string(root_uuid, ids)); if (!arg_data_what) return log_oom(); } if (!arg_hash_what) { memcpy(&verity_uuid, (uint8_t*) m + l - sizeof(verity_uuid), sizeof(verity_uuid)); arg_hash_what = strjoin("/dev/disk/by-partuuid/", id128_to_uuid_string(verity_uuid, ids)); if (!arg_hash_what) return log_oom(); } return 1; }
static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_DISCARD, ARG_ROOT_HASH, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "mount", no_argument, NULL, 'm' }, { "read-only", no_argument, NULL, 'r' }, { "discard", required_argument, NULL, ARG_DISCARD }, { "root-hash", required_argument, NULL, ARG_ROOT_HASH }, {} }; int c, r; assert(argc >= 0); assert(argv); while ((c = getopt_long(argc, argv, "hmr", options, NULL)) >= 0) { switch (c) { case 'h': help(); return 0; case ARG_VERSION: return version(); case 'm': arg_action = ACTION_MOUNT; break; case 'r': arg_flags |= DISSECT_IMAGE_READ_ONLY; break; case ARG_DISCARD: { DissectImageFlags flags; if (streq(optarg, "disabled")) flags = 0; else if (streq(optarg, "loop")) flags = DISSECT_IMAGE_DISCARD_ON_LOOP; else if (streq(optarg, "all")) flags = DISSECT_IMAGE_DISCARD_ON_LOOP | DISSECT_IMAGE_DISCARD; else if (streq(optarg, "crypt")) flags = DISSECT_IMAGE_DISCARD_ANY; else { log_error("Unknown --discard= parameter: %s", optarg); return -EINVAL; } arg_flags = (arg_flags & ~DISSECT_IMAGE_DISCARD_ANY) | flags; break; } case ARG_ROOT_HASH: { void *p; size_t l; r = unhexmem(optarg, strlen(optarg), &p, &l); if (r < 0) return log_error_errno(r, "Failed to parse root hash: %s", optarg); if (l < sizeof(sd_id128_t)) { log_error("Root hash must be at least 128bit long: %s", optarg); free(p); return -EINVAL; } free(arg_root_hash); arg_root_hash = p; arg_root_hash_size = l; break; } case '?': return -EINVAL; default: assert_not_reached("Unhandled option"); } } switch (arg_action) { case ACTION_DISSECT: if (optind + 1 != argc) { log_error("Expected a file path as only argument."); return -EINVAL; } arg_image = argv[optind]; arg_flags |= DISSECT_IMAGE_READ_ONLY; break; case ACTION_MOUNT: if (optind + 2 != argc) { log_error("Expected a file path and mount point path as only arguments."); return -EINVAL; } arg_image = argv[optind]; arg_path = argv[optind + 1]; break; default: assert_not_reached("Unknown action."); } return 1; }