2 Copyright 2015, 2016, 2017 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
26 #include <sys/types.h>
28 #include <json-c/json.h>
30 #include "utils-json.h"
31 #include "utils-systemd.h"
32 #include "utils-file.h"
37 static const char x_afm_prefix[] = "X-AFM-";
38 static const char service_extension[] = ".service";
39 static const char key_unit_path[] = "-unit-path";
40 static const char key_unit_name[] = "-unit-name";
41 static const char key_unit_scope[] = "-unit-scope";
42 static const char scope_user[] = "user";
43 static const char scope_system[] = "system";
44 static const char key_id[] = "id";
46 #define x_afm_prefix_length (sizeof x_afm_prefix - 1)
47 #define service_extension_length (sizeof service_extension - 1)
50 * The structure afm_apps records the data about applications
51 * for several accesses.
54 struct json_object *prvarr; /* array of the private data of apps */
55 struct json_object *pubarr; /* array of the public data of apps */
56 struct json_object *pubobj; /* hash of application's publics */
57 struct json_object *prvobj; /* hash of application's privates */
61 * The structure afm_udb records the applications
62 * for a set of directories recorded as a linked list
65 struct afm_apps applications; /* the data about applications */
66 int refcount; /* count of references to the structure */
67 int system; /* is managing system units? */
68 int user; /* is managing user units? */
69 size_t prefixlen; /* length of the prefix */
70 char prefix[1]; /* filtering prefix */
74 * The structure afm_updt is internally used for updates
77 struct afm_udb *afudb;
78 struct afm_apps applications;
82 * Release the data of the afm_apps object 'apps'.
84 static void apps_put(struct afm_apps *apps)
86 json_object_put(apps->prvarr);
87 json_object_put(apps->pubarr);
88 json_object_put(apps->pubobj);
89 json_object_put(apps->prvobj);
93 * Adds the field of 'name' and 'value' in 'priv' and also if possible in 'pub'
94 * Returns 0 on success or -1 on error.
97 struct json_object *priv,
98 struct json_object *pub,
105 struct json_object *v;
107 /* try to adapt the value to its type */
109 ival = strtol(value, &end, 10);
110 if (*value && !*end && !errno) {
112 v = json_object_new_int64(ival);
115 v = json_object_new_string(value);
123 if (name[0] == '-') {
124 json_object_object_add(priv, &name[1], v);
126 json_object_object_add(priv, name, json_object_get(v));
127 json_object_object_add(pub, name, v);
133 * Adds the field of 'name' and 'value' in 'priv' and also if possible in 'pub'
134 * Returns 0 on success or -1 on error.
136 static int add_fields_of_content(
137 struct json_object *priv,
138 struct json_object *pub,
143 char *name, *value, *read, *write;
145 read = strstr(content, x_afm_prefix);
147 name = read + x_afm_prefix_length;
148 value = strchr(name, '=');
150 read = strstr(name, x_afm_prefix);
153 read = write = value;
154 while(*read && *read != '\n') {
159 case 'n': *write++ = '\n'; break;
160 case '\n': *write++ = ' '; break;
161 default: *write++ = '\\'; *write++ = *read; break;
166 read = strstr(read, x_afm_prefix);
168 if (add_field(priv, pub, name, value) < 0)
176 * Adds the application widget 'desc' of the directory 'path' to the
177 * afm_apps object 'apps'.
178 * Returns 0 in case of success.
179 * Returns -1 and set errno in case of error
182 struct afm_apps *apps,
184 const char *unitpath,
185 const char *unitname,
190 struct json_object *priv, *pub, *id;
193 /* create the application structure */
194 priv = json_object_new_object();
198 pub = json_object_new_object();
202 /* adds the values */
203 if (add_fields_of_content(priv, pub, content, length)
204 || add_field(priv, pub, key_unit_path, unitpath)
205 || add_field(priv, pub, key_unit_name, unitname)
206 || add_field(priv, pub, key_unit_scope, isuser ? scope_user : scope_system))
210 if (!json_object_object_get_ex(pub, key_id, &id)) {
214 strid = json_object_get_string(id);
216 /* record the application structure */
217 json_object_get(pub);
218 json_object_array_add(apps->pubarr, pub);
219 json_object_object_add(apps->pubobj, strid, pub);
220 json_object_get(priv);
221 json_object_array_add(apps->prvarr, priv);
222 json_object_object_add(apps->prvobj, strid, priv);
226 json_object_put(pub);
227 json_object_put(priv);
232 * called for each unit
234 static int update_cb(void *closure, const char *name, const char *path, int isuser)
236 struct afm_updt *updt = closure;
241 /* prefix filtering */
242 length = updt->afudb->prefixlen;
243 if (length && strncmp(updt->afudb->prefix, name, length))
247 length = strlen(name);
248 if (length < service_extension_length || strcmp(service_extension, name + length - service_extension_length))
252 rc = getfile(path, &content, &length);
256 /* process the file */
257 rc = addunit(&updt->applications, isuser, path, name, content, length);
263 * Creates an afm_udb object and returns it with one reference added.
264 * Return NULL with errno = ENOMEM if memory exhausted.
266 struct afm_udb *afm_udb_create(int sys, int usr, const char *prefix)
269 struct afm_udb *afudb;
271 length = prefix ? strlen(prefix) : 0;
272 afudb = malloc(length + sizeof * afudb);
277 afudb->applications.prvarr = NULL;
278 afudb->applications.pubarr = NULL;
279 afudb->applications.pubobj = NULL;
280 afudb->applications.prvobj = NULL;
283 afudb->prefixlen = length;
285 memcpy(afudb->prefix, prefix, length);
286 afudb->prefix[length] = 0;
287 if (afm_udb_update(afudb) < 0) {
288 afm_udb_unref(afudb);
296 * Adds a reference to an existing afm_udb.
298 void afm_udb_addref(struct afm_udb *afudb)
305 * Removes a reference to an existing afm_udb object.
306 * Removes the objet if there no more reference to it.
308 void afm_udb_unref(struct afm_udb *afudb)
311 if (!--afudb->refcount) {
312 /* no more reference, clean the memory used by the object */
313 apps_put(&afudb->applications);
319 * Regenerate the list of applications of the afm_bd object 'afudb'.
320 * Returns 0 in case of success.
321 * Returns -1 and set errno in case of error
323 int afm_udb_update(struct afm_udb *afudb)
325 struct afm_updt updt;
329 afm_udb_addref(afudb);
332 /* create the result */
333 updt.applications.prvarr = json_object_new_array();
334 updt.applications.pubarr = json_object_new_array();
335 updt.applications.pubobj = json_object_new_object();
336 updt.applications.prvobj = json_object_new_object();
337 if (updt.applications.pubarr == NULL
338 || updt.applications.prvarr == NULL
339 || updt.applications.pubobj == NULL
340 || updt.applications.prvobj == NULL) {
347 if (systemd_unit_list(1, update_cb, &updt) < 0)
350 if (systemd_unit_list(0, update_cb, &updt) < 0)
353 /* commit the result */
354 tmp = afudb->applications;
355 afudb->applications = updt.applications;
357 afm_udb_addref(afudb);
361 apps_put(&updt.applications);
362 afm_udb_addref(afudb);
367 * Get the list of the applications private data of the afm_udb object 'afudb'.
368 * The list is returned as a JSON-array that must be released using
370 * Returns NULL in case of error.
372 struct json_object *afm_udb_applications_private(struct afm_udb *afudb)
374 return json_object_get(afudb->applications.prvarr);
378 * Get the list of the applications public data of the afm_udb object 'afudb'.
379 * The list is returned as a JSON-array that must be released using
381 * Returns NULL in case of error.
383 struct json_object *afm_udb_applications_public(struct afm_udb *afudb)
385 return json_object_get(afudb->applications.pubarr);
389 * Get the private data of the applications of 'id' in the afm_udb object 'afudb'.
390 * It returns a JSON-object that must be released using 'json_object_put'.
391 * Returns NULL in case of error.
393 static struct json_object *get_no_case(struct json_object *object, const char *id)
395 struct json_object *result;
396 struct json_object_iter i;
398 /* search case sensitively */
399 if (json_object_object_get_ex(object, id, &result))
400 return json_object_get(result);
402 /* fallback to a case insensitive search */
403 json_object_object_foreachC(object, i) {
404 if (!strcasecmp(i.key, id))
405 return json_object_get(i.val);
411 * Get the private data of the applications of 'id' in the afm_udb object 'afudb'.
412 * It returns a JSON-object that must be released using 'json_object_put'.
413 * Returns NULL in case of error.
415 struct json_object *afm_udb_get_application_private(struct afm_udb *afudb, const char *id)
417 return get_no_case(afudb->applications.prvobj, id);
421 * Get the public data of the applications of 'id' in the afm_udb object 'afudb'.
422 * It returns a JSON-object that must be released using 'json_object_put'.
423 * Returns NULL in case of error.
425 struct json_object *afm_udb_get_application_public(struct afm_udb *afudb,
428 return get_no_case(afudb->applications.pubobj, id);
433 #if defined(TESTAPPFWK)
437 struct afm_udb *afudb = afm_udb_create(1, 1, NULL);
438 printf("array = %s\n", json_object_to_json_string_ext(afudb->applications.pubarr, 3));
439 printf("pubobj = %s\n", json_object_to_json_string_ext(afudb->applications.pubobj, 3));
440 printf("prvobj = %s\n", json_object_to_json_string_ext(afudb->applications.prvobj, 3));