2025-12-20 08:40:57 +01:00
|
|
|
#include "amduat/asl/asl_store_fs.h"
|
|
|
|
|
#include "amduat/asl/asl_store_fs_meta.h"
|
|
|
|
|
#include "amduat/asl/store.h"
|
|
|
|
|
#include "amduat/enc/asl1_core.h"
|
|
|
|
|
#include "amduat/enc/asl1_core_codec.h"
|
|
|
|
|
#include "amduat/hash/asl1.h"
|
|
|
|
|
#include "amduat/util/hex.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_OK = 0,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_USAGE = 2,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_IO = 3,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_NOT_FOUND = 4,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_STORE = 5,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_UNSUPPORTED = 6,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_CODEC = 7,
|
|
|
|
|
AMDUAT_ASL_CLI_EXIT_CONFIG = 8
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
AMDUAT_ASL_CLI_STORE_ID_MAX = AMDUAT_ASL_STORE_FS_STORE_ID_MAX,
|
|
|
|
|
AMDUAT_ASL_CLI_BUF_CHUNK = 4096
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *const AMDUAT_ASL_CLI_DEFAULT_ROOT = ".amduat-asl";
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
AMDUAT_ASL_CLI_REF_HEX = 0,
|
|
|
|
|
AMDUAT_ASL_CLI_REF_BYTES = 1
|
|
|
|
|
} amduat_asl_cli_ref_format_t;
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
AMDUAT_ASL_CLI_IO_RAW = 0,
|
|
|
|
|
AMDUAT_ASL_CLI_IO_ARTIFACT = 1
|
|
|
|
|
} amduat_asl_cli_io_format_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
const char *root;
|
|
|
|
|
const char *store_id;
|
|
|
|
|
const char *profile;
|
|
|
|
|
const char *hash;
|
|
|
|
|
bool force;
|
2025-12-20 10:53:22 +01:00
|
|
|
bool quiet;
|
2025-12-20 08:40:57 +01:00
|
|
|
} amduat_asl_cli_init_opts_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
const char *root;
|
|
|
|
|
const char *input_path;
|
|
|
|
|
const char *output_path;
|
|
|
|
|
amduat_asl_cli_io_format_t input_format;
|
|
|
|
|
amduat_asl_cli_ref_format_t ref_format;
|
|
|
|
|
bool has_type_tag;
|
|
|
|
|
amduat_type_tag_t type_tag;
|
2025-12-20 10:53:22 +01:00
|
|
|
bool quiet;
|
2025-12-20 08:40:57 +01:00
|
|
|
} amduat_asl_cli_put_opts_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
const char *root;
|
|
|
|
|
const char *ref;
|
|
|
|
|
const char *output_path;
|
|
|
|
|
amduat_asl_cli_io_format_t output_format;
|
|
|
|
|
amduat_asl_cli_ref_format_t ref_format;
|
|
|
|
|
bool has_expect_type_tag;
|
|
|
|
|
amduat_type_tag_t expect_type_tag;
|
|
|
|
|
bool print_type_tag;
|
2025-12-20 10:53:22 +01:00
|
|
|
bool quiet;
|
2025-12-20 08:40:57 +01:00
|
|
|
} amduat_asl_cli_get_opts_t;
|
|
|
|
|
|
|
|
|
|
static void amduat_asl_cli_print_usage(FILE *stream) {
|
|
|
|
|
fprintf(stream,
|
|
|
|
|
"usage:\n"
|
|
|
|
|
" amduat-asl init [--root PATH] [--store-id ID]\n"
|
|
|
|
|
" [--profile PROFILE_ID|name]\n"
|
2025-12-20 10:53:22 +01:00
|
|
|
" [--hash HASH_ID|name] [--force] [--quiet]\n"
|
2025-12-20 08:40:57 +01:00
|
|
|
" amduat-asl put [--root PATH] [--type-tag TAG]\n"
|
|
|
|
|
" [--input PATH|-] [--input-format raw|artifact]\n"
|
|
|
|
|
" [--ref-format hex|bytes] [--output PATH|-]\n"
|
2025-12-20 10:53:22 +01:00
|
|
|
" [--quiet]\n"
|
2025-12-20 08:40:57 +01:00
|
|
|
" amduat-asl get --ref REF [--root PATH]\n"
|
|
|
|
|
" [--ref-format hex|bytes] [--output PATH|-]\n"
|
|
|
|
|
" [--output-format raw|artifact]\n"
|
|
|
|
|
" [--expect-type-tag TAG] [--print-type-tag]\n"
|
2025-12-20 10:53:22 +01:00
|
|
|
" [--quiet]\n"
|
2025-12-20 08:40:57 +01:00
|
|
|
"\n"
|
|
|
|
|
"defaults:\n"
|
|
|
|
|
" --root %s\n"
|
|
|
|
|
" --input -\n"
|
|
|
|
|
" --output -\n"
|
|
|
|
|
" --input-format raw\n"
|
|
|
|
|
" --output-format raw\n"
|
|
|
|
|
" --ref-format hex\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"notes:\n"
|
|
|
|
|
" --ref-format bytes expects --ref as a path or -\n",
|
|
|
|
|
AMDUAT_ASL_CLI_DEFAULT_ROOT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_is_store_id_char(char c) {
|
|
|
|
|
if (c >= 'a' && c <= 'z') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c >= 'A' && c <= 'Z') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return c == '.' || c == '_' || c == '-';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_validate_store_id(const char *store_id) {
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
if (store_id == NULL || store_id[0] == '\0') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; store_id[i] != '\0'; ++i) {
|
|
|
|
|
if (i >= AMDUAT_ASL_CLI_STORE_ID_MAX) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_is_store_id_char(store_id[i])) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_copy_store_id(
|
|
|
|
|
char out_id[AMDUAT_ASL_CLI_STORE_ID_MAX + 1],
|
|
|
|
|
const char *store_id) {
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
if (out_id == NULL || store_id == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_validate_store_id(store_id)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
len = strlen(store_id);
|
|
|
|
|
if (len > AMDUAT_ASL_CLI_STORE_ID_MAX) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
memcpy(out_id, store_id, len);
|
|
|
|
|
out_id[len] = '\0';
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_u16(const char *text, uint16_t *out) {
|
|
|
|
|
char *end;
|
|
|
|
|
unsigned long value;
|
|
|
|
|
|
|
|
|
|
if (text == NULL || text[0] == '\0' || out == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
value = strtoul(text, &end, 0);
|
|
|
|
|
if (errno != 0 || end == text || *end != '\0' || value > UINT16_MAX) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out = (uint16_t)value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_u32(const char *text, uint32_t *out) {
|
|
|
|
|
char *end;
|
|
|
|
|
unsigned long value;
|
|
|
|
|
|
|
|
|
|
if (text == NULL || text[0] == '\0' || out == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
value = strtoul(text, &end, 0);
|
|
|
|
|
if (errno != 0 || end == text || *end != '\0' || value > UINT32_MAX) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out = (uint32_t)value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_profile_id(
|
|
|
|
|
const char *text,
|
|
|
|
|
amduat_asl_encoding_profile_id_t *out_id) {
|
|
|
|
|
uint16_t id;
|
|
|
|
|
size_t i;
|
|
|
|
|
size_t count;
|
|
|
|
|
const amduat_enc_asl1_core_profile_desc_t *descs;
|
|
|
|
|
|
|
|
|
|
if (text == NULL || out_id == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (amduat_asl_cli_parse_u16(text, &id)) {
|
|
|
|
|
if (amduat_enc_asl1_core_desc_lookup(id) == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out_id = id;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
descs = amduat_enc_asl1_core_descs(&count);
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
if (descs[i].name != NULL && strcmp(descs[i].name, text) == 0) {
|
|
|
|
|
*out_id = descs[i].profile_id;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_hash_id(const char *text,
|
|
|
|
|
amduat_hash_id_t *out_id) {
|
|
|
|
|
uint16_t id;
|
|
|
|
|
size_t i;
|
|
|
|
|
size_t count;
|
|
|
|
|
const amduat_hash_asl1_desc_t *descs;
|
|
|
|
|
|
|
|
|
|
if (text == NULL || out_id == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (amduat_asl_cli_parse_u16(text, &id)) {
|
|
|
|
|
if (amduat_hash_asl1_desc_lookup(id) == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out_id = id;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
descs = amduat_hash_asl1_descs(&count);
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
if (descs[i].name != NULL && strcmp(descs[i].name, text) == 0) {
|
|
|
|
|
*out_id = descs[i].hash_id;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_type_tag(const char *text,
|
|
|
|
|
amduat_type_tag_t *out_tag) {
|
|
|
|
|
uint32_t tag_id;
|
|
|
|
|
|
|
|
|
|
if (text == NULL || out_tag == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_u32(text, &tag_id)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out_tag = amduat_type_tag(tag_id);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_ref_format(
|
|
|
|
|
const char *text,
|
|
|
|
|
amduat_asl_cli_ref_format_t *out_fmt) {
|
|
|
|
|
if (text == NULL || out_fmt == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(text, "hex") == 0) {
|
|
|
|
|
*out_fmt = AMDUAT_ASL_CLI_REF_HEX;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(text, "bytes") == 0) {
|
|
|
|
|
*out_fmt = AMDUAT_ASL_CLI_REF_BYTES;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_parse_io_format(
|
|
|
|
|
const char *text,
|
|
|
|
|
amduat_asl_cli_io_format_t *out_fmt) {
|
|
|
|
|
if (text == NULL || out_fmt == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(text, "raw") == 0) {
|
|
|
|
|
*out_fmt = AMDUAT_ASL_CLI_IO_RAW;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(text, "artifact") == 0) {
|
|
|
|
|
*out_fmt = AMDUAT_ASL_CLI_IO_ARTIFACT;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_read_stream(FILE *stream,
|
|
|
|
|
uint8_t **out,
|
|
|
|
|
size_t *out_len) {
|
|
|
|
|
uint8_t *buffer;
|
|
|
|
|
size_t cap;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
if (out == NULL || out_len == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out = NULL;
|
|
|
|
|
*out_len = 0;
|
|
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
|
cap = 0;
|
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
if (len == cap) {
|
|
|
|
|
size_t new_cap = cap == 0 ? AMDUAT_ASL_CLI_BUF_CHUNK : cap * 2u;
|
|
|
|
|
uint8_t *next;
|
|
|
|
|
if (new_cap < cap) {
|
|
|
|
|
free(buffer);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
next = (uint8_t *)realloc(buffer, new_cap);
|
|
|
|
|
if (next == NULL) {
|
|
|
|
|
free(buffer);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
buffer = next;
|
|
|
|
|
cap = new_cap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t nread = fread(buffer + len, 1u, cap - len, stream);
|
|
|
|
|
len += nread;
|
|
|
|
|
if (nread == 0u) {
|
|
|
|
|
if (ferror(stream)) {
|
|
|
|
|
free(buffer);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len == 0u) {
|
|
|
|
|
free(buffer);
|
|
|
|
|
buffer = NULL;
|
|
|
|
|
}
|
|
|
|
|
*out = buffer;
|
|
|
|
|
*out_len = len;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_read_path(const char *path,
|
|
|
|
|
uint8_t **out,
|
|
|
|
|
size_t *out_len) {
|
|
|
|
|
FILE *stream;
|
|
|
|
|
bool ok;
|
|
|
|
|
|
|
|
|
|
if (path == NULL || out == NULL || out_len == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp(path, "-") == 0) {
|
|
|
|
|
return amduat_asl_cli_read_stream(stdin, out, out_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stream = fopen(path, "rb");
|
|
|
|
|
if (stream == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ok = amduat_asl_cli_read_stream(stream, out, out_len);
|
|
|
|
|
if (fclose(stream) != 0) {
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_write_stream(FILE *stream,
|
|
|
|
|
const uint8_t *bytes,
|
|
|
|
|
size_t len) {
|
|
|
|
|
size_t offset;
|
|
|
|
|
|
|
|
|
|
if (len != 0u && bytes == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset = 0u;
|
|
|
|
|
while (offset < len) {
|
|
|
|
|
size_t written = fwrite(bytes + offset, 1u, len - offset, stream);
|
|
|
|
|
if (written == 0u) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
offset += written;
|
|
|
|
|
}
|
|
|
|
|
return fflush(stream) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_write_path(const char *path,
|
|
|
|
|
const uint8_t *bytes,
|
|
|
|
|
size_t len) {
|
|
|
|
|
FILE *stream;
|
|
|
|
|
bool ok;
|
|
|
|
|
|
|
|
|
|
if (path == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(path, "-") == 0) {
|
|
|
|
|
return amduat_asl_cli_write_stream(stdout, bytes, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stream = fopen(path, "wb");
|
|
|
|
|
if (stream == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ok = amduat_asl_cli_write_stream(stream, bytes, len);
|
|
|
|
|
if (fclose(stream) != 0) {
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_write_text_line(const char *path,
|
|
|
|
|
const char *text) {
|
|
|
|
|
FILE *stream;
|
|
|
|
|
bool ok;
|
|
|
|
|
|
|
|
|
|
if (path == NULL || text == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(path, "-") == 0) {
|
|
|
|
|
stream = stdout;
|
|
|
|
|
} else {
|
|
|
|
|
stream = fopen(path, "wb");
|
|
|
|
|
if (stream == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ok = fputs(text, stream) >= 0 && fputc('\n', stream) != EOF &&
|
|
|
|
|
fflush(stream) == 0;
|
|
|
|
|
if (stream != stdout && fclose(stream) != 0) {
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_encode_reference_hex(amduat_reference_t ref,
|
|
|
|
|
char **out_hex) {
|
|
|
|
|
amduat_octets_t bytes;
|
|
|
|
|
char *hex;
|
|
|
|
|
size_t hex_size;
|
|
|
|
|
|
|
|
|
|
if (out_hex == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*out_hex = NULL;
|
|
|
|
|
|
|
|
|
|
if (!amduat_enc_asl1_core_encode_reference_v1(ref, &bytes)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
hex_size = amduat_hex_encoded_size(bytes.len);
|
|
|
|
|
if (hex_size == 0u) {
|
|
|
|
|
free((void *)bytes.data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
hex = (char *)malloc(hex_size);
|
|
|
|
|
if (hex == NULL) {
|
|
|
|
|
free((void *)bytes.data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_hex_encode_lower(bytes.data, bytes.len, hex, hex_size)) {
|
|
|
|
|
free(hex);
|
|
|
|
|
free((void *)bytes.data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
free((void *)bytes.data);
|
|
|
|
|
*out_hex = hex;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_decode_reference_hex(const char *hex,
|
|
|
|
|
amduat_reference_t *out_ref) {
|
|
|
|
|
uint8_t *bytes;
|
|
|
|
|
size_t len;
|
|
|
|
|
const char *hex_text;
|
|
|
|
|
bool ok;
|
|
|
|
|
|
|
|
|
|
if (hex == NULL || out_ref == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hex_text = hex;
|
|
|
|
|
if (hex_text[0] == '0' && (hex_text[1] == 'x' || hex_text[1] == 'X')) {
|
|
|
|
|
hex_text += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytes = NULL;
|
|
|
|
|
len = 0;
|
|
|
|
|
if (!amduat_hex_decode_alloc(hex_text, &bytes, &len)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ok = amduat_enc_asl1_core_decode_reference_v1(
|
|
|
|
|
amduat_octets(bytes, len),
|
|
|
|
|
out_ref);
|
|
|
|
|
free(bytes);
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool amduat_asl_cli_decode_reference_bytes(const uint8_t *bytes,
|
|
|
|
|
size_t len,
|
|
|
|
|
amduat_reference_t *out_ref) {
|
|
|
|
|
if (out_ref == NULL || (len != 0u && bytes == NULL)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return amduat_enc_asl1_core_decode_reference_v1(
|
|
|
|
|
amduat_octets(bytes, len),
|
|
|
|
|
out_ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void amduat_asl_cli_free_reference(amduat_reference_t *ref) {
|
|
|
|
|
if (ref == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
free((void *)ref->digest.data);
|
|
|
|
|
ref->digest.data = NULL;
|
|
|
|
|
ref->digest.len = 0u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void amduat_asl_cli_free_artifact(amduat_artifact_t *artifact) {
|
|
|
|
|
if (artifact == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
free((void *)artifact->bytes.data);
|
|
|
|
|
artifact->bytes.data = NULL;
|
|
|
|
|
artifact->bytes.len = 0u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void amduat_asl_cli_print_store_meta(
|
|
|
|
|
const amduat_asl_store_fs_config_t *cfg) {
|
|
|
|
|
if (cfg == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fprintf(stderr, "store_id=%s\n", cfg->store_id);
|
|
|
|
|
fprintf(stderr, "profile=0x%04x\n",
|
|
|
|
|
(unsigned int)cfg->config.encoding_profile_id);
|
|
|
|
|
fprintf(stderr, "hash=0x%04x\n", (unsigned int)cfg->config.hash_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *amduat_asl_cli_store_error_str(
|
|
|
|
|
amduat_asl_store_error_t err) {
|
|
|
|
|
switch (err) {
|
|
|
|
|
case AMDUAT_ASL_STORE_ERR_NOT_FOUND:
|
|
|
|
|
return "not found";
|
|
|
|
|
case AMDUAT_ASL_STORE_ERR_UNSUPPORTED:
|
|
|
|
|
return "unsupported";
|
|
|
|
|
case AMDUAT_ASL_STORE_ERR_INTEGRITY:
|
|
|
|
|
return "integrity";
|
|
|
|
|
case AMDUAT_ASL_STORE_OK:
|
|
|
|
|
return "ok";
|
|
|
|
|
default:
|
|
|
|
|
return "unknown";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int amduat_asl_cli_map_store_error(amduat_asl_store_error_t err) {
|
|
|
|
|
switch (err) {
|
|
|
|
|
case AMDUAT_ASL_STORE_ERR_NOT_FOUND:
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_NOT_FOUND;
|
|
|
|
|
case AMDUAT_ASL_STORE_ERR_UNSUPPORTED:
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_UNSUPPORTED;
|
|
|
|
|
case AMDUAT_ASL_STORE_ERR_INTEGRITY:
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_STORE;
|
|
|
|
|
case AMDUAT_ASL_STORE_OK:
|
|
|
|
|
default:
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_STORE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int amduat_asl_cli_cmd_init(int argc, char **argv) {
|
|
|
|
|
amduat_asl_cli_init_opts_t opts;
|
|
|
|
|
amduat_asl_store_fs_config_t cfg_in;
|
|
|
|
|
amduat_asl_store_fs_config_t cfg_out;
|
|
|
|
|
bool ok;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
|
opts.root = AMDUAT_ASL_CLI_DEFAULT_ROOT;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
|
if (strcmp(argv[i], "--root") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --root requires a path\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.root = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--store-id") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --store-id requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.store_id = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--profile") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --profile requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.profile = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--hash") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --hash requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.hash = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--force") == 0) {
|
|
|
|
|
opts.force = true;
|
2025-12-20 10:53:22 +01:00
|
|
|
} else if (strcmp(argv[i], "--quiet") == 0) {
|
|
|
|
|
opts.quiet = true;
|
2025-12-20 08:40:57 +01:00
|
|
|
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
|
|
|
|
amduat_asl_cli_print_usage(stdout);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&cfg_in, 0, sizeof(cfg_in));
|
|
|
|
|
if (opts.store_id != NULL) {
|
|
|
|
|
if (!amduat_asl_cli_copy_store_id(cfg_in.store_id, opts.store_id)) {
|
|
|
|
|
fprintf(stderr, "error: invalid store-id\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (opts.profile != NULL) {
|
|
|
|
|
if (!amduat_asl_cli_parse_profile_id(
|
|
|
|
|
opts.profile,
|
|
|
|
|
&cfg_in.config.encoding_profile_id)) {
|
|
|
|
|
fprintf(stderr, "error: unknown profile: %s\n", opts.profile);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (opts.hash != NULL) {
|
|
|
|
|
if (!amduat_asl_cli_parse_hash_id(opts.hash, &cfg_in.config.hash_id)) {
|
|
|
|
|
fprintf(stderr, "error: unknown hash: %s\n", opts.hash);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ok = amduat_asl_store_fs_init_root(opts.root, &cfg_in, &cfg_out);
|
|
|
|
|
if (!ok && opts.force) {
|
|
|
|
|
ok = amduat_asl_store_fs_init_root(opts.root, NULL, &cfg_out);
|
2025-12-20 10:53:22 +01:00
|
|
|
if (ok && (opts.store_id || opts.profile || opts.hash) && !opts.quiet) {
|
2025-12-20 08:40:57 +01:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"warning: existing config kept; overrides ignored\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!ok) {
|
|
|
|
|
fprintf(stderr, "error: failed to initialize store root: %s\n",
|
|
|
|
|
opts.root);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-20 10:53:22 +01:00
|
|
|
if (!opts.quiet) {
|
|
|
|
|
fprintf(stderr, "root=%s\n", opts.root);
|
|
|
|
|
amduat_asl_cli_print_store_meta(&cfg_out);
|
|
|
|
|
}
|
2025-12-20 08:40:57 +01:00
|
|
|
return AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int amduat_asl_cli_cmd_put(int argc, char **argv) {
|
|
|
|
|
amduat_asl_cli_put_opts_t opts;
|
|
|
|
|
amduat_asl_store_fs_config_t cfg;
|
|
|
|
|
amduat_asl_store_fs_t fs;
|
|
|
|
|
amduat_asl_store_t store;
|
|
|
|
|
amduat_artifact_t artifact;
|
|
|
|
|
amduat_reference_t ref;
|
|
|
|
|
uint8_t *input_bytes;
|
|
|
|
|
size_t input_len;
|
|
|
|
|
amduat_octets_t encoded_ref;
|
|
|
|
|
bool ok;
|
|
|
|
|
int i;
|
|
|
|
|
int exit_code;
|
|
|
|
|
|
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
|
opts.root = AMDUAT_ASL_CLI_DEFAULT_ROOT;
|
|
|
|
|
opts.input_path = "-";
|
|
|
|
|
opts.output_path = "-";
|
|
|
|
|
opts.input_format = AMDUAT_ASL_CLI_IO_RAW;
|
|
|
|
|
opts.ref_format = AMDUAT_ASL_CLI_REF_HEX;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
|
if (strcmp(argv[i], "--root") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --root requires a path\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.root = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--type-tag") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --type-tag requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_type_tag(argv[++i], &opts.type_tag)) {
|
|
|
|
|
fprintf(stderr, "error: invalid type-tag\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.has_type_tag = true;
|
|
|
|
|
} else if (strcmp(argv[i], "--input") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --input requires a path or -\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.input_path = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--input-format") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --input-format requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_io_format(argv[++i], &opts.input_format)) {
|
|
|
|
|
fprintf(stderr, "error: invalid input-format\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(argv[i], "--ref-format") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --ref-format requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_ref_format(argv[++i], &opts.ref_format)) {
|
|
|
|
|
fprintf(stderr, "error: invalid ref-format\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(argv[i], "--output") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --output requires a path or -\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.output_path = argv[++i];
|
2025-12-20 10:53:22 +01:00
|
|
|
} else if (strcmp(argv[i], "--quiet") == 0) {
|
|
|
|
|
opts.quiet = true;
|
2025-12-20 08:40:57 +01:00
|
|
|
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
|
|
|
|
amduat_asl_cli_print_usage(stdout);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts.input_format == AMDUAT_ASL_CLI_IO_ARTIFACT && opts.has_type_tag) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"error: --type-tag is not valid with --input-format artifact\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!amduat_asl_store_fs_load_config(opts.root, &cfg)) {
|
|
|
|
|
fprintf(stderr, "error: failed to load store config: %s\n", opts.root);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_store_fs_init(&fs, cfg.config, opts.root)) {
|
|
|
|
|
fprintf(stderr, "error: failed to initialize store\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs);
|
|
|
|
|
|
|
|
|
|
input_bytes = NULL;
|
|
|
|
|
input_len = 0u;
|
|
|
|
|
if (!amduat_asl_cli_read_path(opts.input_path, &input_bytes, &input_len)) {
|
|
|
|
|
fprintf(stderr, "error: failed to read input: %s\n", opts.input_path);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_IO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts.input_format == AMDUAT_ASL_CLI_IO_ARTIFACT) {
|
|
|
|
|
ok = amduat_enc_asl1_core_decode_artifact_v1(
|
|
|
|
|
amduat_octets(input_bytes, input_len),
|
|
|
|
|
&artifact);
|
|
|
|
|
free(input_bytes);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
fprintf(stderr, "error: invalid artifact encoding\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CODEC;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
artifact = opts.has_type_tag
|
|
|
|
|
? amduat_artifact_with_type(
|
|
|
|
|
amduat_octets(input_bytes, input_len),
|
|
|
|
|
opts.type_tag)
|
|
|
|
|
: amduat_artifact(amduat_octets(input_bytes, input_len));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&ref, 0, sizeof(ref));
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
{
|
|
|
|
|
amduat_asl_store_error_t err =
|
|
|
|
|
amduat_asl_store_put(&store, artifact, &ref);
|
|
|
|
|
if (err != AMDUAT_ASL_STORE_OK) {
|
|
|
|
|
fprintf(stderr, "error: store put failed: %s\n",
|
|
|
|
|
amduat_asl_cli_store_error_str(err));
|
|
|
|
|
exit_code = amduat_asl_cli_map_store_error(err);
|
|
|
|
|
} else {
|
|
|
|
|
if (opts.ref_format == AMDUAT_ASL_CLI_REF_HEX) {
|
|
|
|
|
char *hex_ref = NULL;
|
|
|
|
|
if (!amduat_asl_cli_encode_reference_hex(ref, &hex_ref)) {
|
|
|
|
|
fprintf(stderr, "error: failed to encode reference\n");
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_CODEC;
|
|
|
|
|
} else {
|
|
|
|
|
if (!amduat_asl_cli_write_text_line(opts.output_path, hex_ref)) {
|
|
|
|
|
fprintf(stderr, "error: failed to write output: %s\n",
|
|
|
|
|
opts.output_path);
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_IO;
|
|
|
|
|
}
|
|
|
|
|
free(hex_ref);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!amduat_enc_asl1_core_encode_reference_v1(ref, &encoded_ref)) {
|
|
|
|
|
fprintf(stderr, "error: failed to encode reference\n");
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_CODEC;
|
|
|
|
|
} else {
|
|
|
|
|
if (!amduat_asl_cli_write_path(opts.output_path,
|
|
|
|
|
encoded_ref.data,
|
|
|
|
|
encoded_ref.len)) {
|
|
|
|
|
fprintf(stderr, "error: failed to write output: %s\n",
|
|
|
|
|
opts.output_path);
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_IO;
|
|
|
|
|
}
|
|
|
|
|
free((void *)encoded_ref.data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-20 10:53:22 +01:00
|
|
|
if (exit_code == AMDUAT_ASL_CLI_EXIT_OK && !opts.quiet) {
|
2025-12-20 08:40:57 +01:00
|
|
|
char *hex_ref = NULL;
|
|
|
|
|
fprintf(stderr, "root=%s\n", opts.root);
|
|
|
|
|
amduat_asl_cli_print_store_meta(&cfg);
|
|
|
|
|
fprintf(stderr, "bytes=%zu\n", artifact.bytes.len);
|
|
|
|
|
if (artifact.has_type_tag) {
|
|
|
|
|
fprintf(stderr, "type_tag=0x%08x\n",
|
|
|
|
|
(unsigned int)artifact.type_tag.tag_id);
|
|
|
|
|
}
|
|
|
|
|
if (amduat_asl_cli_encode_reference_hex(ref, &hex_ref)) {
|
|
|
|
|
fprintf(stderr, "ref=%s\n", hex_ref);
|
|
|
|
|
free(hex_ref);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts.input_format == AMDUAT_ASL_CLI_IO_ARTIFACT) {
|
|
|
|
|
amduat_asl_cli_free_artifact(&artifact);
|
|
|
|
|
} else {
|
|
|
|
|
free((void *)artifact.bytes.data);
|
|
|
|
|
}
|
|
|
|
|
amduat_asl_cli_free_reference(&ref);
|
|
|
|
|
return exit_code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int amduat_asl_cli_cmd_get(int argc, char **argv) {
|
|
|
|
|
amduat_asl_cli_get_opts_t opts;
|
|
|
|
|
amduat_asl_store_fs_config_t cfg;
|
|
|
|
|
amduat_asl_store_fs_t fs;
|
|
|
|
|
amduat_asl_store_t store;
|
|
|
|
|
amduat_artifact_t artifact;
|
|
|
|
|
amduat_reference_t ref;
|
|
|
|
|
uint8_t *ref_bytes;
|
|
|
|
|
size_t ref_len;
|
|
|
|
|
amduat_octets_t encoded_artifact;
|
|
|
|
|
bool ok;
|
|
|
|
|
int i;
|
|
|
|
|
int exit_code;
|
|
|
|
|
|
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
|
opts.root = AMDUAT_ASL_CLI_DEFAULT_ROOT;
|
|
|
|
|
opts.output_path = "-";
|
|
|
|
|
opts.output_format = AMDUAT_ASL_CLI_IO_RAW;
|
|
|
|
|
opts.ref_format = AMDUAT_ASL_CLI_REF_HEX;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
|
if (strcmp(argv[i], "--ref") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --ref requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.ref = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--root") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --root requires a path\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.root = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--ref-format") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --ref-format requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_ref_format(argv[++i], &opts.ref_format)) {
|
|
|
|
|
fprintf(stderr, "error: invalid ref-format\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(argv[i], "--output") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --output requires a path or -\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.output_path = argv[++i];
|
|
|
|
|
} else if (strcmp(argv[i], "--output-format") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --output-format requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_io_format(argv[++i], &opts.output_format)) {
|
|
|
|
|
fprintf(stderr, "error: invalid output-format\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(argv[i], "--expect-type-tag") == 0) {
|
|
|
|
|
if (i + 1 >= argc) {
|
|
|
|
|
fprintf(stderr, "error: --expect-type-tag requires a value\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_cli_parse_type_tag(argv[++i],
|
|
|
|
|
&opts.expect_type_tag)) {
|
|
|
|
|
fprintf(stderr, "error: invalid expect-type-tag\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
opts.has_expect_type_tag = true;
|
|
|
|
|
} else if (strcmp(argv[i], "--print-type-tag") == 0) {
|
|
|
|
|
opts.print_type_tag = true;
|
2025-12-20 10:53:22 +01:00
|
|
|
} else if (strcmp(argv[i], "--quiet") == 0) {
|
|
|
|
|
opts.quiet = true;
|
2025-12-20 08:40:57 +01:00
|
|
|
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
|
|
|
|
amduat_asl_cli_print_usage(stdout);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts.ref == NULL) {
|
|
|
|
|
fprintf(stderr, "error: --ref is required\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!amduat_asl_store_fs_load_config(opts.root, &cfg)) {
|
|
|
|
|
fprintf(stderr, "error: failed to load store config: %s\n", opts.root);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
if (!amduat_asl_store_fs_init(&fs, cfg.config, opts.root)) {
|
|
|
|
|
fprintf(stderr, "error: failed to initialize store\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs);
|
|
|
|
|
|
|
|
|
|
memset(&ref, 0, sizeof(ref));
|
|
|
|
|
if (opts.ref_format == AMDUAT_ASL_CLI_REF_HEX) {
|
|
|
|
|
if (!amduat_asl_cli_decode_reference_hex(opts.ref, &ref)) {
|
|
|
|
|
fprintf(stderr, "error: invalid hex reference\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CODEC;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ref_bytes = NULL;
|
|
|
|
|
ref_len = 0u;
|
|
|
|
|
if (!amduat_asl_cli_read_path(opts.ref, &ref_bytes, &ref_len)) {
|
|
|
|
|
fprintf(stderr, "error: failed to read reference: %s\n", opts.ref);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_IO;
|
|
|
|
|
}
|
|
|
|
|
ok = amduat_asl_cli_decode_reference_bytes(ref_bytes, ref_len, &ref);
|
|
|
|
|
free(ref_bytes);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
fprintf(stderr, "error: invalid reference bytes\n");
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_CODEC;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&artifact, 0, sizeof(artifact));
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
{
|
|
|
|
|
amduat_asl_store_error_t err = amduat_asl_store_get(&store, ref, &artifact);
|
|
|
|
|
if (err != AMDUAT_ASL_STORE_OK) {
|
|
|
|
|
fprintf(stderr, "error: store get failed: %s\n",
|
|
|
|
|
amduat_asl_cli_store_error_str(err));
|
|
|
|
|
exit_code = amduat_asl_cli_map_store_error(err);
|
|
|
|
|
} else {
|
|
|
|
|
if (opts.has_expect_type_tag) {
|
|
|
|
|
if (!artifact.has_type_tag ||
|
|
|
|
|
artifact.type_tag.tag_id != opts.expect_type_tag.tag_id) {
|
|
|
|
|
fprintf(stderr, "error: type-tag mismatch\n");
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_UNSUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exit_code == AMDUAT_ASL_CLI_EXIT_OK) {
|
|
|
|
|
if (opts.output_format == AMDUAT_ASL_CLI_IO_RAW) {
|
|
|
|
|
if (!amduat_asl_cli_write_path(opts.output_path,
|
|
|
|
|
artifact.bytes.data,
|
|
|
|
|
artifact.bytes.len)) {
|
|
|
|
|
fprintf(stderr, "error: failed to write output: %s\n",
|
|
|
|
|
opts.output_path);
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_IO;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (!amduat_enc_asl1_core_encode_artifact_v1(
|
|
|
|
|
artifact, &encoded_artifact)) {
|
|
|
|
|
fprintf(stderr, "error: failed to encode artifact\n");
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_CODEC;
|
|
|
|
|
} else {
|
|
|
|
|
if (!amduat_asl_cli_write_path(opts.output_path,
|
|
|
|
|
encoded_artifact.data,
|
|
|
|
|
encoded_artifact.len)) {
|
|
|
|
|
fprintf(stderr, "error: failed to write output: %s\n",
|
|
|
|
|
opts.output_path);
|
|
|
|
|
exit_code = AMDUAT_ASL_CLI_EXIT_IO;
|
|
|
|
|
}
|
|
|
|
|
free((void *)encoded_artifact.data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-20 10:53:22 +01:00
|
|
|
if (exit_code == AMDUAT_ASL_CLI_EXIT_OK && !opts.quiet) {
|
2025-12-20 08:40:57 +01:00
|
|
|
fprintf(stderr, "root=%s\n", opts.root);
|
|
|
|
|
amduat_asl_cli_print_store_meta(&cfg);
|
|
|
|
|
fprintf(stderr, "bytes=%zu\n", artifact.bytes.len);
|
|
|
|
|
if (opts.print_type_tag) {
|
|
|
|
|
if (artifact.has_type_tag) {
|
|
|
|
|
fprintf(stderr, "type_tag=0x%08x\n",
|
|
|
|
|
(unsigned int)artifact.type_tag.tag_id);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "type_tag=none\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amduat_asl_cli_free_reference(&ref);
|
|
|
|
|
amduat_asl_cli_free_artifact(&artifact);
|
|
|
|
|
return exit_code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
|
if (argc < 2) {
|
|
|
|
|
amduat_asl_cli_print_usage(stderr);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp(argv[1], "init") == 0) {
|
|
|
|
|
return amduat_asl_cli_cmd_init(argc - 2, argv + 2);
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(argv[1], "put") == 0) {
|
|
|
|
|
return amduat_asl_cli_cmd_put(argc - 2, argv + 2);
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(argv[1], "get") == 0) {
|
|
|
|
|
return amduat_asl_cli_cmd_get(argc - 2, argv + 2);
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
|
|
|
|
amduat_asl_cli_print_usage(stdout);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "error: unknown command: %s\n", argv[1]);
|
|
|
|
|
amduat_asl_cli_print_usage(stderr);
|
|
|
|
|
return AMDUAT_ASL_CLI_EXIT_USAGE;
|
|
|
|
|
}
|