70d8656ee87c4cec804f5636620aaee8fd8ded50
[src/app-framework-main.git] / src / afm-system-daemon.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
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
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
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.
17 */
18
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <time.h>
22 #include <getopt.h>
23 #include <errno.h>
24
25 #include <json.h>
26
27 #include "verbose.h"
28 #include "utils-jbus.h"
29 #include "afm.h"
30 #include "afm-db.h"
31 #include "wgt-info.h"
32 #include "wgtpkg-install.h"
33
34 static const char appname[] = "afm-system-daemon";
35
36 static void usage()
37 {
38         printf(
39                 "usage: %s [-q] [-v] [-r rootdir]... [-a appdir]...\n"
40                 "\n"
41                 "   -a appdir    adds an application directory\n"
42                 "   -r rootdir   adds a root directory of applications\n"
43                 "   -d           run as a daemon\n"
44                 "   -q           quiet\n"
45                 "   -v           verbose\n"
46                 "\n",
47                 appname
48         );
49 }
50
51 static struct option options[] = {
52         { "root",        required_argument, NULL, 'r' },
53         { "application", required_argument, NULL, 'a' },
54         { "daemon",      no_argument,       NULL, 'd' },
55         { "quiet",       no_argument,       NULL, 'q' },
56         { "verbose",     no_argument,       NULL, 'v' },
57         { "help",        no_argument,       NULL, 'h' },
58         { NULL, 0, NULL, 0 }
59 };
60
61 static struct jbus *jbus;
62 static struct afm_db *afdb;
63
64 const char error_nothing[] = "[]";
65 const char error_bad_request[] = "\"bad request\"";
66 const char error_not_found[] = "\"not found\"";
67 const char error_cant_start[] = "\"can't start\"";
68
69 static const char *getappid(struct json_object *obj)
70 {
71         return json_type_string == json_object_get_type(obj) ? json_object_get_string(obj) : NULL;
72 }
73
74 static void reply(struct jreq *jreq, struct json_object *resp, const char *errstr)
75 {
76         if (resp)
77                 jbus_reply_j(jreq, resp);
78         else
79                 jbus_reply_error_s(jreq, errstr);
80 }
81
82 static void on_runnables(struct jreq *jreq, struct json_object *obj)
83 {
84         struct json_object *resp = afm_db_application_list(afdb);
85         jbus_reply_j(jreq, resp);
86         json_object_put(resp);
87 }
88
89 static void on_detail(struct jreq *jreq, struct json_object *obj)
90 {
91         const char *appid = getappid(obj);
92         struct json_object *resp = afm_db_get_application_public(afdb, appid);
93         reply(jreq, resp, error_not_found);
94         json_object_put(resp);
95 }
96
97 static const char *j_get_string(struct json_object *obj, const char *key, const char *defval)
98 {
99         struct json_object *o;
100         return json_object_object_get_ex(obj, key, &o) && json_object_get_type(o) == json_type_string ? json_object_get_string(o) : defval;
101 }
102
103 static int j_get_boolean(struct json_object *obj, const char *key, int defval)
104 {
105         struct json_object *o;
106         return json_object_object_get_ex(obj, key, &o) && json_object_get_type(o) == json_type_boolean ? json_object_get_boolean(o) : defval;
107 }
108
109 static int json_add(struct json_object *obj, const char *key, struct json_object *val)
110 {
111         json_object_object_add(obj, key, val);
112         return 0;
113 }
114
115 static int json_add_str(struct json_object *obj, const char *key, const char *val)
116 {
117         struct json_object *str = json_object_new_string (val ? val : "");
118         return str ? json_add(obj, key, str) : (errno = ENOMEM, -1);
119 }
120 /*
121 static int json_add_int(struct json_object *obj, const char *key, int val)
122 {
123         struct json_object *v = json_object_new_int (val);
124         return v ? json_add(obj, key, v) : (errno = ENOMEM, -1);
125 }
126 */
127 static void on_install(struct jreq *jreq, struct json_object *req)
128 {
129         const char *wgtfile;
130         const char *root;
131         int force;
132         struct wgt_info *ifo;
133         struct json_object *resp;
134
135         /* scan the request */
136         switch (json_object_get_type(req)) {
137         case json_type_string:
138                 wgtfile = json_object_get_string(req);
139                 root = FWK_APP_DIR;
140                 force = 0;
141                 break;
142         case json_type_object:
143                 wgtfile = j_get_string(req, "wgt", NULL);
144                 if (wgtfile != NULL) {
145                         root = j_get_string(req, "root", FWK_APP_DIR);
146                         force = j_get_boolean(req, "force", 0);
147                         break;
148                 }
149         default:
150                 jbus_reply_error_s(jreq, error_bad_request);
151                 return;
152         }
153
154         /* install the widget */
155         ifo = install_widget(wgtfile, root, force);
156         if (ifo == NULL) {
157                 jbus_reply_error_s(jreq, "\"installation failed\"");
158                 return;
159         }
160
161         /* build the response */
162         resp = json_object_new_object();
163         if(!resp || json_add_str(resp, "added", wgt_info_desc(ifo)->idaver)) {
164                 json_object_put(resp);
165                 wgt_info_unref(ifo);
166                 jbus_reply_error_s(jreq, "\"out of memory but installed!\"");
167                 return;
168         }
169         wgt_info_unref(ifo);
170
171         /* update the current database */
172         afm_db_update_applications(afdb);
173
174         /* reply and propagate event */
175         jbus_reply_j(jreq, resp);
176         jbus_send_signal_j(jbus, "changed", resp);
177         json_object_put(resp);
178 }
179
180 static void on_uninstall(struct jreq *jreq, struct json_object *req)
181 {
182         jbus_reply_error_s(jreq, "\"not yet implemented\"");
183 }
184
185 static int daemonize()
186 {
187         int rc = fork();
188         if (rc < 0)
189                 return rc;
190         if (rc)
191                 _exit(0);
192         return 0;
193 }
194
195 int main(int ac, char **av)
196 {
197         int i, daemon = 0;
198
199         LOGAUTH(appname);
200
201         /* first interpretation of arguments */
202         while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
203                 switch (i) {
204                 case 'h':
205                         usage();
206                         return 0;
207                 case 'q':
208                         if (verbosity)
209                                 verbosity--;
210                         break;
211                 case 'v':
212                         verbosity++;
213                         break;
214                 case 'd':
215                         daemon = 1;
216                         break;
217                 case 'r':
218                         break;
219                 case 'a':
220                         break;
221                 case ':':
222                         ERROR("missing argument value");
223                         return 1;
224                 default:
225                         ERROR("unrecognized option");
226                         return 1;
227                 }
228         }
229
230         /* init framework */
231         afdb = afm_db_create();
232         if (!afdb) {
233                 ERROR("afm_create failed");
234                 return 1;
235         }
236         if (afm_db_add_root(afdb, FWK_APP_DIR)) {
237                 ERROR("can't add root %s", FWK_APP_DIR);
238                 return 1;
239         }
240
241         /* second interpretation of arguments */
242         optind = 1;
243         while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
244                 switch (i) {
245                 case 'r':
246                         if (afm_db_add_root(afdb, optarg)) {
247                                 ERROR("can't add root %s", optarg);
248                                 return 1;
249                         }
250                         break;
251                 case 'a':
252                         if (afm_db_add_application(afdb, optarg)) {
253                                 ERROR("can't add application %s", optarg);
254                                 return 1;
255                         }
256                         break;
257                 }
258         }
259
260         /* update the database */
261         if (afm_db_update_applications(afdb)) {
262                 ERROR("afm_update_applications failed");
263                 return 1;
264         }
265
266         if (daemon && daemonize()) {
267                 ERROR("daemonization failed");
268                 return 1;
269         }
270
271         /* init service */
272         jbus = create_jbus(0, AFM_SYSTEM_DBUS_PATH);
273         if (!jbus) {
274                 ERROR("create_jbus failed");
275                 return 1;
276         }
277         if(jbus_add_service_j(jbus, "runnables", on_runnables)
278         || jbus_add_service_j(jbus, "detail", on_detail)
279         || jbus_add_service_j(jbus, "install", on_install)
280         || jbus_add_service_j(jbus, "uninstall", on_uninstall)) {
281                 ERROR("adding services failed");
282                 return 1;
283         }
284
285         /* start and run */
286         if (jbus_start_serving(jbus)) {
287                 ERROR("can't start server");
288                 return 1;
289         }
290         while (!jbus_read_write_dispatch(jbus, -1));
291         return 0;
292 }
293