improve opacity and fix bug
[src/app-framework-main.git] / src / wgtpkg-install.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #define _BSD_SOURCE /* see readdir */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <dirent.h>
23 #include <unistd.h>
24 #include <limits.h>
25 #include <errno.h>
26 #include <syslog.h>
27 #include <getopt.h>
28
29 #include "verbose.h"
30 #include "wgtpkg.h"
31 #include "wgt.h"
32 #include "wgt-info.h"
33
34 static const char appname[] = "wgtpkg-install";
35 static const char *root;
36 static char **permissions = NULL;
37 static int force;
38
39 static void install(const char *wgtfile);
40 static void add_permissions(const char *list);
41
42 static void usage()
43 {
44         printf(
45                 "usage: %s [-f] [-q] [-v] [-p list] rootdir wgtfile...\n"
46                 "\n"
47                 "   rootdir       the root directory for installing\n"
48                 "   -p list       a list of comma separated permissions to allow\n"
49                 "   -f            force overwriting\n"
50                 "   -q            quiet\n"
51                 "   -v            verbose\n"
52                 "\n",
53                 appname
54         );
55 }
56
57 static struct option options[] = {
58         { "permissions", required_argument, NULL, 'p' },
59         { "force",       no_argument,       NULL, 'f' },
60         { "help",        no_argument,       NULL, 'h' },
61         { "quiet",       no_argument,       NULL, 'q' },
62         { "verbose",     no_argument,       NULL, 'v' },
63         { NULL, 0, NULL, 0 }
64 };
65
66 /* install the widgets of the list */
67 int main(int ac, char **av)
68 {
69         int i;
70         char *wpath;
71
72         openlog(appname, LOG_PERROR, LOG_AUTH);
73
74         xmlsec_init();
75
76         force = 0;
77         for (;;) {
78                 i = getopt_long(ac, av, "hfqvp:", options, NULL);
79                 if (i < 0)
80                         break;
81                 switch (i) {
82                 case 'f':
83                         force = 1;
84                         break;
85                 case 'h':
86                         usage();
87                         return 0;
88                 case 'q':
89                         if (verbosity)
90                                 verbosity--;
91                         break;
92                 case 'v':
93                         verbosity++;
94                         break;
95                 case 'p':
96                         add_permissions(optarg);
97                         break;
98                 case ':':
99                         syslog(LOG_ERR, "missing argument value");
100                         return 1;
101                 default:
102                         syslog(LOG_ERR, "unrecognized option");
103                         return 1;
104                 }
105         }
106
107         ac -= optind;
108         if (ac < 2) {
109                 syslog(LOG_ERR, "arguments are missing");
110                 return 1;
111         }
112
113         /* canonic names for files */
114         av += optind;
115         for (i = 0 ; av[i] != NULL ; i++) {
116                 wpath = realpath(av[i], NULL);
117                 if (wpath == NULL) {
118                         syslog(LOG_ERR, "error while getting realpath of %dth widget: %s", i+1, av[i]);
119                         return 1;
120                 }
121                 av[i] = wpath;
122         }
123         root = *av++;
124
125         /* install widgets */
126         for ( ; *av ; av++)
127                 install(*av);
128
129         return 0;
130 }
131
132 /* checks if the permission 'name' is granted */
133 static int has_permission(const char *name)
134 {
135         char **p = permissions;
136         if (p) {
137                 while(*p) {
138                         if (0 == strcmp(*p, name))
139                                 return 1;
140                         p++;
141                 }
142         }
143         return 0;
144 }
145
146 /* add permissions granted for installation */
147 static void add_permissions(const char *list)
148 {
149         char **ps, *p;
150         const char *iter;
151         int n, on;
152         static const char separators[] = " \t\n\r,";
153
154         n = 0;
155         iter = list + strspn(list, separators);
156         while(*iter) {
157                 n++;
158                 iter += strcspn(iter, separators);
159                 iter += strspn(iter, separators);
160         }
161         if (n == 0)
162                 return;
163
164         on = 0;
165         ps = permissions;
166         if (ps)
167                 while(*ps++)
168                         on++;
169
170         ps = realloc(permissions, (1 + on + n) * sizeof * ps);
171         if (!ps) {
172                 syslog(LOG_ERR, "Can't allocate memory for permissions");
173                 exit(1);
174         }
175
176         permissions = ps;
177         ps[on] = NULL;
178
179         iter = list + strspn(list, separators);
180         while(*iter) {
181                 n = strcspn(iter, separators);
182                 p = strndup(iter, n);
183                 if (!p) {
184                         syslog(LOG_ERR, "Can't allocate permission");
185                         exit(1);
186                 }
187                 if (has_permission(p))
188                         free(p);
189                 else {
190                         ps[on] = p;
191                         ps[++on] = NULL;
192                 }
193                 iter += n;
194                 iter += strspn(iter, separators);
195         }
196 }
197
198
199 static struct wgt *wgt_at_workdir()
200 {
201         int rc, wfd;
202         struct wgt *wgt;
203
204         wfd = workdirfd();
205         if (wfd < 0)
206                 return NULL;
207
208         wgt = wgt_create();
209         if (!wgt) {
210                 syslog(LOG_ERR, "failed to allocate wgt");
211                 close(wfd);
212                 return NULL;
213         }
214
215         rc = wgt_connectat(wgt, wfd, NULL);
216         if (rc) {
217                 syslog(LOG_ERR, "failed to connect wgt to workdir");
218                 close(wfd);
219                 wgt_unref(wgt);
220                 return NULL;
221         }
222
223         return wgt;
224 }
225
226
227 static int check_and_place()
228 {
229         struct wgt *wgt;
230         struct wgt_info *ifo;
231
232         wgt = wgt_at_workdir();
233         if (!wgt)
234                 return -1;
235
236         ifo = wgt_info_get(wgt, 1, 1, 1);
237         if (!ifo) {
238                 wgt_unref(wgt);
239                 return -1;
240         }
241         wgt_info_dump(ifo, 1, "");
242         wgt_info_unref(ifo);
243         wgt_unref(wgt);
244         return 0;
245 }
246
247 /* install the widget of the file */
248 static void install(const char *wgtfile)
249 {
250         notice("-- INSTALLING widget %s --", wgtfile);
251
252         /* workdir */
253         if (make_workdir_base(root, "UNPACK", 0)) {
254                 syslog(LOG_ERR, "failed to create a working directory");
255                 goto error1;
256         }
257
258         if (enter_workdir(0))
259                 goto error2;
260
261         if (zread(wgtfile, 0))
262                 goto error2;
263
264         if (check_all_signatures())
265                 goto error2;
266
267         if (check_and_place())
268                 goto error2;
269         
270         return;
271
272 error2:
273         remove_workdir();
274
275 error1:
276         return;
277 }
278
279