Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/pkg.c
2645 views
1
/*-
2
* Copyright (c) 2011-2025 Baptiste Daroussin <[email protected]>
3
* Copyright (c) 2011-2012 Julien Laffaye <[email protected]>
4
* Copyright (c) 2012 Bryan Drewery <[email protected]>
5
* Copyright (c) 2013 Matthew Seaman <[email protected]>
6
* Copyright (c) 2017 Vsevolod Stakhov <[email protected]>
7
* Copyright (c) 2023, Serenity Cyber Security, LLC
8
* Author: Gleb Popov <[email protected]>
9
*
10
* SPDX-License-Identifier: BSD-2-Clause
11
*/
12
13
#include <archive.h>
14
#include <archive_entry.h>
15
#include <assert.h>
16
#include <errno.h>
17
#include <fcntl.h>
18
#include <string.h>
19
#include <pwd.h>
20
#include <grp.h>
21
22
#include "pkg.h"
23
#include "private/event.h"
24
#include "private/pkg.h"
25
#include "private/pkgdb.h"
26
#include "private/utils.h"
27
#include "xmalloc.h"
28
29
#define dbg(x, ...) pkg_dbg(PKG_DBG_PACKAGE, x, __VA_ARGS__)
30
31
int
32
pkg_new(struct pkg **pkg, pkg_t type)
33
{
34
*pkg = xcalloc(1, sizeof(struct pkg));
35
(*pkg)->type = type;
36
(*pkg)->rootfd = -1;
37
(*pkg)->list_sorted = false;
38
39
return (EPKG_OK);
40
}
41
42
static void
43
pkg_message_free(struct pkg_message *m)
44
{
45
free(m->str);
46
free(m->maximum_version);
47
free(m->minimum_version);
48
free(m);
49
}
50
51
void
52
pkg_free(struct pkg *pkg)
53
{
54
if (pkg == NULL)
55
return;
56
57
free(pkg->name);
58
free(pkg->origin);
59
free(pkg->old_version);
60
free(pkg->version);
61
free(pkg->maintainer);
62
free(pkg->www);
63
free(pkg->altabi);
64
free(pkg->abi);
65
free(pkg->uid);
66
free(pkg->digest);
67
free(pkg->old_digest);
68
free(pkg->prefix);
69
free(pkg->oprefix);
70
free(pkg->comment);
71
free(pkg->desc);
72
free(pkg->sum);
73
free(pkg->repopath);
74
free(pkg->reponame);
75
free(pkg->repourl);
76
free(pkg->reason);
77
free(pkg->dep_formula);
78
free(pkg->rootpath);
79
80
for (int i = 0; i < PKG_NUM_SCRIPTS; i++)
81
xstring_free(pkg->scripts[i]);
82
for (int i = 0; i < PKG_NUM_LUA_SCRIPTS; i++)
83
vec_free_and_free(&pkg->lua_scripts[i], free);
84
85
pkg_list_free(pkg, PKG_DEPS);
86
pkg_list_free(pkg, PKG_RDEPS);
87
pkg_list_free(pkg, PKG_FILES);
88
pkg_list_free(pkg, PKG_DIRS);
89
pkg_list_free(pkg, PKG_OPTIONS);
90
pkg_list_free(pkg, PKG_CONFIG_FILES);
91
92
vec_free_and_free(&pkg->users, free);
93
pkg->flags &= ~PKG_LOAD_USERS;
94
vec_free_and_free(&pkg->groups, free);
95
pkg->flags &= ~PKG_LOAD_GROUPS;
96
vec_free_and_free(&pkg->shlibs_required, free);
97
pkg->flags &= ~PKG_LOAD_SHLIBS_REQUIRED;
98
vec_free_and_free(&pkg->shlibs_required_ignore, free);
99
pkg->flags &= ~PKG_LOAD_SHLIBS_REQUIRED_IGNORE;
100
vec_free_and_free(&pkg->shlibs_provided, free);
101
pkg->flags &= ~PKG_LOAD_SHLIBS_PROVIDED;
102
vec_free_and_free(&pkg->shlibs_provided_ignore, free);
103
pkg->flags &= ~PKG_LOAD_SHLIBS_PROVIDED_IGNORE;
104
vec_free_and_free(&pkg->provides, free);
105
pkg->flags &= ~PKG_LOAD_PROVIDES;
106
vec_free_and_free(&pkg->requires, free);
107
pkg->flags &= ~PKG_LOAD_REQUIRES;
108
vec_free_and_free(&pkg->categories, free);
109
pkg->flags &= ~PKG_LOAD_CATEGORIES;
110
vec_free_and_free(&pkg->licenses, free);
111
pkg->flags &= ~PKG_LOAD_LICENSES;
112
113
vec_free_and_free(&pkg->message, pkg_message_free);
114
vec_free_and_free(&pkg->annotations, pkg_kv_free);
115
116
vec_free_and_free(&pkg->dir_to_del, free);
117
118
if (pkg->rootfd != -1)
119
close(pkg->rootfd);
120
121
free(pkg);
122
}
123
124
pkg_t
125
pkg_type(const struct pkg * restrict pkg)
126
{
127
assert(pkg != NULL);
128
129
return (pkg->type);
130
}
131
132
int
133
pkg_is_valid(const struct pkg * restrict pkg)
134
{
135
if (pkg == NULL) {
136
pkg_emit_error("Invalid package: not allocated");
137
return (EPKG_FATAL);
138
}
139
140
if (pkg->origin == NULL) {
141
pkg_emit_error("Invalid package: object has missing property origin");
142
return (EPKG_FATAL);
143
}
144
145
if (pkg->name == NULL) {
146
pkg_emit_error("Invalid package: object has missing property name");
147
return (EPKG_FATAL);
148
}
149
150
if (pkg->comment == NULL) {
151
pkg_emit_error("Invalid package: object has missing property comment");
152
return (EPKG_FATAL);
153
}
154
155
if (pkg->version == NULL) {
156
pkg_emit_error("Invalid package: object has missing property version");
157
return (EPKG_FATAL);
158
}
159
160
if (pkg->desc == NULL) {
161
pkg_emit_error("Invalid package: object has missing property desc");
162
return (EPKG_FATAL);
163
}
164
165
if (pkg->maintainer == NULL) {
166
pkg_emit_error("Invalid package: object has missing property maintainer");
167
return (EPKG_FATAL);
168
}
169
170
if (pkg->www == NULL) {
171
pkg_emit_error("Invalid package: object has missing property www");
172
return (EPKG_FATAL);
173
}
174
175
if (pkg->prefix == NULL) {
176
pkg_emit_error("Invalid package: object has missing property prefix");
177
return (EPKG_FATAL);
178
}
179
180
return (EPKG_OK);
181
}
182
183
int
184
pkg_set_i(struct pkg *pkg, pkg_attr attr, int64_t val)
185
{
186
switch (attr) {
187
case PKG_ATTR_FLATSIZE:
188
pkg->flatsize = val;
189
break;
190
case PKG_ATTR_OLD_FLATSIZE:
191
pkg->old_flatsize = val;
192
break;
193
case PKG_ATTR_PKGSIZE:
194
pkg->pkgsize = val;
195
break;
196
case PKG_ATTR_TIME:
197
pkg->timestamp = val;
198
break;
199
default:
200
pkg_emit_error("%d does not accept int64_t values", attr);
201
return (EPKG_FATAL);
202
}
203
return (EPKG_OK);
204
}
205
206
int
207
pkg_set_b(struct pkg *pkg, pkg_attr attr, bool boolean)
208
{
209
switch (attr) {
210
case PKG_ATTR_AUTOMATIC:
211
pkg->automatic = boolean;
212
break;
213
case PKG_ATTR_LOCKED:
214
pkg->locked = boolean;
215
break;
216
case PKG_ATTR_VITAL:
217
pkg->vital = boolean;
218
break;
219
default:
220
pkg_emit_error("%d does not accept bool values", attr);
221
return (EPKG_FATAL);
222
}
223
return (EPKG_OK);
224
}
225
226
int
227
pkg_set_s(struct pkg *pkg, pkg_attr attr, const char *str)
228
{
229
char *endptr;
230
ucl_object_t *obj;
231
int64_t i;
232
233
switch (attr) {
234
case PKG_ATTR_NAME:
235
free(pkg->name);
236
pkg->name = xstrdup(str);
237
free(pkg->uid);
238
pkg->uid = xstrdup(str);
239
break;
240
case PKG_ATTR_ORIGIN:
241
free(pkg->origin);
242
pkg->origin = xstrdup(str);
243
break;
244
case PKG_ATTR_VERSION:
245
free(pkg->version);
246
pkg->version = xstrdup(str);
247
break;
248
case PKG_ATTR_DESC:
249
free(pkg->desc);
250
pkg->desc = xstrdup(str);
251
break;
252
case PKG_ATTR_COMMENT:
253
free(pkg->comment);
254
pkg->comment = xstrdup(str);
255
break;
256
case PKG_ATTR_MESSAGE:
257
vec_free_and_free(&pkg->message, pkg_message_free);
258
if (*str == '[') {
259
pkg_message_from_str(pkg, str, strlen(str));
260
} else {
261
obj = ucl_object_fromstring_common(str, strlen(str),
262
UCL_STRING_RAW|UCL_STRING_TRIM);
263
pkg_message_from_ucl(pkg, obj);
264
ucl_object_unref(obj);
265
}
266
break;
267
case PKG_ATTR_ARCH:
268
free(pkg->altabi);
269
pkg->altabi = xstrdup(str);
270
break;
271
case PKG_ATTR_ABI:
272
free(pkg->abi);
273
pkg->abi = xstrdup(str);
274
break;
275
case PKG_ATTR_MAINTAINER:
276
free(pkg->maintainer);
277
pkg->maintainer = xstrdup(str);
278
break;
279
case PKG_ATTR_WWW:
280
free(pkg->www);
281
pkg->www = xstrdup(str);
282
break;
283
case PKG_ATTR_PREFIX:
284
free(pkg->prefix);
285
pkg->prefix = xstrdup(str);
286
break;
287
case PKG_ATTR_REPOPATH:
288
free(pkg->repopath);
289
pkg->repopath = xstrdup(str);
290
break;
291
case PKG_ATTR_CKSUM:
292
free(pkg->sum);
293
pkg->sum = xstrdup(str);
294
break;
295
case PKG_ATTR_OLD_VERSION:
296
free(pkg->old_version);
297
pkg->old_version = xstrdup(str);
298
break;
299
case PKG_ATTR_REPONAME:
300
free(pkg->reponame);
301
pkg->reponame = xstrdup(str);
302
break;
303
case PKG_ATTR_REPOURL:
304
free(pkg->repourl);
305
pkg->repourl = xstrdup(str);
306
break;
307
case PKG_ATTR_DIGEST:
308
free(pkg->digest);
309
pkg->digest = xstrdup(str);
310
break;
311
case PKG_ATTR_REASON:
312
free(pkg->reason);
313
pkg->reason = xstrdup(str);
314
break;
315
case PKG_ATTR_DEP_FORMULA:
316
free(pkg->dep_formula);
317
pkg->dep_formula = xstrdup(str);
318
break;
319
case PKG_ATTR_FLATSIZE:
320
i = strtoimax(str, &endptr, 10);
321
if (endptr != NULL) {
322
pkg_emit_error("Impossible to convert '%s' to int64_t",
323
str);
324
return (EPKG_FATAL);
325
}
326
pkg->flatsize = i;
327
break;
328
case PKG_ATTR_OLD_FLATSIZE:
329
i = strtoimax(str, &endptr, 10);
330
if (endptr != NULL) {
331
pkg_emit_error("Impossible to convert '%s' to int64_t",
332
str);
333
return (EPKG_FATAL);
334
}
335
pkg->old_flatsize = i;
336
break;
337
case PKG_ATTR_PKGSIZE:
338
i = strtoimax(str, &endptr, 10);
339
if (endptr != NULL) {
340
pkg_emit_error("Impossible to convert '%s' to int64_t",
341
str);
342
return (EPKG_FATAL);
343
}
344
pkg->pkgsize = i;
345
break;
346
case PKG_ATTR_TIME:
347
i = strtoimax(str, &endptr, 10);
348
if (endptr != NULL) {
349
pkg_emit_error("Impossible to convert '%s' to int64_t",
350
str);
351
return (EPKG_FATAL);
352
}
353
pkg->timestamp = i;
354
break;
355
default:
356
pkg_emit_error("%d does not accept string values", attr);
357
return (EPKG_FATAL);
358
}
359
return (EPKG_OK);
360
}
361
362
int
363
pkg_set_from_fileat(int fd, struct pkg *pkg, pkg_attr attr, const char *path,
364
bool trimcr)
365
{
366
char *buf = NULL;
367
char *cp;
368
off_t size = 0;
369
int ret = EPKG_OK;
370
371
assert(pkg != NULL);
372
assert(path != NULL);
373
374
if ((ret = file_to_bufferat(fd, path, &buf, &size)) != EPKG_OK)
375
return (ret);
376
377
if (trimcr) {
378
cp = buf + strlen(buf) - 1;
379
while (cp > buf && *cp == '\n') {
380
*cp = 0;
381
cp--;
382
}
383
}
384
385
ret = pkg_set(pkg, attr, buf);
386
387
free(buf);
388
389
return (ret);
390
}
391
392
#define pkg_each(name, type, field) \
393
int \
394
pkg_##name(const struct pkg *p, type **t) { \
395
assert(p != NULL); \
396
if ((*t) == NULL) \
397
(*t) = p->field; \
398
else \
399
(*t) = (*t)->next; \
400
if ((*t) == NULL) \
401
return (EPKG_END); \
402
return (EPKG_OK); \
403
}
404
405
pkg_each(dirs, struct pkg_dir, dirs);
406
pkg_each(files, struct pkg_file, files);
407
pkg_each(deps, struct pkg_dep, depends);
408
pkg_each(rdeps, struct pkg_dep, rdepends);
409
pkg_each(options, struct pkg_option, options);
410
pkg_each(conflicts, struct pkg_conflict, conflicts);
411
pkg_each(config_files, struct pkg_config_file, config_files);
412
413
int
414
pkg_adduser(struct pkg *pkg, const char *name)
415
{
416
return (pkg_addstring(&pkg->users, name, "user"));
417
}
418
419
int
420
pkg_addgroup(struct pkg *pkg, const char *name)
421
{
422
return (pkg_addstring(&pkg->groups, name, "group"));
423
}
424
425
int
426
pkg_adddep(struct pkg *pkg, const char *name, const char *origin, const char *version, bool locked)
427
{
428
if (pkg_adddep_chain(NULL, pkg, name, origin, version, locked) == NULL) {
429
return (EPKG_FATAL);
430
}
431
432
return (EPKG_OK);
433
}
434
435
struct pkg_dep *
436
pkg_adddep_chain(struct pkg_dep *chain,
437
struct pkg *pkg,
438
const char *name,
439
const char *origin,
440
const char *version, bool locked)
441
{
442
struct pkg_dep *d = NULL;
443
444
assert(pkg != NULL);
445
assert(name != NULL && name[0] != '\0');
446
447
dbg(3, "add a new dependency origin: %s, name: %s", origin ? origin : "", name);
448
if (pkghash_get(pkg->depshash, name) != NULL) {
449
pkg_emit_error("%s: duplicate dependency listing: %s",
450
pkg->name, name);
451
return (NULL);
452
}
453
454
d = xcalloc(1, sizeof(*d));
455
if (origin != NULL && origin[0] != '\0')
456
d->origin = xstrdup(origin);
457
d->name = xstrdup(name);
458
if (version != NULL && version[0] != '\0')
459
d->version = xstrdup(version);
460
d->uid = xstrdup(name);
461
d->locked = locked;
462
463
pkghash_safe_add(pkg->depshash, d->name, d, NULL);
464
if (chain == NULL) {
465
DL_APPEND(pkg->depends, d);
466
chain = pkg->depends;
467
}
468
else {
469
DL_APPEND2(chain, d, alt_prev, alt_next);
470
}
471
472
return (chain);
473
}
474
475
int
476
pkg_addrdep(struct pkg *pkg, const char *name, const char *origin, const char *version, bool locked)
477
{
478
struct pkg_dep *d;
479
480
assert(pkg != NULL);
481
assert(name != NULL && name[0] != '\0');
482
483
dbg(3, "add a new reverse dependency origin: %s, name: %s", origin ? origin : "", name);
484
485
d = xcalloc(1, sizeof(*d));
486
if (origin != NULL && origin[0] != '\0')
487
d->origin = xstrdup(origin);
488
d->name = xstrdup(name);
489
if (version != NULL && version[0] != '\0')
490
d->version = xstrdup(version);
491
d->uid = xstrdup(name);
492
d->locked = locked;
493
494
pkghash_safe_add(pkg->rdepshash, d->name, d, NULL);
495
LL_PREPEND(pkg->rdepends, d);
496
497
return (EPKG_OK);
498
}
499
500
int
501
pkg_addfile(struct pkg *pkg, const char *path, const char *sum, bool check_duplicates)
502
{
503
return (pkg_addfile_attr(pkg, path, sum, NULL, NULL, 0, 0, 0, NULL, check_duplicates));
504
}
505
506
int
507
pkg_addfile_attr(struct pkg *pkg, const char *path, const char *sum,
508
const char *uname, const char *gname, mode_t perm,
509
u_long fflags, time_t mtime,
510
const char *symlink_target, bool check_duplicates)
511
{
512
struct pkg_file *f = NULL;
513
char abspath[MAXPATHLEN];
514
515
assert(pkg != NULL);
516
assert(path != NULL && path[0] != '\0');
517
518
path = pkg_absolutepath(path, abspath, sizeof(abspath), false);
519
dbg(3, "add new file '%s'", path);
520
521
if (check_duplicates && pkghash_get(pkg->filehash, path) != NULL) {
522
if (ctx.developer_mode) {
523
pkg_emit_error("duplicate file listing: %s, fatal (developer mode)", path);
524
return (EPKG_FATAL);
525
} else {
526
pkg_emit_error("duplicate file listing: %s, ignoring", path);
527
return (EPKG_OK);
528
}
529
}
530
531
f = xcalloc(1, sizeof(*f));
532
f->path = xstrdup(path);
533
534
if (sum != NULL)
535
f->sum = xstrdup(sum);
536
537
if (uname != NULL)
538
f->uname = xstrdup(uname);
539
540
if (gname != NULL)
541
f->gname = xstrdup(gname);
542
543
if (perm != 0)
544
f->perm = perm;
545
546
if (fflags != 0)
547
f->fflags = fflags;
548
549
if (symlink_target != NULL)
550
f->symlink_target = xstrdup(symlink_target);
551
552
if (mtime > 0)
553
f->time[1].tv_sec = mtime;
554
555
pkghash_safe_add(pkg->filehash, f->path, f, NULL);
556
DL_APPEND(pkg->files, f);
557
558
return (EPKG_OK);
559
}
560
561
int
562
pkg_addconfig_file(struct pkg *pkg, const char *path, const char *content)
563
{
564
struct pkg_config_file *f = NULL;
565
char abspath[MAXPATHLEN];
566
567
path = pkg_absolutepath(path, abspath, sizeof(abspath), false);
568
dbg(3, "add new config file '%s'", path);
569
570
if (pkghash_get(pkg->config_files_hash, path) != NULL) {
571
pkg_emit_error("duplicate file listing: %s", path);
572
return (EPKG_FATAL);
573
}
574
f = xcalloc(1, sizeof(*f));
575
f->path = xstrdup(path);
576
577
if (content != NULL)
578
f->content = xstrdup(content);
579
580
pkghash_safe_add(pkg->config_files_hash, f->path, f, NULL);
581
DL_APPEND(pkg->config_files, f);
582
583
return (EPKG_OK);
584
}
585
586
int
587
pkg_addstring(charv_t *list, const char *val, const char *title)
588
{
589
assert(val != NULL);
590
assert(title != NULL);
591
592
char *tmp = xstrdup(val);
593
if (charv_insert_sorted(list, tmp) != NULL) {
594
free(tmp);
595
if (ctx.developer_mode) {
596
pkg_emit_error("duplicate %s listing: %s, fatal"
597
" (developer mode)", title, val);
598
return (EPKG_FATAL);
599
}
600
pkg_emit_error("duplicate %s listing: %s, "
601
"ignoring", title, val);
602
return (EPKG_OK);
603
}
604
605
return (EPKG_OK);
606
}
607
608
int
609
pkg_adddir(struct pkg *pkg, const char *path, bool check_duplicates)
610
{
611
return(pkg_adddir_attr(pkg, path, NULL, NULL, 0, 0, check_duplicates));
612
}
613
614
int
615
pkg_adddir_attr(struct pkg *pkg, const char *path, const char *uname,
616
const char *gname, mode_t perm, u_long fflags, bool check_duplicates)
617
{
618
struct pkg_dir *d = NULL;
619
char abspath[MAXPATHLEN];
620
621
assert(pkg != NULL);
622
assert(path != NULL && path[0] != '\0');
623
624
if (STREQ(path, "/")) {
625
pkg_emit_error("skipping useless directory: '%s'\n", path);
626
return (EPKG_OK);
627
}
628
path = pkg_absolutepath(path, abspath, sizeof(abspath), false);
629
dbg(3, "add new directory '%s'", path);
630
if (check_duplicates && pkghash_get(pkg->dirhash, path) != NULL) {
631
if (ctx.developer_mode) {
632
pkg_emit_error("duplicate directory listing: %s, fatal (developer mode)", path);
633
return (EPKG_FATAL);
634
} else {
635
pkg_emit_error("duplicate directory listing: %s, ignoring", path);
636
return (EPKG_OK);
637
}
638
}
639
640
d = xcalloc(1, sizeof(*d));
641
d->path = xstrdup(path);
642
643
if (uname != NULL)
644
d->uname = xstrdup(uname);
645
646
if (gname != NULL)
647
d->gname = xstrdup(gname);
648
649
if (perm != 0)
650
d->perm = perm;
651
652
if (fflags != 0)
653
d->fflags = fflags;
654
655
pkghash_safe_add(pkg->dirhash, d->path, d, NULL);
656
DL_APPEND(pkg->dirs, d);
657
658
return (EPKG_OK);
659
}
660
661
int
662
pkg_addscript(struct pkg *pkg, const char *data, pkg_script type)
663
{
664
665
assert(pkg != NULL);
666
xstring_renew(pkg->scripts[type]);
667
fprintf(pkg->scripts[type]->fp, "%s", data);
668
669
return (EPKG_OK);
670
}
671
672
int
673
pkg_add_lua_script(struct pkg *pkg, const char *data, pkg_lua_script type)
674
{
675
assert(pkg != NULL);
676
677
if (type >= PKG_LUA_UNKNOWN)
678
return (EPKG_FATAL);
679
680
vec_push(&pkg->lua_scripts[type], xstrdup(data));
681
682
return (EPKG_OK);
683
}
684
685
int
686
pkg_addluascript_fileat(int fd, struct pkg *pkg, const char *filename)
687
{
688
char *data;
689
pkg_lua_script type;
690
int ret = EPKG_OK;
691
off_t sz = 0;
692
693
assert(pkg != NULL);
694
assert(filename != NULL);
695
696
dbg(1, "Adding script from: '%s'", filename);
697
698
if ((ret = file_to_bufferat(fd, filename, &data, &sz)) != EPKG_OK)
699
return (ret);
700
701
if (STREQ(filename, "pkg-pre-install.lua")) {
702
type = PKG_LUA_PRE_INSTALL;
703
} else if (STREQ(filename, "pkg-post-install.lua")) {
704
type = PKG_LUA_POST_INSTALL;
705
} else if (STREQ(filename, "pkg-pre-deinstall.lua")) {
706
type = PKG_LUA_PRE_DEINSTALL;
707
} else if (STREQ(filename, "pkg-post-deinstall.lua")) {
708
type = PKG_LUA_POST_DEINSTALL;
709
} else {
710
pkg_emit_error("unknown lua script '%s'", filename);
711
ret = EPKG_FATAL;
712
goto cleanup;
713
}
714
715
ret = pkg_add_lua_script(pkg, data, type);
716
cleanup:
717
free(data);
718
return (ret);
719
}
720
721
int
722
pkg_addscript_fileat(int fd, struct pkg *pkg, const char *filename)
723
{
724
char *data;
725
pkg_script type;
726
int ret = EPKG_OK;
727
off_t sz = 0;
728
729
assert(pkg != NULL);
730
assert(filename != NULL);
731
732
dbg(1, "Adding script from: '%s'", filename);
733
734
if ((ret = file_to_bufferat(fd, filename, &data, &sz)) != EPKG_OK)
735
return (ret);
736
737
if (STREQ(filename, "pkg-pre-install") ||
738
STREQ(filename, "+PRE_INSTALL")) {
739
type = PKG_SCRIPT_PRE_INSTALL;
740
} else if (STREQ(filename, "pkg-post-install") ||
741
STREQ(filename, "+POST_INSTALL")) {
742
type = PKG_SCRIPT_POST_INSTALL;
743
} else if (STREQ(filename, "pkg-install") ||
744
STREQ(filename, "+INSTALL")) {
745
type = PKG_SCRIPT_INSTALL;
746
} else if (STREQ(filename, "pkg-pre-deinstall") ||
747
STREQ(filename, "+PRE_DEINSTALL")) {
748
type = PKG_SCRIPT_PRE_DEINSTALL;
749
} else if (STREQ(filename, "pkg-post-deinstall") ||
750
STREQ(filename, "+POST_DEINSTALL")) {
751
type = PKG_SCRIPT_POST_DEINSTALL;
752
} else if (STREQ(filename, "pkg-deinstall") ||
753
STREQ(filename, "+DEINSTALL")) {
754
type = PKG_SCRIPT_DEINSTALL;
755
} else {
756
pkg_emit_error("unknown script '%s'", filename);
757
ret = EPKG_FATAL;
758
goto cleanup;
759
}
760
761
ret = pkg_addscript(pkg, data, type);
762
cleanup:
763
free(data);
764
return (ret);
765
}
766
767
int
768
pkg_appendscript(struct pkg *pkg, const char *cmd, pkg_script type)
769
{
770
771
assert(pkg != NULL);
772
assert(cmd != NULL && cmd[0] != '\0');
773
774
if (pkg->scripts[type] == NULL)
775
pkg->scripts[type] = xstring_new();
776
777
fprintf(pkg->scripts[type]->fp, "%s", cmd);
778
779
return (EPKG_OK);
780
}
781
782
int
783
pkg_addoption(struct pkg *pkg, const char *key, const char *value)
784
{
785
struct pkg_option *o = NULL;
786
787
assert(pkg != NULL);
788
assert(key != NULL && key[0] != '\0');
789
assert(value != NULL && value[0] != '\0');
790
791
/* There might be a default or description for the option
792
already, so we only count it as a duplicate if the value
793
field is already set. Which implies there could be a
794
default value or description for an option but no actual
795
value. */
796
797
dbg(2,"adding options: %s = %s", key, value);
798
if (pkghash_get(pkg->optionshash, key) != NULL) {
799
if (ctx.developer_mode) {
800
pkg_emit_error("duplicate options listing: %s, fatal (developer mode)", key);
801
return (EPKG_FATAL);
802
} else {
803
pkg_emit_error("duplicate options listing: %s, ignoring", key);
804
return (EPKG_OK);
805
}
806
}
807
o = xcalloc(1, sizeof(*o));
808
o->key = xstrdup(key);
809
o->value = xstrdup(value);
810
pkghash_safe_add(pkg->optionshash, o->key, o, NULL);
811
DL_APPEND(pkg->options, o);
812
813
return (EPKG_OK);
814
}
815
816
int
817
pkg_addoption_default(struct pkg *pkg, const char *key,
818
const char *default_value)
819
{
820
struct pkg_option *o = NULL;
821
822
assert(pkg != NULL);
823
assert(key != NULL && key[0] != '\0');
824
assert(default_value != NULL && default_value[0] != '\0');
825
826
/* There might be a value or description for the option
827
already, so we only count it as a duplicate if the
828
default_value field is already set. Which implies there
829
could be a default value or description for an option but
830
no actual value. */
831
832
if (pkghash_get(pkg->optionshash, key) != NULL) {
833
if (ctx.developer_mode) {
834
pkg_emit_error("duplicate default value for option: %s, fatal (developer mode)", key);
835
return (EPKG_FATAL);
836
} else {
837
pkg_emit_error("duplicate default value for option: %s, ignoring", key);
838
return (EPKG_OK);
839
}
840
}
841
o = xcalloc(1, sizeof(*o));
842
o->key = xstrdup(key);
843
o->default_value = xstrdup(default_value);
844
pkghash_safe_add(pkg->optionshash, o->key, o, NULL);
845
DL_APPEND(pkg->options, o);
846
847
return (EPKG_OK);
848
}
849
850
int
851
pkg_addoption_description(struct pkg *pkg, const char *key,
852
const char *description)
853
{
854
struct pkg_option *o = NULL;
855
856
assert(pkg != NULL);
857
assert(key != NULL && key[0] != '\0');
858
assert(description != NULL && description[0] != '\0');
859
860
/* There might be a value or default for the option already,
861
so we only count it as a duplicate if the description field
862
is already set. Which implies there could be a default
863
value or description for an option but no actual value. */
864
865
if (pkghash_get(pkg->optionshash, key) != NULL) {
866
if (ctx.developer_mode) {
867
pkg_emit_error("duplicate description for option: %s, fatal (developer mode)", key);
868
return (EPKG_FATAL);
869
} else {
870
pkg_emit_error("duplicate description for option: %s, ignoring", key);
871
return (EPKG_OK);
872
}
873
}
874
875
o = xcalloc(1, sizeof(*o));
876
o->key = xstrdup(key);
877
o->description = xstrdup(description);
878
pkghash_safe_add(pkg->optionshash, o->key, o, NULL);
879
DL_APPEND(pkg->options, o);
880
881
return (EPKG_OK);
882
}
883
884
enum pkg_shlib_flags
885
pkg_shlib_flags_from_abi(const struct pkg_abi *shlib_abi)
886
{
887
enum pkg_shlib_flags flags = PKG_SHLIB_FLAGS_NONE;
888
889
if (ctx.abi.os == PKG_OS_FREEBSD) {
890
if (shlib_abi->os == PKG_OS_LINUX && ctx.track_linux_compat_shlibs)
891
flags |= PKG_SHLIB_FLAGS_COMPAT_LINUX;
892
893
switch (ctx.abi.arch) {
894
case PKG_ARCH_AMD64:
895
if (shlib_abi->arch == PKG_ARCH_I386) {
896
flags |= PKG_SHLIB_FLAGS_COMPAT_32;
897
}
898
break;
899
case PKG_ARCH_AARCH64:
900
if (shlib_abi->arch == PKG_ARCH_ARMV7) {
901
flags |= PKG_SHLIB_FLAGS_COMPAT_32;
902
}
903
break;
904
case PKG_ARCH_POWERPC64:
905
if (shlib_abi->arch == PKG_ARCH_POWERPC) {
906
flags |= PKG_SHLIB_FLAGS_COMPAT_32;
907
}
908
break;
909
}
910
}
911
912
return (flags);
913
}
914
915
/*
916
* Format examples:
917
*
918
* libfoo.so.1.0.0 - native
919
* libfoo.so.1.0.0:32 - compat 32
920
* libfoo.so.1.0.0:Linux - compat Linux
921
* libfoo.so.1.0.0:Linux:32 - compat Linux 32
922
*/
923
char *
924
pkg_shlib_name_with_flags(const char *name, enum pkg_shlib_flags flags)
925
{
926
const char *compat_os = "";
927
if ((flags & PKG_SHLIB_FLAGS_COMPAT_LINUX) != 0) {
928
compat_os = ":Linux";
929
}
930
931
const char *compat_arch = "";
932
if ((flags & PKG_SHLIB_FLAGS_COMPAT_32) != 0) {
933
compat_arch = ":32";
934
}
935
936
char *ret;
937
xasprintf(&ret, "%s%s%s", name, compat_os, compat_arch);
938
return (ret);
939
}
940
941
int
942
pkg_addshlib_required(struct pkg *pkg, const char *name,
943
enum pkg_shlib_flags flags)
944
{
945
assert(pkg != NULL);
946
assert(name != NULL && name[0] != '\0');
947
948
char *full_name = pkg_shlib_name_with_flags(name, flags);
949
950
/* silently ignore duplicates in case of shlibs */
951
if (charv_insert_sorted(&pkg->shlibs_required, full_name) != NULL) {
952
free(full_name);
953
return (EPKG_OK);
954
}
955
956
dbg(3, "added shlib deps for %s on %s", pkg->name, full_name);
957
958
return (EPKG_OK);
959
}
960
961
int
962
pkg_addshlib_required_ignore(struct pkg *pkg, const char *name)
963
{
964
assert(pkg != NULL);
965
assert(name != NULL && name[0] != '\0');
966
967
char *owned_name = xstrdup(name);
968
969
/* silently ignore duplicates in case of shlibs */
970
if (charv_insert_sorted(&pkg->shlibs_required_ignore, owned_name) != NULL) {
971
free(owned_name);
972
return (EPKG_OK);
973
}
974
975
dbg(3, "added shlib required ignore for %s on %s", pkg->name, owned_name);
976
977
return (EPKG_OK);
978
}
979
980
int
981
pkg_addshlib_provided(struct pkg *pkg, const char *name,
982
enum pkg_shlib_flags flags)
983
{
984
assert(pkg != NULL);
985
assert(name != NULL && name[0] != '\0');
986
987
char *full_name = pkg_shlib_name_with_flags(name, flags);
988
989
/* silently ignore duplicates in case of shlibs */
990
if (charv_insert_sorted(&pkg->shlibs_provided, full_name) != NULL) {
991
free(full_name);
992
return (EPKG_OK);
993
}
994
995
dbg(3, "added shlib provide %s for %s", full_name, pkg->name);
996
997
return (EPKG_OK);
998
}
999
1000
int
1001
pkg_addshlib_provided_ignore(struct pkg *pkg, const char *name)
1002
{
1003
assert(pkg != NULL);
1004
assert(name != NULL && name[0] != '\0');
1005
1006
char *owned_name = xstrdup(name);
1007
1008
/* silently ignore duplicates in case of shlibs */
1009
if (charv_insert_sorted(&pkg->shlibs_provided_ignore, owned_name) != NULL) {
1010
free(owned_name);
1011
return (EPKG_OK);
1012
}
1013
1014
dbg(3, "added shlib provided ignore %s for %s", owned_name, pkg->name);
1015
1016
return (EPKG_OK);
1017
}
1018
1019
int
1020
pkg_addconflict(struct pkg *pkg, const char *uniqueid)
1021
{
1022
struct pkg_conflict *c = NULL;
1023
1024
assert(pkg != NULL);
1025
assert(uniqueid != NULL && uniqueid[0] != '\0');
1026
1027
if (pkghash_get(pkg->conflictshash, uniqueid) != NULL) {
1028
/* silently ignore duplicates in case of conflicts */
1029
return (EPKG_OK);
1030
}
1031
1032
c = xcalloc(1, sizeof(*c));
1033
c->uid = xstrdup(uniqueid);
1034
dbg(3, "add a new conflict origin: %s, with %s", pkg->uid, uniqueid);
1035
1036
pkghash_safe_add(pkg->conflictshash, c->uid, c, NULL);
1037
DL_APPEND(pkg->conflicts, c);
1038
1039
return (EPKG_OK);
1040
}
1041
1042
int
1043
pkg_addrequire(struct pkg *pkg, const char *name)
1044
{
1045
assert(pkg != NULL);
1046
assert(name != NULL && name[0] != '\0');
1047
1048
char *tmp = xstrdup(name);
1049
1050
if (charv_insert_sorted(&pkg->requires, tmp) != NULL) {
1051
/* silently ignore duplicates in case of conflicts */
1052
free(tmp);
1053
return (EPKG_OK);
1054
}
1055
1056
return (EPKG_OK);
1057
}
1058
1059
int
1060
pkg_addprovide(struct pkg *pkg, const char *name)
1061
{
1062
assert(pkg != NULL);
1063
assert(name != NULL && name[0] != '\0');
1064
1065
char *tmp = xstrdup(name);
1066
1067
if (charv_insert_sorted(&pkg->provides, tmp) != NULL) {
1068
/* silently ignore duplicates in case of conflicts */
1069
free(tmp);
1070
return (EPKG_OK);
1071
}
1072
1073
return (EPKG_OK);
1074
}
1075
1076
const char *
1077
pkg_kv_get(const kvlist_t *kv, const char *tag)
1078
{
1079
assert(tag != NULL);
1080
1081
vec_foreach(*kv, i) {
1082
if (STREQ(kv->d[i]->key, tag))
1083
return (kv->d[i]->value);
1084
}
1085
1086
return (NULL);
1087
}
1088
1089
int
1090
pkg_kv_add(kvlist_t *list, const char *key, const char *val, const char *title)
1091
{
1092
struct pkg_kv *kv;
1093
1094
assert(val != NULL);
1095
assert(title != NULL);
1096
1097
kv = pkg_kv_new(key, val);
1098
if (pkg_kv_insert_sorted(list, kv) != NULL) {
1099
pkg_kv_free(kv);
1100
if (ctx.developer_mode) {
1101
pkg_emit_error("duplicate %s: %s, fatal"
1102
" (developer mode)", title, key);
1103
return (EPKG_FATAL);
1104
}
1105
pkg_emit_error("duplicate %s: %s, "
1106
"ignoring", title, val);
1107
return (EPKG_OK);
1108
}
1109
1110
return (EPKG_OK);
1111
}
1112
1113
int
1114
pkg_list_count(const struct pkg *pkg, pkg_list list)
1115
{
1116
switch (list) {
1117
case PKG_DEPS:
1118
return (pkghash_count(pkg->depshash));
1119
case PKG_RDEPS:
1120
return (pkghash_count(pkg->rdepshash));
1121
case PKG_OPTIONS:
1122
return (pkghash_count(pkg->optionshash));
1123
case PKG_FILES:
1124
return (pkghash_count(pkg->filehash));
1125
case PKG_DIRS:
1126
return (pkghash_count(pkg->dirhash));
1127
case PKG_CONFLICTS:
1128
return (pkghash_count(pkg->conflictshash));
1129
case PKG_CONFIG_FILES:
1130
return (pkghash_count(pkg->config_files_hash));
1131
case PKG_USERS:
1132
return (vec_len(&pkg->users));
1133
case PKG_GROUPS:
1134
return (vec_len(&pkg->groups));
1135
case PKG_SHLIBS_REQUIRED:
1136
return (vec_len(&pkg->shlibs_required));
1137
case PKG_SHLIBS_PROVIDED:
1138
return (vec_len(&pkg->shlibs_provided));
1139
case PKG_REQUIRES:
1140
return (vec_len(&pkg->requires));
1141
case PKG_PROVIDES:
1142
return (vec_len(&pkg->provides));
1143
}
1144
1145
return (0);
1146
}
1147
1148
void
1149
pkg_list_free(struct pkg *pkg, pkg_list list) {
1150
struct pkg_dep *cur;
1151
1152
switch (list) {
1153
case PKG_DEPS:
1154
DL_FOREACH (pkg->depends, cur) {
1155
if (cur->alt_next) {
1156
DL_FREE2(cur->alt_next, pkg_dep_free, alt_prev, alt_next);
1157
}
1158
}
1159
DL_FREE(pkg->depends, pkg_dep_free);
1160
pkghash_destroy(pkg->depshash);
1161
pkg->depshash = NULL;
1162
pkg->flags &= ~PKG_LOAD_DEPS;
1163
break;
1164
case PKG_RDEPS:
1165
LL_FREE(pkg->rdepends, pkg_dep_free);
1166
pkghash_destroy(pkg->rdepshash);
1167
pkg->depshash = NULL;
1168
pkg->flags &= ~PKG_LOAD_RDEPS;
1169
break;
1170
case PKG_OPTIONS:
1171
DL_FREE(pkg->options, pkg_option_free);
1172
pkghash_destroy(pkg->optionshash);
1173
pkg->optionshash = NULL;
1174
pkg->flags &= ~PKG_LOAD_OPTIONS;
1175
break;
1176
case PKG_FILES:
1177
case PKG_CONFIG_FILES:
1178
DL_FREE(pkg->files, pkg_file_free);
1179
pkghash_destroy(pkg->filehash);
1180
pkg->filehash = NULL;
1181
DL_FREE(pkg->config_files, pkg_config_file_free);
1182
pkghash_destroy(pkg->config_files_hash);
1183
pkg->config_files_hash = NULL;
1184
pkg->flags &= ~PKG_LOAD_FILES;
1185
break;
1186
case PKG_DIRS:
1187
DL_FREE(pkg->dirs, pkg_dir_free);
1188
pkghash_destroy(pkg->dirhash);
1189
pkg->dirhash = NULL;
1190
pkg->flags &= ~PKG_LOAD_DIRS;
1191
break;
1192
case PKG_CONFLICTS:
1193
DL_FREE(pkg->conflicts, pkg_conflict_free);
1194
pkghash_destroy(pkg->conflictshash);
1195
pkg->conflictshash = NULL;
1196
pkg->flags &= ~PKG_LOAD_CONFLICTS;
1197
break;
1198
}
1199
}
1200
1201
int
1202
pkg_open(struct pkg **pkg_p, const char *path, int flags)
1203
{
1204
struct archive *a;
1205
struct archive_entry *ae;
1206
int ret;
1207
1208
ret = pkg_open2(pkg_p, &a, &ae, path, flags, -1);
1209
1210
if (ret != EPKG_OK && ret != EPKG_END)
1211
return (EPKG_FATAL);
1212
1213
archive_read_close(a);
1214
archive_read_free(a);
1215
1216
return (EPKG_OK);
1217
}
1218
1219
int
1220
pkg_open_fd(struct pkg **pkg_p, int fd, int flags)
1221
{
1222
struct archive *a;
1223
struct archive_entry *ae;
1224
int ret;
1225
1226
ret = pkg_open2(pkg_p, &a, &ae, NULL, flags, fd);
1227
1228
if (ret != EPKG_OK && ret != EPKG_END)
1229
return (EPKG_FATAL);
1230
1231
archive_read_close(a);
1232
archive_read_free(a);
1233
1234
return (EPKG_OK);
1235
}
1236
1237
static int
1238
pkg_parse_archive(struct pkg *pkg, struct archive *a, size_t len)
1239
{
1240
void *buffer;
1241
int rc;
1242
1243
buffer = xmalloc(len);
1244
1245
archive_read_data(a, buffer, len);
1246
rc = pkg_parse_manifest(pkg, buffer, len);
1247
free(buffer);
1248
return (rc);
1249
}
1250
1251
int
1252
pkg_open2(struct pkg **pkg_p, struct archive **a, struct archive_entry **ae,
1253
const char *path, int flags, int fd)
1254
{
1255
struct pkg *pkg = NULL;
1256
pkg_error_t retcode = EPKG_OK;
1257
int ret;
1258
const char *fpath;
1259
bool manifest = false;
1260
bool read_from_stdin = 0;
1261
1262
*a = archive_read_new();
1263
archive_read_support_filter_all(*a);
1264
archive_read_support_format_tar(*a);
1265
1266
/* archive_read_open_filename() treats a path of NULL as
1267
* meaning "read from stdin," but we want this behaviour if
1268
* path is exactly "-". In the unlikely event of wanting to
1269
* read an on-disk file called "-", just say "./-" or some
1270
* other leading path. */
1271
1272
if (fd == -1) {
1273
if (path == NULL) {
1274
pkg_emit_error("bad usage of pkg_open2");
1275
retcode = EPKG_FATAL;
1276
goto cleanup;
1277
}
1278
read_from_stdin = (strncmp(path, "-", 2) == 0);
1279
1280
if (archive_read_open_filename(*a,
1281
read_from_stdin ? NULL : path, 4096) != ARCHIVE_OK) {
1282
if ((flags & PKG_OPEN_TRY) == 0)
1283
pkg_emit_error("archive_read_open_filename(%s): %s", path,
1284
archive_error_string(*a));
1285
1286
retcode = EPKG_FATAL;
1287
goto cleanup;
1288
}
1289
} else {
1290
if (archive_read_open_fd(*a, fd, 4096) != ARCHIVE_OK) {
1291
if ((flags & PKG_OPEN_TRY) == 0)
1292
pkg_emit_error("archive_read_open_fd: %s",
1293
archive_error_string(*a));
1294
1295
retcode = EPKG_FATAL;
1296
goto cleanup;
1297
}
1298
}
1299
1300
retcode = pkg_new(pkg_p, PKG_FILE);
1301
if (retcode != EPKG_OK)
1302
goto cleanup;
1303
1304
pkg = *pkg_p;
1305
1306
while ((ret = archive_read_next_header(*a, ae)) == ARCHIVE_OK) {
1307
fpath = archive_entry_pathname(*ae);
1308
if (fpath[0] != '+')
1309
break;
1310
1311
if (!manifest &&
1312
(flags & PKG_OPEN_MANIFEST_COMPACT) &&
1313
STREQ(fpath, "+COMPACT_MANIFEST")) {
1314
manifest = true;
1315
1316
ret = pkg_parse_archive(pkg, *a, archive_entry_size(*ae));
1317
if (ret != EPKG_OK) {
1318
retcode = EPKG_FATAL;
1319
goto cleanup;
1320
}
1321
/* Do not read anything more */
1322
break;
1323
}
1324
if (!manifest && STREQ(fpath, "+MANIFEST")) {
1325
manifest = true;
1326
1327
ret = pkg_parse_archive(pkg, *a, archive_entry_size(*ae));
1328
if (ret != EPKG_OK) {
1329
if ((flags & PKG_OPEN_TRY) == 0)
1330
pkg_emit_error("%s is not a valid package: "
1331
"Invalid manifest", path);
1332
1333
retcode = EPKG_FATAL;
1334
goto cleanup;
1335
}
1336
1337
if (flags & PKG_OPEN_MANIFEST_ONLY)
1338
break;
1339
}
1340
}
1341
1342
if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF) {
1343
if ((flags & PKG_OPEN_TRY) == 0)
1344
pkg_emit_error("archive_read_next_header(): %s",
1345
archive_error_string(*a));
1346
1347
retcode = EPKG_FATAL;
1348
}
1349
1350
if (ret == ARCHIVE_EOF)
1351
retcode = EPKG_END;
1352
1353
if (!manifest) {
1354
retcode = EPKG_FATAL;
1355
if ((flags & PKG_OPEN_TRY) == 0)
1356
pkg_emit_error("%s is not a valid package: no manifest found", path);
1357
}
1358
1359
cleanup:
1360
if (retcode != EPKG_OK && retcode != EPKG_END) {
1361
if (*a != NULL) {
1362
archive_read_close(*a);
1363
archive_read_free(*a);
1364
}
1365
free(pkg);
1366
*pkg_p = NULL;
1367
*a = NULL;
1368
*ae = NULL;
1369
}
1370
1371
return (retcode);
1372
}
1373
1374
int
1375
pkg_validate(struct pkg *pkg, struct pkgdb *db)
1376
{
1377
assert(pkg != NULL);
1378
unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS|
1379
PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES|
1380
PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|
1381
PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS;
1382
1383
if (pkg->uid == NULL) {
1384
/* Keep that part for the day we have to change it */
1385
/* Generate uid from name*/
1386
if (pkg->name == NULL)
1387
return (EPKG_FATAL);
1388
1389
pkg->uid = xstrdup(pkg->name);
1390
}
1391
1392
if (pkg->digest == NULL || !pkg_checksum_is_valid(pkg->digest,
1393
strlen(pkg->digest))) {
1394
/* Calculate new digest */
1395
if (pkgdb_ensure_loaded(db, pkg, flags)) {
1396
return (pkg_checksum_calculate(pkg, db, false, true, false));
1397
}
1398
return (EPKG_FATAL);
1399
}
1400
1401
return (EPKG_OK);
1402
}
1403
1404
enum {
1405
FILE_OK = 0,
1406
1407
FILE_MISSING = 1 << 0,
1408
FILE_SUM_MISMATCH = 1 << 1,
1409
1410
FILE_META_MISMATCH_TYPE = 1 << 2,
1411
FILE_META_MISMATCH_UNAME = 1 << 3,
1412
FILE_META_MISMATCH_GNAME = 1 << 4,
1413
FILE_META_MISMATCH_MODE = 1 << 5,
1414
FILE_META_MISMATCH_FFLAGS = 1 << 6,
1415
FILE_META_MISMATCH_MTIME = 1 << 7,
1416
FILE_META_MISMATCH_SYMLINK = 1 << 8,
1417
};
1418
1419
static int
1420
pkg_stat(const char *path, struct stat *st, char *symlink_target,
1421
size_t symlink_target_size, unsigned *file_status)
1422
{
1423
ssize_t linklen;
1424
1425
if (fstatat(ctx.rootfd, RELATIVE_PATH(path), st,
1426
AT_SYMLINK_NOFOLLOW) == -1) {
1427
1428
if (errno == ENOENT)
1429
*file_status |= FILE_MISSING;
1430
else
1431
pkg_emit_errno("fstatat", RELATIVE_PATH(path));
1432
return (EPKG_FATAL);
1433
}
1434
1435
symlink_target[0] = '\0';
1436
if (S_ISLNK(st->st_mode)) {
1437
linklen = readlinkat(ctx.rootfd, RELATIVE_PATH(path),
1438
symlink_target, symlink_target_size - 1);
1439
if (linklen == -1) {
1440
symlink_target[0] = '\0';
1441
pkg_emit_errno("readlinkat", RELATIVE_PATH(path));
1442
return (EPKG_FATAL);
1443
} else {
1444
symlink_target[linklen] = '\0';
1445
}
1446
}
1447
1448
return (EPKG_OK);
1449
}
1450
1451
static unsigned
1452
pkg_check_meta(struct stat *st, const char *uname, const char *gname,
1453
mode_t perm, u_long fflags, time_t mtime_sec,
1454
char *db_symlink_target, char *fs_symlink_target)
1455
{
1456
unsigned file_status = FILE_OK;
1457
uid_t fs_uid;
1458
gid_t fs_gid;
1459
1460
fs_uid = get_uid_from_uname(uname);
1461
if (fs_uid != st->st_uid)
1462
file_status |= FILE_META_MISMATCH_UNAME;
1463
fs_gid = get_gid_from_gname(gname);
1464
if (fs_gid != st->st_gid)
1465
file_status |= FILE_META_MISMATCH_GNAME;
1466
if (perm != (st->st_mode & ~S_IFMT))
1467
file_status |= FILE_META_MISMATCH_MODE;
1468
#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(HAVE_FFLAGSTOSTR)
1469
#ifdef __FreeBSD__
1470
/* ZFS sets UF_ARCHIVE implicitly, so we can't check for it. */
1471
#define IGNORE_FLAGS UF_ARCHIVE
1472
#else
1473
#define IGNORE_FLAGS 0
1474
#endif
1475
if ((fflags & ~IGNORE_FLAGS) != (st->st_flags & ~IGNORE_FLAGS))
1476
file_status |= FILE_META_MISMATCH_FFLAGS;
1477
#endif
1478
/* we don't check mtime for directories */
1479
if (!S_ISDIR(st->st_mode)) {
1480
if (mtime_sec != st->st_mtim.tv_sec)
1481
file_status |= FILE_META_MISMATCH_MTIME;
1482
}
1483
1484
if (S_ISLNK(st->st_mode) != (fs_symlink_target[0] != '\0'))
1485
file_status |= FILE_META_MISMATCH_SYMLINK;
1486
else if (S_ISLNK(st->st_mode) &&
1487
strcmp(db_symlink_target ? db_symlink_target : "", fs_symlink_target) != 0)
1488
file_status |= FILE_META_MISMATCH_SYMLINK;
1489
1490
return file_status;
1491
}
1492
1493
static const char *
1494
stat_type_tostring(mode_t mode) {
1495
/* adapted from freebsd-src/usr.bin/stat.c */
1496
switch (mode & S_IFMT) {
1497
case S_IFIFO: return "Fifo file";
1498
case S_IFCHR: return "Character Device";
1499
case S_IFDIR: return "Directory";
1500
case S_IFBLK: return "Block Device";
1501
case S_IFREG: return "Regular File";
1502
case S_IFLNK: return "Symbolic Link";
1503
case S_IFSOCK: return "Socket";
1504
#ifdef S_IFWHT
1505
case S_IFWHT: return "Whiteout File";
1506
#endif
1507
default: return "???";
1508
}
1509
}
1510
1511
static int
1512
pkg_check_file(struct pkg *pkg, struct pkg_file *f, bool metadata, unsigned file_status)
1513
{
1514
int rc = EPKG_OK;
1515
int ret;
1516
struct stat st;
1517
char symlink_target[MAXPATHLEN];
1518
struct passwd *pwd;
1519
struct group *grp;
1520
char db_str[1024], fs_str[1024];
1521
char *db_fflags, *fs_fflags;
1522
time_t tmp_time;
1523
struct tm *tm;
1524
1525
ret = pkg_stat(f->path, &st, symlink_target, sizeof(symlink_target), &file_status);
1526
if (ret != EPKG_OK) {
1527
rc = EPKG_FATAL;
1528
goto emit_status;
1529
}
1530
1531
if (metadata) {
1532
file_status |= pkg_check_meta(&st, f->uname, f->gname, f->perm, f->fflags,
1533
f->time[1].tv_sec, f->symlink_target,
1534
symlink_target);
1535
1536
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1537
file_status |= FILE_META_MISMATCH_TYPE;
1538
if (S_ISREG(st.st_mode) && (symlink_target[0] != '\0'))
1539
file_status |= FILE_META_MISMATCH_TYPE;
1540
if (S_ISLNK(st.st_mode) && (symlink_target[0] == '\0'))
1541
file_status |= FILE_META_MISMATCH_TYPE;
1542
}
1543
1544
1545
emit_status:
1546
if (file_status & FILE_MISSING)
1547
pkg_emit_file_missing(pkg, f);
1548
if (file_status & FILE_SUM_MISMATCH)
1549
pkg_emit_file_mismatch(pkg, f, f->sum);
1550
1551
if (file_status & FILE_META_MISMATCH_TYPE) {
1552
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_TYPE,
1553
f->symlink_target == NULL ? "Regular File" : "Symbolic Link",
1554
stat_type_tostring(st.st_mode));
1555
}
1556
1557
if (file_status & FILE_META_MISMATCH_UNAME) {
1558
pwd = getpwuid(st.st_uid);
1559
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_UNAME,
1560
f->uname, pwd != NULL ? pwd->pw_name : NULL);
1561
}
1562
if (file_status & FILE_META_MISMATCH_GNAME) {
1563
grp = getgrgid(st.st_gid);
1564
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_GNAME,
1565
f->gname, grp != NULL ? grp->gr_name : NULL);
1566
}
1567
if (file_status & FILE_META_MISMATCH_MODE) {
1568
strmode(f->perm, db_str);
1569
strmode(st.st_mode, fs_str);
1570
db_str[10] = '\0'; /* trim last space character */
1571
fs_str[10] = '\0';
1572
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_PERM,
1573
db_str + 1, fs_str + 1);
1574
}
1575
1576
#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(HAVE_FFLAGSTOSTR)
1577
if (file_status & FILE_META_MISMATCH_FFLAGS) {
1578
db_fflags = fflagstostr(f->fflags);
1579
fs_fflags = fflagstostr(st.st_flags);
1580
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_FFLAGS,
1581
db_fflags, fs_fflags);
1582
free(db_fflags);
1583
free(fs_fflags);
1584
}
1585
#endif
1586
if (file_status & FILE_META_MISMATCH_MTIME) {
1587
tmp_time = f->time[1].tv_sec;
1588
tm = localtime(&tmp_time);
1589
strftime(db_str, sizeof(db_str), "%c", tm);
1590
tmp_time = st.st_mtim.tv_sec;
1591
tm = localtime(&tmp_time);
1592
strftime(fs_str, sizeof(fs_str), "%c", tm);
1593
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_MTIME,
1594
db_str, fs_str);
1595
}
1596
if (file_status & FILE_META_MISMATCH_SYMLINK) {
1597
pkg_emit_file_meta_mismatch(pkg, f, PKG_META_ATTR_SYMLINK,
1598
f->symlink_target, symlink_target);
1599
}
1600
1601
if (file_status == FILE_OK) {
1602
if (metadata)
1603
pkg_emit_file_meta_ok(pkg, f);
1604
} else {
1605
rc = EPKG_FATAL;
1606
}
1607
1608
return rc;
1609
}
1610
1611
1612
static int
1613
pkg_check_dir(struct pkg *pkg, struct pkg_dir *d, unsigned file_status)
1614
{
1615
int rc = EPKG_OK;
1616
int err;
1617
struct stat st;
1618
char *db_symlink_target = "";
1619
char symlink_target[MAXPATHLEN];
1620
char db_str[1024], fs_str[1024];
1621
char *db_fflags, *fs_fflags;
1622
struct passwd *pwd;
1623
struct group *grp;
1624
1625
err = pkg_stat(d->path, &st, symlink_target, sizeof(symlink_target), &file_status);
1626
if (err != EPKG_OK) {
1627
rc = EPKG_FATAL;
1628
goto emit_status;
1629
}
1630
1631
file_status |= pkg_check_meta(&st, d->uname, d->gname, d->perm, d->fflags,
1632
d->time[1].tv_sec, db_symlink_target,
1633
symlink_target);
1634
1635
if (!S_ISDIR(st.st_mode))
1636
file_status |= FILE_META_MISMATCH_TYPE;
1637
1638
emit_status:
1639
if (file_status & FILE_MISSING)
1640
pkg_emit_dir_missing(pkg, d);
1641
1642
if (file_status & FILE_META_MISMATCH_TYPE) {
1643
pkg_emit_dir_meta_mismatch(pkg, d, PKG_META_ATTR_TYPE,
1644
"Directory", stat_type_tostring(st.st_mode));
1645
}
1646
1647
if (file_status & FILE_META_MISMATCH_UNAME) {
1648
pwd = getpwuid(st.st_uid);
1649
pkg_emit_dir_meta_mismatch(pkg, d, PKG_META_ATTR_UNAME,
1650
d->uname, pwd != NULL ? pwd->pw_name : NULL);
1651
}
1652
if (file_status & FILE_META_MISMATCH_GNAME) {
1653
grp = getgrgid(st.st_gid);
1654
pkg_emit_dir_meta_mismatch(pkg, d, PKG_META_ATTR_GNAME,
1655
d->gname, grp != NULL ? grp->gr_name : NULL);
1656
}
1657
if (file_status & FILE_META_MISMATCH_MODE) {
1658
strmode(d->perm, db_str);
1659
strmode(st.st_mode, fs_str);
1660
db_str[10] = '\0'; /* trim last space character */
1661
db_str[10] = '\0';
1662
pkg_emit_dir_meta_mismatch(pkg, d, PKG_META_ATTR_PERM,
1663
db_str + 1, fs_str + 1);
1664
}
1665
#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(HAVE_FFLAGSTOSTR)
1666
if (file_status & FILE_META_MISMATCH_FFLAGS) {
1667
db_fflags = fflagstostr(d->fflags);
1668
fs_fflags = fflagstostr(st.st_flags);
1669
pkg_emit_dir_meta_mismatch(pkg, d, PKG_META_ATTR_FFLAGS,
1670
db_fflags, fs_fflags);
1671
free(db_fflags);
1672
free(fs_fflags);
1673
}
1674
#endif
1675
if (file_status == FILE_OK)
1676
pkg_emit_dir_meta_ok(pkg, d);
1677
else
1678
rc = EPKG_FATAL;
1679
1680
return (rc);
1681
}
1682
1683
int
1684
pkg_check_files(struct pkg *pkg, bool checksum, bool metadata)
1685
{
1686
struct pkg_file *f = NULL;
1687
struct pkg_dir *d = NULL;
1688
int rc = EPKG_OK;
1689
int ret;
1690
unsigned file_status;
1691
1692
assert(pkg != NULL);
1693
1694
while (pkg_files(pkg, &f) == EPKG_OK) {
1695
file_status = FILE_OK;
1696
1697
if (checksum && f->sum != NULL &&
1698
/* skip config files as they can be modified */
1699
pkghash_get_value(pkg->config_files_hash, f->path) == NULL) {
1700
ret = pkg_checksum_validate_fileat(ctx.rootfd,
1701
RELATIVE_PATH(f->path), f->sum);
1702
if (ret != 0) {
1703
if (ret == ENOENT)
1704
file_status |= FILE_MISSING;
1705
else
1706
file_status |= FILE_SUM_MISMATCH;
1707
rc = EPKG_FATAL;
1708
}
1709
}
1710
1711
ret = pkg_check_file(pkg, f, metadata, file_status);
1712
if (ret != EPKG_OK)
1713
rc = EPKG_FATAL;
1714
}
1715
1716
if (metadata) {
1717
while (pkg_dirs(pkg, &d) == EPKG_OK) {
1718
file_status = FILE_OK;
1719
ret = pkg_check_dir(pkg, d, file_status);
1720
if (ret != EPKG_OK)
1721
rc = EPKG_FATAL;
1722
}
1723
}
1724
1725
return (rc);
1726
}
1727
1728
int
1729
pkg_test_filesum(struct pkg *pkg)
1730
{
1731
return pkg_check_files(pkg, true, false);
1732
}
1733
1734
int
1735
pkg_try_installed(struct pkgdb *db, const char *name,
1736
struct pkg **pkg, unsigned flags) {
1737
struct pkgdb_it *it = NULL;
1738
int ret = EPKG_FATAL;
1739
1740
if ((it = pkgdb_query(db, name, MATCH_INTERNAL)) == NULL)
1741
return (EPKG_FATAL);
1742
1743
ret = pkgdb_it_next(it, pkg, flags);
1744
pkgdb_it_free(it);
1745
1746
return (ret);
1747
}
1748
1749
int
1750
pkg_is_installed(struct pkgdb *db, const char *name)
1751
{
1752
struct pkg *pkg = NULL;
1753
int ret = EPKG_FATAL;
1754
1755
ret = pkg_try_installed(db, name, &pkg, PKG_LOAD_BASIC);
1756
pkg_free(pkg);
1757
1758
return (ret);
1759
}
1760
1761
bool
1762
pkg_has_message(struct pkg *p)
1763
{
1764
return (vec_len(&p->message) > 0);
1765
}
1766
1767
bool
1768
pkg_is_locked(const struct pkg * restrict p)
1769
{
1770
assert(p != NULL);
1771
1772
return (p->locked);
1773
}
1774
1775
bool
1776
pkg_is_config_file(struct pkg *p, const char *path,
1777
const struct pkg_file **file,
1778
struct pkg_config_file **cfile)
1779
{
1780
*file = NULL;
1781
*cfile = NULL;
1782
1783
if (pkghash_count(p->config_files_hash) == 0)
1784
return (false);
1785
1786
*file = pkghash_get_value(p->filehash, path);
1787
if (*file == NULL)
1788
return (false);
1789
*cfile = pkghash_get_value(p->config_files_hash, path);
1790
if (*cfile == NULL) {
1791
*file = NULL;
1792
return (false);
1793
}
1794
1795
return (true);
1796
}
1797
1798
struct pkg_dir *
1799
pkg_get_dir(struct pkg *p, const char *path)
1800
{
1801
return (pkghash_get_value(p->dirhash, path));
1802
}
1803
1804
struct pkg_file *
1805
pkg_get_file(struct pkg *p, const char *path)
1806
{
1807
return (pkghash_get_value(p->filehash, path));
1808
}
1809
1810
bool
1811
pkg_has_file(struct pkg *p, const char *path)
1812
{
1813
return (pkghash_get(p->filehash, path) != NULL);
1814
}
1815
1816
bool
1817
pkg_has_dir(struct pkg *p, const char *path)
1818
{
1819
return (pkghash_get(p->dirhash, path) != NULL);
1820
}
1821
1822
int
1823
pkg_open_root_fd(struct pkg *pkg)
1824
{
1825
const char *path;
1826
char rootpath[MAXPATHLEN];
1827
1828
if (pkg->rootfd != -1)
1829
return (EPKG_OK);
1830
1831
path = pkg_kv_get(&pkg->annotations, "relocated");
1832
if (path == NULL) {
1833
if ((pkg->rootfd = dup(ctx.rootfd)) == -1) {
1834
pkg_emit_errno("dup", "rootfd");
1835
return (EPKG_FATAL);
1836
}
1837
return (EPKG_OK);
1838
}
1839
1840
pkg_absolutepath(path, rootpath, sizeof(rootpath), false);
1841
1842
if ((pkg->rootfd = openat(ctx.rootfd, RELATIVE_PATH(rootpath), O_DIRECTORY)) >= 0 ) {
1843
pkg->rootpath = xstrdup(rootpath);
1844
return (EPKG_OK);
1845
}
1846
1847
pkg_emit_errno("open", path);
1848
1849
return (EPKG_FATAL);
1850
}
1851
1852
int
1853
pkg_message_from_ucl(struct pkg *pkg, const ucl_object_t *obj)
1854
{
1855
struct pkg_message *msg = NULL;
1856
const ucl_object_t *elt, *cur;
1857
ucl_object_iter_t it = NULL;
1858
1859
if (ucl_object_type(obj) == UCL_STRING) {
1860
msg = xcalloc(1, sizeof(*msg));
1861
msg->str = xstrdup(ucl_object_tostring(obj));
1862
msg->type = PKG_MESSAGE_ALWAYS;
1863
vec_push(&pkg->message, msg);
1864
return (EPKG_OK);
1865
}
1866
1867
/* New format of pkg message */
1868
if (ucl_object_type(obj) != UCL_ARRAY)
1869
pkg_emit_error("package message badly formatted, an array was"
1870
" expected");
1871
1872
while ((cur = ucl_iterate_object(obj, &it, true))) {
1873
elt = ucl_object_find_key(cur, "message");
1874
1875
if (elt == NULL || ucl_object_type(elt) != UCL_STRING) {
1876
pkg_emit_error("package message lacks 'message' key"
1877
" that is required");
1878
1879
return (EPKG_FATAL);
1880
}
1881
1882
msg = xcalloc(1, sizeof(*msg));
1883
1884
msg->str = xstrdup(ucl_object_tostring(elt));
1885
msg->type = PKG_MESSAGE_ALWAYS;
1886
elt = ucl_object_find_key(cur, "type");
1887
if (elt != NULL && ucl_object_type(elt) == UCL_STRING) {
1888
if (STRIEQ(ucl_object_tostring(elt), "install"))
1889
msg->type = PKG_MESSAGE_INSTALL;
1890
else if (STRIEQ(ucl_object_tostring(elt), "remove"))
1891
msg->type = PKG_MESSAGE_REMOVE;
1892
else if (STRIEQ(ucl_object_tostring(elt), "upgrade"))
1893
msg->type = PKG_MESSAGE_UPGRADE;
1894
else
1895
pkg_emit_error("Unknown message type,"
1896
" message will always be printed");
1897
}
1898
if (msg->type != PKG_MESSAGE_UPGRADE) {
1899
vec_push(&pkg->message, msg);
1900
continue;
1901
}
1902
1903
elt = ucl_object_find_key(cur, "minimum_version");
1904
if (elt != NULL && ucl_object_type(elt) == UCL_STRING) {
1905
msg->minimum_version = xstrdup(ucl_object_tostring(elt));
1906
}
1907
1908
elt = ucl_object_find_key(cur, "maximum_version");
1909
if (elt != NULL && ucl_object_type(elt) == UCL_STRING) {
1910
msg->maximum_version = xstrdup(ucl_object_tostring(elt));
1911
}
1912
1913
vec_push(&pkg->message, msg);
1914
}
1915
1916
return (EPKG_OK);
1917
}
1918
1919
int
1920
pkg_message_from_str(struct pkg *pkg, const char *str, size_t len)
1921
{
1922
struct ucl_parser *parser;
1923
ucl_object_t *obj;
1924
int ret = EPKG_FATAL;
1925
1926
assert(str != NULL);
1927
1928
if (len == 0) {
1929
len = strlen(str);
1930
}
1931
1932
parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
1933
if (pkg->prefix != NULL) {
1934
ucl_parser_register_variable(parser, "PREFIX", pkg->prefix);
1935
}
1936
if (pkg->name != NULL) {
1937
ucl_parser_register_variable(parser, "PKGNAME", pkg->name);
1938
}
1939
if (pkg->origin != NULL) {
1940
ucl_parser_register_variable(parser, "PKGORIGIN", pkg->origin);
1941
}
1942
if (pkg->maintainer != NULL) {
1943
ucl_parser_register_variable(parser, "MAINTAINER", pkg->maintainer);
1944
}
1945
1946
if (ucl_parser_add_chunk(parser, (const unsigned char*)str, len)) {
1947
obj = ucl_parser_get_object(parser);
1948
ucl_parser_free(parser);
1949
1950
ret = pkg_message_from_ucl(pkg, obj);
1951
ucl_object_unref(obj);
1952
1953
return (ret);
1954
}
1955
1956
ucl_parser_free (parser);
1957
1958
return (ret);
1959
}
1960
1961
ucl_object_t*
1962
pkg_message_to_ucl(const struct pkg *pkg)
1963
{
1964
struct pkg_message *msg;
1965
ucl_object_t *array;
1966
ucl_object_t *obj;
1967
1968
array = ucl_object_typed_new(UCL_ARRAY);
1969
vec_foreach(pkg->message, i) {
1970
msg = pkg->message.d[i];
1971
obj = ucl_object_typed_new (UCL_OBJECT);
1972
1973
ucl_object_insert_key(obj,
1974
ucl_object_fromstring_common(msg->str, 0,
1975
UCL_STRING_RAW|UCL_STRING_TRIM),
1976
"message", 0, false);
1977
1978
switch (msg->type) {
1979
case PKG_MESSAGE_ALWAYS:
1980
break;
1981
case PKG_MESSAGE_INSTALL:
1982
ucl_object_insert_key(obj,
1983
ucl_object_fromstring("install"),
1984
"type", 0, false);
1985
break;
1986
case PKG_MESSAGE_UPGRADE:
1987
ucl_object_insert_key(obj,
1988
ucl_object_fromstring("upgrade"),
1989
"type", 0, false);
1990
break;
1991
case PKG_MESSAGE_REMOVE:
1992
ucl_object_insert_key(obj,
1993
ucl_object_fromstring("remove"),
1994
"type", 0, false);
1995
break;
1996
}
1997
if (msg->maximum_version) {
1998
ucl_object_insert_key(obj,
1999
ucl_object_fromstring(msg->maximum_version),
2000
"maximum_version", 0, false);
2001
}
2002
if (msg->minimum_version) {
2003
ucl_object_insert_key(obj,
2004
ucl_object_fromstring(msg->minimum_version),
2005
"minimum_version", 0, false);
2006
}
2007
ucl_array_append(array, obj);
2008
}
2009
2010
return (array);
2011
}
2012
2013
char*
2014
pkg_message_to_str(struct pkg *pkg)
2015
{
2016
ucl_object_t *obj;
2017
char *ret = NULL;
2018
2019
if (vec_len(&pkg->message) <= 0)
2020
return (NULL);
2021
2022
obj = pkg_message_to_ucl(pkg);
2023
ret = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
2024
ucl_object_unref(obj);
2025
2026
return (ret);
2027
}
2028
2029
static int
2030
pkg_dep_cmp(struct pkg_dep *a, struct pkg_dep *b)
2031
{
2032
return (STREQ(a->name, b->name));
2033
}
2034
2035
static int
2036
pkg_file_cmp(struct pkg_file *a, struct pkg_file *b)
2037
{
2038
return (STREQ(a->path, b->path));
2039
}
2040
2041
static int
2042
pkg_dir_cmp(struct pkg_dir *a, struct pkg_dir *b)
2043
{
2044
return (STREQ(a->path, b->path));
2045
}
2046
2047
static int
2048
pkg_option_cmp(struct pkg_option *a, struct pkg_option *b)
2049
{
2050
return (STREQ(a->key, b->key));
2051
}
2052
2053
static int
2054
pkg_cf_cmp(struct pkg_config_file *a, struct pkg_config_file *b)
2055
{
2056
return (STREQ(a->path, b->path));
2057
}
2058
2059
void
2060
pkg_lists_sort(struct pkg *p)
2061
{
2062
if (p->list_sorted)
2063
return;
2064
p->list_sorted = true;
2065
2066
DL_SORT(p->depends, pkg_dep_cmp);
2067
DL_SORT(p->files, pkg_file_cmp);
2068
DL_SORT(p->dirs, pkg_dir_cmp);
2069
DL_SORT(p->options, pkg_option_cmp);
2070
DL_SORT(p->config_files, pkg_cf_cmp);
2071
}
2072
2073
static int
2074
pkgs_cmp(const void *a, const void *b)
2075
{
2076
struct pkg *pa = *(struct pkg **)a;
2077
struct pkg *pb = *(struct pkg **)b;
2078
2079
return (strcmp(pa->name, pb->name));
2080
}
2081
2082
void
2083
pkgs_sort(pkgs_t *pkgs)
2084
{
2085
if (pkgs->len == 0)
2086
return;
2087
qsort(pkgs->d, pkgs->len, sizeof(pkgs->d[0]), pkgs_cmp);
2088
}
2089
2090
DEFINE_VEC_INSERT_SORTED_FUNC(pkgs_t, pkgs, struct pkg *, pkgs_cmp)
2091
2092
struct pkg **
2093
pkgs_search(pkgs_t *pkgs, char *el)
2094
{
2095
struct pkg target = { .name = el };
2096
struct pkg *tgt = &target;
2097
if (pkgs->len == 0)
2098
return (NULL);
2099
struct pkg **res = bsearch(&tgt, pkgs->d, pkgs->len, sizeof(pkgs->d[0]), pkgs_cmp);
2100
return (res);
2101
}
2102
2103