[pve-devel] [PATCH cluster] add get_guest_config_property IPCC method
Thomas Lamprecht
t.lamprecht at proxmox.com
Wed Jun 12 13:48:57 CEST 2019
On 6/12/19 1:12 PM, Wolfgang Bumiller wrote:
> On Tue, Jun 11, 2019 at 06:02:22AM +0200, Thomas Lamprecht wrote:
>> [snip]
>>
>> +// checks the conf for a line starting with '$prop:' and returns the value
>> +// afterwards, whitout initial whitespace(s), we only deal with the format
>> +// restricion imposed by our perl VM config parser, main reference is
>> +// PVE::QemuServer::parse_vm_config this allows to be very fast and still
>> +// relatively simple
>> +// main restrictions used for our advantage is the properties match reges:
>> +// ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) from parse_vm_config
>> +// currently we only look at the current configuration in place, i.e., *no*
>> +// snapshort and *no* pending changes
>> +static char *
>> +_get_property_value(char *conf, char *prop, int prop_len)
>
> prop should be const
>
ok
>> +{
>> + char *line, *temp;
>
> initializing `temp` to NULL shutsup a warning gcc seems to spit out on
> my end here...
> status.c:816:10: error: ‘__s’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
> char *v_start = &line[prop_len + 1];
>
> `__s` seems to come from inlining strtok or some such, a gcc bug
> apparently...
ah yes, I remember that, I'm currently on Buster with gcc-8, which
has this behaviour fixed, but I can set it to NULL just fine.
>
>
>> +
>> + line = strtok_r(conf, "\n", &temp);
>> + while (line != NULL) {
>> + if (!line[0]) goto next;
>> +
>> + // snapshot or pending section start and nothing found yet
>> + if (line[0] == '[') return NULL;
>> + // properties start with /^[a-z]/, so continue early if not
>> + if (line[0] < 'a' || line[0] > 'z') goto next;
>> +
>> + int line_len = strlen(line);
>> + if (line_len <= prop_len + 1) goto next;
>> +
>> + if (line[prop_len] == ':' && strncmp(line, prop, prop_len) == 0) { // found
>
> This strncmp could be a memcmp given all the checks above (particularly
> the strlen() check). strncmp() checks for null bytes, memcmp doesn't
> care (and we already verified with strlen() that there aren't any null
> bytes within [0..prop_len].
OK
>
>> + char *v_start = &line[prop_len + 1];
>> +
>> + // drop initial value whitespaces here already
>> + while (*v_start && isspace(*v_start)) v_start++;
>> +
>> + // TODO: drop trailing whitespace here too??
>
> We already have `line_len`, so going backwards from that should be
> efficient enough.
yes, was just to lazy at the end, will do
>
>> +
>> + if (!*v_start) return NULL;
>> + return v_start;
>> + }
>> +next:
>> + line = strtok_r(NULL, "\n", &temp);
>> + }
>> +
>> + return NULL; // not found
>> +}
>> +
>> +int
>> +cfs_create_guest_conf_property_msg(GString *str, memdb_t *memdb, char *prop, uint32_t vmid)
>
> prop should be const
>
OK
>> +{
>> + g_return_val_if_fail(cfs_status.vmlist != NULL, -EINVAL);
>> + g_return_val_if_fail(str != NULL, -EINVAL);
>> +
>> + int prop_len = strlen(prop);
>> + int res = 0;
>> + GString *path = NULL;
>> +
>> + g_mutex_lock (&mutex);
>> +
>> + g_string_printf(str,"{\n");
>> +
>> + GHashTable *ht = cfs_status.vmlist;
>> + if (!g_hash_table_size(ht)) {
>> + goto ret;
>> + }
>> +
>> + path = g_string_new_len(NULL, 256);
>> + if (vmid >= 100) {
>> + vminfo_t *vminfo = (vminfo_t *) g_hash_table_lookup(cfs_status.vmlist, &vmid);
>> + if (vminfo == NULL) goto enoent;
>> +
>> + if (!vminfo_to_path(vminfo, path)) goto err;
>> +
>> + gpointer tmp = NULL;
>> + int size = memdb_read(memdb, path->str, &tmp);
>> + if (tmp == NULL || size <= prop_len) goto err;
>
> The 'or' part of the condition would have a valid `tmp` pointer needing
> to be `g_free()`d, no? So maybe just unconditionally call free before
> the goto?
yes, true that, thanks for catching
>
>> +
>> + char *val = _get_property_value(tmp, prop, prop_len);
>> + if (val == NULL) {
>> + g_free(tmp);
>> + goto ret;
>> + }
>> +
>> + g_string_append_printf(str,"\"%u\": { \"%s\": \"%s\"\n }", vmid, prop, val);
>
> Should we not sanity-check the value for double quotes here?
we normally do not have any here, but we can have in theory..
Maybe do the warn-and-ignore approach for now? and if we really
need it directly go to a libjson approach..
>
>> + g_free(tmp);
>> +
>> + } else {
>> + GHashTableIter iter;
>> + g_hash_table_iter_init (&iter, ht);
>> +
>> + gpointer key, value;
>> + int first = 1;
>> + while (g_hash_table_iter_next (&iter, &key, &value)) {
>> + vminfo_t *vminfo = (vminfo_t *)value;
>> +
>> + if (!vminfo_to_path(vminfo, path)) goto err;
>> +
>> + gpointer tmp = NULL;
>> + int size = memdb_read(memdb, path->str, &tmp);
>> + if (tmp == NULL || size <= prop_len) continue;
>
> Same g_free(tmp) as above
OK.
>
>> +
>> + char *val = _get_property_value(tmp, prop, prop_len);
>> + if (val == NULL) {
>> + g_free(tmp);
>> + continue;
>> + }
>> +
>> + if (!first) g_string_append_printf(str, ",\n");
>> + else first = 0;
>> +
>> + g_string_append_printf(str,"\"%u\": {\"%s\": \"%s\"}", vminfo->vmid, prop, val);
>> + g_free(tmp);
>> + }
>> + }
>> +ret:
>> + g_string_free(path, TRUE);
>> + g_string_append_printf(str,"\n}\n");
>> + g_mutex_unlock (&mutex);
>> +
>> + return res;
>> +err:
>> + res = -1;
>
> I'm not a fan of mixing hardcoded values and errno values. This
> corresponds to EPERM which is a rather weird error in those cases.
> Granted, there is often no good error code, so I'd just stick to EINVAL
> (or EIO to distinguish it from the preconditions).
OK, was a bit oriented on other functions we have here, but seems
reasonable to me.
>
>> + goto ret;
>> +enoent:
>> + res = -ENOENT;
>> + goto ret;
>> +}
>> +
>> void
>> record_memdb_change(const char *path)
>> {
>> diff --git a/data/src/status.h b/data/src/status.h
>> index 2e4153a..bda3e36 100644
>> --- a/data/src/status.h
>> +++ b/data/src/status.h
>> @@ -25,6 +25,7 @@
>>
>> #include "dfsm.h"
>> #include "logger.h"
>> +#include "memdb.h"
>>
>> #define VMTYPE_QEMU 1
>> #define VMTYPE_OPENVZ 2
>> @@ -158,5 +159,7 @@ int
>> cfs_create_memberlist_msg(
>> GString *str);
>>
>> +int
>> +cfs_create_guest_conf_property_msg(GString *str, memdb_t *memdb, char *prop, uint32_t vmid);
>>
>> #endif /* _PVE_STATUS_H_ */
>> --
>> 2.20.1
More information about the pve-devel
mailing list