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


_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to