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