[Libguestfs] [libguestfs-common PATCH 09/12] options: generalize "--key" selector parsing for C-language utilities
Laszlo Ersek
lersek at redhat.com
Wed Jun 29 12:21:47 UTC 2022
On 06/28/22 16:39, Richard W.M. Jones wrote:
> On Tue, Jun 28, 2022 at 01:49:12PM +0200, Laszlo Ersek wrote:
>> The key_store_add_from_selector() function parses the argument of the
>> "--key" option in C-language tools:
>>
>> OPTION_key [options/options.h]
>> key_store_add_from_selector() [options/keys.c]
>> key_store_import_key() [options/keys.c]
>>
>> The function currently (a) uses a horrible "goto", (b) is not flexible
>> enough for selector types that do not take precisely 1 type-specific
>> parameter. Rewrite the function with more informative error messages and
>> an easier to follow structure, plus make the type-specific parameter count
>> a function of the type.
>>
>> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
>> Signed-off-by: Laszlo Ersek <lersek at redhat.com>
>> ---
>> options/keys.c | 46 ++++++++++----------
>> 1 file changed, 24 insertions(+), 22 deletions(-)
>>
>> diff --git a/options/keys.c b/options/keys.c
>> index 7729fe79c99b..a6ef2d78b589 100644
>> --- a/options/keys.c
>> +++ b/options/keys.c
>> @@ -210,48 +210,50 @@ free_keys (struct matching_key *keys, size_t nr_matches)
>> }
>>
>> struct key_store *
>> key_store_add_from_selector (struct key_store *ks, const char *selector)
>> {
>> - CLEANUP_FREE_STRING_LIST char **fields =
>> - guestfs_int_split_string (':', selector);
>> + CLEANUP_FREE_STRING_LIST char **fields;
>> + size_t field_count;
>> struct key_store_key key;
>>
>> + fields = guestfs_int_split_string (':', selector);
>
> This code isn't wrong, but there is a "fun" catch with __attribute__((cleanup))
> to be aware of. It wasn't obvious to me until I'd hit this
> problem a few times.
>
> __attribute__((cleanup, free_strings)) char **fields;
>
> fields = something;
>
> is fine, but:
>
> __attribute__((cleanup, free_strings)) char **fields;
>
> /* Add some new code */
> if (!check_something)
> return;
>
> fields = something;
>
> is very bad. It will call free_strings on an uninitialized stack
> value.
>
> That was probably the reason why the original code tries to initialize
> fields where it was defined.
>
> Now again, this is not wrong, as long as everyone is aware that a
> future code addition could break things. Libvirt style insists that
> such variables are always initialized to NULL, but we don't do that
> consistently.
I'll initialize the variable to NULL.
>
>> if (!fields)
>> error (EXIT_FAILURE, errno, "guestfs_int_split_string");
>> + field_count = guestfs_int_count_strings (fields);
>>
>> - if (guestfs_int_count_strings (fields) != 3) {
>> - invalid_selector:
>> - error (EXIT_FAILURE, 0, "invalid selector for --key: %s", selector);
>> - }
>> -
>> - /* 1: device */
>> + /* field#0: ID */
>> + if (field_count < 1)
>> + error (EXIT_FAILURE, 0, _("selector '%s': missing ID"), selector);
>> key.id = strdup (fields[0]);
>> if (!key.id)
>> error (EXIT_FAILURE, errno, "strdup");
>>
>> - /* 2: key type */
>> - if (STREQ (fields[1], "key"))
>> + /* field#1...: TYPE, and TYPE-specific properties */
>> + if (field_count < 2)
>> + error (EXIT_FAILURE, 0, _("selector '%s': missing TYPE"), selector);
>> +
>> + if (STREQ (fields[1], "key")) {
>> key.type = key_string;
>> - else if (STREQ (fields[1], "file"))
>> - key.type = key_file;
>> - else
>> - goto invalid_selector;
>> -
>> - /* 3: actual key */
>> - switch (key.type) {
>> - case key_string:
>> + if (field_count != 3)
>> + error (EXIT_FAILURE, 0,
>> + _("selector '%s': missing KEY_STRING, or too many fields"),
>> + selector);
>> key.string.s = strdup (fields[2]);
>> if (!key.string.s)
>> error (EXIT_FAILURE, errno, "strdup");
>> - break;
>> - case key_file:
>> + } else if (STREQ (fields[1], "file")) {
>> + key.type = key_file;
>> + if (field_count != 3)
>> + error (EXIT_FAILURE, 0,
>> + _("selector '%s': missing FILENAME, or too many fields"),
>> + selector);
>> key.file.name = strdup (fields[2]);
>> if (!key.file.name)
>> error (EXIT_FAILURE, errno, "strdup");
>> - break;
>> - }
>> + } else
>> + error (EXIT_FAILURE, 0, _("selector '%s': invalid TYPE"), selector);
>>
>> return key_store_import_key (ks, &key);
>
> Reviewed-by: Richard W.M. Jones <rjones at redhat.com>
>
>
Thanks!
More information about the Libguestfs
mailing list