Merge pull request #25180 from keszybz/ukify

ukify: add helper to create UKIs
This commit is contained in:
Lennart Poettering
2022-12-08 15:11:18 +01:00
committed by GitHub
23 changed files with 1844 additions and 54 deletions
+7 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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) {