e0557f411f7a6e738df3a838c221e461ff40bd56
[src/app-framework-main.git] / src / afm-system-daemon.c
1 /*
2  Copyright 2015, 2016, 2017 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 <systemd/sd-bus.h>
26 #include <systemd/sd-event.h>
27 #include <json-c/json.h>
28
29 #include "verbose.h"
30 #include "utils-jbus.h"
31 #include "utils-json.h"
32 #include "utils-systemd.h"
33 #include "afm.h"
34 #include "afm-db.h"
35 #include "wgt-info.h"
36 #include "wgtpkg-install.h"
37 #include "wgtpkg-uninstall.h"
38
39 static const char appname[] = "afm-system-daemon";
40 static const char *rootdir = NULL;
41
42 static void usage()
43 {
44         printf(
45                 "usage: %s [-q] [-v] [-r rootdir]\n"
46                 "\n"
47                 "   -r rootdir   set root directory of applications\n"
48                 "   -d           run as a daemon\n"
49                 "   -q           quiet\n"
50                 "   -v           verbose\n"
51                 "\n",
52                 appname
53         );
54 }
55
56 static struct option options[] = {
57         { "root",        required_argument, NULL, 'r' },
58         { "daemon",      no_argument,       NULL, 'd' },
59         { "quiet",       no_argument,       NULL, 'q' },
60         { "verbose",     no_argument,       NULL, 'v' },
61         { "help",        no_argument,       NULL, 'h' },
62         { NULL, 0, NULL, 0 }
63 };
64
65 static struct jbus *jbus;
66
67 const char error_nothing[] = "[]";
68 const char error_bad_request[] = "\"bad request\"";
69 const char error_not_found[] = "\"not found\"";
70 const char error_cant_start[] = "\"can't start\"";
71
72 static void do_reloads()
73 {
74 #ifndef LEGACY_MODE_WITHOUT_SYSTEMD
75         /* enforce daemon reload */
76         systemd_daemon_reload(0);
77         systemd_unit_restart_name(0, "sockets.target");
78 #endif
79 }
80
81 static void on_install(struct sd_bus_message *smsg, struct json_object *req, void *unused)
82 {
83         const char *wgtfile;
84         const char *root;
85         int force;
86         int reload;
87         struct wgt_info *ifo;
88         struct json_object *resp;
89
90         /* scan the request */
91         switch (json_object_get_type(req)) {
92         case json_type_string:
93                 wgtfile = json_object_get_string(req);
94                 root = rootdir;
95                 force = 0;
96                 reload = 1;
97                 break;
98         case json_type_object:
99                 wgtfile = j_string_at(req, "wgt", NULL);
100                 if (wgtfile != NULL) {
101                         root = j_string_at(req, "root", rootdir);
102                         force = j_boolean_at(req, "force", 0);
103                         reload = j_boolean_at(req, "reload", 1);
104                         break;
105                 }
106                 /*@fallthrough@*/
107         default:
108                 jbus_reply_error_s(smsg, error_bad_request);
109                 return;
110         }
111
112         /* install the widget */
113         ifo = install_widget(wgtfile, root, force);
114         if (ifo == NULL)
115                 jbus_reply_error_s(smsg, "\"installation failed\"");
116         else {
117                 /* reload if needed */
118                 if (reload)
119                         do_reloads();
120
121                 /* build the response */
122                 resp = json_object_new_object();
123                 if(!resp || !j_add_string(resp, "added", wgt_info_desc(ifo)->idaver))
124                         jbus_reply_error_s(smsg, "\"out of memory but installed!\"");
125                 else {
126                         jbus_send_signal_s(jbus, "changed", "true");
127                         jbus_reply_j(smsg, resp);
128                 }
129
130                 /* clean-up */
131                 wgt_info_unref(ifo);
132                 json_object_put(resp);
133         }
134 }
135
136 static void on_uninstall(struct sd_bus_message *smsg, struct json_object *req, void *unused)
137 {
138         const char *idaver;
139         const char *root;
140         int rc;
141
142         /* scan the request */
143         switch (json_object_get_type(req)) {
144         case json_type_string:
145                 idaver = json_object_get_string(req);
146                 root = rootdir;
147                 break;
148         case json_type_object:
149                 idaver = j_string_at(req, "id", NULL);
150                 if (idaver != NULL) {
151                         root = j_string_at(req, "root", rootdir);
152                         break;
153                 }
154                 /*@fallthrough@*/
155         default:
156                 jbus_reply_error_s(smsg, error_bad_request);
157                 return;
158         }
159
160         /* install the widget */
161         rc = uninstall_widget(idaver, root);
162         if (rc)
163                 jbus_reply_error_s(smsg, "\"uninstallation had error\"");
164         else {
165                 jbus_send_signal_s(jbus, "changed", "true");
166                 jbus_reply_s(smsg, "true");
167         }
168 }
169
170 static int daemonize()
171 {
172         int rc = fork();
173         if (rc < 0)
174                 return rc;
175         if (rc)
176                 _exit(0);
177         return 0;
178 }
179
180 int main(int ac, char **av)
181 {
182         int i, daemon = 0, rc;
183         struct sd_event *evloop;
184         struct sd_bus *sysbus;
185
186         LOGAUTH(appname);
187
188         /* interpretation of arguments */
189         while ((i = getopt_long(ac, av, "hdqvr:", options, NULL)) >= 0) {
190                 switch (i) {
191                 case 'h':
192                         usage();
193                         return 0;
194                 case 'q':
195                         if (verbosity)
196                                 verbosity--;
197                         break;
198                 case 'v':
199                         verbosity++;
200                         break;
201                 case 'd':
202                         daemon = 1;
203                         break;
204                 case 'r':
205                         if (rootdir == NULL)
206                                 rootdir = optarg;
207                         else {
208                                 ERROR("duplicate definition of rootdir");
209                                 return 1;
210                         }
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         /* check the rootdir */
222         if (rootdir == NULL)
223                 rootdir = FWK_APP_DIR;
224         else {
225                 rootdir = realpath(rootdir, NULL);
226                 if (rootdir == NULL) {
227                         ERROR("out of memory");
228                         return 1;
229                 }
230         }
231         if (chdir(rootdir)) {
232                 ERROR("can't enter %s", rootdir);
233                 return 1;
234         }
235
236         /* daemonize */
237         if (daemon && daemonize()) {
238                 ERROR("daemonization failed");
239                 return 1;
240         }
241
242         /* get systemd objects */
243         rc = sd_event_new(&evloop);
244         if (rc < 0) {
245                 ERROR("can't create event loop");
246                 return 1;
247         }
248         rc = sd_bus_open_system(&sysbus);
249         if (rc < 0) {
250                 ERROR("can't create system bus");
251                 return 1;
252         }
253         rc = sd_bus_attach_event(sysbus, evloop, 0);
254         if (rc < 0) {
255                 ERROR("can't attach system bus to event loop");
256                 return 1;
257         }
258
259         /* init service */
260         jbus = create_jbus(sysbus, AFM_SYSTEM_DBUS_PATH);
261         if (!jbus) {
262                 ERROR("create_jbus failed");
263                 return 1;
264         }
265         if(jbus_add_service_j(jbus, "install", on_install, NULL)
266         || jbus_add_service_j(jbus, "uninstall", on_uninstall, NULL)) {
267                 ERROR("adding services failed");
268                 return 1;
269         }
270
271         /* start and run */
272         if (jbus_start_serving(jbus) < 0) {
273                 ERROR("can't start server");
274                 return 1;
275         }
276         for(;;)
277                 sd_event_run(evloop, (uint64_t)-1);
278         return 0;
279 }