X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafm-udb.c;h=4dfc79fa26ba57a8d76b6e61040ad7cfc5325f1f;hb=a123bb31906ef03ff813559aee426282416d729d;hp=0a48810694eca6a39f5a057a4150955c5843ac44;hpb=5d7e7dc483a98a31323079953f548648a2c53cda;p=src%2Fapp-framework-main.git diff --git a/src/afm-udb.c b/src/afm-udb.c index 0a48810..4dfc79f 100644 --- a/src/afm-udb.c +++ b/src/afm-udb.c @@ -1,5 +1,5 @@ /* - Copyright 2015, 2016, 2017 IoT.bzh + Copyright (C) 2015-2020 IoT.bzh author: José Bollo @@ -34,7 +34,6 @@ #include "afm-udb.h" - static const char x_afm_prefix[] = "X-AFM-"; static const char service_extension[] = ".service"; static const char key_unit_path[] = "-unit-path"; @@ -43,6 +42,8 @@ static const char key_unit_scope[] = "-unit-scope"; static const char scope_user[] = "user"; static const char scope_system[] = "system"; static const char key_id[] = "id"; +static const char key_visibility[] = "visibility"; +static const char value_visible[] = "visible"; #define x_afm_prefix_length (sizeof x_afm_prefix - 1) #define service_extension_length (sizeof service_extension - 1) @@ -52,10 +53,11 @@ static const char key_id[] = "id"; * for several accesses. */ struct afm_apps { - struct json_object *prvarr; /* array of the private data of apps */ - struct json_object *pubarr; /* array of the public data of apps */ - struct json_object *pubobj; /* hash of application's publics */ - struct json_object *prvobj; /* hash of application's privates */ + struct { + struct json_object *visibles; /* array of the private data of visible apps */ + struct json_object *all; /* array of the private data of all apps */ + struct json_object *byname; /* hash of application's privates */ + } privates, publics; }; /* @@ -79,15 +81,44 @@ struct afm_updt { struct afm_apps applications; }; +/* + * The default language + */ +static char *default_lang; + +/* + * initilize object 'apps'. + * returns 1 if okay or 0 on case of memory depletion + */ +static int apps_init(struct afm_apps *apps) +{ + apps->publics.all = json_object_new_array(); + apps->publics.visibles = json_object_new_array(); + apps->publics.byname = json_object_new_object(); + + apps->privates.all = json_object_new_array(); + apps->privates.visibles = json_object_new_array(); + apps->privates.byname = json_object_new_object(); + + return apps->publics.all + && apps->publics.visibles + && apps->publics.byname + && apps->privates.all + && apps->privates.visibles + && apps->privates.byname; +} + /* * Release the data of the afm_apps object 'apps'. */ static void apps_put(struct afm_apps *apps) { - json_object_put(apps->prvarr); - json_object_put(apps->pubarr); - json_object_put(apps->pubobj); - json_object_put(apps->prvobj); + json_object_put(apps->publics.all); + json_object_put(apps->publics.visibles); + json_object_put(apps->publics.byname); + json_object_put(apps->privates.all); + json_object_put(apps->privates.visibles); + json_object_put(apps->privates.byname); } /* @@ -113,7 +144,7 @@ static int append_field( array = json_object_new_array(); if (!array) goto error; - json_object_array_add(array, item); + json_object_array_add(array, json_object_get(item)); json_object_object_add(object, name, array); } json_object_array_add(array, data); @@ -157,8 +188,10 @@ static int add_field( /* add the value */ if (name[0] == '-') { + /* private value */ append_field(priv, &name[1], v); } else { + /* public value */ append_field(priv, name, json_object_get(v)); append_field(pub, name, v); } @@ -178,17 +211,25 @@ static int add_fields_of_content( { char *name, *value, *read, *write; - read = strstr(content, x_afm_prefix); - while (read) { + /* start at the beginning */ + read = content; + for (;;) { + /* search the next key */ + read = strstr(read, x_afm_prefix); + if (!read) + return 0; + + /* search to equal */ name = read + x_afm_prefix_length; value = strchr(name, '='); if (value == NULL) - read = strstr(name, x_afm_prefix); + read = name; /* not found */ else { + /* get the value (translate it) */ *value++ = 0; read = write = value; while(*read && *read != '\n') { - if (read[0] != '\\') + if (*read != '\\') *write++ = *read++; else { switch(*++read) { @@ -199,13 +240,14 @@ static int add_fields_of_content( read += !!*read; } } - read = strstr(read, x_afm_prefix); + read += !!*read; *write = 0; + + /* add the found field now */ if (add_field(priv, pub, name, value) < 0) return -1; } } - return 0; } /* @@ -223,9 +265,8 @@ static int addunit( size_t length ) { - struct json_object *priv, *pub, *id; + struct json_object *priv, *pub, *id, *visi; const char *strid; - char *un = NULL; size_t len; /* create the application structure */ @@ -241,26 +282,13 @@ static int addunit( len = strlen(unitname); assert(len >= (sizeof service_extension - 1)); assert(!memcmp(&unitname[len - (sizeof service_extension - 1)], service_extension, sizeof service_extension)); - if (unitname[len - sizeof service_extension] == '@') { - char buffer[40]; - size_t l = (size_t)snprintf(buffer, sizeof buffer, "%d", (int)getuid()); - un = malloc(len + l + 1); - if (!un) - goto error; - memcpy(&un[0], unitname, len - (sizeof service_extension - 1)); - if (l) - memcpy(&un[len - (sizeof service_extension - 1)], buffer, l); - memcpy(&un[len - (sizeof service_extension - 1) + l], service_extension, sizeof service_extension); - } /* adds the values */ if (add_fields_of_content(priv, pub, content, length) || add_field(priv, pub, key_unit_path, unitpath) - || add_field(priv, pub, key_unit_name, un ? : unitname) + || add_field(priv, pub, key_unit_name, unitname) || add_field(priv, pub, key_unit_scope, isuser ? scope_user : scope_system)) goto error; - free(un); - un = NULL; /* get the id */ if (!json_object_object_get_ex(pub, key_id, &id)) { @@ -271,75 +299,98 @@ static int addunit( /* record the application structure */ json_object_get(pub); - json_object_array_add(apps->pubarr, pub); - json_object_object_add(apps->pubobj, strid, pub); + json_object_array_add(apps->publics.all, pub); + json_object_object_add(apps->publics.byname, strid, pub); json_object_get(priv); - json_object_array_add(apps->prvarr, priv); - json_object_object_add(apps->prvobj, strid, priv); + json_object_array_add(apps->privates.all, priv); + json_object_object_add(apps->privates.byname, strid, priv); + + /* handle visibility */ + if (json_object_object_get_ex(priv, key_visibility, &visi) + && !strcasecmp(json_object_get_string(visi), value_visible)) { + json_object_array_add(apps->publics.visibles, json_object_get(pub)); + json_object_array_add(apps->privates.visibles, json_object_get(priv)); + } + return 0; error: - free(un); json_object_put(pub); json_object_put(priv); return -1; } /* - * read a unit file + * Crop and trim unit 'content' of 'length'. Return the new length. */ -static int read_unit_file(const char *path, char **content, size_t *length) +static size_t crop_and_trim_unit_content(char *content, size_t length) { - int rc, st; + int st; char c, *read, *write; - /* read the file */ - rc = getfile(path, content, length); - if (rc >= 0) { - /* removes any comment and join lines */ - st = 0; - read = write = *content; - for (;;) { - do { c = *read++; } while (c == '\r'); - if (!c) + /* removes any comment and join continued lines */ + st = 0; + read = write = content; + for (;;) { + do { c = *read++; } while (c == '\r'); + if (!c) + break; + switch (st) { + case 0: + /* state 0: begin of a line */ + if (c == ';' || c == '#') { + st = 3; /* removes lines starting with ; or # */ break; - switch (st) { - case 0: - if (c == ';' || c == '#') { - st = 3; /* removes lines starting with ; or # */ - break; - } - if (c == '\n') - break; /* removes empty lines */ + } + if (c == '\n') + break; /* removes empty lines */ enter_state_1: - st = 1; - /*@fallthrough@*/ - case 1: - if (c == '\\') - st = 2; - else { - *write++ = c; - if (c == '\n') - st = 0; - } - break; - case 2: - if (c == '\n') - c = ' '; - else - *write++ = '\\'; - goto enter_state_1; - case 3: + st = 1; + /*@fallthrough@*/ + case 1: + /* state 1: emitting a normal line */ + if (c == '\\') + st = 2; + else { + *write++ = c; if (c == '\n') st = 0; - break; } + break; + case 2: + /* state 2: character after '\' */ + if (c == '\n') + c = ' '; + else + *write++ = '\\'; + goto enter_state_1; + case 3: + /* state 3: inside a comment, wait its end */ + if (c == '\n') + st = 0; + break; } - if (st == 1) - *write++ = '\n'; - *write = 0; - *length = (size_t)(write - *content); - *content = realloc(*content, *length + 1); + } + if (st == 1) + *write++ = '\n'; + *write = 0; + return (size_t)(write - content); +} + +/* + * read a unit file + */ +static int read_unit_file(const char *path, char **content, size_t *length) +{ + int rc; + size_t nl; + + /* read the file */ + rc = getfile(path, content, length); + if (rc >= 0) { + /* crop and trim it */ + *length = nl = crop_and_trim_unit_content(*content, *length); + *content = realloc(*content, nl + 1); } return rc; } @@ -367,12 +418,14 @@ static int update_cb(void *closure, const char *name, const char *path, int isus /* reads the file */ rc = read_unit_file(path, &content, &length); if (rc < 0) - return rc; + return 0; /* process the file */ rc = addunit(&updt->applications, isuser, path, name, content, length); + /* TODO: if (rc < 0) + ERROR("Ignored boggus unit %s (error: %m)", path); */ free(content); - return rc; + return 0; } /* @@ -390,10 +443,7 @@ struct afm_udb *afm_udb_create(int sys, int usr, const char *prefix) errno = ENOMEM; else { afudb->refcount = 1; - afudb->applications.prvarr = NULL; - afudb->applications.pubarr = NULL; - afudb->applications.pubobj = NULL; - afudb->applications.prvobj = NULL; + memset(&afudb->applications, 0, sizeof afudb->applications); afudb->system = sys; afudb->user = usr; afudb->prefixlen = length; @@ -440,43 +490,43 @@ int afm_udb_update(struct afm_udb *afudb) { struct afm_updt updt; struct afm_apps tmp; + int result; /* lock the db */ afm_udb_addref(afudb); updt.afudb = afudb; - /* create the result */ - updt.applications.prvarr = json_object_new_array(); - updt.applications.pubarr = json_object_new_array(); - updt.applications.pubobj = json_object_new_object(); - updt.applications.prvobj = json_object_new_object(); - if (updt.applications.pubarr == NULL - || updt.applications.prvarr == NULL - || updt.applications.pubobj == NULL - || updt.applications.prvobj == NULL) { - errno = ENOMEM; - goto error; + /* create the apps */ + if (!apps_init(&updt.applications)) + result = -1; + else { + /* scan the units */ + if (afudb->user && systemd_unit_list(1, update_cb, &updt) < 0) + result = -1; + else if (afudb->system && systemd_unit_list(0, update_cb, &updt) < 0) + result = -1; + else { + /* commit the result */ + tmp = afudb->applications; + afudb->applications = updt.applications; + updt.applications = tmp; + result = 0; + } + apps_put(&updt.applications); } + /* unlock the db and return status */ + afm_udb_unref(afudb); + return result; +} - /* scan the units */ - if (afudb->user) - if (systemd_unit_list(1, update_cb, &updt) < 0) - goto error; - if (afudb->system) - if (systemd_unit_list(0, update_cb, &updt) < 0) - goto error; - - /* commit the result */ - tmp = afudb->applications; - afudb->applications = updt.applications; - apps_put(&tmp); - afm_udb_addref(afudb); - return 0; - -error: - apps_put(&updt.applications); - afm_udb_addref(afudb); - return -1; +/* + * set the default language to 'lang' + */ +void afm_udb_set_default_lang(const char *lang) +{ + char *oldval = default_lang; + default_lang = lang ? strdup(lang) : NULL; + free(oldval); } /* @@ -485,9 +535,9 @@ error: * 'json_object_put'. * Returns NULL in case of error. */ -struct json_object *afm_udb_applications_private(struct afm_udb *afudb) +struct json_object *afm_udb_applications_private(struct afm_udb *afudb, int all, int uid) { - return json_object_get(afudb->applications.prvarr); + return json_object_get(all ? afudb->applications.privates.all : afudb->applications.privates.visibles); } /* @@ -496,9 +546,9 @@ struct json_object *afm_udb_applications_private(struct afm_udb *afudb) * 'json_object_put'. * Returns NULL in case of error. */ -struct json_object *afm_udb_applications_public(struct afm_udb *afudb) +struct json_object *afm_udb_applications_public(struct afm_udb *afudb, int all, int uid, const char *lang) { - return json_object_get(afudb->applications.pubarr); + return json_object_get(all ? afudb->applications.publics.all : afudb->applications.publics.visibles); } /* @@ -506,7 +556,7 @@ struct json_object *afm_udb_applications_public(struct afm_udb *afudb) * It returns a JSON-object that must be released using 'json_object_put'. * Returns NULL in case of error. */ -static struct json_object *get_no_case(struct json_object *object, const char *id) +static struct json_object *get_no_case(struct json_object *object, const char *id, int uid, const char *lang) { struct json_object *result; struct json_object_iter i; @@ -528,9 +578,9 @@ static struct json_object *get_no_case(struct json_object *object, const char *i * It returns a JSON-object that must be released using 'json_object_put'. * Returns NULL in case of error. */ -struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const char *id) +struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const char *id, int uid) { - return get_no_case(afudb->applications.prvobj, id); + return get_no_case(afudb->applications.privates.byname, id, uid, NULL); } /* @@ -539,9 +589,9 @@ struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const * Returns NULL in case of error. */ struct json_object *afm_udb_get_application_public(struct afm_udb *afudb, - const char *id) + const char *id, int uid, const char *lang) { - return get_no_case(afudb->applications.pubobj, id); + return get_no_case(afudb->applications.publics.byname, id, uid, lang); } @@ -551,9 +601,9 @@ struct json_object *afm_udb_get_application_public(struct afm_udb *afudb, int main() { struct afm_udb *afudb = afm_udb_create(1, 1, NULL); -printf("array = %s\n", json_object_to_json_string_ext(afudb->applications.pubarr, 3)); -printf("pubobj = %s\n", json_object_to_json_string_ext(afudb->applications.pubobj, 3)); -printf("prvobj = %s\n", json_object_to_json_string_ext(afudb->applications.prvobj, 3)); +printf("publics.all = %s\n", json_object_to_json_string_ext(afudb->applications.publics.all, 3)); +printf("publics.byname = %s\n", json_object_to_json_string_ext(afudb->applications.publics.byname, 3)); +printf("privates.byname = %s\n", json_object_to_json_string_ext(afudb->applications.privates.byname, 3)); return 0; } #endif