Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2012-2013 Bryan Drewery <bdrewery@FreeBSD.org>
5 : : * All rights reserved.
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions
9 : : * are met:
10 : : * 1. Redistributions of source code must retain the above copyright
11 : : * notice, this list of conditions and the following disclaimer
12 : : * in this position and unchanged.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : : */
28 : :
29 : : #include "pkg_config.h"
30 : :
31 : : #ifdef HAVE_CAPSICUM
32 : : #include <sys/capsicum.h>
33 : : #endif
34 : :
35 : : #include <sys/stat.h>
36 : : #include <sys/types.h>
37 : : #include <sys/wait.h>
38 : :
39 : : #include <assert.h>
40 : : #include <ctype.h>
41 : : #include <errno.h>
42 : : #include <regex.h>
43 : : #include <stdio.h>
44 : : #include <stdlib.h>
45 : : #include <stdbool.h>
46 : : #include <string.h>
47 : : #include <fcntl.h>
48 : : #include <unistd.h>
49 : : #include <err.h>
50 : :
51 : : #include "pkg.h"
52 : : #include "private/utils.h"
53 : : #include "private/event.h"
54 : : #include "private/pkg.h"
55 : : #include "private/lua.h"
56 : :
57 : : static ucl_object_t *keyword_schema = NULL;
58 : :
59 : : static int override_prefix(struct plist *, char *, struct file_attr *);
60 : : static int setprefix(struct plist *, char *, struct file_attr *);
61 : : static int dir(struct plist *, char *, struct file_attr *);
62 : : static int file(struct plist *, char *, struct file_attr *);
63 : : static int setmod(struct plist *, char *, struct file_attr *);
64 : : static int setowner(struct plist *, char *, struct file_attr *);
65 : : static int setgroup(struct plist *, char *, struct file_attr *);
66 : : static int comment_key(struct plist *, char *, struct file_attr *);
67 : : static int config(struct plist *, char *, struct file_attr *);
68 : : /* compat with old packages */
69 : : static int name_key(struct plist *, char *, struct file_attr *);
70 : : static int include_plist(struct plist *, char *, struct file_attr *);
71 : : static int add_variable(struct plist *, char *, struct file_attr *);
72 : :
73 : : static struct action_cmd {
74 : : const char *name;
75 : : int (*perform)(struct plist *, char *, struct file_attr *);
76 : : size_t namelen;
77 : : } list_actions[] = {
78 : : { "setprefix", setprefix, 9},
79 : : { "dir", dir, 3 },
80 : : { "file", file, 4 },
81 : : { "setmode", setmod, 6 },
82 : : { "setowner", setowner, 8 },
83 : : { "setgroup", setgroup, 8 },
84 : : { "comment", comment_key, 7 },
85 : : { "config", config, 6 },
86 : : { "override_prefix", override_prefix, 15 },
87 : : /* compat with old packages */
88 : : { "name", name_key, 4 },
89 : : { NULL, NULL, 0 }
90 : : };
91 : :
92 : : static ucl_object_t *
93 : 19 : keyword_open_schema(void)
94 : : {
95 : : struct ucl_parser *parser;
96 : : static const char keyword_schema_str[] = ""
97 : : "{"
98 : : " type = object;"
99 : : " properties {"
100 : : " actions = { "
101 : : " type = array; "
102 : : " items = { type = string }; "
103 : : " uniqueItems: true "
104 : : " }; "
105 : : " actions_script = { type = string }; "
106 : : " arguments = { type = boolean }; "
107 : : " preformat_arguments { type = boolean }; "
108 : : " prepackaging = { type = string }; "
109 : : " deprecated = { type = boolean }; "
110 : : " deprecation_message = { type = string }; "
111 : : " attributes = { "
112 : : " type = object; "
113 : : " properties { "
114 : : " owner = { type = string }; "
115 : : " group = { type = string }; "
116 : : " mode = { oneOf: [ { type = integer }, { type = string } ] }; "
117 : : " }"
118 : : " }; "
119 : : " pre-install = { type = string }; "
120 : : " post-install = { type = string }; "
121 : : " pre-deinstall = { type = string }; "
122 : : " post-deinstall = { type = string }; "
123 : : " pre-install-lua = { type = string }; "
124 : : " post-install-lua = { type = string }; "
125 : : " pre-deinstall-lua = { type = string }; "
126 : : " post-deinstall-lua = { type = string }; "
127 : : " messages: {"
128 : : " type = array; "
129 : : " items = {"
130 : : " type = object;"
131 : : " properties {"
132 : : " message = { type = string };"
133 : : " type = { enum = [ upgrade, remove, install ] };"
134 : : " };"
135 : : " required [ message ];"
136 : : " };"
137 : : " };"
138 : : " }"
139 : : "}";
140 : :
141 [ + + ]: 19 : if (keyword_schema != NULL)
142 : 4 : return (keyword_schema);
143 : :
144 : 15 : parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
145 [ + - ]: 15 : if (!ucl_parser_add_chunk(parser, keyword_schema_str,
146 : : sizeof(keyword_schema_str) -1)) {
147 : 0 : pkg_emit_error("Cannot parse schema for keywords: %s",
148 : 0 : ucl_parser_get_error(parser));
149 : 0 : ucl_parser_free(parser);
150 : 0 : return (NULL);
151 : : }
152 : :
153 : 15 : keyword_schema = ucl_parser_get_object(parser);
154 : 15 : ucl_parser_free(parser);
155 : :
156 : 15 : return (keyword_schema);
157 : 19 : }
158 : :
159 : : void *
160 : 12 : parse_mode(const char *str)
161 : : {
162 [ + - - + ]: 12 : if (str == NULL || *str == '\0')
163 : 0 : return (NULL);
164 : :
165 [ + + - + : 23 : if (strstr(str, "u+") || strstr(str, "o+") || strstr(str, "g+") ||
- + - + ]
166 [ - + - + : 11 : strstr(str, "u-") || strstr(str, "o-") || strstr(str, "g-") ||
- + ]
167 [ - + ]: 11 : strstr(str, "a+") || strstr(str, "a-"))
168 : 1 : return (NULL);
169 : :
170 : 11 : return (setmode(str));
171 : 12 : }
172 : :
173 : : void
174 : 83 : free_file_attr(struct file_attr *a)
175 : : {
176 [ + + ]: 83 : if (a == NULL)
177 : 67 : return;
178 : 16 : free(a->owner);
179 : 16 : free(a->group);
180 : 16 : free(a);
181 : 83 : }
182 : :
183 : : static int
184 : 2 : override_prefix(struct plist *p, char *line, struct file_attr *a __unused)
185 : : {
186 : 2 : char *np = NULL;
187 : :
188 [ - + ]: 2 : if (line[0] != '\0')
189 : 2 : np = xstrdup(line);
190 : 2 : free(p->pkg->oprefix);
191 : 2 : p->pkg->oprefix = np;
192 : 2 : return (EPKG_OK);
193 : : }
194 : :
195 : : static int
196 : 4 : setprefix(struct plist *p, char *line, struct file_attr *a __unused)
197 : : {
198 : : /* if no arguments then set default prefix */
199 [ + + ]: 4 : if (line[0] == '\0') {
200 : 1 : strlcpy(p->prefix, p->pkg->prefix, sizeof(p->prefix));
201 : 1 : }
202 : : else
203 : 3 : strlcpy(p->prefix, line, sizeof(p->prefix));
204 : :
205 [ + + ]: 4 : if (p->pkg->prefix == NULL)
206 : 1 : p->pkg->prefix = xstrdup(line);
207 : :
208 : 4 : p->slash = p->prefix[strlen(p->prefix) -1] == '/' ? "" : "/";
209 : :
210 : 4 : fprintf(p->post_install_buf->fp, "cd %s\n", p->prefix);
211 : 4 : fprintf(p->pre_deinstall_buf->fp, "cd %s\n", p->prefix);
212 : 4 : fprintf(p->post_deinstall_buf->fp, "cd %s\n", p->prefix);
213 : :
214 : 4 : return (EPKG_OK);
215 : : }
216 : :
217 : : static int
218 : 3 : name_key(struct plist *p, char *line, struct file_attr *a __unused)
219 : : {
220 : : char *tmp;
221 : :
222 [ + + ]: 3 : if (p->pkg->name != NULL) {
223 : 1 : return (EPKG_OK);
224 : : }
225 : 2 : tmp = strrchr(line, '-');
226 [ + + ]: 2 : if (tmp == NULL) {
227 : 1 : pkg_emit_error("Invalid @name key: '%s' expecting <name>-<version>", line);
228 : 1 : return (EPKG_FATAL);
229 : : }
230 : 1 : tmp[0] = '\0';
231 : 1 : tmp++;
232 : 1 : p->pkg->name = xstrdup(line);
233 : 1 : p->pkg->version = xstrdup(tmp);
234 : :
235 : 1 : return (EPKG_OK);
236 : 3 : }
237 : :
238 : : static int
239 : 8 : lua_meta(lua_State *L,
240 : : int (*perform)(struct plist *, char *, struct file_attr *))
241 : : {
242 : 8 : int n = lua_gettop(L);
243 : : int ret;
244 [ + - # # : 8 : luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
# # ]
245 : : "takes exactly one argument");
246 : 8 : char *str = strdup(luaL_checkstring(L, 1));
247 : 8 : lua_getglobal(L, "plist");
248 : 8 : struct plist *p = lua_touserdata(L, -1);
249 : 8 : lua_getglobal(L, "attrs");
250 : 8 : struct file_attr *a = lua_touserdata(L, -1);
251 : :
252 : 8 : ret = perform(p, str, a);
253 : 8 : free(str);
254 : 8 : lua_pushboolean(L, ret == EPKG_OK);
255 : 8 : return (1);
256 : : }
257 : :
258 : : static int
259 : 0 : lua_dir(lua_State *L)
260 : : {
261 : 0 : return (lua_meta(L, dir));
262 : : }
263 : :
264 : : static int
265 : 0 : lua_config(lua_State *L) {
266 : 0 : return (lua_meta(L, config));
267 : : }
268 : :
269 : : static int
270 : 8 : lua_file(lua_State *L) {
271 : 8 : return (lua_meta(L, file));
272 : : }
273 : :
274 : :
275 : : static int
276 : 6 : dir(struct plist *p, char *line, struct file_attr *a)
277 : : {
278 : : char path[MAXPATHLEN+1];
279 : : char *cp;
280 : : struct stat st;
281 : 6 : int ret = EPKG_OK;
282 : :
283 : 6 : cp = line + strlen(line) -1;
284 [ + + + - : 6 : while (cp > line && isspace(*cp)) {
- + ]
285 : 0 : *cp = 0;
286 : 0 : cp--;
287 : : }
288 : :
289 [ + + ]: 6 : if (line[0] == '/')
290 : 1 : snprintf(path, sizeof(path), "%s/", line);
291 : : else
292 : 10 : snprintf(path, sizeof(path), "%s%s%s/", p->prefix, p->slash,
293 : 5 : line);
294 : :
295 [ + + + + ]: 12 : if (fstatat(p->stagefd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW)
296 : 6 : == -1) {
297 [ + - ]: 1 : pkg_errno("Unable to access file %s%s",
298 : : p->stage ? p->stage: "", path);
299 [ - + ]: 1 : if (p->stage != NULL)
300 : 1 : ret = EPKG_FATAL;
301 [ + - ]: 1 : if (ctx.developer_mode) {
302 : 0 : pkg_emit_developer_mode("Plist error: @dir %s", line);
303 : 0 : ret = EPKG_FATAL;
304 : 0 : }
305 : 1 : } else {
306 [ + + ]: 5 : if (a != NULL)
307 : 2 : ret = pkg_adddir_attr(p->pkg, path,
308 [ + - ]: 1 : a->owner ? a->owner : p->uname,
309 [ - + ]: 1 : a->group ? a->group : p->gname,
310 [ - + ]: 1 : a->mode ? a->mode : p->perm,
311 : 1 : a->fflags, true);
312 : : else
313 : 8 : ret = pkg_adddir_attr(p->pkg, path, p->uname, p->gname,
314 : 4 : p->perm, 0, true);
315 : : }
316 : :
317 : 6 : return (ret);
318 : : }
319 : :
320 : : static int
321 : 93 : meta_file(struct plist *p, char *line, struct file_attr *a, bool is_config)
322 : : {
323 : : size_t len;
324 : : char path[MAXPATHLEN];
325 : : struct stat st;
326 : 93 : char *buf = NULL;
327 : 93 : bool regular = false;
328 : 93 : int ret = EPKG_OK;
329 : :
330 : 93 : len = strlen(line);
331 : :
332 [ - + ]: 93 : while (isspace(line[len - 1]))
333 : 0 : line[--len] = '\0';
334 : :
335 [ + + ]: 93 : if (line[0] == '/')
336 : 46 : snprintf(path, sizeof(path), "%s", line);
337 : : else
338 : 94 : snprintf(path, sizeof(path), "%s%s%s", p->prefix,
339 : 47 : p->slash, line);
340 : :
341 [ + + + + ]: 186 : if (fstatat(p->stagefd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW)
342 : 93 : == -1) {
343 [ + - ]: 6 : pkg_errno("Unable to access file %s%s",
344 : : p->stage ? p->stage : "", path);
345 [ - + ]: 6 : if (p->stage != NULL)
346 : 6 : ret = EPKG_FATAL;
347 [ + - ]: 6 : if (ctx.developer_mode) {
348 : 0 : pkg_emit_developer_mode("Plist error, missing file: %s",
349 : 0 : line);
350 : 0 : ret = EPKG_FATAL;
351 : 0 : }
352 : 6 : return (ret);
353 : : }
354 : 87 : buf = NULL;
355 : 87 : regular = false;
356 : :
357 [ + + ]: 87 : if (S_ISREG(st.st_mode)) {
358 [ + + ]: 82 : if (st.st_nlink > 1)
359 : 10 : regular = !check_for_hardlink(&p->hardlinks, &st);
360 : : else
361 : 72 : regular = true;
362 [ - + ]: 87 : } else if (S_ISLNK(st.st_mode))
363 : 5 : regular = false;
364 : :
365 : 87 : buf = pkg_checksum_generate_fileat(p->stagefd, RELATIVE_PATH(path),
366 : : PKG_HASH_TYPE_SHA256_HEX);
367 [ + - ]: 87 : if (buf == NULL) {
368 : 0 : return (EPKG_FATAL);
369 : : }
370 : :
371 [ + + ]: 87 : if (regular) {
372 : 77 : p->flatsize += st.st_size;
373 [ + + ]: 77 : if (is_config) {
374 : : off_t sz;
375 : : char *content;
376 : 13 : file_to_bufferat(p->stagefd, RELATIVE_PATH(path),
377 : : &content, &sz);
378 : 13 : ret = pkg_addconfig_file(p->pkg, path, content);
379 [ + + ]: 13 : if (ret != EPKG_OK) {
380 : 1 : return (ret);
381 : : }
382 : 12 : free(content);
383 : 12 : }
384 : 76 : }
385 : :
386 [ - + ]: 86 : if (S_ISDIR(st.st_mode)) {
387 : 0 : pkg_emit_error("Plist error, directory listed as a file: %s",
388 : 0 : line);
389 : 0 : free(buf);
390 : 0 : return (EPKG_FATAL);
391 : : }
392 : :
393 [ + + ]: 86 : if (a != NULL) {
394 : 32 : ret = pkg_addfile_attr(p->pkg, path, buf,
395 [ + + ]: 16 : a->owner ? a->owner : p->uname,
396 [ + + ]: 16 : a->group ? a->group : p->gname,
397 [ + + ]: 16 : a->mode ? a->mode : p->perm,
398 : 16 : a->fflags, true);
399 : 16 : } else {
400 : 140 : ret = pkg_addfile_attr(p->pkg, path, buf, p->uname,
401 : 70 : p->gname, p->perm, 0, true);
402 : : }
403 : :
404 : 86 : free(buf);
405 : :
406 : 86 : return (ret);
407 : 93 : }
408 : :
409 : : static int
410 : 14 : config(struct plist *p, char *line, struct file_attr *a)
411 : : {
412 : 14 : return (meta_file(p, line, a, true));
413 : : }
414 : :
415 : : static int
416 : 79 : file(struct plist *p, char *line, struct file_attr *a)
417 : : {
418 : 79 : return (meta_file(p, line, a, false));
419 : : }
420 : :
421 : : static int
422 : 2 : setmod(struct plist *p, char *line, struct file_attr *a __unused)
423 : : {
424 : : void *set;
425 : :
426 : 2 : p->perm = 0;
427 : :
428 [ + + ]: 2 : if (line[0] == '\0')
429 : 1 : return (EPKG_OK);
430 : :
431 [ + - ]: 1 : if ((set = parse_mode(line)) == NULL) {
432 : 0 : pkg_emit_error("%s wrong mode value", line);
433 : 0 : return (EPKG_FATAL);
434 : : }
435 : 1 : p->perm = getmode(set, 0);
436 : 1 : return (EPKG_OK);
437 : 2 : }
438 : :
439 : : static int
440 : 2 : setowner(struct plist *p, char *line, struct file_attr *a __unused)
441 : : {
442 : 2 : free(p->uname);
443 [ + + ]: 2 : if (line[0] == '\0')
444 : 1 : p->uname = xstrdup("root");
445 : : else
446 : 1 : p->uname = xstrdup(line);
447 : 2 : return (EPKG_OK);
448 : : }
449 : :
450 : : static int
451 : 2 : setgroup(struct plist *p, char *line, struct file_attr *a __unused)
452 : : {
453 : 2 : free(p->gname);
454 [ + + ]: 2 : if (line[0] == '\0')
455 : 1 : p->gname = xstrdup("wheel");
456 : : else
457 : 1 : p->gname = xstrdup(line);
458 : 2 : return (EPKG_OK);
459 : : }
460 : :
461 : : static int
462 : 2 : comment_key(struct plist *p __unused, char *line __unused , struct file_attr *a __unused)
463 : : {
464 : : /* ignore md5 will be recomputed anyway */
465 : 2 : return (EPKG_OK);
466 : : }
467 : :
468 : : static struct keyact {
469 : : const char *key;
470 : : int (*action)(struct plist *, char *, struct file_attr *);
471 : : } keyacts[] = {
472 : : { "cwd", setprefix },
473 : : { "comment", comment_key },
474 : : { "config", config },
475 : : { "dir", dir },
476 : : { "include", include_plist },
477 : : { "mode", setmod },
478 : : { "owner", setowner },
479 : : { "group", setgroup },
480 : : { "override_prefix", override_prefix },
481 : : { "var", add_variable },
482 : : /* old pkg compat */
483 : : { "name", name_key },
484 : : { NULL, NULL },
485 : : };
486 : :
487 : : static struct lua_map {
488 : : const char *key;
489 : : pkg_lua_script type;
490 : : } lua_mapping[] = {
491 : : { "pre-install-lua", PKG_LUA_PRE_INSTALL },
492 : : { "post-install-lua", PKG_LUA_POST_INSTALL },
493 : : { "pre-deinstall-lua", PKG_LUA_PRE_DEINSTALL },
494 : : { "post-deinstall-lua", PKG_LUA_POST_DEINSTALL },
495 : : };
496 : :
497 : : static struct script_map {
498 : : const char *key;
499 : : pkg_script type;
500 : : } script_mapping[] = {
501 : : { "pre-install", PKG_SCRIPT_PRE_INSTALL },
502 : : { "post-install", PKG_SCRIPT_POST_INSTALL },
503 : : { "pre-deinstall", PKG_SCRIPT_PRE_DEINSTALL },
504 : : { "post-deinstall", PKG_SCRIPT_POST_DEINSTALL },
505 : : };
506 : :
507 : : static void
508 : 78 : populate_keywords(struct plist *p)
509 : : {
510 : : struct keyword *k;
511 : : struct action *a;
512 : : int i;
513 : :
514 [ + + ]: 936 : for (i = 0; keyacts[i].key != NULL; i++) {
515 : 858 : k = xcalloc(1, sizeof(struct keyword));
516 : 858 : a = xmalloc(sizeof(struct action));
517 : 858 : k->keyword = xstrdup(keyacts[i].key);
518 : 858 : a->perform = keyacts[i].action;
519 [ - + + - : 858 : tll_push_back(k->actions, a);
# # - + -
+ ]
520 [ + + - + ]: 1638 : pkghash_safe_add(p->keywords, k->keyword, k, NULL);
521 : 858 : }
522 : 78 : }
523 : :
524 : : static void
525 : 858 : keyword_free(struct keyword *k)
526 : : {
527 : 858 : free(k->keyword);
528 [ + - + + : 1716 : tll_free_and_free(k->actions, free);
- + ]
529 : 858 : free(k);
530 : 858 : }
531 : :
532 : : static int
533 : 14 : parse_actions(const ucl_object_t *o, struct plist *p,
534 : : char *line, struct file_attr *a, int argc, char **argv)
535 : : {
536 : : const ucl_object_t *cur;
537 : : const char *actname;
538 : 14 : ucl_object_iter_t it = NULL;
539 : 14 : int i, j = 0;
540 : 14 : int r, rc = EPKG_OK;
541 : :
542 [ + + ]: 18 : while ((cur = ucl_iterate_object(o, &it, true))) {
543 : 5 : actname = ucl_object_tostring(cur);
544 [ - + ]: 13 : for (i = 0; list_actions[i].name != NULL; i++) {
545 [ + - ]: 31 : if (!strncasecmp(actname, list_actions[i].name,
546 [ + + + + ]: 26 : list_actions[i].namelen) &&
547 [ + - ]: 5 : (actname[list_actions[i].namelen ] == '\0' ||
548 : 5 : actname[list_actions[i].namelen ] == '(' )) {
549 : 5 : actname += list_actions[i].namelen;
550 [ - + ]: 5 : if (*actname == '(') {
551 [ + + + + ]: 10 : if (strspn(actname + 1, "1234567890")
552 : 5 : != strlen(actname + 1) - 1) {
553 : 1 : pkg_emit_error(
554 : : "Invalid argument: "
555 : : "expecting a number "
556 : 1 : "got %s", actname);
557 : 1 : return (EPKG_FATAL);
558 : : }
559 : 4 : j = strtol(actname+1, NULL, 10);
560 [ + - ]: 4 : if (j > argc) {
561 : 0 : pkg_emit_error(
562 : : "Invalid argument requested %d"
563 : 0 : " available: %d", j, argc);
564 : 0 : return (EPKG_FATAL);
565 : : }
566 : 4 : }
567 [ + - ]: 4 : r = list_actions[i].perform(p, j > 0 ? argv[j - 1] : line, a);
568 [ - + # # ]: 4 : if (r != EPKG_OK && rc == EPKG_OK)
569 : 0 : rc = r;
570 : 4 : break;
571 : : }
572 : 8 : }
573 : : }
574 : :
575 : 13 : return (rc);
576 : 14 : }
577 : :
578 : : static void
579 : 0 : parse_attributes(const ucl_object_t *o, struct file_attr **a)
580 : : {
581 : : const ucl_object_t *cur;
582 : 0 : ucl_object_iter_t it = NULL;
583 : : const char *key;
584 : :
585 [ # # ]: 0 : if (*a == NULL)
586 : 0 : *a = xcalloc(1, sizeof(struct file_attr));
587 : :
588 [ # # ]: 0 : while ((cur = ucl_iterate_object(o, &it, true))) {
589 : 0 : key = ucl_object_key(cur);
590 [ # # ]: 0 : if (key == NULL)
591 : 0 : continue;
592 [ # # # # ]: 0 : if (STRIEQ(key, "owner") && cur->type == UCL_STRING) {
593 : 0 : free((*a)->owner);
594 : 0 : (*a)->owner = xstrdup(ucl_object_tostring(cur));
595 : 0 : continue;
596 : : }
597 [ # # # # ]: 0 : if (STRIEQ(key, "group") && cur->type == UCL_STRING) {
598 : 0 : free((*a)->group);
599 : 0 : (*a)->group = xstrdup(ucl_object_tostring(cur));
600 : 0 : continue;
601 : : }
602 [ # # ]: 0 : if (STRIEQ(key, "mode")) {
603 [ # # ]: 0 : if (cur->type == UCL_STRING) {
604 : : void *set;
605 [ # # ]: 0 : if ((set = parse_mode(ucl_object_tostring(cur))) == NULL) {
606 : 0 : pkg_emit_error("Bad format for the mode attribute: %s", ucl_object_tostring(cur));
607 : 0 : return;
608 : : }
609 : 0 : (*a)->mode = getmode(set, 0);
610 : 0 : free(set);
611 : 0 : } else {
612 : 0 : pkg_emit_error("Expecting a string for the mode attribute, ignored");
613 : : }
614 : 0 : }
615 : : }
616 : 0 : }
617 : :
618 : : static void
619 : 3 : append_script(struct plist *p, pkg_script t, const char *cmd)
620 : : {
621 [ - - + - : 3 : switch (t) {
- ]
622 : : case PKG_SCRIPT_PRE_INSTALL:
623 : 0 : fprintf(p->pre_install_buf->fp, "%s\n", cmd);
624 : 0 : break;
625 : : case PKG_SCRIPT_POST_INSTALL:
626 : 3 : fprintf(p->post_install_buf->fp, "%s\n", cmd);
627 : 3 : break;
628 : : case PKG_SCRIPT_PRE_DEINSTALL:
629 : 0 : fprintf(p->pre_deinstall_buf->fp, "%s\n", cmd);
630 : 0 : break;
631 : : case PKG_SCRIPT_POST_DEINSTALL:
632 : 0 : fprintf(p->post_deinstall_buf->fp, "%s\n", cmd);
633 : 0 : break;
634 : : }
635 : 3 : }
636 : :
637 : : static int
638 : 19 : apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, struct file_attr *attr)
639 : : {
640 : : const ucl_object_t *o, *cur, *elt;
641 : 19 : ucl_object_iter_t it = NULL;
642 : : struct pkg_message *msg;
643 : : char *cmd;
644 : 19 : const char *l = line;
645 : 19 : char *formated_line = NULL;
646 : 19 : char **args = NULL;
647 : 19 : char *buf, *tofree = NULL;
648 : 19 : struct file_attr *freeattr = NULL;
649 : 19 : int spaces, argc = 0;
650 : 19 : int ret = EPKG_FATAL;
651 : :
652 [ + + - + ]: 19 : if ((o = ucl_object_find_key(obj, "arguments")) && ucl_object_toboolean(o)) {
653 : 15 : spaces = pkg_utils_count_spaces(line);
654 : 15 : args = xmalloc((spaces + 1)* sizeof(char *));
655 : 15 : tofree = buf = xstrdup(line);
656 [ + + ]: 52 : while (buf != NULL) {
657 : 37 : args[argc++] = pkg_utils_tokenize(&buf);
658 : : }
659 : 15 : }
660 : :
661 [ + - ]: 19 : if ((o = ucl_object_find_key(obj, "attributes")))
662 [ # # ]: 0 : parse_attributes(o, attr != NULL ? &attr : &freeattr);
663 : :
664 [ - + # # ]: 19 : if ((o = ucl_object_find_key(obj, "preformat_arguments")) &&
665 : 0 : ucl_object_toboolean(o)) {
666 : 0 : format_exec_cmd(&formated_line, line, p->prefix, p->last_file, NULL, 0,
667 : : NULL, false);
668 : 0 : l = formated_line;
669 : 0 : }
670 : : /* add all shell scripts */
671 [ + + ]: 92 : for (int i = 0; i < NELEM(script_mapping); i++) {
672 [ + + ]: 74 : if ((o = ucl_object_find_key(obj, script_mapping[i].key))) {
673 [ + + + + : 12 : if (format_exec_cmd(&cmd, ucl_object_tostring(o), p->prefix,
+ + ]
674 : 8 : p->last_file, l, argc, args, false) != EPKG_OK)
675 : 1 : goto keywords_cleanup;
676 : 3 : append_script(p, script_mapping[i].type, cmd);
677 : 3 : free(cmd);
678 : 3 : }
679 : 73 : }
680 : :
681 : : /* add all lua scripts */
682 [ + + ]: 90 : for (int i = 0; i < NELEM(lua_mapping); i++) {
683 [ + + ]: 72 : if ((o = ucl_object_find_key(obj, lua_mapping[i].key))) {
684 [ + - + - : 6 : if (format_exec_cmd(&cmd, ucl_object_tostring(o), p->prefix,
+ - ]
685 : 4 : p->last_file, l, argc, args, true) != EPKG_OK)
686 : 0 : goto keywords_cleanup;
687 : 2 : pkg_add_lua_script(p->pkg, cmd, lua_mapping[i].type);
688 : 2 : free(cmd);
689 : 2 : }
690 : 72 : }
691 : 18 : free(formated_line);
692 : :
693 [ + + ]: 18 : if ((o = ucl_object_find_key(obj, "messages"))) {
694 [ + + ]: 4 : while ((cur = ucl_iterate_object(o, &it, true))) {
695 : 3 : elt = ucl_object_find_key(cur, "message");
696 : 3 : msg = xcalloc(1, sizeof(*msg));
697 : 3 : msg->str = xstrdup(ucl_object_tostring(elt));
698 : 3 : msg->type = PKG_MESSAGE_ALWAYS;
699 : 3 : elt = ucl_object_find_key(cur, "type");
700 [ + + ]: 3 : if (elt != NULL) {
701 [ + + ]: 2 : if (STRIEQ(ucl_object_tostring(elt), "install"))
702 : 1 : msg->type = PKG_MESSAGE_INSTALL;
703 [ - + ]: 1 : else if (STRIEQ(ucl_object_tostring(elt), "remove"))
704 : 0 : msg->type = PKG_MESSAGE_REMOVE;
705 [ - + ]: 1 : else if (STRIEQ(ucl_object_tostring(elt), "upgrade"))
706 : 1 : msg->type = PKG_MESSAGE_UPGRADE;
707 : 2 : }
708 [ - + - + : 3 : tll_push_back(p->pkg->message, msg);
+ - + - -
+ ]
709 : : }
710 : 1 : }
711 : :
712 : 18 : ret = EPKG_OK;
713 [ + + ]: 18 : if ((o = ucl_object_find_key(obj, "actions")))
714 : 14 : ret = parse_actions(o, p, line, attr, argc, args);
715 : :
716 [ + + + + ]: 28 : if (ret == EPKG_OK && (o = ucl_object_find_key(obj, "prepackaging"))) {
717 : 10 : lua_State *L = luaL_newstate();
718 : : static const luaL_Reg plist_lib[] = {
719 : : { "config", lua_config },
720 : : { "dir", lua_dir },
721 : : { "file", lua_file },
722 : : { NULL, NULL },
723 : : };
724 : 10 : luaL_openlibs(L);
725 : 10 : lua_pushlightuserdata(L, p);
726 : 10 : lua_setglobal(L, "plist");
727 : 10 : lua_pushlightuserdata(L, attr);
728 : 10 : lua_setglobal(L, "attrs");
729 : 10 : lua_pushstring(L, line);
730 : 10 : lua_setglobal(L, "line");
731 : 10 : lua_args_table(L, args, argc);
732 : 10 : luaL_newlib(L, plist_lib);
733 : 10 : lua_setglobal(L, "pkg");
734 : 10 : lua_override_ios(L, false);
735 : 10 : pkg_debug(3, "Scripts: executing lua\n--- BEGIN ---"
736 : 10 : "\n%s\nScripts: --- END ---", ucl_object_tostring(o));
737 [ + - - + ]: 10 : if (luaL_dostring(L, ucl_object_tostring(o))) {
738 : 0 : pkg_emit_error("Failed to execute lua script: "
739 : 0 : "%s", lua_tostring(L, -1));
740 : 0 : ret = EPKG_FATAL;
741 : 0 : }
742 [ + + ]: 10 : if (lua_tonumber(L, -1) != 0) {
743 : 8 : ret = EPKG_FATAL;
744 : 8 : }
745 : 10 : lua_close(L);
746 : 10 : }
747 : :
748 : : keywords_cleanup:
749 : 19 : free(args);
750 : 19 : free(tofree);
751 : 19 : return (ret);
752 : : }
753 : :
754 : : static int
755 : 22 : external_keyword(struct plist *plist, char *keyword, char *line, struct file_attr *attr)
756 : : {
757 : : struct ucl_parser *parser;
758 : 22 : const char *keyword_dir = NULL;
759 : : char keyfile_path[MAXPATHLEN];
760 : 22 : int ret = EPKG_UNKNOWN, fd;
761 : : ucl_object_t *o, *schema;
762 : : const ucl_object_t *obj;
763 : : struct ucl_schema_error err;
764 : :
765 : 22 : keyword_dir = pkg_object_string(pkg_config_get("PLIST_KEYWORDS_DIR"));
766 [ + + ]: 22 : if (keyword_dir == NULL) {
767 : 2 : keyword_dir = pkg_object_string(pkg_config_get("PORTSDIR"));
768 : 4 : snprintf(keyfile_path, sizeof(keyfile_path),
769 : 2 : "%s/Keywords/%s.ucl", keyword_dir, keyword);
770 : 2 : } else {
771 : 40 : snprintf(keyfile_path, sizeof(keyfile_path),
772 : 20 : "%s/%s.ucl", keyword_dir, keyword);
773 : : }
774 : :
775 : 22 : fd = open(keyfile_path, O_RDONLY);
776 [ + + ]: 22 : if (fd == -1) {
777 : 3 : pkg_emit_error("cannot load keyword from %s: %s",
778 : 3 : keyfile_path, strerror(errno));
779 : 3 : return (EPKG_UNKNOWN);
780 : : }
781 : :
782 : 19 : parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
783 [ + - ]: 19 : if (!ucl_parser_add_fd(parser, fd)) {
784 : 0 : pkg_emit_error("cannot parse keyword: %s",
785 : 0 : ucl_parser_get_error(parser));
786 : 0 : ucl_parser_free(parser);
787 : 0 : close(fd);
788 : 0 : return (EPKG_UNKNOWN);
789 : : }
790 : :
791 : 19 : close(fd);
792 : 19 : o = ucl_parser_get_object(parser);
793 : 19 : ucl_parser_free(parser);
794 : :
795 : 19 : schema = keyword_open_schema();
796 : :
797 [ - + ]: 19 : if (schema != NULL) {
798 [ + - ]: 19 : if (!ucl_object_validate(schema, o, &err)) {
799 : 0 : pkg_emit_error("Keyword definition %s cannot be validated: %s", keyfile_path, err.msg);
800 : 0 : ucl_object_unref(o);
801 : 0 : return (EPKG_FATAL);
802 : : }
803 : 19 : }
804 : :
805 [ + + - + ]: 19 : if ((obj = ucl_object_find_key(o, "deprecated")) &&
806 : 2 : ucl_object_toboolean(obj)) {
807 : 2 : obj = ucl_object_find_key(o, "deprecation_message");
808 : 4 : pkg_emit_error("Use of '@%s' is deprecated%s%s", keyword,
809 : 2 : obj != NULL ? ": " : "",
810 [ + + ]: 2 : obj != NULL ? ucl_object_tostring(obj) : "");
811 [ - + ]: 2 : if (ctx.developer_mode) {
812 : 0 : ucl_object_unref(o);
813 : 0 : return (EPKG_FATAL);
814 : : }
815 : 2 : }
816 : 19 : ret = apply_keyword_file(o, plist, line, attr);
817 [ + + ]: 19 : if (ret != EPKG_OK) {
818 : 10 : pkg_emit_error("Fail to apply keyword '%s'", keyword);
819 : 10 : }
820 : :
821 : 19 : return (ret);
822 : 22 : }
823 : :
824 : : struct file_attr *
825 : 23 : parse_keyword_args(char *args, char *keyword)
826 : : {
827 : : struct file_attr *attr;
828 : : char *owner, *group, *permstr, *fflags;
829 : 23 : void *set = NULL;
830 : 23 : u_long fset = 0;
831 : :
832 : 23 : owner = group = permstr = fflags = NULL;
833 : :
834 : : /* remove last ')' */
835 : 23 : args[strlen(args) -1] = '\0';
836 : :
837 : 66 : do {
838 : 66 : args[0] = '\0';
839 : 66 : args++;
840 [ + + ]: 75 : while (isspace(*args))
841 : 9 : args++;
842 [ + + ]: 66 : if (*args == '\0')
843 : 14 : break;
844 [ + + ]: 52 : if (owner == NULL) {
845 : 21 : owner = args;
846 [ + + ]: 52 : } else if (group == NULL) {
847 : 18 : group = args;
848 [ + + ]: 31 : } else if (permstr == NULL) {
849 : 10 : permstr = args;
850 [ - + ]: 13 : } else if (fflags == NULL) {
851 : 3 : fflags = args;
852 : 3 : break;
853 : : } else {
854 : 0 : return (NULL);
855 : : }
856 [ + + ]: 49 : } while ((args = strchr(args, ',')) != NULL);
857 : :
858 [ + + - + ]: 23 : if (fflags != NULL && *fflags != '\0') {
859 : : #ifdef HAVE_STRTOFFLAGS
860 [ + + ]: 3 : if (strtofflags(&fflags, &fset, NULL) != 0) {
861 : 2 : pkg_emit_error("Malformed keyword '%s', wrong fflags",
862 : 2 : keyword);
863 : 2 : return (NULL);
864 : : }
865 : : #else
866 : : pkg_emit_error("Malformed keyword '%s', maximum 3 arguments "
867 : : "are accepted", keyword);
868 : : #endif
869 : 1 : }
870 : :
871 [ + + + + ]: 21 : if (permstr != NULL && *permstr != '\0') {
872 [ + - ]: 7 : if ((set = parse_mode(permstr)) == NULL) {
873 : 0 : pkg_emit_error("Malformed keyword '%s', wrong mode "
874 : 0 : "section", keyword);
875 : 0 : return (NULL);
876 : : }
877 : 7 : }
878 [ + + - + : 21 : if (owner == NULL && group == NULL && set == NULL)
- + ]
879 : 2 : return (NULL);
880 : :
881 : 19 : attr = xcalloc(1, sizeof(struct file_attr));
882 [ + - + + ]: 19 : if (owner != NULL && *owner != '\0')
883 : 14 : attr->owner = xstrdup(rtrimspace(owner));
884 [ + + + + ]: 19 : if (group != NULL && *group != '\0')
885 : 11 : attr->group = xstrdup(rtrimspace(group));
886 [ + + ]: 19 : if (set != NULL) {
887 : 7 : attr->mode = getmode(set, 0);
888 : 7 : free(set);
889 : 7 : }
890 : 19 : attr->fflags = fset;
891 : :
892 : 19 : return (attr);
893 : 23 : }
894 : :
895 : : static int
896 : 79 : parse_keywords(struct plist *plist, char *keyword,
897 : : char *line, struct file_attr *attr)
898 : : {
899 : 79 : struct keyword *k = NULL;
900 : 79 : int ret = EPKG_FATAL;
901 : :
902 : : /* if keyword is empty consider it as a file */
903 [ + + ]: 79 : if (*keyword == '\0')
904 : 11 : return (file(plist, line, attr));
905 : :
906 : 68 : k = pkghash_get_value(plist->keywords, keyword);
907 [ + + ]: 68 : if (k != NULL) {
908 [ + - + + : 87 : tll_foreach(k->actions, a) {
- + ]
909 : 46 : ret = a->item->perform(plist, line, attr);
910 [ + + ]: 46 : if (ret != EPKG_OK)
911 : 5 : break;
912 : 41 : }
913 : 46 : return (ret);
914 : : }
915 : :
916 : : /*
917 : : * if we are here it means the keyword has not been found
918 : : * maybe it is defined externally
919 : : * let's try to find it
920 : : */
921 : 22 : return (external_keyword(plist, keyword, line, attr));
922 : 79 : }
923 : :
924 : : char *
925 : 87 : extract_keywords(char *line, char **keyword, struct file_attr **attr)
926 : : {
927 : : char *k, *buf, *tmp;
928 : 87 : struct file_attr *a = NULL;
929 : :
930 : 87 : buf = k = line;
931 [ + + + + : 480 : while (!(isspace(buf[0]) || buf[0] == '\0')) {
+ + ]
932 [ + + + + ]: 394 : if (buf[0] == '(' && (buf = strchr(buf, ')')) == NULL)
933 : 1 : return (NULL);
934 : 393 : buf++;
935 : : }
936 [ + + ]: 86 : if (buf[0] != '\0') {
937 : 78 : buf[0] = '\0';
938 : 78 : buf++;
939 : 78 : }
940 : :
941 : : /* trim spaces after the keyword */
942 [ + + ]: 88 : while (isspace(buf[0]))
943 : 2 : buf++;
944 : :
945 : 86 : pkg_debug(1, "Parsing plist, found keyword: '%s", k);
946 : :
947 [ + + + - ]: 86 : if ((tmp = strchr(k, '(')) != NULL && k[strlen(k) -1] != ')')
948 : 0 : return (NULL);
949 : :
950 [ + + ]: 86 : if (tmp != NULL) {
951 : 18 : a = parse_keyword_args(tmp, k);
952 [ + + ]: 18 : if (a == NULL)
953 : 2 : return (NULL);
954 : 16 : }
955 : :
956 : 84 : *attr = a;
957 : 84 : *keyword = k;
958 : :
959 : 84 : return (buf);
960 : 87 : }
961 : :
962 : : static void
963 : 304 : flush_script_buffer(xstring *buf, struct pkg *p, int type)
964 : : {
965 : 304 : fflush(buf->fp);
966 [ + + ]: 304 : if (buf->buf[0] != '\0') {
967 : 3 : pkg_appendscript(p, buf->buf, type);
968 : 3 : }
969 : 304 : }
970 : :
971 : : int
972 : 142 : plist_parse_line(struct plist *plist, char *line)
973 : : {
974 : : char *buf, *bkpline;
975 : :
976 [ + + ]: 142 : if (line[0] == '\0')
977 : 4 : return (EPKG_OK);
978 : :
979 : 138 : pkg_debug(1, "Parsing plist line: '%s'", line);
980 : 138 : bkpline = xstrdup(line);
981 : :
982 [ + + ]: 138 : if (line[0] == '@') {
983 : 80 : char *keyword = 0;
984 : 80 : struct file_attr *a = 0;
985 : 80 : buf = extract_keywords(line + 1, &keyword, &a);
986 [ + + ]: 80 : if (buf == NULL) {
987 : 1 : pkg_emit_error("Malformed keyword %s, expecting @keyword "
988 : 1 : "or @keyword(owner,group,mode)", bkpline);
989 : 1 : free_file_attr(a);
990 : 1 : free(bkpline);
991 : 1 : return (EPKG_FATAL);
992 : : }
993 : :
994 [ + + + ]: 79 : switch (parse_keywords(plist, keyword, buf, a)) {
995 : : case EPKG_UNKNOWN:
996 : 18 : pkg_emit_error("unknown keyword %s: %s",
997 : 3 : keyword, line);
998 : : /* FALLTHRU */
999 : : case EPKG_FATAL:
1000 : 18 : free_file_attr(a);
1001 : 18 : free(bkpline);
1002 : 18 : return (EPKG_FATAL);
1003 : : }
1004 : 61 : free_file_attr(a);
1005 : 61 : } else {
1006 : 58 : buf = line;
1007 : 58 : strlcpy(plist->last_file, buf, sizeof(plist->last_file));
1008 : :
1009 : : /* remove spaces at the begining and at the end */
1010 [ + + ]: 60 : while (isspace(buf[0]))
1011 : 2 : buf++;
1012 : :
1013 [ + + ]: 58 : if (file(plist, buf, NULL) != EPKG_OK) {
1014 : 4 : free(bkpline);
1015 : 4 : return (EPKG_FATAL);
1016 : : }
1017 : : }
1018 : :
1019 : 115 : free(bkpline);
1020 : 115 : return (EPKG_OK);
1021 : 142 : }
1022 : :
1023 : : struct plist *
1024 : 79 : plist_new(struct pkg *pkg, const char *stage)
1025 : : {
1026 : : struct plist *p;
1027 : :
1028 : 79 : p = xcalloc(1, sizeof(struct plist));
1029 : 79 : p->plistdirfd = -1;
1030 [ + + ]: 79 : p->stagefd = open(stage ? stage : "/", O_DIRECTORY | O_CLOEXEC);
1031 [ + + ]: 79 : if (p->stagefd == -1) {
1032 : 1 : free(p);
1033 : 1 : return (NULL);
1034 : : }
1035 : :
1036 : 78 : p->pkg = pkg;
1037 [ + + ]: 78 : if (pkg->prefix != NULL)
1038 : 76 : strlcpy(p->prefix, pkg->prefix, sizeof(p->prefix));
1039 [ + + + + ]: 78 : p->slash = *p->prefix != '\0' && p->prefix[strlen(p->prefix) - 1] == '/' ? "" : "/";
1040 : 78 : p->stage = stage;
1041 : :
1042 : 78 : p->uname = xstrdup("root");
1043 : 78 : p->gname = xstrdup("wheel");
1044 : :
1045 : 78 : p->pre_install_buf = xstring_new();
1046 : 78 : p->post_install_buf = xstring_new();
1047 : 78 : p->pre_deinstall_buf = xstring_new();
1048 : 78 : p->post_deinstall_buf = xstring_new();
1049 : 78 : pkgvec_init(&p->hardlinks);
1050 : :
1051 : 78 : populate_keywords(p);
1052 : :
1053 : 78 : return (p);
1054 : 79 : }
1055 : :
1056 : : void
1057 : 78 : plist_free(struct plist *p)
1058 : : {
1059 [ + - ]: 78 : if (p == NULL)
1060 : 0 : return;
1061 : :
1062 [ - + ]: 78 : if (p->stagefd != -1)
1063 : 78 : close(p->stagefd);
1064 [ + + ]: 78 : if (p->plistdirfd != -1)
1065 : 76 : close(p->plistdirfd);
1066 : :
1067 : 78 : pkghash_it it = pkghash_iterator(p->keywords);
1068 [ + + ]: 936 : while (pkghash_next(&it))
1069 : 858 : keyword_free((struct keyword *)it.value);
1070 : 78 : pkghash_destroy(p->keywords);
1071 : 78 : p->keywords = NULL;
1072 : :
1073 : 78 : free(p->uname);
1074 : 78 : free(p->gname);
1075 [ + + ]: 83 : pkgvec_free_and_free(&p->hardlinks, free);
1076 : :
1077 : 78 : xstring_free(p->post_deinstall_buf);
1078 : 78 : xstring_free(p->post_install_buf);
1079 : 78 : xstring_free(p->pre_deinstall_buf);
1080 : 78 : xstring_free(p->pre_install_buf);
1081 : :
1082 : 78 : free(p);
1083 : 78 : }
1084 : :
1085 : : char *
1086 : 134 : expand_plist_variables(const char *in, kvlist_t *vars)
1087 : : {
1088 : : xstring *buf;
1089 : : const char *cp;
1090 : : size_t len;
1091 : :
1092 [ + + ]: 134 : if (tll_length(*vars) == 0)
1093 : 109 : return (xstrdup(in));
1094 : :
1095 : 25 : buf = xstring_new();
1096 : 25 : cp = NULL;
1097 [ + + ]: 271 : while (in[0] != '\0') {
1098 [ + + ]: 247 : if (in[0] != '%') {
1099 : 214 : fputc(in[0], buf->fp);
1100 : 214 : in++;
1101 : 214 : continue;
1102 : : }
1103 : 33 : in++;
1104 [ + + ]: 33 : if (in[0] == '\0') {
1105 : 1 : fputc('%', buf->fp);
1106 : 1 : break;
1107 : : }
1108 [ + + ]: 32 : if (in[0] != '%') {
1109 : 7 : fputc('%', buf->fp);
1110 : 7 : fputc(in[0], buf->fp);
1111 : 7 : in++;
1112 : 7 : continue;
1113 : : }
1114 : 25 : in++;
1115 : 25 : cp = in;
1116 [ + - + + : 113 : while (in[0] != '\0' && !isspace(in[0])) {
+ + ]
1117 [ + + + - ]: 109 : if (in[0] == '%' && in[1] == '%') {
1118 : 21 : in++;
1119 : 21 : break;
1120 : : }
1121 : 88 : in++;
1122 : : }
1123 [ + + ]: 25 : if (in[0] != '%') {
1124 : 4 : fprintf(buf->fp, "%%%%%.*s", (int)(in - cp), cp);
1125 : 4 : continue;
1126 : : }
1127 : 21 : len = in - cp -1;
1128 : : /* we have a variable */
1129 : 21 : bool found = false;
1130 [ + - + + : 40 : tll_foreach(*vars, i) {
+ + ]
1131 [ + + ]: 38 : if (strncmp(cp, i->item->key, len) != 0)
1132 : 19 : continue;
1133 : 19 : fputs(i->item->value, buf->fp);
1134 : 19 : found = true;
1135 : 19 : in++;
1136 : 19 : break;
1137 : : }
1138 [ + + ]: 21 : if (found)
1139 : 19 : continue;
1140 : 2 : fprintf(buf->fp, "%%%%%.*s%%", (int)(in - cp), cp);
1141 : 2 : in++;
1142 : : }
1143 : 25 : return (xstring_get(buf));
1144 : 134 : }
1145 : :
1146 : : static int
1147 : 78 : plist_parse(struct plist *pplist, FILE *f)
1148 : : {
1149 : 78 : int ret, rc = EPKG_OK;
1150 : 78 : size_t linecap = 0;
1151 : : ssize_t linelen;
1152 : 78 : char *line = NULL;
1153 : : char *l;
1154 : :
1155 [ + + ]: 203 : while ((linelen = getline(&line, &linecap, f)) > 0) {
1156 [ - + ]: 125 : if (line[linelen - 1] == '\n')
1157 : 125 : line[linelen - 1] = '\0';
1158 : 125 : l = expand_plist_variables(line, &pplist->variables);
1159 : 125 : ret = plist_parse_line(pplist, l);
1160 : 125 : free(l);
1161 [ + + + + ]: 125 : if (ret != EPKG_OK && rc == EPKG_OK)
1162 : 16 : rc = ret;
1163 : : }
1164 : 78 : free(line);
1165 : :
1166 : 78 : return (rc);
1167 : : }
1168 : :
1169 : : static int
1170 : 76 : open_directory_of(const char *file)
1171 : : {
1172 : : char path[MAXPATHLEN];
1173 : : char *walk;
1174 : :
1175 [ + + ]: 76 : if (strchr(file, '/') == NULL) {
1176 [ + - ]: 73 : if (getcwd(path, MAXPATHLEN) == NULL) {
1177 : 0 : pkg_emit_error("Unable to determine current location");
1178 : 0 : return (-1);
1179 : : }
1180 : 73 : return (open(path, O_DIRECTORY));
1181 : : }
1182 : 3 : strlcpy(path, file, sizeof(path));
1183 : 3 : walk = strrchr(path, '/');
1184 : 3 : *walk = '\0';
1185 : 3 : return (open(path, O_DIRECTORY));
1186 : 76 : }
1187 : :
1188 : : int
1189 : 8 : add_variable(struct plist *p, char *line, struct file_attr *a __unused)
1190 : : {
1191 : : const char *key;
1192 : : char *val;
1193 : :
1194 : 8 : key = val = line;
1195 [ + + + + : 40 : while (*val != '\0' && !isspace(*val))
+ + ]
1196 : 32 : val++;
1197 [ + + ]: 8 : if (*val != '\0') {
1198 : 6 : *val = '\0';
1199 : 6 : val++;
1200 : 6 : }
1201 : :
1202 [ + - ]: 8 : if (*key == '\0') {
1203 : 0 : pkg_emit_error("Inside in @include it is not allowed to reuse @include");
1204 : 0 : return (EPKG_FATAL);
1205 : : }
1206 : :
1207 [ + + + - : 8 : while (*val != '\0' && isspace(*val))
- + ]
1208 : 0 : val++;
1209 : :
1210 [ + + + + : 18 : tll_foreach(p->variables, v) {
+ + ]
1211 [ + + ]: 12 : if (STREQ(v->item->key, key)) {
1212 : 2 : free(v->item->value);
1213 : 2 : v->item->value = xstrdup(val);
1214 : 2 : return (EPKG_OK);
1215 : : }
1216 : 10 : }
1217 : 6 : struct pkg_kv *kv = pkg_kv_new(key, val);
1218 [ + + + + : 6 : tll_push_back(p->variables, kv);
+ - - + +
+ ]
1219 : 6 : return (EPKG_OK);
1220 : 8 : }
1221 : :
1222 : : int
1223 : 3 : include_plist(struct plist *p, char *name, struct file_attr *a __unused)
1224 : : {
1225 : : FILE *f;
1226 : : int fd;
1227 : : int rc;
1228 : :
1229 [ + + ]: 3 : if (p->in_include) {
1230 : 1 : pkg_emit_error("Inside in @include it is not allowed to reuse @include");
1231 : 1 : return (EPKG_FATAL);
1232 : : }
1233 : 2 : p->in_include = true;
1234 : :
1235 : 2 : fd = openat(p->plistdirfd, name, O_RDONLY);
1236 [ + - ]: 2 : if (fd == -1) {
1237 : 0 : pkg_emit_errno("Inpossible to include", name);
1238 : 0 : return (EPKG_FATAL);
1239 : : }
1240 : 2 : f = fdopen(fd, "r");
1241 [ + - ]: 2 : if (f == NULL) {
1242 : 0 : pkg_emit_errno("Inpossible to include", name);
1243 : 0 : close(fd);
1244 : 0 : return (EPKG_FATAL);
1245 : : }
1246 : :
1247 : 2 : rc = plist_parse(p, f);
1248 : :
1249 : 2 : fclose(f);
1250 : 2 : return (rc);
1251 : 3 : }
1252 : :
1253 : : int
1254 : 76 : ports_parse_plist(struct pkg *pkg, const char *plist, const char *stage)
1255 : : {
1256 : 76 : int rc = EPKG_OK;
1257 : : struct plist *pplist;
1258 : : FILE *plist_f;
1259 : :
1260 [ + - ]: 76 : assert(pkg != NULL);
1261 [ + - ]: 76 : assert(plist != NULL);
1262 : :
1263 [ + - ]: 76 : if ((pplist = plist_new(pkg, stage)) == NULL)
1264 : 0 : return (EPKG_FATAL);
1265 : :
1266 : 76 : pplist->plistdirfd = open_directory_of(plist);
1267 [ + - ]: 76 : if (pplist->plistdirfd == -1) {
1268 : 0 : pkg_emit_error("impossible to open the directory where the plist is: %s", plist);
1269 : 0 : plist_free(pplist);
1270 : 0 : return (EPKG_FATAL);
1271 : : }
1272 [ + - ]: 76 : if ((plist_f = fopen(plist, "re")) == NULL) {
1273 : 0 : pkg_emit_error("Unable to open plist file: %s", plist);
1274 : 0 : plist_free(pplist);
1275 : 0 : return (EPKG_FATAL);
1276 : : }
1277 : :
1278 : 76 : rc = plist_parse(pplist, plist_f);
1279 : :
1280 : 76 : pkg->flatsize = pplist->flatsize;
1281 : :
1282 : 76 : flush_script_buffer(pplist->pre_install_buf, pkg,
1283 : : PKG_SCRIPT_PRE_INSTALL);
1284 : 76 : flush_script_buffer(pplist->post_install_buf, pkg,
1285 : : PKG_SCRIPT_POST_INSTALL);
1286 : 76 : flush_script_buffer(pplist->pre_deinstall_buf, pkg,
1287 : : PKG_SCRIPT_PRE_DEINSTALL);
1288 : 76 : flush_script_buffer(pplist->post_deinstall_buf, pkg,
1289 : : PKG_SCRIPT_POST_DEINSTALL);
1290 : :
1291 : 76 : fclose(plist_f);
1292 : :
1293 : 76 : plist_free(pplist);
1294 : :
1295 : 76 : return (rc);
1296 : 76 : }
1297 : :
1298 : : /*
1299 : : * if the provided database is NULL then we don't want to register the package
1300 : : * in the database aka NO_PKG_REGISTER
1301 : : */
1302 : : int
1303 : 77 : pkg_add_port(struct pkgdb *db, struct pkg *pkg, const char *input_path,
1304 : : const char *reloc, bool testing)
1305 : : {
1306 : : const char *location;
1307 : 77 : int rc = EPKG_OK;
1308 : : xstring *message;
1309 : :
1310 [ + + + + ]: 77 : if (db != NULL && pkg_is_installed(db, pkg->name) != EPKG_END) {
1311 : 1 : return(EPKG_INSTALLED);
1312 : : }
1313 : :
1314 : 76 : location = reloc;
1315 [ + + ]: 76 : if (ctx.pkg_rootdir != NULL)
1316 : 2 : location = ctx.pkg_rootdir;
1317 : :
1318 [ + + - + ]: 76 : if (ctx.pkg_rootdir == NULL && location != NULL)
1319 : 0 : pkg_kv_add(&pkg->annotations, "relocated", location, "annotation");
1320 : :
1321 : 76 : pkg_emit_install_begin(pkg);
1322 : :
1323 [ + + ]: 76 : if (db != NULL) {
1324 : 75 : rc = pkgdb_register_pkg(db, pkg, 0, NULL);
1325 [ + + ]: 75 : if (rc != EPKG_OK) {
1326 : 1 : db = NULL;
1327 : 1 : goto cleanup;
1328 : : }
1329 : 74 : }
1330 : :
1331 [ + + ]: 75 : if (!testing) {
1332 : : /* Execute pre-install scripts */
1333 : 63 : pkg_lua_script_run(pkg, PKG_LUA_PRE_INSTALL, false);
1334 : 63 : pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL, false);
1335 : :
1336 [ + + ]: 63 : if (input_path != NULL) {
1337 : 3 : pkg_register_cleanup_callback(pkg_rollback_cb, pkg);
1338 : 3 : rc = pkg_add_fromdir(pkg, input_path);
1339 : 3 : pkg_unregister_cleanup_callback(pkg_rollback_cb, pkg);
1340 [ + - ]: 3 : if (rc != EPKG_OK) {
1341 : 0 : pkg_rollback_pkg(pkg);
1342 [ # # ]: 0 : if (db != NULL)
1343 : 0 : pkg_delete_dirs(db, pkg, NULL);
1344 : 0 : }
1345 : 3 : }
1346 : :
1347 : : /* Execute post-install scripts */
1348 : 63 : pkg_lua_script_run(pkg, PKG_LUA_POST_INSTALL, false);
1349 : 63 : pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL, false);
1350 : 63 : }
1351 : :
1352 [ - + ]: 75 : if (rc == EPKG_OK) {
1353 : 75 : pkg_emit_install_finished(pkg, NULL);
1354 [ + + ]: 75 : if (pkg_has_message(pkg))
1355 : 11 : message = xstring_new();
1356 [ + + + + : 94 : tll_foreach(pkg->message, m) {
+ + ]
1357 [ + + + + ]: 19 : if (m->item->type == PKG_MESSAGE_ALWAYS ||
1358 : 8 : m->item->type == PKG_MESSAGE_INSTALL) {
1359 : 13 : fprintf(message->fp, "%s\n", m->item->str);
1360 : 13 : }
1361 : 19 : }
1362 [ + + ]: 75 : if (pkg_has_message(pkg)) {
1363 : 11 : fflush(message->fp);
1364 [ - + ]: 11 : if (message->buf[0] != '\0') {
1365 : 11 : pkg_emit_message(message->buf);
1366 : 11 : }
1367 : 11 : xstring_free(message);
1368 : 11 : }
1369 : 75 : }
1370 : : /* it is impossible at this point to get any cleanup triggers to run */
1371 : 75 : triggers_execute(NULL);
1372 : :
1373 : : cleanup:
1374 [ + + ]: 76 : if (db != NULL)
1375 : 74 : pkgdb_register_finale(db, rc, NULL);
1376 : :
1377 : 76 : return (rc);
1378 : 77 : }
|