utils-json: refactoring
[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 "utils-json.h"
30 #include "afm.h"
31 #include "afm-db.h"
32 #include "wgt-info.h"
33 #include "wgtpkg-install.h"
34 #include "wgtpkg-uninstall.h"
35
36 static const char appname[] = "afm-system-daemon";
37 static const char *rootdir = NULL;
38
39 static void usage()
40 {
41         printf(
42                 "usage: %s [-q] [-v] [-r rootdir]\n"
43                 "\n"
44                 "   -r rootdir   set root directory of applications\n"
45                 "   -d           run as a daemon\n"
46                 "   -q           quiet\n"
47                 "   -v           verbose\n"
48                 "\n",
49                 appname
50         );
51 }
52
53 static struct option options[] = {
54         { "root",        required_argument, NULL, 'r' },
55         { "daemon",      no_argument,       NULL, 'd' },
56         { "quiet",       no_argument,       NULL, 'q' },
57         { "verbose",     no_argument,       NULL, 'v' },
58         { "help",        no_argument,       NULL, 'h' },
59         { NULL, 0, NULL, 0 }
60 };
61
62 static struct jbus *jbus;
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 void on_install(struct jreq *jreq, struct json_object *req)
70 {
71         const char *wgtfile;
72         const char *root;
73         int force;
74         struct wgt_info *ifo;
75         struct json_object *resp;
76
77         /* scan the request */
78         switch (json_object_get_type(req)) {
79         case json_type_string:
80                 wgtfile = json_object_get_string(req);
81                 root = rootdir;
82                 force = 0;
83                 break;
84         case json_type_object:
85                 wgtfile = j_string_at(req, "wgt", NULL);
86                 if (wgtfile != NULL) {
87                         root = j_string_at(req, "root", rootdir);
88                         force = j_boolean_at(req, "force", 0);
89                         break;
90                 }
91         default:
92                 jbus_reply_error_s(jreq, error_bad_request);
93                 return;
94         }
95
96         /* install the widget */
97         ifo = install_widget(wgtfile, root, force);
98         if (ifo == NULL)
99                 jbus_reply_error_s(jreq, "\"installation failed\"");
100         else {
101                 /* build the response */
102                 resp = json_object_new_object();
103                 if(!resp || !j_add_string(resp, "added", wgt_info_desc(ifo)->idaver))
104                         jbus_reply_error_s(jreq, "\"out of memory but installed!\"");
105                 else
106                         jbus_reply_j(jreq, resp);
107
108                 /* clean-up */
109                 wgt_info_unref(ifo);
110                 json_object_put(resp);
111         }
112
113         /* still sends the signal */
114         jbus_send_signal_s(jbus, "changed", "true");
115 }
116
117 static void on_uninstall(struct jreq *jreq, struct json_object *req)
118 {
119         const char *idaver;
120         const char *root;
121         int rc;
122
123         /* scan the request */
124         switch (json_object_get_type(req)) {
125         case json_type_string:
126                 idaver = json_object_get_string(req);
127                 root = rootdir;
128                 break;
129         case json_type_object:
130                 idaver = j_string_at(req, "id", NULL);
131                 if (idaver != NULL) {
132                         root = j_string_at(req, "root", rootdir);
133                         break;
134                 }
135         default:
136                 jbus_reply_error_s(jreq, error_bad_request);
137                 return;
138         }
139
140         /* install the widget */
141         rc = uninstall_widget(idaver, root);
142         if (rc)
143                 jbus_reply_error_s(jreq, "\"uninstallation had error\"");
144         else
145                 jbus_reply_s(jreq, "true");
146
147         /* still sends the signal */
148         jbus_send_signal_s(jbus, "changed", "true");
149 }
150
151 static int daemonize()
152 {
153         int rc = fork();
154         if (rc < 0)
155                 return rc;
156         if (rc)
157                 _exit(0);
158         return 0;
159 }
160
161 int main(int ac, char **av)
162 {
163         int i, daemon = 0;
164
165         LOGAUTH(appname);
166
167         /* interpretation of arguments */
168         while ((i = getopt_long(ac, av, "hdqvr:", options, NULL)) >= 0) {
169                 switch (i) {
170                 case 'h':
171                         usage();
172                         return 0;
173                 case 'q':
174                         if (verbosity)
175                                 verbosity--;
176                         break;
177                 case 'v':
178                         verbosity++;
179                         break;
180                 case 'd':
181                         daemon = 1;
182                         break;
183                 case 'r':
184                         if (rootdir == NULL)
185                                 rootdir = optarg;
186                         else {
187                                 ERROR("duplicate definition of rootdir");
188                                 return 1;
189                         }
190                         break;
191                 case ':':
192                         ERROR("missing argument value");
193                         return 1;
194                 default:
195                         ERROR("unrecognized option");
196                         return 1;
197                 }
198         }
199
200         /* check the rootdir */
201         if (rootdir == NULL)
202                 rootdir = FWK_APP_DIR;
203         else {
204                 rootdir = realpath(rootdir, NULL);
205                 if (rootdir == NULL) {
206                         ERROR("out of memory");
207                         return 1;
208                 }
209         }
210         if (chdir(rootdir)) {
211                 ERROR("can't enter %s", rootdir);
212                 return 1;
213         }
214
215         /* daemonize */
216         if (daemon && daemonize()) {
217                 ERROR("daemonization failed");
218                 return 1;
219         }
220
221         /* init service */
222         jbus = create_jbus(0, AFM_SYSTEM_DBUS_PATH);
223         if (!jbus) {
224                 ERROR("create_jbus failed");
225                 return 1;
226         }
227         if(jbus_add_service_j(jbus, "install", on_install)
228         || jbus_add_service_j(jbus, "uninstall", on_uninstall)) {
229                 ERROR("adding services failed");
230                 return 1;
231         }
232
233         /* start and run */
234         if (jbus_start_serving(jbus)) {
235                 ERROR("can't start server");
236                 return 1;
237         }
238         while (!jbus_read_write_dispatch(jbus, -1));
239         return 0;
240 }
241