allows to add directories
[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 "af-db.h"
29 #include "af-run.h"
30
31 static const char appname[] = "afm-user-daemon";
32
33 static void usage()
34 {
35         printf(
36                 "usage: %s [-q] [-v] [-r rootdir]... [-a appdir]...\n"
37                 "\n"
38                 "   -a appdir    adds an application directory\n"
39                 "   -r rootdir   adds a root directory of applications\n"
40                 "   -d           run as a daemon\n"
41                 "   -q           quiet\n"
42                 "   -v           verbose\n"
43                 "\n",
44                 appname
45         );
46 }
47
48 static struct option options[] = {
49         { "root",        required_argument, NULL, 'r' },
50         { "application", required_argument, NULL, 'a' },
51         { "daemon",      no_argument,       NULL, 'd' },
52         { "quiet",       no_argument,       NULL, 'q' },
53         { "verbose",     no_argument,       NULL, 'v' },
54         { "help",        no_argument,       NULL, 'h' },
55         { NULL, 0, NULL, 0 }
56 };
57
58 static struct jbus *jbus;
59 static struct af_db *afdb;
60
61 const char error_nothing[] = "[]";
62 const char error_bad_request[] = "\"bad request\"";
63 const char error_not_found[] = "\"not found\"";
64 const char error_cant_start[] = "\"can't start\"";
65
66 static const char *getappid(struct json_object *obj)
67 {
68         return json_type_string == json_object_get_type(obj) ? json_object_get_string(obj) : NULL;
69 }
70
71 static int getrunid(struct json_object *obj)
72 {
73         return json_type_int == json_object_get_type(obj) ? json_object_get_int(obj) : 0;
74 }
75
76 static void reply(struct jreq *jreq, struct json_object *resp, const char *errstr)
77 {
78         if (resp)
79                 jbus_reply_j(jreq, resp);
80         else
81                 jbus_reply_error_s(jreq, errstr);
82 }
83
84 static void reply_status(struct jreq *jreq, int status)
85 {
86         if (status)
87                 jbus_reply_error_s(jreq, error_not_found);
88         else
89                 jbus_reply_s(jreq, "true");
90 }
91
92 static void on_runnables(struct jreq *jreq, struct json_object *obj)
93 {
94         struct json_object *resp = af_db_application_list(afdb);
95         jbus_reply_j(jreq, resp);
96         json_object_put(obj);
97 }
98
99 static void on_detail(struct jreq *jreq, struct json_object *obj)
100 {
101         const char *appid = getappid(obj);
102         struct json_object *resp = af_db_get_application_public(afdb, appid);
103         reply(jreq, resp, error_not_found);
104         json_object_put(obj);
105 }
106
107 static void on_start(struct jreq *jreq, struct json_object *obj)
108 {
109         const char *appid;
110         struct json_object *appli;
111         int runid;
112         char runidstr[20];
113
114         appid = getappid(obj);
115         if (appid == NULL)
116                 jbus_reply_error_s(jreq, error_bad_request);
117         else {
118                 appli = af_db_get_application(afdb, appid);
119                 if (appli == NULL)
120                         jbus_reply_error_s(jreq, error_not_found);
121                 else {
122                         runid = af_run_start(appli);
123                         if (runid <= 0)
124                                 jbus_reply_error_s(jreq, error_cant_start);
125                         else {
126                                 snprintf(runidstr, sizeof runidstr, "%d", runid);
127                                 runidstr[sizeof runidstr - 1] = 0;
128                                 jbus_reply_s(jreq, runidstr);
129                         }
130                 }
131         }
132         json_object_put(obj);
133 }
134
135 static void on_stop(struct jreq *jreq, struct json_object *obj)
136 {
137         int runid = getrunid(obj);
138         int status = af_run_stop(runid);
139         reply_status(jreq, status);
140         json_object_put(obj);
141 }
142
143 static void on_continue(struct jreq *jreq, struct json_object *obj)
144 {
145         int runid = getrunid(obj);
146         int status = af_run_continue(runid);
147         reply_status(jreq, status);
148         json_object_put(obj);
149 }
150
151 static void on_terminate(struct jreq *jreq, struct json_object *obj)
152 {
153         int runid = getrunid(obj);
154         int status = af_run_terminate(runid);
155         reply_status(jreq, status);
156         json_object_put(obj);
157 }
158
159 static void on_runners(struct jreq *jreq, struct json_object *obj)
160 {
161         struct json_object *resp = af_run_list();
162         jbus_reply_j(jreq, resp);
163         json_object_put(resp);
164         json_object_put(obj);
165 }
166
167 static void on_state(struct jreq *jreq, struct json_object *obj)
168 {
169         int runid = getrunid(obj);
170         struct json_object *resp = af_run_state(runid);
171         reply(jreq, resp, error_not_found);
172         json_object_put(resp);
173         json_object_put(obj);
174 }
175
176 static int daemonize()
177 {
178         int rc = fork();
179         if (rc < 0)
180                 return rc;
181         if (rc)
182                 _exit(0);
183         return 0;
184 }
185
186 int main(int ac, char **av)
187 {
188         int i, daemon = 0;
189
190         LOGAUTH(appname);
191
192         /* first interpretation of arguments */
193         while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
194                 switch (i) {
195                 case 'h':
196                         usage();
197                         return 0;
198                 case 'q':
199                         if (verbosity)
200                                 verbosity--;
201                         break;
202                 case 'v':
203                         verbosity++;
204                         break;
205                 case 'd':
206                         daemon = 1;
207                         break;
208                 case 'r':
209                         break;
210                 case 'a':
211                         break;
212                 case ':':
213                         ERROR("missing argument value");
214                         return 1;
215                 default:
216                         ERROR("unrecognized option");
217                         return 1;
218                 }
219         }
220
221         /* init random generator */
222         srandom((unsigned int)time(NULL));
223
224         /* init runners */
225         if (af_run_init()) {
226                 ERROR("af_run_init failed");
227                 return 1;
228         }
229
230         /* init framework */
231         afdb = af_db_create();
232         if (!afdb) {
233                 ERROR("af_create failed");
234                 return 1;
235         }
236         if (af_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 (af_db_add_root(afdb, optarg)) {
247                                 ERROR("can't add root %s", optarg);
248                                 return 1;
249                         }
250                         break;
251                 case 'a':
252                         if (af_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 (af_db_update_applications(afdb)) {
262                 ERROR("af_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(1, "/org/AGL/afmMain");
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, "start", on_start)
280         || jbus_add_service_j(jbus, "terminate", on_terminate)
281         || jbus_add_service_j(jbus, "stop", on_stop)
282         || jbus_add_service_j(jbus, "continue", on_continue)
283         || jbus_add_service_j(jbus, "runners", on_runners)
284         || jbus_add_service_j(jbus, "state", on_state)) {
285                 ERROR("adding services failed");
286                 return 1;
287         }
288
289         /* start and run */
290         if (jbus_start_serving(jbus)) {
291                 ERROR("cant start server");
292                 return 1;
293         }
294         while (!jbus_read_write_dispatch(jbus, -1));
295         return 0;
296 }
297