Moves handling of reloads
[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         default:
107                 jbus_reply_error_s(smsg, error_bad_request);
108                 return;
109         }
110
111         /* install the widget */
112         ifo = install_widget(wgtfile, root, force);
113         if (ifo == NULL)
114                 jbus_reply_error_s(smsg, "\"installation failed\"");
115         else {
116                 /* reload if needed */
117                 if (reload)
118                         do_reloads();
119
120                 /* build the response */
121                 resp = json_object_new_object();
122                 if(!resp || !j_add_string(resp, "added", wgt_info_desc(ifo)->idaver))
123                         jbus_reply_error_s(smsg, "\"out of memory but installed!\"");
124                 else {
125                         jbus_send_signal_s(jbus, "changed", "true");
126                         jbus_reply_j(smsg, resp);
127                 }
128
129                 /* clean-up */
130                 wgt_info_unref(ifo);
131                 json_object_put(resp);
132         }
133 }
134
135 static void on_uninstall(struct sd_bus_message *smsg, struct json_object *req, void *unused)
136 {
137         const char *idaver;
138         const char *root;
139         int rc;
140
141         /* scan the request */
142         switch (json_object_get_type(req)) {
143         case json_type_string:
144                 idaver = json_object_get_string(req);
145                 root = rootdir;
146                 break;
147         case json_type_object:
148                 idaver = j_string_at(req, "id", NULL);
149                 if (idaver != NULL) {
150                         root = j_string_at(req, "root", rootdir);
151                         break;
152                 }
153         default:
154                 jbus_reply_error_s(smsg, error_bad_request);
155                 return;
156         }
157
158         /* install the widget */
159         rc = uninstall_widget(idaver, root);
160         if (rc)
161                 jbus_reply_error_s(smsg, "\"uninstallation had error\"");
162         else {
163                 jbus_send_signal_s(jbus, "changed", "true");
164                 jbus_reply_s(smsg, "true");
165         }
166 }
167
168 static int daemonize()
169 {
170         int rc = fork();
171         if (rc < 0)
172                 return rc;
173         if (rc)
174                 _exit(0);
175         return 0;
176 }
177
178 int main(int ac, char **av)
179 {
180         int i, daemon = 0, rc;
181         struct sd_event *evloop;
182         struct sd_bus *sysbus;
183
184         LOGAUTH(appname);
185
186         /* interpretation of arguments */
187         while ((i = getopt_long(ac, av, "hdqvr:", options, NULL)) >= 0) {
188                 switch (i) {
189                 case 'h':
190                         usage();
191                         return 0;
192                 case 'q':
193                         if (verbosity)
194                                 verbosity--;
195                         break;
196                 case 'v':
197                         verbosity++;
198                         break;
199                 case 'd':
200                         daemon = 1;
201                         break;
202                 case 'r':
203                         if (rootdir == NULL)
204                                 rootdir = optarg;
205                         else {
206                                 ERROR("duplicate definition of rootdir");
207                                 return 1;
208                         }
209                         break;
210                 case ':':
211                         ERROR("missing argument value");
212                         return 1;
213                 default:
214                         ERROR("unrecognized option");
215                         return 1;
216                 }
217         }
218
219         /* check the rootdir */
220         if (rootdir == NULL)
221                 rootdir = FWK_APP_DIR;
222         else {
223                 rootdir = realpath(rootdir, NULL);
224                 if (rootdir == NULL) {
225                         ERROR("out of memory");
226                         return 1;
227                 }
228         }
229         if (chdir(rootdir)) {
230                 ERROR("can't enter %s", rootdir);
231                 return 1;
232         }
233
234         /* daemonize */
235         if (daemon && daemonize()) {
236                 ERROR("daemonization failed");
237                 return 1;
238         }
239
240         /* get systemd objects */
241         rc = sd_event_new(&evloop);
242         if (rc < 0) {
243                 ERROR("can't create event loop");
244                 return 1;
245         }
246         rc = sd_bus_open_system(&sysbus);
247         if (rc < 0) {
248                 ERROR("can't create system bus");
249                 return 1;
250         }
251         rc = sd_bus_attach_event(sysbus, evloop, 0);
252         if (rc < 0) {
253                 ERROR("can't attach system bus to event loop");
254                 return 1;
255         }
256
257         /* init service */
258         jbus = create_jbus(sysbus, AFM_SYSTEM_DBUS_PATH);
259         if (!jbus) {
260                 ERROR("create_jbus failed");
261                 return 1;
262         }
263         if(jbus_add_service_j(jbus, "install", on_install, NULL)
264         || jbus_add_service_j(jbus, "uninstall", on_uninstall, NULL)) {
265                 ERROR("adding services failed");
266                 return 1;
267         }
268
269         /* start and run */
270         if (jbus_start_serving(jbus) < 0) {
271                 ERROR("can't start server");
272                 return 1;
273         }
274         for(;;)
275                 sd_event_run(evloop, (uint64_t)-1);
276         return 0;
277 }