/*
- Copyright 2015, 2016, 2017 IoT.bzh
+ Copyright (C) 2015-2020 IoT.bzh
author: José Bollo <jose.bollo@iot.bzh>
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)
* 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;
};
/*
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);
}
/*
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);
/* 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);
}
{
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) {
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;
}
/*
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 */
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)) {
/* 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;
}
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;
{
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);
}
/*
* '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);
}
/*
* '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);
}
/*
* 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;
* 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);
}
/*
* 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);
}
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