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"
37 static const char _added_[] = "added";
38 static const char _a_l_c_[] = "application-list-changed";
39 static const char _detail_[] = "detail";
40 static const char _id_[] = "id";
41 static const char _install_[] = "install";
42 static const char _lang_[] = "lang";
43 static const char _not_found_[] = "not-found";
44 static const char _once_[] = "once";
45 static const char _pause_[] = "pause";
46 static const char _resume_[] = "resume";
47 static const char _runid_[] = "runid";
48 static const char _runnables_[] = "runnables";
49 static const char _runners_[] = "runners";
50 static const char _start_[] = "start";
51 static const char _state_[] = "state";
52 static const char _terminate_[] = "terminate";
53 static const char _uninstall_[] = "uninstall";
55 static const char *rootdir = FWK_APP_DIR;
56 static struct afb_event applist_changed_event;
57 static struct afm_udb *afudb;
58 static struct json_object *json_true;
60 static void do_reloads()
62 /* enforce daemon reload */
63 systemd_daemon_reload(0);
64 systemd_unit_restart_name(0, "sockets.target");
67 static void bad_request(struct afb_req req)
69 afb_req_fail(req, "bad-request", NULL);
72 static void not_found(struct afb_req req)
74 afb_req_fail(req, _not_found_, NULL);
77 static void cant_start(struct afb_req req)
79 afb_req_fail(req, "cannot-start", NULL);
83 * Broadcast the event "application-list-changed".
84 * This event is sent was the event "changed" is received from dbus.
86 static void application_list_changed(const char *operation, const char *data)
88 struct json_object *e = NULL;
89 wrap_json_pack(&e, "{ss ss}", "operation", operation, "data", data);
90 afb_event_broadcast(applist_changed_event, e);
94 * Retrieve the required language from 'req'.
96 static const char *get_lang(struct afb_req req)
100 /* get the optional language */
101 lang = afb_req_value(req, _lang_);
103 /* TODO use the req to get the lang of the session (if any) */
110 * retrieves the 'appid' in parameters received with the
111 * request 'req' for the 'method'.
113 * Returns 1 in case of success.
114 * Otherwise, if the 'appid' can't be retrieved, an error stating
115 * the bad request is replied for 'req' and 0 is returned.
117 static int onappid(struct afb_req req, const char *method, const char **appid)
119 struct json_object *json;
121 /* get the paramaters of the request */
122 json = afb_req_json(req);
124 /* get the appid if any */
125 if (!wrap_json_unpack(json, "s", appid)
126 || !wrap_json_unpack(json, "{si}", _id_, appid)) {
128 INFO("method %s called for %s", method, *appid);
132 /* nothing appropriate */
133 INFO("bad request method %s: %s", method,
134 json_object_to_json_string(json));
140 * retrieves the 'runid' in parameters received with the
141 * request 'req' for the 'method'.
143 * Returns 1 in case of success.
144 * Otherwise, if the 'runid' can't be retrieved, an error stating
145 * the bad request is replied for 'req' and 0 is returned.
147 static int onrunid(struct afb_req req, const char *method, int *runid)
149 struct json_object *json;
152 /* get the paramaters of the request */
153 json = afb_req_json(req);
155 /* get the runid if any */
156 if (!wrap_json_unpack(json, "i", runid)
157 || !wrap_json_unpack(json, "{si}", _runid_, runid)) {
158 INFO("method %s called for %d", method, *runid);
162 /* get the appid if any */
163 if (!onappid(req, method, &appid))
166 /* search the runid of the appid */
167 *runid = afm_urun_search_runid(afudb, appid, afb_req_get_uid(req));
169 /* nothing appropriate */
170 INFO("method %s can't get runid for %s: %m", method,
177 INFO("method %s called for %s -> %d", method, appid, *runid);
182 * Sends the reply 'resp' to the request 'req' if 'resp' is not NULLzero.
183 * Otherwise, when 'resp' is NULL replies the error string 'errstr'.
185 static void reply(struct afb_req req, struct json_object *resp, const char *errstr)
188 afb_req_fail(req, errstr, NULL);
190 afb_req_success(req, resp, NULL);
194 * Sends the reply "true" to the request 'req' if 'status' is zero.
195 * Otherwise, when 'status' is not zero replies the error string 'errstr'.
197 static void reply_status(struct afb_req req, int status, const char *errstr)
199 reply(req, status ? NULL : json_object_get(json_true), errstr);
203 * On query "runnables"
205 static void runnables(struct afb_req req)
208 struct json_object *resp;
210 /* get the language */
211 lang = get_lang(req);
213 /* get the details */
214 resp = afm_udb_applications_public(afudb, afb_req_get_uid(req), lang);
215 afb_req_success(req, resp, NULL);
221 static void detail(struct afb_req req)
225 struct json_object *resp;
227 /* scan the request */
228 if (!onappid(req, _detail_, &appid))
231 /* get the language */
232 lang = get_lang(req);
234 /* wants details for appid */
235 resp = afm_udb_get_application_public(afudb, appid, afb_req_get_uid(req), lang);
237 afb_req_success(req, resp, NULL);
245 static void start(struct afb_req req)
248 struct json_object *appli, *resp;
251 /* scan the request */
252 if (!onappid(req, _start_, &appid))
255 /* get the application */
256 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
262 /* launch the application */
263 runid = afm_urun_start(appli, afb_req_get_uid(req));
272 wrap_json_pack(&resp, "{si}", _runid_, runid);
274 wrap_json_pack(&resp, "i", runid);
276 afb_req_success(req, resp, NULL);
282 static void once(struct afb_req req)
285 struct json_object *appli, *resp;
288 /* scan the request */
289 if (!onappid(req, _once_, &appid))
292 /* get the application */
293 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
299 /* launch the application */
300 runid = afm_urun_once(appli, afb_req_get_uid(req));
306 /* returns the state */
307 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
308 afb_req_success(req, resp, NULL);
314 static void pause(struct afb_req req)
317 if (onrunid(req, "pause", &runid)) {
318 status = afm_urun_pause(runid, afb_req_get_uid(req));
319 reply_status(req, status, _not_found_);
324 * On query "resume" from 'smsg' with parameters of 'obj'.
326 static void resume(struct afb_req req)
329 if (onrunid(req, "resume", &runid)) {
330 status = afm_urun_resume(runid, afb_req_get_uid(req));
331 reply_status(req, status, _not_found_);
336 * On query "terminate"
338 static void terminate(struct afb_req req)
341 if (onrunid(req, "terminate", &runid)) {
342 status = afm_urun_terminate(runid, afb_req_get_uid(req));
343 reply_status(req, status, _not_found_);
350 static void runners(struct afb_req req)
352 struct json_object *resp;
353 resp = afm_urun_list(afudb, afb_req_get_uid(req));
354 afb_req_success(req, resp, NULL);
360 static void state(struct afb_req req)
363 struct json_object *resp;
364 if (onrunid(req, "state", &runid)) {
365 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
366 reply(req, resp, _not_found_);
371 * On querying installation of widget(s)
373 static void install(struct afb_req req)
379 struct wgt_info *ifo;
380 struct json_object *json;
381 struct json_object *resp;
383 /* default settings */
388 /* scan the request */
389 json = afb_req_json(req);
390 if (wrap_json_unpack(json, "s", &wgtfile)
391 && wrap_json_unpack(json, "{ss s?s s?b s?b}",
395 "reload", &reload)) {
396 return bad_request(req);
399 /* install the widget */
400 ifo = install_widget(wgtfile, root, force);
402 afb_req_fail_f(req, "failed", "installation failed: %m");
404 afm_udb_update(afudb);
405 /* reload if needed */
409 /* build the response */
410 wrap_json_pack(&resp, "{ss}", _added_, wgt_info_desc(ifo)->idaver);
411 afb_req_success(req, resp, NULL);
412 application_list_changed(_install_, wgt_info_desc(ifo)->idaver);
419 static void uninstall(struct afb_req req)
423 struct json_object *json;
426 /* default settings */
429 /* scan the request */
430 json = afb_req_json(req);
431 if (wrap_json_unpack(json, "s", &idaver)
432 && wrap_json_unpack(json, "{ss s?s}",
435 return bad_request(req);
438 /* install the widget */
439 rc = uninstall_widget(idaver, root);
441 afb_req_fail_f(req, "failed", "uninstallation failed: %m");
443 afm_udb_update(afudb);
444 afb_req_success(req, NULL, NULL);
445 application_list_changed(_uninstall_, idaver);
452 afudb = afm_udb_create(1, 0, "afm-appli-");
454 ERROR("afm_udb_create failed");
459 json_true = json_object_new_boolean(1);
461 /* create the event */
462 applist_changed_event = afb_daemon_make_event(_a_l_c_);
463 return -!afb_event_is_valid(applist_changed_event);
466 static const struct afb_auth
468 .type = afb_auth_Permission,
469 .text = "urn:AGL:permission:afm:system:widget:install"
472 .type = afb_auth_Permission,
473 .text = "urn:AGL:permission:afm:system:widget:uninstall"
477 static const struct afb_verb_v2 verbs[] =
479 {_runnables_, runnables, NULL, "Get list of runnable applications", AFB_SESSION_CHECK_V2 },
480 {_detail_ , detail, NULL, "Get the details for one application", AFB_SESSION_CHECK_V2 },
481 {_start_ , start, NULL, "Start an application", AFB_SESSION_CHECK_V2 },
482 {_once_ , once, NULL, "Start once an application", AFB_SESSION_CHECK_V2 },
483 {_terminate_, terminate, NULL, "Terminate a running application", AFB_SESSION_CHECK_V2 },
484 {_pause_ , pause, NULL, "Pause a running application", AFB_SESSION_CHECK_V2 },
485 {_resume_ , resume, NULL, "Resume a paused application", AFB_SESSION_CHECK_V2 },
486 {_runners_ , runners, NULL, "Get the list of running applications", AFB_SESSION_CHECK_V2 },
487 {_state_ , state, NULL, "Get the state of a running application", AFB_SESSION_CHECK_V2 },
488 {_install_ , install, NULL, "Install an application using a widget file", AFB_SESSION_CHECK_V2 },
489 {_uninstall_, uninstall, NULL, "Uninstall an application", AFB_SESSION_CHECK_V2 },
490 { NULL, NULL, NULL, NULL, 0 }
493 const struct afb_binding_v2 afbBindingV2 = {
495 .specification = NULL,
496 .info = "Application Framework Master Service",
501 .noconcurrency = 1 /* relies on binder for serialisation of requests */