Adds 2017 to copyrights
[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 "afm.h"
33 #include "afm-db.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 usage()
42 {
43         printf(
44                 "usage: %s [-q] [-v] [-r rootdir]\n"
45                 "\n"
46                 "   -r rootdir   set root directory of applications\n"
47                 "   -d           run as a daemon\n"
48                 "   -q           quiet\n"
49                 "   -v           verbose\n"
50                 "\n",
51                 appname
52         );
53 }
54
55 static struct option options[] = {
56         { "root",        required_argument, NULL, 'r' },
57         { "daemon",      no_argument,       NULL, 'd' },
58         { "quiet",       no_argument,       NULL, 'q' },
59         { "verbose",     no_argument,       NULL, 'v' },
60         { "help",        no_argument,       NULL, 'h' },
61         { NULL, 0, NULL, 0 }
62 };
63
64 static struct jbus *jbus;
65
66 const char error_nothing[] = "[]";
67 const char error_bad_request[] = "\"bad request\"";
68 const char error_not_found[] = "\"not found\"";
69 const char error_cant_start[] = "\"can't start\"";
70
71 static void on_install(struct sd_bus_message *smsg, struct json_object *req, void *unused)
72 {
73         const char *wgtfile;
74         const char *root;
75         int force;
76         struct wgt_info *ifo;
77         struct json_object *resp;
78
79         /* scan the request */
80         switch (json_object_get_type(req)) {
81         case json_type_string:
82                 wgtfile = json_object_get_string(req);
83                 root = rootdir;
84                 force = 0;
85                 break;
86         case json_type_object:
87                 wgtfile = j_string_at(req, "wgt", NULL);
88                 if (wgtfile != NULL) {
89                         root = j_string_at(req, "root", rootdir);
90                         force = j_boolean_at(req, "force", 0);
91                         break;
92                 }
93         default:
94                 jbus_reply_error_s(smsg, error_bad_request);
95                 return;
96         }
97
98         /* install the widget */
99         ifo = install_widget(wgtfile, root, force);
100         if (ifo == NULL)
101                 jbus_reply_error_s(smsg, "\"installation failed\"");
102         else {
103                 /* build the response */
104                 resp = json_object_new_object();
105                 if(!resp || !j_add_string(resp, "added", wgt_info_desc(ifo)->idaver))
106                         jbus_reply_error_s(smsg, "\"out of memory but installed!\"");
107                 else {
108                         jbus_send_signal_s(jbus, "changed", "true");
109                         jbus_reply_j(smsg, resp);
110                 }
111
112                 /* clean-up */
113                 wgt_info_unref(ifo);
114                 json_object_put(resp);
115         }
116 }
117
118 static void on_uninstall(struct sd_bus_message *smsg, struct json_object *req, void *unused)
119 {
120         const char *idaver;
121         const char *root;
122         int rc;
123
124         /* scan the request */
125         switch (json_object_get_type(req)) {
126         case json_type_string:
127                 idaver = json_object_get_string(req);
128                 root = rootdir;
129                 break;
130         case json_type_object:
131                 idaver = j_string_at(req, "id", NULL);
132                 if (idaver != NULL) {
133                         root = j_string_at(req, "root", rootdir);
134                         break;
135                 }
136         default:
137                 jbus_reply_error_s(smsg, error_bad_request);
138                 return;
139         }
140
141         /* install the widget */
142         rc = uninstall_widget(idaver, root);
143         if (rc)
144                 jbus_reply_error_s(smsg, "\"uninstallation had error\"");
145         else {
146                 jbus_send_signal_s(jbus, "changed", "true");
147                 jbus_reply_s(smsg, "true");
148         }
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, rc;
164         struct sd_event *evloop;
165         struct sd_bus *sysbus;
166
167         LOGAUTH(appname);
168
169         /* interpretation of arguments */
170         while ((i = getopt_long(ac, av, "hdqvr:", options, NULL)) >= 0) {
171                 switch (i) {
172                 case 'h':
173                         usage();
174                         return 0;
175                 case 'q':
176                         if (verbosity)
177                                 verbosity--;
178                         break;
179                 case 'v':
180                         verbosity++;
181                         break;
182                 case 'd':
183                         daemon = 1;
184                         break;
185                 case 'r':
186                         if (rootdir == NULL)
187                                 rootdir = optarg;
188                         else {
189                                 ERROR("duplicate definition of rootdir");
190                                 return 1;
191                         }
192                         break;
193                 case ':':
194                         ERROR("missing argument value");
195                         return 1;
196                 default:
197                         ERROR("unrecognized option");
198                         return 1;
199                 }
200         }
201
202         /* check the rootdir */
203         if (rootdir == NULL)
204                 rootdir = FWK_APP_DIR;
205         else {
206                 rootdir = realpath(rootdir, NULL);
207                 if (rootdir == NULL) {
208                         ERROR("out of memory");
209                         return 1;
210                 }
211         }
212         if (chdir(rootdir)) {
213                 ERROR("can't enter %s", rootdir);
214                 return 1;
215         }
216
217         /* daemonize */
218         if (daemon && daemonize()) {
219                 ERROR("daemonization failed");
220                 return 1;
221         }
222
223         /* get systemd objects */
224         rc = sd_event_new(&evloop);
225         if (rc < 0) {
226                 ERROR("can't create event loop");
227                 return 1;
228         }
229         rc = sd_bus_open_system(&sysbus);
230         if (rc < 0) {
231                 ERROR("can't create system bus");
232                 return 1;
233         }
234         rc = sd_bus_attach_event(sysbus, evloop, 0);
235         if (rc < 0) {
236                 ERROR("can't attach system bus to event loop");
237                 return 1;
238         }
239
240         /* init service */
241         jbus = create_jbus(sysbus, AFM_SYSTEM_DBUS_PATH);
242         if (!jbus) {
243                 ERROR("create_jbus failed");
244                 return 1;
245         }
246         if(jbus_add_service_j(jbus, "install", on_install, NULL)
247         || jbus_add_service_j(jbus, "uninstall", on_uninstall, NULL)) {
248                 ERROR("adding services failed");
249                 return 1;
250         }
251
252         /* start and run */
253         if (jbus_start_serving(jbus) < 0) {
254                 ERROR("can't start server");
255                 return 1;
256         }
257         for(;;)
258                 sd_event_run(evloop, (uint64_t)-1);
259         return 0;
260 }