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 struct afb_auth
65 .type = afb_auth_Permission,
66 .text = "urn:AGL:permission:afm:system:widget:install"
69 .type = afb_auth_Permission,
70 .text = "urn:AGL:permission:afm:system:widget:uninstall"
73 .type = afb_auth_Permission,
74 .text = "urn:AGL:permission:afm:system:widget:preinstall"
77 .type = afb_auth_Permission,
78 .text = "urn:AGL:permission:afm:system:widget:detail"
81 .type = afb_auth_Permission,
82 .text = "urn:AGL:permission:afm:system:widget:start"
85 .type = afb_auth_Permission,
86 .text = "urn:AGL:permission:afm:system:widget:view-all"
89 .type = afb_auth_Permission,
90 .text = "urn:AGL:permission:afm:system:runner:state"
93 .type = afb_auth_Permission,
94 .text = "urn:AGL:permission:afm:system:runner:kill"
101 static const char *rootdir = FWK_APP_DIR;
104 * the internal application database
106 static struct afm_udb *afudb;
109 * the event signalling that application list changed
111 static struct afb_event applist_changed_event;
114 * the preallocated true json_object
116 static struct json_object *json_true;
118 /* enforce daemon reload */
119 static void do_reloads()
121 systemd_daemon_reload(0);
122 systemd_unit_restart_name(0, "sockets.target");
125 /* common bad request reply */
126 static void bad_request(struct afb_req req)
128 afb_req_fail(req, _bad_request_, NULL);
131 /* common not found reply */
132 static void not_found(struct afb_req req)
134 afb_req_fail(req, _not_found_, NULL);
137 /* common can't start reply */
138 static void cant_start(struct afb_req req)
140 afb_req_fail(req, _cannot_start_, NULL);
144 * Broadcast the event "application-list-changed".
145 * This event is sent was the event "changed" is received from dbus.
147 static void application_list_changed(const char *operation, const char *data)
149 struct json_object *e = NULL;
150 wrap_json_pack(&e, "{ss ss}", "operation", operation, "data", data);
151 afb_event_broadcast(applist_changed_event, e);
155 * Retrieve the required language from 'req'.
157 static const char *get_lang(struct afb_req req)
161 /* get the optional language */
162 lang = afb_req_value(req, _lang_);
164 /* TODO use the req to get the lang of the session (if any) */
171 * retrieves the 'appid' in parameters received with the
172 * request 'req' for the 'method'.
174 * Returns 1 in case of success.
175 * Otherwise, if the 'appid' can't be retrieved, an error stating
176 * the bad request is replied for 'req' and 0 is returned.
178 static int onappid(struct afb_req req, const char *method, const char **appid)
180 struct json_object *json;
182 /* get the paramaters of the request */
183 json = afb_req_json(req);
185 /* get the appid if any */
186 if (!wrap_json_unpack(json, "s", appid)
187 || !wrap_json_unpack(json, "{si}", _id_, appid)) {
189 INFO("method %s called for %s", method, *appid);
193 /* nothing appropriate */
194 INFO("bad request method %s: %s", method,
195 json_object_to_json_string(json));
201 * retrieves the 'runid' in parameters received with the
202 * request 'req' for the 'method'.
204 * Returns 1 in case of success.
205 * Otherwise, if the 'runid' can't be retrieved, an error stating
206 * the bad request is replied for 'req' and 0 is returned.
208 static int onrunid(struct afb_req req, const char *method, int *runid)
210 struct json_object *json;
213 /* get the paramaters of the request */
214 json = afb_req_json(req);
216 /* get the runid if any */
217 if (!wrap_json_unpack(json, "i", runid)
218 || !wrap_json_unpack(json, "{si}", _runid_, runid)) {
219 INFO("method %s called for %d", method, *runid);
223 /* get the appid if any */
224 if (!onappid(req, method, &appid))
227 /* search the runid of the appid */
228 *runid = afm_urun_search_runid(afudb, appid, afb_req_get_uid(req));
230 /* nothing appropriate */
231 INFO("method %s can't get runid for %s: %m", method,
238 INFO("method %s called for %s -> %d", method, appid, *runid);
243 * Sends the reply 'resp' to the request 'req' if 'resp' is not NULLzero.
244 * Otherwise, when 'resp' is NULL replies the error string 'errstr'.
246 static void reply(struct afb_req req, struct json_object *resp, const char *errstr)
249 afb_req_fail(req, errstr, NULL);
251 afb_req_success(req, resp, NULL);
255 * Sends the reply "true" to the request 'req' if 'status' is zero.
256 * Otherwise, when 'status' is not zero replies the error string 'errstr'.
258 static void reply_status(struct afb_req req, int status, const char *errstr)
260 reply(req, status ? NULL : json_object_get(json_true), errstr);
264 * On query "runnables"
266 static void runnables(struct afb_req req)
269 struct json_object *resp;
271 /* get the language */
272 lang = get_lang(req);
274 /* get the details */
275 resp = afm_udb_applications_public(afudb, afb_req_get_uid(req), lang);
276 afb_req_success(req, resp, NULL);
282 static void detail(struct afb_req req)
286 struct json_object *resp;
288 /* scan the request */
289 if (!onappid(req, _detail_, &appid))
292 /* get the language */
293 lang = get_lang(req);
295 /* wants details for appid */
296 resp = afm_udb_get_application_public(afudb, appid, afb_req_get_uid(req), lang);
298 afb_req_success(req, resp, NULL);
306 static void start(struct afb_req req)
309 struct json_object *appli, *resp;
312 /* scan the request */
313 if (!onappid(req, _start_, &appid))
316 /* get the application */
317 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
323 /* launch the application */
324 runid = afm_urun_start(appli, afb_req_get_uid(req));
333 wrap_json_pack(&resp, "{si}", _runid_, runid);
335 wrap_json_pack(&resp, "i", runid);
337 afb_req_success(req, resp, NULL);
343 static void once(struct afb_req req)
346 struct json_object *appli, *resp;
349 /* scan the request */
350 if (!onappid(req, _once_, &appid))
353 /* get the application */
354 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
360 /* launch the application */
361 runid = afm_urun_once(appli, afb_req_get_uid(req));
367 /* returns the state */
368 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
369 afb_req_success(req, resp, NULL);
375 static void pause(struct afb_req req)
378 if (onrunid(req, "pause", &runid)) {
379 status = afm_urun_pause(runid, afb_req_get_uid(req));
380 reply_status(req, status, _not_found_);
385 * On query "resume" from 'smsg' with parameters of 'obj'.
387 static void resume(struct afb_req req)
390 if (onrunid(req, "resume", &runid)) {
391 status = afm_urun_resume(runid, afb_req_get_uid(req));
392 reply_status(req, status, _not_found_);
397 * On query "terminate"
399 static void terminate(struct afb_req req)
402 if (onrunid(req, "terminate", &runid)) {
403 status = afm_urun_terminate(runid, afb_req_get_uid(req));
404 reply_status(req, status, _not_found_);
411 static void runners(struct afb_req req)
413 struct json_object *resp;
414 resp = afm_urun_list(afudb, afb_req_get_uid(req));
415 afb_req_success(req, resp, NULL);
421 static void state(struct afb_req req)
424 struct json_object *resp;
425 if (onrunid(req, "state", &runid)) {
426 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
427 reply(req, resp, _not_found_);
432 * On querying installation of widget(s)
434 static void install(struct afb_req req)
440 struct wgt_info *ifo;
441 struct json_object *json;
442 struct json_object *resp;
444 /* default settings */
449 /* scan the request */
450 json = afb_req_json(req);
451 if (wrap_json_unpack(json, "s", &wgtfile)
452 && wrap_json_unpack(json, "{ss s?s s?b s?b}",
456 "reload", &reload)) {
457 return bad_request(req);
460 /* install the widget */
461 ifo = install_widget(wgtfile, root, force);
463 afb_req_fail_f(req, "failed", "installation failed: %m");
465 afm_udb_update(afudb);
466 /* reload if needed */
470 /* build the response */
471 wrap_json_pack(&resp, "{ss}", _added_, wgt_info_desc(ifo)->idaver);
472 afb_req_success(req, resp, NULL);
473 application_list_changed(_install_, wgt_info_desc(ifo)->idaver);
481 * On querying uninstallation of widget(s)
483 static void uninstall(struct afb_req req)
487 struct json_object *json;
490 /* default settings */
493 /* scan the request */
494 json = afb_req_json(req);
495 if (wrap_json_unpack(json, "s", &idaver)
496 && wrap_json_unpack(json, "{ss s?s}",
499 return bad_request(req);
502 /* install the widget */
503 rc = uninstall_widget(idaver, root);
505 afb_req_fail_f(req, "failed", "uninstallation failed: %m");
507 afm_udb_update(afudb);
508 afb_req_success(req, NULL, NULL);
509 application_list_changed(_uninstall_, idaver);
516 afudb = afm_udb_create(1, 0, "afm-appli-");
518 ERROR("afm_udb_create failed");
523 json_true = json_object_new_boolean(1);
525 /* create the event */
526 applist_changed_event = afb_daemon_make_event(_a_l_c_);
527 return -!afb_event_is_valid(applist_changed_event);
530 static const struct afb_verb_v2 verbs[] =
532 {_runnables_, runnables, &auth_detail, "Get list of runnable applications", AFB_SESSION_CHECK_V2 },
533 {_detail_ , detail, &auth_detail, "Get the details for one application", AFB_SESSION_CHECK_V2 },
534 {_start_ , start, &auth_start, "Start an application", AFB_SESSION_CHECK_V2 },
535 {_once_ , once, &auth_start, "Start once an application", AFB_SESSION_CHECK_V2 },
536 {_terminate_, terminate, &auth_kill, "Terminate a running application", AFB_SESSION_CHECK_V2 },
537 {_pause_ , pause, &auth_kill, "Pause a running application", AFB_SESSION_CHECK_V2 },
538 {_resume_ , resume, &auth_kill, "Resume a paused application", AFB_SESSION_CHECK_V2 },
539 {_runners_ , runners, &auth_state, "Get the list of running applications", AFB_SESSION_CHECK_V2 },
540 {_state_ , state, &auth_state, "Get the state of a running application", AFB_SESSION_CHECK_V2 },
541 {_install_ , install, &auth_install, "Install an application using a widget file", AFB_SESSION_CHECK_V2 },
542 {_uninstall_, uninstall, &auth_uninstall, "Uninstall an application", AFB_SESSION_CHECK_V2 },
543 { NULL, NULL, NULL, NULL, 0 }
546 const struct afb_binding_v2 afbBindingV2 = {
548 .specification = NULL,
549 .info = "Application Framework Master Service",
554 .noconcurrency = 1 /* relies on binder for serialisation of requests */