refactoring and moving forward
[src/app-framework-main.git] / src / afm-user-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
24 #include <json.h>
25
26 #include "verbose.h"
27 #include "utils-jbus.h"
28 #include "afm.h"
29 #include "afm-db.h"
30 #include "afm-run.h"
31
32 static const char appname[] = "afm-user-daemon";
33
34 static void usage()
35 {
36         printf(
37                 "usage: %s [-q] [-v] [-r rootdir]... [-a appdir]...\n"
38                 "\n"
39                 "   -a appdir    adds an application directory\n"
40                 "   -r rootdir   adds a root directory of applications\n"
41                 "   -d           run as a daemon\n"
42                 "   -q           quiet\n"
43                 "   -v           verbose\n"
44                 "\n",
45                 appname
46         );
47 }
48
49 static struct option options[] = {
50         { "root",        required_argument, NULL, 'r' },
51         { "application", required_argument, NULL, 'a' },
52         { "daemon",      no_argument,       NULL, 'd' },
53         { "quiet",       no_argument,       NULL, 'q' },
54         { "verbose",     no_argument,       NULL, 'v' },
55         { "help",        no_argument,       NULL, 'h' },
56         { NULL, 0, NULL, 0 }
57 };
58
59 static struct jbus *jbus;
60 static struct jbus *jbusys;
61 static struct afm_db *afdb;
62
63 const char error_nothing[] = "[]";
64 const char error_bad_request[] = "\"bad request\"";
65 const char error_not_found[] = "\"not found\"";
66 const char error_cant_start[] = "\"can't start\"";
67
68 static const char *getappid(struct json_object *obj)
69 {
70         return json_type_string == json_object_get_type(obj) ? json_object_get_string(obj) : NULL;
71 }
72
73 static int getrunid(struct json_object *obj)
74 {
75         return json_type_int == json_object_get_type(obj) ? json_object_get_int(obj) : 0;
76 }
77
78 static void reply(struct jreq *jreq, struct json_object *resp, const char *errstr)
79 {
80         if (resp)
81                 jbus_reply_j(jreq, resp);
82         else
83                 jbus_reply_error_s(jreq, errstr);
84 }
85
86 static void reply_status(struct jreq *jreq, int status)
87 {
88         if (status)
89                 jbus_reply_error_s(jreq, error_not_found);
90         else
91                 jbus_reply_s(jreq, "true");
92 }
93
94 static void on_runnables(struct jreq *jreq, struct json_object *obj)
95 {
96         struct json_object *resp = afm_db_application_list(afdb);
97         jbus_reply_j(jreq, resp);
98         json_object_put(resp);
99 }
100
101 static void on_detail(struct jreq *jreq, struct json_object *obj)
102 {
103         const char *appid = getappid(obj);
104         struct json_object *resp = afm_db_get_application_public(afdb, appid);
105         reply(jreq, resp, error_not_found);
106         json_object_put(resp);
107 }
108
109 static void on_start(struct jreq *jreq, struct json_object *obj)
110 {
111         const char *appid;
112         struct json_object *appli;
113         int runid;
114         char runidstr[20];
115
116         appid = getappid(obj);
117         if (appid == NULL)
118                 jbus_reply_error_s(jreq, error_bad_request);
119         else {
120                 appli = afm_db_get_application(afdb, appid);
121                 if (appli == NULL)
122                         jbus_reply_error_s(jreq, error_not_found);
123                 else {
124                         runid = afm_run_start(appli);
125                         if (runid <= 0)
126                                 jbus_reply_error_s(jreq, error_cant_start);
127                         else {
128                                 snprintf(runidstr, sizeof runidstr, "%d", runid);
129                                 runidstr[sizeof runidstr - 1] = 0;
130                                 jbus_reply_s(jreq, runidstr);
131                         }
132                 }
133         }
134 }
135
136 static void on_stop(struct jreq *jreq, struct json_object *obj)
137 {
138         int runid = getrunid(obj);
139         int status = afm_run_stop(runid);
140         reply_status(jreq, status);
141 }
142
143 static void on_continue(struct jreq *jreq, struct json_object *obj)
144 {
145         int runid = getrunid(obj);
146         int status = afm_run_continue(runid);
147         reply_status(jreq, status);
148 }
149
150 static void on_terminate(struct jreq *jreq, struct json_object *obj)
151 {
152         int runid = getrunid(obj);
153         int status = afm_run_terminate(runid);
154         reply_status(jreq, status);
155 }
156
157 static void on_runners(struct jreq *jreq, struct json_object *obj)
158 {
159         struct json_object *resp = afm_run_list();
160         jbus_reply_j(jreq, resp);
161         json_object_put(resp);
162 }
163
164 static void on_state(struct jreq *jreq, struct json_object *obj)
165 {
166         int runid = getrunid(obj);
167         struct json_object *resp = afm_run_state(runid);
168         reply(jreq, resp, error_not_found);
169         json_object_put(resp);
170 }
171
172 static void on_signal_changed(struct json_object *obj)
173 {
174         /* update the database */
175         afm_db_update_applications(afdb);
176         /* propagate now */
177         jbus_send_signal_j(jbus, "changed", obj);
178 }
179
180 static int daemonize()
181 {
182         int rc = fork();
183         if (rc < 0)
184                 return rc;
185         if (rc)
186                 _exit(0);
187         return 0;
188 }
189
190 int main(int ac, char **av)
191 {
192         int i, daemon = 0;
193
194         LOGAUTH(appname);
195
196         /* first interpretation of arguments */
197         while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
198                 switch (i) {
199                 case 'h':
200                         usage();
201                         return 0;
202                 case 'q':
203                         if (verbosity)
204                                 verbosity--;
205                         break;
206                 case 'v':
207                         verbosity++;
208                         break;
209                 case 'd':
210                         daemon = 1;
211                         break;
212                 case 'r':
213                         break;
214                 case 'a':
215                         break;
216                 case ':':
217                         ERROR("missing argument value");
218                         return 1;
219                 default:
220                         ERROR("unrecognized option");
221                         return 1;
222                 }
223         }
224
225         /* init random generator */
226         srandom((unsigned int)time(NULL));
227
228         /* init runners */
229         if (afm_run_init()) {
230                 ERROR("afm_run_init failed");
231                 return 1;
232         }
233
234         /* init framework */
235         afdb = afm_db_create();
236         if (!afdb) {
237                 ERROR("afm_create failed");
238                 return 1;
239         }
240         if (afm_db_add_root(afdb, FWK_APP_DIR)) {
241                 ERROR("can't add root %s", FWK_APP_DIR);
242                 return 1;
243         }
244
245         /* second interpretation of arguments */
246         optind = 1;
247         while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
248                 switch (i) {
249                 case 'r':
250                         if (afm_db_add_root(afdb, optarg)) {
251                                 ERROR("can't add root %s", optarg);
252                                 return 1;
253                         }
254                         break;
255                 case 'a':
256                         if (afm_db_add_application(afdb, optarg)) {
257                                 ERROR("can't add application %s", optarg);
258                                 return 1;
259                         }
260                         break;
261                 }
262         }
263
264         /* update the database */
265         if (afm_db_update_applications(afdb)) {
266                 ERROR("afm_update_applications failed");
267                 return 1;
268         }
269
270         if (daemon && daemonize()) {
271                 ERROR("daemonization failed");
272                 return 1;
273         }
274
275         /* init observers */
276         jbusys = create_jbus(0, AFM_SYSTEM_DBUS_PATH);
277         if (!jbusys) {
278                 ERROR("create_jbus failed for system");
279                 return 1;
280         }
281         if(jbus_on_signal_j(jbusys, "changed", on_signal_changed)) {
282                 ERROR("adding signal observer failed");
283                 return 1;
284         }
285
286         /* init service */
287         jbus = create_jbus(1, AFM_USER_DBUS_PATH);
288         if (!jbus) {
289                 ERROR("create_jbus failed");
290                 return 1;
291         }
292         if(jbus_add_service_j(jbus, "runnables", on_runnables)
293         || jbus_add_service_j(jbus, "detail", on_detail)
294         || jbus_add_service_j(jbus, "start", on_start)
295         || jbus_add_service_j(jbus, "terminate", on_terminate)
296         || jbus_add_service_j(jbus, "stop", on_stop)
297         || jbus_add_service_j(jbus, "continue", on_continue)
298         || jbus_add_service_j(jbus, "runners", on_runners)
299         || jbus_add_service_j(jbus, "state", on_state)) {
300                 ERROR("adding services failed");
301                 return 1;
302         }
303
304         /* start and run */
305         if (jbus_start_serving(jbus)) {
306                 ERROR("cant start server");
307                 return 1;
308         }
309         while (!jbus_read_write_dispatch(jbus, -1));
310         return 0;
311 }
312