Merge pull request #25180 from keszybz/ukify
ukify: add helper to create UKIs
This commit is contained in:
@@ -1404,6 +1404,8 @@ int show_boot_entries(const BootConfig *config, JsonFormatFlags json_format) {
|
||||
assert(config);
|
||||
|
||||
if (!FLAGS_SET(json_format, JSON_FORMAT_OFF)) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
|
||||
for (size_t i = 0; i < config->n_entries; i++) {
|
||||
_cleanup_free_ char *opts = NULL;
|
||||
const BootEntry *e = config->entries + i;
|
||||
@@ -1443,9 +1445,13 @@ int show_boot_entries(const BootConfig *config, JsonFormatFlags json_format) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
json_variant_dump(v, json_format, stdout, NULL);
|
||||
r = json_variant_append_array(&array, v);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
json_variant_dump(array, json_format | JSON_FORMAT_EMPTY_ARRAY, NULL, NULL);
|
||||
|
||||
} else {
|
||||
for (size_t n = 0; n < config->n_entries; n++) {
|
||||
r = show_boot_entry(
|
||||
|
||||
+129
-49
@@ -553,9 +553,34 @@ static void json_variant_copy_source(JsonVariant *v, JsonVariant *from) {
|
||||
v->source = json_source_ref(from->source);
|
||||
}
|
||||
|
||||
static int _json_variant_array_put_element(JsonVariant *array, JsonVariant *element) {
|
||||
assert(array);
|
||||
JsonVariant *w = array + 1 + array->n_elements;
|
||||
|
||||
uint16_t d = json_variant_depth(element);
|
||||
if (d >= DEPTH_MAX) /* Refuse too deep nesting */
|
||||
return -ELNRNG;
|
||||
if (d >= array->depth)
|
||||
array->depth = d + 1;
|
||||
array->n_elements ++;
|
||||
|
||||
*w = (JsonVariant) {
|
||||
.is_embedded = true,
|
||||
.parent = array,
|
||||
};
|
||||
|
||||
json_variant_set(w, element);
|
||||
json_variant_copy_source(w, element);
|
||||
|
||||
if (!json_variant_is_normalized(element))
|
||||
array->normalized = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
bool normalized = true;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
if (n == 0) {
|
||||
@@ -571,33 +596,15 @@ int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n) {
|
||||
*v = (JsonVariant) {
|
||||
.n_ref = 1,
|
||||
.type = JSON_VARIANT_ARRAY,
|
||||
.normalized = true,
|
||||
};
|
||||
|
||||
for (v->n_elements = 0; v->n_elements < n; v->n_elements++) {
|
||||
JsonVariant *w = v + 1 + v->n_elements,
|
||||
*c = array[v->n_elements];
|
||||
uint16_t d;
|
||||
|
||||
d = json_variant_depth(c);
|
||||
if (d >= DEPTH_MAX) /* Refuse too deep nesting */
|
||||
return -ELNRNG;
|
||||
if (d >= v->depth)
|
||||
v->depth = d + 1;
|
||||
|
||||
*w = (JsonVariant) {
|
||||
.is_embedded = true,
|
||||
.parent = v,
|
||||
};
|
||||
|
||||
json_variant_set(w, c);
|
||||
json_variant_copy_source(w, c);
|
||||
|
||||
if (!json_variant_is_normalized(c))
|
||||
normalized = false;
|
||||
while (v->n_elements < n) {
|
||||
r = _json_variant_array_put_element(v, array[v->n_elements]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
v->normalized = normalized;
|
||||
|
||||
*ret = TAKE_PTR(v);
|
||||
return 0;
|
||||
}
|
||||
@@ -823,6 +830,19 @@ static void json_variant_free_inner(JsonVariant *v, bool force_sensitive) {
|
||||
explicit_bzero_safe(v, json_variant_size(v));
|
||||
}
|
||||
|
||||
static unsigned json_variant_n_ref(const JsonVariant *v) {
|
||||
/* Return the number of references to v.
|
||||
* 0 => NULL or not a regular object or embedded.
|
||||
* >0 => number of references
|
||||
*/
|
||||
|
||||
if (!v || !json_variant_is_regular(v) || v->is_embedded)
|
||||
return 0;
|
||||
|
||||
assert(v->n_ref > 0);
|
||||
return v->n_ref;
|
||||
}
|
||||
|
||||
JsonVariant *json_variant_ref(JsonVariant *v) {
|
||||
if (!v)
|
||||
return NULL;
|
||||
@@ -1790,8 +1810,12 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
|
||||
}
|
||||
|
||||
int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix) {
|
||||
if (!v)
|
||||
return 0;
|
||||
if (!v) {
|
||||
if (flags & JSON_FORMAT_EMPTY_ARRAY)
|
||||
v = JSON_VARIANT_MAGIC_EMPTY_ARRAY;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!f)
|
||||
f = stdout;
|
||||
@@ -2072,28 +2096,54 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element) {
|
||||
|
||||
if (!*v || json_variant_is_null(*v))
|
||||
blank = true;
|
||||
else if (!json_variant_is_array(*v))
|
||||
return -EINVAL;
|
||||
else
|
||||
else if (json_variant_is_array(*v))
|
||||
blank = json_variant_elements(*v) == 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (blank)
|
||||
if (blank) {
|
||||
r = json_variant_new_array(&nv, (JsonVariant*[]) { element }, 1);
|
||||
else {
|
||||
_cleanup_free_ JsonVariant **array = new(JsonVariant*, json_variant_elements(*v) + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (json_variant_n_ref(*v) == 1) {
|
||||
/* Let's bump the reference count on element. We can't do the realloc if we're appending *v
|
||||
* to itself, or one of the objects embedded in *v to *v. If the reference count grows, we
|
||||
* need to fall back to the other method below. */
|
||||
|
||||
_unused_ _cleanup_(json_variant_unrefp) JsonVariant *dummy = json_variant_ref(element);
|
||||
if (json_variant_n_ref(*v) == 1) {
|
||||
/* We hold the only reference. Let's mutate the object. */
|
||||
size_t size = json_variant_elements(*v);
|
||||
void *old = *v;
|
||||
|
||||
if (!GREEDY_REALLOC(*v, size + 1 + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
if (old != *v)
|
||||
/* Readjust the parent pointers to the new address */
|
||||
for (size_t i = 1; i < size; i++)
|
||||
(*v)[1 + i].parent = *v;
|
||||
|
||||
return _json_variant_array_put_element(*v, element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!blank) {
|
||||
size_t size = json_variant_elements(*v);
|
||||
|
||||
_cleanup_free_ JsonVariant **array = new(JsonVariant*, size + 1);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
size_t size = json_variant_elements(*v);
|
||||
for (size_t i = 0; i < size; i++)
|
||||
array[i] = json_variant_by_index(*v, i);
|
||||
|
||||
array[size] = element;
|
||||
|
||||
r = json_variant_new_array(&nv, array, size + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
json_variant_propagate_sensitive(*v, nv);
|
||||
JSON_VARIANT_REPLACE(*v, TAKE_PTR(nv));
|
||||
@@ -3180,16 +3230,53 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
int json_parse(const char *input, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
return json_parse_internal(&input, NULL, flags, ret, ret_line, ret_column, false);
|
||||
int json_parse_with_source(
|
||||
const char *input,
|
||||
const char *source,
|
||||
JsonParseFlags flags,
|
||||
JsonVariant **ret,
|
||||
unsigned *ret_line,
|
||||
unsigned *ret_column) {
|
||||
|
||||
_cleanup_(json_source_unrefp) JsonSource *s = NULL;
|
||||
|
||||
if (source) {
|
||||
s = json_source_new(source);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return json_parse_internal(&input, s, flags, ret, ret_line, ret_column, false);
|
||||
}
|
||||
|
||||
int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
return json_parse_internal(p, NULL, flags, ret, ret_line, ret_column, true);
|
||||
int json_parse_with_source_continue(
|
||||
const char **p,
|
||||
const char *source,
|
||||
JsonParseFlags flags,
|
||||
JsonVariant **ret,
|
||||
unsigned *ret_line,
|
||||
unsigned *ret_column) {
|
||||
|
||||
_cleanup_(json_source_unrefp) JsonSource *s = NULL;
|
||||
|
||||
if (source) {
|
||||
s = json_source_new(source);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return json_parse_internal(p, s, flags, ret, ret_line, ret_column, true);
|
||||
}
|
||||
|
||||
int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
_cleanup_(json_source_unrefp) JsonSource *source = NULL;
|
||||
int json_parse_file_at(
|
||||
FILE *f,
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
JsonParseFlags flags,
|
||||
JsonVariant **ret,
|
||||
unsigned *ret_line,
|
||||
unsigned *ret_column) {
|
||||
|
||||
_cleanup_free_ char *text = NULL;
|
||||
int r;
|
||||
|
||||
@@ -3205,14 +3292,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
|
||||
if (isempty(text))
|
||||
return -ENODATA;
|
||||
|
||||
if (path) {
|
||||
source = json_source_new(path);
|
||||
if (!source)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
const char *p = text;
|
||||
return json_parse_internal(&p, source, flags, ret, ret_line, ret_column, false);
|
||||
return json_parse_with_source(text, path, flags, ret, ret_line, ret_column);
|
||||
}
|
||||
|
||||
int json_buildv(JsonVariant **ret, va_list ap) {
|
||||
|
||||
+12
-3
@@ -194,7 +194,8 @@ typedef enum JsonFormatFlags {
|
||||
JSON_FORMAT_SSE = 1 << 6, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 7, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
JSON_FORMAT_FLUSH = 1 << 8, /* call fflush() after dumping JSON */
|
||||
JSON_FORMAT_OFF = 1 << 9, /* make json_variant_format() fail with -ENOEXEC */
|
||||
JSON_FORMAT_EMPTY_ARRAY = 1 << 9, /* output "[]" for empty input */
|
||||
JSON_FORMAT_OFF = 1 << 10, /* make json_variant_format() fail with -ENOEXEC */
|
||||
} JsonFormatFlags;
|
||||
|
||||
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
|
||||
@@ -222,8 +223,16 @@ typedef enum JsonParseFlags {
|
||||
JSON_PARSE_SENSITIVE = 1 << 0, /* mark variant as "sensitive", i.e. something containing secret key material or such */
|
||||
} JsonParseFlags;
|
||||
|
||||
int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_with_source(const char *string, const char *source, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_with_source_continue(const char **p, const char *source, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
static inline int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
return json_parse_with_source(string, NULL, flags, ret, ret_line, ret_column);
|
||||
}
|
||||
static inline int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
return json_parse_with_source_continue(p, NULL, flags, ret, ret_line, ret_column);
|
||||
}
|
||||
|
||||
int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
static inline int json_parse_file(FILE *f, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
|
||||
Reference in New Issue
Block a user