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