utils-jbus: adds closure
[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, void *unused)
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_send_signal_s(jbus, "changed", "true");
107                         jbus_reply_j(jreq, resp);
108                 }
109
110                 /* clean-up */
111                 wgt_info_unref(ifo);
112                 json_object_put(resp);
113         }
114 }
115
116 static void on_uninstall(struct jreq *jreq, struct json_object *req, void *unused)
117 {
118         const char *idaver;
119         const char *root;
120         int rc;
121
122         /* scan the request */
123         switch (json_object_get_type(req)) {
124         case json_type_string:
125                 idaver = json_object_get_string(req);
126                 root = rootdir;
127                 break;
128         case json_type_object:
129                 idaver = j_string_at(req, "id", NULL);
130                 if (idaver != NULL) {
131                         root = j_string_at(req, "root", rootdir);
132                         break;
133                 }
134         default:
135                 jbus_reply_error_s(jreq, error_bad_request);
136                 return;
137         }
138
139         /* install the widget */
140         rc = uninstall_widget(idaver, root);
141         if (rc)
142                 jbus_reply_error_s(jreq, "\"uninstallation had error\"");
143         else {
144                 jbus_send_signal_s(jbus, "changed", "true");
145                 jbus_reply_s(jreq, "true");
146         }
147 }
148
149 static int daemonize()
150 {
151         int rc = fork();
152         if (rc < 0)
153                 return rc;
154         if (rc)
155                 _exit(0);
156         return 0;
157 }
158
159 int main(int ac, char **av)
160 {
161         int i, daemon = 0;
162
163         LOGAUTH(appname);
164
165         /* interpretation of arguments */
166         while ((i = getopt_long(ac, av, "hdqvr:", options, NULL)) >= 0) {
167                 switch (i) {
168                 case 'h':
169                         usage();
170                         return 0;
171                 case 'q':
172                         if (verbosity)
173                                 verbosity--;
174                         break;
175                 case 'v':
176                         verbosity++;
177                         break;
178                 case 'd':
179                         daemon = 1;
180                         break;
181                 case 'r':
182                         if (rootdir == NULL)
183                                 rootdir = optarg;
184                         else {
185                                 ERROR("duplicate definition of rootdir");
186                                 return 1;
187                         }
188                         break;
189                 case ':':
190                         ERROR("missing argument value");
191                         return 1;
192                 default:
193                         ERROR("unrecognized option");
194                         return 1;
195                 }
196         }
197
198         /* check the rootdir */
199         if (rootdir == NULL)
200                 rootdir = FWK_APP_DIR;
201         else {
202                 rootdir = realpath(rootdir, NULL);
203                 if (rootdir == NULL) {
204                         ERROR("out of memory");
205                         return 1;
206                 }
207         }
208         if (chdir(rootdir)) {
209                 ERROR("can't enter %s", rootdir);
210                 return 1;
211         }
212
213         /* daemonize */
214         if (daemon && daemonize()) {
215                 ERROR("daemonization failed");
216                 return 1;
217         }
218
219         /* init service */
220         jbus = create_jbus_system(AFM_SYSTEM_DBUS_PATH);
221         if (!jbus) {
222                 ERROR("create_jbus failed");
223                 return 1;
224         }
225         if(jbus_add_service_j(jbus, "install", on_install, NULL)
226         || jbus_add_service_j(jbus, "uninstall", on_uninstall, NULL)) {
227                 ERROR("adding services failed");
228                 return 1;
229         }
230
231         /* start and run */
232         if (jbus_start_serving(jbus)) {
233                 ERROR("can't start server");
234                 return 1;
235         }
236         while (!jbus_read_write_dispatch(jbus, -1));
237         return 0;
238 }
239