1 /* $NetBSD: perform.c,v 1.4 2021/04/10 19:49:59 nia Exp $ */
2
3 #if HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 #include <nbcompat.h>
7 #if HAVE_SYS_CDEFS_H
8 #include <sys/cdefs.h>
9 #endif
10 __RCSID("$NetBSD: perform.c,v 1.4 2021/04/10 19:49:59 nia Exp $");
11
12 /*-
13 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in
24 * the documentation and/or other materials provided with the
25 * distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
35 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41 /*
42 * FreeBSD install - a package for the installation and maintainance
43 * of non-core utilities.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 *
54 * Jordan K. Hubbard
55 * 23 Aug 1993
56 *
57 * This is the main body of the info module.
58 *
59 */
60
61 #include "lib.h"
62 #include "info.h"
63
64 #if HAVE_SYS_TYPES_H
65 #include <sys/types.h>
66 #endif
67 #if HAVE_SYS_STAT_H
68 #include <sys/stat.h>
69 #endif
70 #if HAVE_SYS_QUEUE_H
71 #include <sys/queue.h>
72 #endif
73 #if HAVE_SYS_WAIT_H
74 #include <sys/wait.h>
75 #endif
76
77 #ifndef BOOTSTRAP
78 #include <archive.h>
79 #include <archive_entry.h>
80 #endif
81 #if HAVE_ERR_H
82 #include <err.h>
83 #endif
84 #include <ctype.h>
85 #include <dirent.h>
86 #include <errno.h>
87 #include <fcntl.h>
88 #include <limits.h>
89 #include <stddef.h>
90 #include <signal.h>
91
92 #define LOAD_CONTENTS (1 << 0)
93 #define LOAD_COMMENT (1 << 1)
94 #define LOAD_DESC (1 << 2)
95 #define LOAD_INSTALL (1 << 3)
96 #define LOAD_DEINSTALL (1 << 4)
97 #define LOAD_DISPLAY (1 << 5)
98 #define LOAD_MTREE (1 << 6)
99 #define LOAD_BUILD_VERSION (1 << 7)
100 #define LOAD_BUILD_INFO (1 << 8)
101 #define LOAD_SIZE_PKG (1 << 9)
102 #define LOAD_SIZE_ALL (1 << 10)
103 #define LOAD_PRESERVE (1 << 11)
104 #define LOAD_REQUIRED_BY (1 << 12)
105 #define LOAD_INSTALLED_INFO (1 << 13)
106
107 static const struct pkg_meta_desc {
108 size_t entry_offset;
109 const char *entry_filename;
110 int entry_mask;
111 int required_file;
112 } pkg_meta_descriptors[] = {
113 { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME,
114 LOAD_CONTENTS, 1},
115 { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME,
116 LOAD_COMMENT, 1 },
117 { offsetof(struct pkg_meta, meta_desc), DESC_FNAME,
118 LOAD_DESC, 1 },
119 { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME,
120 LOAD_INSTALL, 0 },
121 { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME,
122 LOAD_DEINSTALL, 0 },
123 { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME,
124 LOAD_DISPLAY, 0 },
125 { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME,
126 LOAD_MTREE, 0 },
127 { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME,
128 LOAD_BUILD_VERSION, 0 },
129 { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME,
130 LOAD_BUILD_INFO, 0 },
131 { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME,
132 LOAD_SIZE_PKG, 0 },
133 { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME,
134 LOAD_SIZE_ALL, 0 },
135 { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME,
136 LOAD_PRESERVE, 0 },
137 { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME,
138 LOAD_REQUIRED_BY, 0 },
139 { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME,
140 LOAD_INSTALLED_INFO, 0 },
141 { 0, NULL, 0, 0 },
142 };
143
144 static int desired_meta_data;
145
146 static void
free_pkg_meta(struct pkg_meta * meta)147 free_pkg_meta(struct pkg_meta *meta)
148 {
149 const struct pkg_meta_desc *descr;
150
151 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr)
152 free(*(char **)((char *)meta + descr->entry_offset));
153
154 free(meta);
155 }
156
157 #ifndef BOOTSTRAP
158 static struct pkg_meta *
read_meta_data_from_archive(struct archive * archive,struct archive_entry * entry)159 read_meta_data_from_archive(struct archive *archive,
160 struct archive_entry *entry)
161 {
162 struct pkg_meta *meta;
163 const char *fname;
164 const struct pkg_meta_desc *descr, *last_descr;
165 char **target;
166 int64_t size;
167 int r, found_required;
168
169 found_required = 0;
170
171 meta = xcalloc(1, sizeof(*meta));
172
173 last_descr = 0;
174 if (entry != NULL) {
175 r = ARCHIVE_OK;
176 goto has_entry;
177 }
178
179 while ((r = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
180 has_entry:
181 fname = archive_entry_pathname(entry);
182
183 for (descr = pkg_meta_descriptors; descr->entry_filename;
184 ++descr) {
185 if (strcmp(descr->entry_filename, fname) == 0)
186 break;
187 }
188 if (descr->entry_filename == NULL)
189 break;
190
191 if (descr->required_file)
192 ++found_required;
193
194 target = (char **)((char *)meta + descr->entry_offset);
195 if (*target)
196 errx(2, "duplicate entry, package corrupt");
197 if (descr < last_descr)
198 warnx("misordered package, continuing");
199 else
200 last_descr = descr;
201
202 if ((descr->entry_mask & desired_meta_data) == 0) {
203 if (archive_read_data_skip(archive))
204 errx(2, "cannot read package meta data");
205 continue;
206 }
207
208 size = archive_entry_size(entry);
209 if (size > SSIZE_MAX - 1)
210 errx(2, "package meta data too large to process");
211 *target = xmalloc(size + 1);
212 if (archive_read_data(archive, *target, size) != size)
213 errx(2, "cannot read package meta data");
214 (*target)[size] = '\0';
215 }
216
217 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
218 if (descr->required_file)
219 --found_required;
220 }
221
222 meta->is_installed = 0;
223 if (found_required != 0 || (r != ARCHIVE_OK && r != ARCHIVE_EOF)) {
224 free_pkg_meta(meta);
225 meta = NULL;
226 }
227
228 return meta;
229 }
230 #endif
231
232 static struct pkg_meta *
read_meta_data_from_pkgdb(const char * pkg)233 read_meta_data_from_pkgdb(const char *pkg)
234 {
235 struct pkg_meta *meta;
236 const struct pkg_meta_desc *descr;
237 char **target;
238 char *fname;
239 int fd;
240 struct stat st;
241
242 meta = xcalloc(1, sizeof(*meta));
243
244 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
245 if ((descr->entry_mask & desired_meta_data) == 0)
246 continue;
247
248 fname = pkgdb_pkg_file(pkg, descr->entry_filename);
249 fd = open(fname, O_RDONLY, 0);
250 free(fname);
251 if (fd == -1) {
252 if (errno == ENOENT && descr->required_file == 0)
253 continue;
254 err(2, "cannot read meta data file %s of package %s",
255 descr->entry_filename, pkg);
256 }
257 target = (char **)((char *)meta + descr->entry_offset);
258
259 if (fstat(fd, &st) == -1)
260 err(2, "cannot stat meta data");
261 if ((st.st_mode & S_IFMT) != S_IFREG)
262 errx(1, "meta data is not regular file");
263 if (st.st_size > SSIZE_MAX - 1)
264 err(2, "meta data file too large to process");
265 *target = xmalloc(st.st_size + 1);
266 if (read(fd, *target, st.st_size) != st.st_size)
267 err(2, "cannot read meta data");
268 (*target)[st.st_size] = '\0';
269 close(fd);
270 }
271
272 meta->is_installed = 1;
273
274 return meta;
275 }
276
277 static void
build_full_reqby(lpkg_head_t * reqby,struct pkg_meta * meta,int limit)278 build_full_reqby(lpkg_head_t *reqby, struct pkg_meta *meta, int limit)
279 {
280 char *iter, *eol, *next;
281 lpkg_t *lpp;
282 struct pkg_meta *meta_dep;
283
284 if (limit == 65536)
285 errx(1, "Cycle in the dependency tree, bailing out");
286
287 if (meta->is_installed == 0 || meta->meta_required_by == NULL)
288 return;
289
290 for (iter = meta->meta_required_by; *iter != '\0'; iter = next) {
291 eol = iter + strcspn(iter, "\n");
292 if (*eol == '\n')
293 next = eol + 1;
294 else
295 next = eol;
296 if (iter == eol)
297 continue;
298 TAILQ_FOREACH(lpp, reqby, lp_link) {
299 if (strlen(lpp->lp_name) + iter != eol)
300 continue;
301 if (memcmp(lpp->lp_name, iter, eol - iter) == 0)
302 break;
303 }
304 if (lpp != NULL)
305 continue;
306 *eol = '\0';
307 lpp = alloc_lpkg(iter);
308 if (next != eol)
309 *eol = '\n';
310
311 meta_dep = read_meta_data_from_pkgdb(lpp->lp_name);
312 if (meta_dep == NULL)
313 continue;
314 build_full_reqby(reqby, meta_dep, limit + 1);
315 free_pkg_meta(meta_dep);
316
317 TAILQ_INSERT_HEAD(reqby, lpp, lp_link);
318 }
319 }
320
321 static lfile_head_t files;
322
323 static int
pkg_do(const char * pkg)324 pkg_do(const char *pkg)
325 {
326 struct pkg_meta *meta;
327 int code = 0;
328 const char *binpkgfile = NULL;
329 char *pkgdir;
330
331 if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) {
332 #ifdef BOOTSTRAP
333 errx(2, "Binary packages not supported during bootstrap");
334 #else
335 struct archive *archive;
336 struct archive_entry *entry;
337 char *archive_name, *pkgname;
338
339 archive = open_archive(pkg, &archive_name);
340 if (archive == NULL) {
341 warnx("can't find package `%s', skipped", pkg);
342 return -1;
343 }
344 pkgname = NULL;
345 entry = NULL;
346 pkg_verify_signature(archive_name, &archive, &entry, &pkgname);
347 if (archive == NULL)
348 return -1;
349 free(pkgname);
350
351 meta = read_meta_data_from_archive(archive, entry);
352 archive_read_free(archive);
353 if (!IS_URL(pkg))
354 binpkgfile = pkg;
355 #endif
356 } else {
357 /*
358 * It's not an uninstalled package, try and find it among the
359 * installed
360 */
361 pkgdir = pkgdb_pkg_dir(pkg);
362 if (!fexists(pkgdir) || !(isdir(pkgdir) || islinktodir(pkgdir))) {
363 switch (add_installed_pkgs_by_basename(pkg, &pkgs)) {
364 case 1:
365 return 0;
366 case 0:
367 /* No match */
368 warnx("can't find package `%s'", pkg);
369 return 1;
370 case -1:
371 errx(EXIT_FAILURE, "Error during search in pkgdb for %s", pkg);
372 }
373 }
374 free(pkgdir);
375 meta = read_meta_data_from_pkgdb(pkg);
376 }
377
378 if (meta == NULL) {
379 warnx("invalid package `%s' skipped", pkg);
380 return 1;
381 }
382
383 /*
384 * Index is special info type that has to override all others to make
385 * any sense.
386 */
387 if (Flags & SHOW_INDEX) {
388 char tmp[MaxPathSize];
389
390 (void) snprintf(tmp, sizeof(tmp), "%-19s ", pkg);
391 show_index(meta->meta_comment, tmp);
392 } else if (Flags & SHOW_BI_VAR) {
393 if (strcspn(BuildInfoVariable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
394 == strlen(BuildInfoVariable)) {
395 if (meta->meta_installed_info)
396 show_var(meta->meta_installed_info, BuildInfoVariable);
397 } else {
398 if (meta->meta_build_info)
399 show_var(meta->meta_build_info, BuildInfoVariable);
400 else
401 warnx("Build information missing");
402 }
403 } else {
404 package_t plist;
405
406 /* Read the contents list */
407 parse_plist(&plist, meta->meta_contents);
408
409 /* Start showing the package contents */
410 if (!Quiet && !(Flags & SHOW_SUMMARY)) {
411 printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
412 if (meta->meta_preserve) {
413 printf("*** PACKAGE MAY NOT BE DELETED ***\n");
414 }
415 }
416 if (Flags & SHOW_SUMMARY) {
417 show_summary(meta, &plist, binpkgfile);
418 }
419 if (Flags & SHOW_COMMENT) {
420 show_file(meta->meta_comment, "Comment:\n", TRUE);
421 }
422 if (Flags & SHOW_DEPENDS) {
423 show_depends("Requires:\n", &plist);
424 }
425 if (Flags & SHOW_BLD_DEPENDS) {
426 show_bld_depends("Built using:\n", &plist);
427 }
428 if ((Flags & SHOW_REQBY) && meta->meta_required_by) {
429 show_file(meta->meta_required_by, "Required by:\n", TRUE);
430 }
431 if ((Flags & SHOW_FULL_REQBY) && meta->is_installed) {
432 lpkg_head_t reqby;
433 TAILQ_INIT(&reqby);
434 build_full_reqby(&reqby, meta, 0);
435 show_list(&reqby, "Full required by list:\n");
436 }
437 if (Flags & SHOW_DESC) {
438 show_file(meta->meta_desc, "Description:\n", TRUE);
439 }
440 if ((Flags & SHOW_DISPLAY) && meta->meta_display) {
441 show_file(meta->meta_display, "Install notice:\n",
442 TRUE);
443 }
444 if (Flags & SHOW_PLIST) {
445 show_plist("Packing list:\n", &plist, PLIST_SHOW_ALL);
446 }
447 if ((Flags & SHOW_INSTALL) && meta->meta_install) {
448 show_file(meta->meta_install, "Install script:\n",
449 TRUE);
450 }
451 if ((Flags & SHOW_DEINSTALL) && meta->meta_deinstall) {
452 show_file(meta->meta_deinstall, "De-Install script:\n",
453 TRUE);
454 }
455 if ((Flags & SHOW_MTREE) && meta->meta_mtree) {
456 show_file(meta->meta_mtree, "mtree file:\n", TRUE);
457 }
458 if (Flags & SHOW_PREFIX) {
459 show_plist("Prefix(s):\n", &plist, PLIST_CWD);
460 }
461 if (Flags & SHOW_FILES) {
462 show_files("Files:\n", &plist);
463 }
464 if ((Flags & SHOW_BUILD_VERSION) && meta->meta_build_version) {
465 show_file(meta->meta_build_version, "Build version:\n",
466 TRUE);
467 }
468 if (Flags & SHOW_BUILD_INFO) {
469 if (meta->meta_build_info) {
470 show_file(meta->meta_build_info, "Build information:\n",
471 TRUE);
472 }
473 if (meta->meta_installed_info) {
474 show_file(meta->meta_installed_info, "Installed information:\n",
475 TRUE);
476 }
477 }
478 if ((Flags & SHOW_PKG_SIZE) && meta->meta_size_pkg) {
479 show_file(meta->meta_size_pkg, "Size of this package in bytes: ",
480 TRUE);
481 }
482 if ((Flags & SHOW_ALL_SIZE) && meta->meta_size_all) {
483 show_file(meta->meta_size_all, "Size in bytes including required pkgs: ",
484 TRUE);
485 }
486 if (!Quiet && !(Flags & SHOW_SUMMARY)) {
487 if (meta->meta_preserve) {
488 printf("*** PACKAGE MAY NOT BE DELETED ***\n\n");
489 }
490 puts(InfoPrefix);
491 }
492 free_plist(&plist);
493 }
494 free_pkg_meta(meta);
495 return code;
496 }
497
498 struct print_matching_arg {
499 const char *pattern;
500 int got_match;
501 };
502
503 static int
print_matching_pkg(const char * pkgname,void * cookie)504 print_matching_pkg(const char *pkgname, void *cookie)
505 {
506 struct print_matching_arg *arg= cookie;
507
508 if (pkg_match(arg->pattern, pkgname)) {
509 if (!Quiet)
510 puts(pkgname);
511 arg->got_match = 1;
512 }
513
514 return 0;
515 }
516
517 /*
518 * Returns 0 if at least one package matching pkgname.
519 * Returns 1 otherwise.
520 *
521 * If -q was not specified, print all matching packages to stdout.
522 */
523 int
CheckForPkg(const char * pkgname)524 CheckForPkg(const char *pkgname)
525 {
526 struct print_matching_arg arg;
527
528 arg.pattern = pkgname;
529 arg.got_match = 0;
530
531 if (iterate_pkg_db(print_matching_pkg, &arg) == -1) {
532 warnx("cannot iterate pkgdb");
533 return 1;
534 }
535
536 if (arg.got_match == 0 && !ispkgpattern(pkgname)) {
537 char *pattern;
538
539 pattern = xasprintf("%s-[0-9]*", pkgname);
540
541 arg.pattern = pattern;
542 arg.got_match = 0;
543
544 if (iterate_pkg_db(print_matching_pkg, &arg) == -1) {
545 free(pattern);
546 warnx("cannot iterate pkgdb");
547 return 1;
548 }
549 free(pattern);
550 }
551
552 if (arg.got_match)
553 return 0;
554 else
555 return 1;
556 }
557
558 /*
559 * Returns 0 if at least one package matching pkgname.
560 * Returns 1 otherwise.
561 *
562 * If -q was not specified, print best match to stdout.
563 */
564 int
CheckForBestPkg(const char * pkgname)565 CheckForBestPkg(const char *pkgname)
566 {
567 char *pattern, *best_match;
568
569 best_match = find_best_matching_installed_pkg(pkgname, 1);
570 if (best_match == NULL) {
571 if (ispkgpattern(pkgname))
572 return 1;
573
574 pattern = xasprintf("%s-[0-9]*", pkgname);
575 best_match = find_best_matching_installed_pkg(pattern, 1);
576 free(pattern);
577 }
578
579 if (best_match == NULL)
580 return 1;
581 if (!Quiet)
582 puts(best_match);
583 free(best_match);
584 return 0;
585 }
586
587 static int
perform_single_pkg(const char * pkg,void * cookie)588 perform_single_pkg(const char *pkg, void *cookie)
589 {
590 int *err_cnt = cookie;
591
592 if (Which == WHICH_ALL || !is_automatic_installed(pkg))
593 *err_cnt += pkg_do(pkg);
594
595 return 0;
596 }
597
598 int
pkg_perform(lpkg_head_t * pkghead)599 pkg_perform(lpkg_head_t *pkghead)
600 {
601 int err_cnt = 0;
602
603 TAILQ_INIT(&files);
604
605 desired_meta_data = 0;
606 if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0)
607 desired_meta_data |= LOAD_PRESERVE;
608 if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0)
609 desired_meta_data |= LOAD_CONTENTS;
610 if (Flags & (SHOW_COMMENT | SHOW_INDEX | SHOW_SUMMARY))
611 desired_meta_data |= LOAD_COMMENT;
612 if (Flags & (SHOW_BI_VAR | SHOW_BUILD_INFO | SHOW_SUMMARY))
613 desired_meta_data |= LOAD_BUILD_INFO | LOAD_INSTALLED_INFO;
614 if (Flags & (SHOW_SUMMARY | SHOW_PKG_SIZE))
615 desired_meta_data |= LOAD_SIZE_PKG;
616 if (Flags & SHOW_ALL_SIZE)
617 desired_meta_data |= LOAD_SIZE_ALL;
618 if (Flags & (SHOW_SUMMARY | SHOW_DESC))
619 desired_meta_data |= LOAD_DESC;
620 if (Flags & (SHOW_REQBY | SHOW_FULL_REQBY))
621 desired_meta_data |= LOAD_REQUIRED_BY;
622 if (Flags & SHOW_DISPLAY)
623 desired_meta_data |= LOAD_DISPLAY;
624 if (Flags & SHOW_INSTALL)
625 desired_meta_data |= LOAD_INSTALL;
626 if (Flags & SHOW_DEINSTALL)
627 desired_meta_data |= LOAD_DEINSTALL;
628 if (Flags & SHOW_MTREE)
629 desired_meta_data |= LOAD_MTREE;
630 if (Flags & SHOW_BUILD_VERSION)
631 desired_meta_data |= LOAD_BUILD_VERSION;
632
633 if (Which != WHICH_LIST) {
634 if (File2Pkg) {
635 /* Show all files with the package they belong to */
636 if (pkgdb_dump() == -1)
637 err_cnt = 1;
638 } else {
639 if (iterate_pkg_db(perform_single_pkg, &err_cnt) == -1)
640 err_cnt = 1;
641 }
642 } else {
643 /* Show info on individual pkg(s) */
644 lpkg_t *lpp;
645
646 while ((lpp = TAILQ_FIRST(pkghead)) != NULL) {
647 TAILQ_REMOVE(pkghead, lpp, lp_link);
648 err_cnt += pkg_do(lpp->lp_name);
649 free_lpkg(lpp);
650 }
651 }
652 return err_cnt;
653 }
654