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