2 * Copyright (C) 2015, 2016, 2017 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 _not_found_[] = "not-found";
43 static const char _once_[] = "once";
44 static const char _pause_[] = "pause";
45 static const char _resume_[] = "resume";
46 static const char _runid_[] = "runid";
47 static const char _runnables_[] = "runnables";
48 static const char _runners_[] = "runners";
49 static const char _start_[] = "start";
50 static const char _state_[] = "state";
51 static const char _terminate_[] = "terminate";
52 static const char _uninstall_[] = "uninstall";
54 static const char *rootdir = FWK_APP_DIR;
55 static struct afb_event applist_changed_event;
56 static struct afm_udb *afudb;
57 static struct json_object *json_true;
59 static void do_reloads()
61 /* enforce daemon reload */
62 systemd_daemon_reload(0);
63 systemd_unit_restart_name(0, "sockets.target");
66 static void bad_request(struct afb_req req)
68 afb_req_fail(req, "bad-request", NULL);
71 static void not_found(struct afb_req req)
73 afb_req_fail(req, _not_found_, NULL);
76 static void cant_start(struct afb_req req)
78 afb_req_fail(req, "cannot-start", NULL);
82 * Broadcast the event "application-list-changed".
83 * This event is sent was the event "changed" is received from dbus.
85 static void application_list_changed(const char *operation, const char *data)
87 struct json_object *e = NULL;
88 wrap_json_pack(&e, "{ss ss}", "operation", operation, "data", data);
89 afb_event_broadcast(applist_changed_event, e);
93 * retrieves the 'appid' in parameters received with the
94 * request 'req' for the 'method'.
96 * Returns 1 in case of success.
97 * Otherwise, if the 'appid' can't be retrieved, an error stating
98 * the bad request is replied for 'req' and 0 is returned.
100 static int onappid(struct afb_req req, const char *method, const char **appid)
102 struct json_object *json;
104 /* get the paramaters of the request */
105 json = afb_req_json(req);
107 /* get the appid if any */
108 if (!wrap_json_unpack(json, "s", appid)
109 || !wrap_json_unpack(json, "{si}", _id_, appid)) {
111 INFO("method %s called for %s", method, *appid);
115 /* nothing appropriate */
116 INFO("bad request method %s: %s", method,
117 json_object_to_json_string(json));
123 * retrieves the 'runid' in parameters received with the
124 * request 'req' for the 'method'.
126 * Returns 1 in case of success.
127 * Otherwise, if the 'runid' can't be retrieved, an error stating
128 * the bad request is replied for 'req' and 0 is returned.
130 static int onrunid(struct afb_req req, const char *method, int *runid)
132 struct json_object *json;
134 json = afb_req_json(req);
135 if (wrap_json_unpack(json, "i", runid)
136 && wrap_json_unpack(json, "{si}", _runid_, runid)) {
137 INFO("bad request method %s: %s", method,
138 json_object_to_json_string(json));
143 INFO("method %s called for %d", method, *runid);
148 * Sends the reply 'resp' to the request 'req' if 'resp' is not NULLzero.
149 * Otherwise, when 'resp' is NULL replies the error string 'errstr'.
151 static void reply(struct afb_req req, struct json_object *resp, const char *errstr)
154 afb_req_fail(req, errstr, NULL);
156 afb_req_success(req, resp, NULL);
160 * Sends the reply "true" to the request 'req' if 'status' is zero.
161 * Otherwise, when 'status' is not zero replies the error string 'errstr'.
163 static void reply_status(struct afb_req req, int status, const char *errstr)
165 reply(req, status ? NULL : json_object_get(json_true), errstr);
169 * On query "runnables"
171 static void runnables(struct afb_req req)
173 struct json_object *resp;
174 INFO("method runnables called");
175 resp = afm_udb_applications_public(afudb, afb_req_get_uid(req));
176 afb_req_success(req, resp, NULL);
182 static void detail(struct afb_req req)
185 struct json_object *resp;
187 /* scan the request */
188 if (!onappid(req, _detail_, &appid))
191 /* wants details for appid */
192 resp = afm_udb_get_application_public(afudb, appid, afb_req_get_uid(req));
194 afb_req_success(req, resp, NULL);
202 static void start(struct afb_req req)
205 struct json_object *appli, *resp;
208 /* scan the request */
209 if (!onappid(req, _start_, &appid))
212 /* get the application */
213 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
219 /* launch the application */
220 runid = afm_urun_start(appli, afb_req_get_uid(req));
229 wrap_json_pack(&resp, "{si}", _runid_, runid);
231 wrap_json_pack(&resp, "i", runid);
233 afb_req_success(req, resp, NULL);
239 static void once(struct afb_req req)
242 struct json_object *appli, *resp;
245 /* scan the request */
246 if (!onappid(req, _once_, &appid))
249 /* get the application */
250 appli = afm_udb_get_application_private(afudb, appid, afb_req_get_uid(req));
256 /* launch the application */
257 runid = afm_urun_once(appli, afb_req_get_uid(req));
263 /* returns the state */
264 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
265 afb_req_success(req, resp, NULL);
271 static void pause(struct afb_req req)
274 if (onrunid(req, "pause", &runid)) {
275 status = afm_urun_pause(runid, afb_req_get_uid(req));
276 reply_status(req, status, _not_found_);
281 * On query "resume" from 'smsg' with parameters of 'obj'.
283 static void resume(struct afb_req req)
286 if (onrunid(req, "resume", &runid)) {
287 status = afm_urun_resume(runid, afb_req_get_uid(req));
288 reply_status(req, status, _not_found_);
293 * On query "terminate"
295 static void terminate(struct afb_req req)
298 if (onrunid(req, "terminate", &runid)) {
299 status = afm_urun_terminate(runid, afb_req_get_uid(req));
300 reply_status(req, status, _not_found_);
307 static void runners(struct afb_req req)
309 struct json_object *resp;
310 INFO("method runners called");
311 resp = afm_urun_list(afudb, afb_req_get_uid(req));
312 afb_req_success(req, resp, NULL);
318 static void state(struct afb_req req)
321 struct json_object *resp;
322 if (onrunid(req, "state", &runid)) {
323 resp = afm_urun_state(afudb, runid, afb_req_get_uid(req));
324 reply(req, resp, _not_found_);
328 static void install(struct afb_req req)
334 struct wgt_info *ifo;
335 struct json_object *json;
336 struct json_object *resp;
338 /* default settings */
343 /* scan the request */
344 json = afb_req_json(req);
345 if (wrap_json_unpack(json, "s", &wgtfile)
346 && wrap_json_unpack(json, "{ss s?s s?b s?b}",
350 "reload", &reload)) {
351 return bad_request(req);
354 /* install the widget */
355 ifo = install_widget(wgtfile, root, force);
357 afb_req_fail_f(req, "failed", "installation failed: %m");
359 afm_udb_update(afudb);
360 /* reload if needed */
364 /* build the response */
365 wrap_json_pack(&resp, "{ss}", _added_, wgt_info_desc(ifo)->idaver);
366 afb_req_success(req, resp, NULL);
367 application_list_changed(_install_, wgt_info_desc(ifo)->idaver);
374 static void uninstall(struct afb_req req)
378 struct json_object *json;
381 /* default settings */
384 /* scan the request */
385 json = afb_req_json(req);
386 if (wrap_json_unpack(json, "s", &idaver)
387 && wrap_json_unpack(json, "{ss s?s}",
390 return bad_request(req);
393 /* install the widget */
394 rc = uninstall_widget(idaver, root);
396 afb_req_fail_f(req, "failed", "uninstallation failed: %m");
398 afm_udb_update(afudb);
399 afb_req_success(req, NULL, NULL);
400 application_list_changed(_uninstall_, idaver);
407 afudb = afm_udb_create(1, 0, "afm-appli-");
409 ERROR("afm_udb_create failed");
414 json_true = json_object_new_boolean(1);
416 /* create the event */
417 applist_changed_event = afb_daemon_make_event(_a_l_c_);
418 return -!afb_event_is_valid(applist_changed_event);
421 static const struct afb_auth
423 .type = afb_auth_Permission,
424 .text = "urn:AGL:permission:afm:system:widget:install"
427 .type = afb_auth_Permission,
428 .text = "urn:AGL:permission:afm:system:widget:uninstall"
432 static const struct afb_verb_v2 verbs[] =
434 {_runnables_, runnables, NULL, "Get list of runnable applications", AFB_SESSION_CHECK_V2 },
435 {_detail_ , detail, NULL, "Get the details for one application", AFB_SESSION_CHECK_V2 },
436 {_start_ , start, NULL, "Start an application", AFB_SESSION_CHECK_V2 },
437 {_once_ , once, NULL, "Start once an application", AFB_SESSION_CHECK_V2 },
438 {_terminate_, terminate, NULL, "Terminate a running application", AFB_SESSION_CHECK_V2 },
439 {_pause_ , pause, NULL, "Pause a running application", AFB_SESSION_CHECK_V2 },
440 {_resume_ , resume, NULL, "Resume a paused application", AFB_SESSION_CHECK_V2 },
441 {_runners_ , runners, NULL, "Get the list of running applications", AFB_SESSION_CHECK_V2 },
442 {_state_ , state, NULL, "Get the state of a running application", AFB_SESSION_CHECK_V2 },
443 {_install_ , install, NULL, "Install an application using a widget file", AFB_SESSION_CHECK_V2 },
444 {_uninstall_, uninstall, NULL, "Uninstall an application", AFB_SESSION_CHECK_V2 },
445 { NULL, NULL, NULL, NULL, 0 }
448 const struct afb_binding_v2 afbBindingV2 = {
450 .specification = NULL,
451 .info = "Application Framework Master Service",
456 .noconcurrency = 1 /* relies on binder for serialisation of requests */