2 * Copyright (C) 2015-2018 "IoT.bzh"
3 * Author "Fulup Ar Foll"
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #define _GNU_SOURCE /* See feature_test_macros(7) */
23 #include <json-c/json.h>
25 #define AFB_BINDING_VERSION 2
26 #include <afb/afb-binding.h>
29 #include "utils-systemd.h"
33 #include "wgtpkg-install.h"
34 #include "wgtpkg-uninstall.h"
35 #include "wrap-json.h"
40 static const char _added_[] = "added";
41 static const char _a_l_c_[] = "application-list-changed";
42 static const char _bad_request_[] = "bad-request";
43 static const char _cannot_start_[] = "cannot-start";
44 static const char _detail_[] = "detail";
45 static const char _id_[] = "id";
46 static const char _install_[] = "install";
47 static const char _lang_[] = "lang";
48 static const char _not_found_[] = "not-found";
49 static const char _once_[] = "once";
50 static const char _pause_[] = "pause";
51 static const char _resume_[] = "resume";
52 static const char _runid_[] = "runid";
53 static const char _runnables_[] = "runnables";
54 static const char _runners_[] = "runners";
55 static const char _start_[] = "start";
56 static const char _state_[] = "state";
57 static const char _terminate_[] = "terminate";
58 static const char _uninstall_[] = "uninstall";
63 static const char *rootdir = FWK_APP_DIR;
66 * the internal application database
68 static struct afm_udb *afudb;
71 * the event signalling that application list changed
73 static struct afb_event applist_changed_event;
76 * the preallocated true json_object
78 static struct json_object *json_true;
80 /* enforce daemon reload */
81 static void do_reloads()
83 systemd_daemon_reload(0);
84 systemd_unit_restart_name(0, "sockets.target");
87 /* common bad request reply */
88 static void bad_request(struct afb_req req)
90 afb_req_fail(req, _bad_request_, NULL);
93 /* common not found reply */
94 static void not_found(struct afb_req req)
96 afb_req_fail(req, _not_found_, NULL);
99 /* common can't start reply */
100 static void cant_start(struct afb_req req)
102 afb_req_fail(req, _cannot_start_, NULL);
106 * Broadcast the event "application-list-changed".
107 * This event is sent was the event "changed" is received from dbus.
109 static void application_list_changed(const char *operation, const char *data)
111 struct json_object *e = NULL;
112 wrap_json_pack(&e, "{ss ss}", "operation", operation, "data", data);
113 afb_event_broadcast(applist_changed_event, e);
117 * Retrieve the required language from 'req'.
119 static const char *get_lang(struct afb_req req)
123 /* get the optional language */
124 lang = afb_req_value(req, _lang_);
126 /* TODO use the req to get the lang of the session (if any) */
133 * retrieves the 'appid' in parameters received with the
134 * request 'req' for the 'method'.
136 * Returns 1 in case of success.
137 * Otherwise, if the 'appid' can't be retrieved, an error stating
138 * the bad request is replied for 'req' and 0 is returned.
140 static int onappid(struct afb_req req, const char *method, const char **appid)
142 struct json_object *json;
144 /* get the paramaters of the request */
145 json = afb_req_json(req);
147 /* get the appid if any */
148 if (!wrap_json_unpack(json, "s", appid)
149 || !wrap_json_unpack(json, "{si}", _id_, appid)) {
151 INFO("method %s called for %s", method, *appid);
155 /* nothing appropriate */
156 INFO("bad request method %s: %s", method,
157 json_object_to_json_string(json));
163 * retrieves the 'runid' in parameters received with the
164 * request 'req' for the 'method'.
166 * Returns 1 in case of success.
167 * Otherwise, if the 'runid' can't be retrieved, an error stating
168 * the bad request is replied for 'req' and 0 is returned.
170 static int onrunid(struct afb_req req, const char *method, int *runid)
172 struct json_object *json;
175 /* get the paramaters of the request */
176 json = afb_req_json(req);
178 /* get the runid if any */
179 if (!wrap_json_unpack(json, "i", runid)
180 || !wrap_json_unpack(json, "{si}", _runid_, runid)) {
181 INFO("method %s called for %d", method, *runid);
185 /* get the appid if any */
186 if (!onappid(req, method, &appid))
189 /* search the runid of the appid */
190 *runid = afm_urun_search_runid(afudb, appid, afb_req_get_uid(req));
192 /* nothing appropriate */
193 INFO("method %s can't get runid for %s: %m", method,
200 INFO("method %s called for %s -> %d", method, appid, *runid);
205 * Sends the reply 'resp' to the request 'req' if 'resp' is not NULLzero.
206 * Otherwise, when 'resp' is NULL replies the error string 'errstr'.
208 static void reply(struct afb_req req, struct json_object *resp, const char *errstr)
211 afb_req_fail(req, errstr, NULL);
213 afb_req_success(req, resp, NULL);
217 * Sends the reply "true" to the request 'req' if 'status' is zero.
218 * Otherwise, when 'status' is not zero replies the error string 'errstr'.
220 static void reply_status(struct afb_req req, int status, const char *errstr)
222 reply(req, status ? NULL : json_object_get(json_true), errstr);
226 * On query "runnables"
228 static void runnables(struct afb_req req)
231 struct json_object *resp;
233 /* get the language */
234 lang = get_lang(req);
236 /* get the details */
237 resp = afm_udb_applications_public(afudb, afb_req_get_uid(req), lang);
238 afb_req_success(req, resp, NULL);
244 static void detail(struct afb_req req)
248 struct json_object *resp;
250 /* scan the request */
251 if (!onappid(req, _detail_, &appid))
254 /* get the language */
255 lang = get_lang(req);
257 /* wants details for appid */
258 resp = afm_udb_get_application_public(afudb, appid, afb_req_get_uid(req), lang);
260 afb_req_success(req, resp, NULL);
268 static void start(struct afb_req req)
271 struct json_object *appli, *resp;
274 /* scan the request */
275 if (!onappid(req, _start_, &appid))
278 /* get the application */
279 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
285 /* launch the application */
286 runid = afm_urun_start(appli, afb_req_get_uid(req));
295 wrap_json_pack(&resp, "{si}", _runid_, runid);
297 wrap_json_pack(&resp, "i", runid);
299 afb_req_success(req, resp, NULL);
305 static void once(struct afb_req req)
308 struct json_object *appli, *resp;
311 /* scan the request */
312 if (!onappid(req, _once_, &appid))
315 /* get the application */
316 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
322 /* launch the application */
323 runid = afm_urun_once(appli, afb_req_get_uid(req));
329 /* returns the state */
330 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
331 afb_req_success(req, resp, NULL);
337 static void pause(struct afb_req req)
340 if (onrunid(req, "pause", &runid)) {
341 status = afm_urun_pause(runid, afb_req_get_uid(req));
342 reply_status(req, status, _not_found_);
347 * On query "resume" from 'smsg' with parameters of 'obj'.
349 static void resume(struct afb_req req)
352 if (onrunid(req, "resume", &runid)) {
353 status = afm_urun_resume(runid, afb_req_get_uid(req));
354 reply_status(req, status, _not_found_);
359 * On query "terminate"
361 static void terminate(struct afb_req req)
364 if (onrunid(req, "terminate", &runid)) {
365 status = afm_urun_terminate(runid, afb_req_get_uid(req));
366 reply_status(req, status, _not_found_);
373 static void runners(struct afb_req req)
375 struct json_object *resp;
376 resp = afm_urun_list(afudb, afb_req_get_uid(req));
377 afb_req_success(req, resp, NULL);
383 static void state(struct afb_req req)
386 struct json_object *resp;
387 if (onrunid(req, "state", &runid)) {
388 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
389 reply(req, resp, _not_found_);
394 * On querying installation of widget(s)
396 static void install(struct afb_req req)
402 struct wgt_info *ifo;
403 struct json_object *json;
404 struct json_object *resp;
406 /* default settings */
411 /* scan the request */
412 json = afb_req_json(req);
413 if (wrap_json_unpack(json, "s", &wgtfile)
414 && wrap_json_unpack(json, "{ss s?s s?b s?b}",
418 "reload", &reload)) {
419 return bad_request(req);
422 /* install the widget */
423 ifo = install_widget(wgtfile, root, force);
425 afb_req_fail_f(req, "failed", "installation failed: %m");
427 afm_udb_update(afudb);
428 /* reload if needed */
432 /* build the response */
433 wrap_json_pack(&resp, "{ss}", _added_, wgt_info_desc(ifo)->idaver);
434 afb_req_success(req, resp, NULL);
435 application_list_changed(_install_, wgt_info_desc(ifo)->idaver);
443 * On querying uninstallation of widget(s)
445 static void uninstall(struct afb_req req)
449 struct json_object *json;
452 /* default settings */
455 /* scan the request */
456 json = afb_req_json(req);
457 if (wrap_json_unpack(json, "s", &idaver)
458 && wrap_json_unpack(json, "{ss s?s}",
461 return bad_request(req);
464 /* install the widget */
465 rc = uninstall_widget(idaver, root);
467 afb_req_fail_f(req, "failed", "uninstallation failed: %m");
469 afm_udb_update(afudb);
470 afb_req_success(req, NULL, NULL);
471 application_list_changed(_uninstall_, idaver);
478 afudb = afm_udb_create(1, 0, "afm-appli-");
480 ERROR("afm_udb_create failed");
485 json_true = json_object_new_boolean(1);
487 /* create the event */
488 applist_changed_event = afb_daemon_make_event(_a_l_c_);
489 return -!afb_event_is_valid(applist_changed_event);
492 static const struct afb_auth
494 .type = afb_auth_Permission,
495 .text = "urn:AGL:permission:afm:system:widget:install"
498 .type = afb_auth_Permission,
499 .text = "urn:AGL:permission:afm:system:widget:uninstall"
503 static const struct afb_verb_v2 verbs[] =
505 {_runnables_, runnables, NULL, "Get list of runnable applications", AFB_SESSION_CHECK_V2 },
506 {_detail_ , detail, NULL, "Get the details for one application", AFB_SESSION_CHECK_V2 },
507 {_start_ , start, NULL, "Start an application", AFB_SESSION_CHECK_V2 },
508 {_once_ , once, NULL, "Start once an application", AFB_SESSION_CHECK_V2 },
509 {_terminate_, terminate, NULL, "Terminate a running application", AFB_SESSION_CHECK_V2 },
510 {_pause_ , pause, NULL, "Pause a running application", AFB_SESSION_CHECK_V2 },
511 {_resume_ , resume, NULL, "Resume a paused application", AFB_SESSION_CHECK_V2 },
512 {_runners_ , runners, NULL, "Get the list of running applications", AFB_SESSION_CHECK_V2 },
513 {_state_ , state, NULL, "Get the state of a running application", AFB_SESSION_CHECK_V2 },
514 {_install_ , install, NULL, "Install an application using a widget file", AFB_SESSION_CHECK_V2 },
515 {_uninstall_, uninstall, NULL, "Uninstall an application", AFB_SESSION_CHECK_V2 },
516 { NULL, NULL, NULL, NULL, 0 }
519 const struct afb_binding_v2 afbBindingV2 = {
521 .specification = NULL,
522 .info = "Application Framework Master Service",
527 .noconcurrency = 1 /* relies on binder for serialisation of requests */