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