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