Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / pkg_install / dist / lib / plist.c
blob1ae5dcaff566e4c96828db418e5ea89216f85e29
1 /* $NetBSD: plist.c,v 1.29 2009/08/02 17:56:45 joerg Exp $ */
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: plist.c,v 1.29 2009/08/02 17:56:45 joerg Exp $");
13 * FreeBSD install - a package for the installation and maintainance
14 * of non-core utilities.
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 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * Jordan K. Hubbard
26 * 18 July 1993
28 * General packing list routines.
32 /*-
33 * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
45 * distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
50 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
51 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
52 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
53 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
55 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
61 #include "lib.h"
62 #if HAVE_ERRNO_H
63 #include <errno.h>
64 #endif
65 #if HAVE_ERR_H
66 #include <err.h>
67 #endif
68 #ifndef NETBSD
69 #include <nbcompat/md5.h>
70 #else
71 #include <md5.h>
72 #endif
74 static int delete_with_parents(const char *, Boolean, Boolean);
76 /* This struct defines a plist command type */
77 typedef struct cmd_t {
78 const char *c_s; /* string to recognise */
79 pl_ent_t c_type; /* type of command */
80 int c_argc; /* # of arguments */
81 int c_subst; /* can substitute real prefix */
82 } cmd_t;
84 /* Commands to recognise */
85 static const cmd_t cmdv[] = {
86 {"cwd", PLIST_CWD, 1, 1},
87 {"src", PLIST_SRC, 1, 1},
88 {"exec", PLIST_CMD, 1, 0},
89 {"unexec", PLIST_UNEXEC, 1, 0},
90 {"mode", PLIST_CHMOD, 1, 0},
91 {"owner", PLIST_CHOWN, 1, 0},
92 {"group", PLIST_CHGRP, 1, 0},
93 {"comment", PLIST_COMMENT, 1, 0},
94 {"ignore", PLIST_IGNORE, 0, 0},
95 {"name", PLIST_NAME, 1, 0},
96 {"display", PLIST_DISPLAY, 1, 0},
97 {"pkgdep", PLIST_PKGDEP, 1, 0},
98 {"pkgcfl", PLIST_PKGCFL, 1, 0},
99 {"pkgdir", PLIST_PKGDIR, 1, 0},
100 {"dirrm", PLIST_DIR_RM, 1, 0},
101 {"option", PLIST_OPTION, 1, 0},
102 {"blddep", PLIST_BLDDEP, 1, 0},
103 {NULL, FAIL, 0, 0}
107 * Add an item to the end of a packing list
109 void
110 add_plist(package_t *p, pl_ent_t type, const char *arg)
112 plist_t *tmp;
114 tmp = new_plist_entry();
115 tmp->name = (arg == NULL) ? NULL : xstrdup(arg);
116 tmp->type = type;
117 if (!p->head) {
118 p->head = p->tail = tmp;
119 } else {
120 tmp->prev = p->tail;
121 p->tail->next = tmp;
122 p->tail = tmp;
127 * Add an item to the start of a packing list
129 void
130 add_plist_top(package_t *p, pl_ent_t type, const char *arg)
132 plist_t *tmp;
134 tmp = new_plist_entry();
135 tmp->name = (arg == NULL) ? NULL : xstrdup(arg);
136 tmp->type = type;
137 if (!p->head) {
138 p->head = p->tail = tmp;
139 } else {
140 tmp->next = p->head;
141 p->head->prev = tmp;
142 p->head = tmp;
147 * Return the last (most recent) entry in a packing list
149 plist_t *
150 last_plist(package_t *p)
152 return p->tail;
156 * Mark all items in a packing list to prevent iteration over them
158 void
159 mark_plist(package_t *pkg)
161 plist_t *pp;
163 for (pp = pkg->head; pp; pp = pp->next) {
164 pp->marked = TRUE;
169 * Find a given item in a packing list and, if so, return it (else NULL)
171 plist_t *
172 find_plist(package_t *pkg, pl_ent_t type)
174 plist_t *pp;
176 for (pp = pkg->head; pp && pp->type != type; pp = pp->next) {
178 return pp;
182 * Look for a specific boolean option argument in the list
184 char *
185 find_plist_option(package_t *pkg, const char *name)
187 plist_t *p;
189 for (p = pkg->head; p; p = p->next) {
190 if (p->type == PLIST_OPTION
191 && strcmp(p->name, name) == 0) {
192 return p->name;
196 return (char *) NULL;
200 * Delete plist item 'type' in the list (if 'name' is non-null, match it
201 * too.) If 'all' is set, delete all items, not just the first occurance.
203 void
204 delete_plist(package_t *pkg, Boolean all, pl_ent_t type, char *name)
206 plist_t *p = pkg->head;
208 while (p) {
209 plist_t *pnext = p->next;
211 if (p->type == type && (!name || !strcmp(name, p->name))) {
212 free(p->name);
213 if (p->prev)
214 p->prev->next = pnext;
215 else
216 pkg->head = pnext;
217 if (pnext)
218 pnext->prev = p->prev;
219 else
220 pkg->tail = p->prev;
221 free(p);
222 if (!all)
223 return;
224 p = pnext;
225 } else
226 p = p->next;
231 * Allocate a new packing list entry, and return a pointer to it.
233 plist_t *
234 new_plist_entry(void)
236 return xcalloc(1, sizeof(plist_t));
240 * Free an entire packing list
242 void
243 free_plist(package_t *pkg)
245 plist_t *p = pkg->head;
247 while (p) {
248 plist_t *p1 = p->next;
250 free(p->name);
251 free(p);
252 p = p1;
254 pkg->head = pkg->tail = NULL;
258 * For an ASCII string denoting a plist command, return its code and
259 * optionally its argument(s)
261 static int
262 plist_cmd(const char *s, char **arg)
264 const cmd_t *cmdp;
265 const char *cp, *sp;
266 char *sp2;
268 sp = NULL; /* Older GCC can't detect that the loop is executed */
270 for (cmdp = cmdv; cmdp->c_s; ++cmdp) {
271 for (sp = s, cp = cmdp->c_s; *sp && *cp; ++cp, ++sp)
272 if (*sp != *cp)
273 break;
274 if (*cp == '\0')
275 break;
278 if (cmdp->c_s == NULL || arg == NULL)
279 return cmdp->c_type;
281 while (isspace((unsigned char)*sp))
282 ++sp;
283 *arg = xstrdup(sp);
284 if (*sp) {
285 sp2 = *arg + strlen(*arg) - 1;
287 * The earlier loop ensured that at least one non-whitespace
288 * is in the string.
290 while (isspace((unsigned char)*sp2))
291 --sp2;
292 sp2[1] = '\0';
294 return cmdp->c_type;
298 * Parse a packaging list from a memory buffer.
300 void
301 parse_plist(package_t *pkg, const char *buf)
303 int cmd;
304 char *line, *cp;
305 const char *eol, *next;
306 size_t len;
308 pkg->head = NULL;
309 pkg->tail = NULL;
311 for (; *buf; buf = next) {
312 /* Until add_plist can deal with trailing whitespace. */
313 if ((eol = strchr(buf, '\n')) != NULL) {
314 next = eol + 1;
315 len = eol - buf;
316 } else {
317 len = strlen(buf);
318 next = buf + len;
321 while (len && isspace((unsigned char)buf[len - 1]))
322 --len;
324 if (len == 0)
325 continue;
327 line = xmalloc(len + 1);
328 memcpy(line, buf, len);
329 line[len] = '\0';
331 if (*(cp = line) == CMD_CHAR) {
332 if ((cmd = plist_cmd(line + 1, &cp)) == FAIL) {
333 warnx("Unrecognised PLIST command `%s'", line);
334 continue;
336 if (*cp == '\0') {
337 free(cp);
338 cp = NULL;
340 } else {
341 cmd = PLIST_FILE;
343 add_plist(pkg, cmd, cp);
344 free(cp);
349 * Read a packing list from a file
351 void
352 append_plist(package_t *pkg, FILE * fp)
354 char pline[MaxPathSize];
355 char *cp;
356 int cmd;
357 int len;
358 int free_cp;
360 while (fgets(pline, MaxPathSize, fp) != (char *) NULL) {
361 for (len = strlen(pline); len &&
362 isspace((unsigned char) pline[len - 1]);) {
363 pline[--len] = '\0';
365 if (len == 0) {
366 continue;
368 free_cp = 0;
369 if (*(cp = pline) == CMD_CHAR) {
370 if ((cmd = plist_cmd(pline + 1, &cp)) == FAIL) {
371 warnx("Unrecognised PLIST command `%s'", pline);
372 continue;
374 if (*cp == '\0') {
375 free(cp);
376 cp = NULL;
378 free_cp = 1;
379 } else {
380 cmd = PLIST_FILE;
382 add_plist(pkg, cmd, cp);
383 if (free_cp)
384 free(cp);
388 void
389 read_plist(package_t *pkg, FILE * fp)
391 pkg->head = NULL;
392 pkg->tail = NULL;
394 append_plist(pkg, fp);
398 * Write a packing list to a file, converting commands to ASCII equivs
400 void
401 write_plist(package_t *pkg, FILE * fp, char *realprefix)
403 plist_t *p;
404 const cmd_t *cmdp;
406 for (p = pkg->head; p; p = p->next) {
407 if (p->type == PLIST_FILE) {
408 /* Fast-track files - these are the most common */
409 (void) fprintf(fp, "%s\n", p->name);
410 continue;
412 for (cmdp = cmdv; cmdp->c_type != FAIL && cmdp->c_type != p->type; cmdp++) {
414 if (cmdp->c_type == FAIL) {
415 warnx("Unknown PLIST command type %d (%s)", p->type, p->name);
416 } else if (cmdp->c_argc == 0) {
417 (void) fprintf(fp, "%c%s\n", CMD_CHAR, cmdp->c_s);
418 } else if (cmdp->c_subst && realprefix) {
419 (void) fprintf(fp, "%c%s %s\n", CMD_CHAR, cmdp->c_s, realprefix);
420 } else {
421 (void) fprintf(fp, "%c%s %s\n", CMD_CHAR, cmdp->c_s,
422 (p->name) ? p->name : "");
428 * Like write_plist, but compute memory string.
430 void
431 stringify_plist(package_t *pkg, char **real_buf, size_t *real_len,
432 const char *realprefix)
434 plist_t *p;
435 const cmd_t *cmdp;
436 char *buf;
437 size_t len;
438 int item_len;
440 /* Pass One: compute output size only. */
441 len = 0;
443 for (p = pkg->head; p; p = p->next) {
444 if (p->type == PLIST_FILE) {
445 len += strlen(p->name) + 1;
446 continue;
448 for (cmdp = cmdv; cmdp->c_type != FAIL && cmdp->c_type != p->type; cmdp++) {
450 if (cmdp->c_type == FAIL)
451 continue;
452 if (cmdp->c_argc == 0)
453 len += 1 + strlen(cmdp->c_s) + 1;
454 else if (cmdp->c_subst && realprefix)
455 len += 1 + strlen(cmdp->c_s) + 1 + strlen(realprefix) + 1;
456 else
457 len += 1 + strlen(cmdp->c_s) + 1 + strlen(p->name ? p->name : "") + 1;
460 /* Pass Two: build actual string. */
461 buf = xmalloc(len + 1);
462 *real_buf = buf;
463 *real_len = len;
464 ++len;
466 #define UPDATE_LEN \
467 do { \
468 if (item_len < 0 || (size_t)item_len > len) \
469 errx(2, "Size computation failed, aborted."); \
470 buf += item_len; \
471 len -= item_len; \
472 } while (/* CONSTCOND */0)
474 for (p = pkg->head; p; p = p->next) {
475 if (p->type == PLIST_FILE) {
476 /* Fast-track files - these are the most common */
477 item_len = snprintf(buf, len, "%s\n", p->name);
478 UPDATE_LEN;
479 continue;
481 for (cmdp = cmdv; cmdp->c_type != FAIL && cmdp->c_type != p->type; cmdp++) {
483 if (cmdp->c_type == FAIL) {
484 warnx("Unknown PLIST command type %d (%s)", p->type, p->name);
485 } else if (cmdp->c_argc == 0) {
486 item_len = snprintf(buf, len, "%c%s\n", CMD_CHAR, cmdp->c_s);
487 UPDATE_LEN;
488 } else if (cmdp->c_subst && realprefix) {
489 item_len = snprintf(buf, len, "%c%s %s\n", CMD_CHAR, cmdp->c_s, realprefix);
490 UPDATE_LEN;
491 } else {
492 item_len = snprintf(buf, len, "%c%s %s\n", CMD_CHAR, cmdp->c_s,
493 (p->name) ? p->name : "");
494 UPDATE_LEN;
498 if (len != 1)
499 errx(2, "Size computation failed, aborted.");
503 * Delete the results of a package installation.
505 * This is here rather than in the pkg_delete code because pkg_add needs to
506 * run it too in cases of failure.
509 delete_package(Boolean ign_err, package_t *pkg, Boolean NoDeleteFiles,
510 const char *destdir)
512 plist_t *p;
513 const char *last_file = "";
514 int fail = SUCCESS;
515 Boolean preserve;
516 char tmp[MaxPathSize];
517 const char *prefix = NULL, *name = NULL;
519 if (!pkgdb_open(ReadWrite)) {
520 err(EXIT_FAILURE, "cannot open pkgdb");
523 preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
525 for (p = pkg->head; p; p = p->next) {
526 switch (p->type) {
527 case PLIST_NAME:
528 name = p->name;
529 break;
530 case PLIST_CWD:
531 if (prefix == NULL)
532 prefix = p->name;
533 break;
534 default:
535 break;
539 if (name == NULL || prefix == NULL)
540 errx(EXIT_FAILURE, "broken PLIST");
543 * Remove database entries first, directory removal is done
544 * in the main loop below.
546 for (p = pkg->head; p; p = p->next) {
547 if (p->type == PLIST_PKGDIR)
548 delete_pkgdir(name, prefix, p->name);
551 for (p = pkg->head; p; p = p->next) {
552 switch (p->type) {
553 case PLIST_NAME:
554 /* Handled already */
555 break;
557 case PLIST_PKGDIR:
558 case PLIST_DIR_RM:
559 (void) snprintf(tmp, sizeof(tmp), "%s/%s",
560 prefix, p->name);
561 if (has_pkgdir(tmp))
562 continue;
563 (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s",
564 destdir ? destdir : "", destdir ? "/" : "",
565 prefix, p->name);
566 if (!fexists(tmp)) {
567 if (p->type == PLIST_PKGDIR)
568 warnx("Directory `%s' disappeared, skipping", tmp);
569 } else if (!isdir(tmp)) {
570 warnx("attempting to delete a file `%s' as a directory\n"
571 "this packing list is incorrect - ignoring delete request", tmp);
572 } else if (delete_with_parents(tmp, ign_err, TRUE))
573 fail = FAIL;
574 break;
576 case PLIST_IGNORE:
577 p = p->next;
578 break;
580 case PLIST_UNEXEC:
581 if (NoDeleteFiles)
582 break;
583 format_cmd(tmp, sizeof(tmp), p->name, prefix, last_file);
584 printf("Executing `%s'\n", tmp);
585 if (!Fake && system(tmp)) {
586 warnx("unexec command for `%s' failed", tmp);
587 fail = FAIL;
589 break;
591 case PLIST_FILE:
592 last_file = p->name;
593 (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s",
594 destdir ? destdir : "", destdir ? "/" : "",
595 prefix, p->name);
596 if (isdir(tmp)) {
597 warnx("attempting to delete directory `%s' as a file\n"
598 "this packing list is incorrect - ignoring delete request", tmp);
599 } else {
600 int restored = 0; /* restored from preserve? */
602 if (p->next && p->next->type == PLIST_COMMENT) {
603 if (strncmp(p->next->name, CHECKSUM_HEADER, ChecksumHeaderLen) == 0) {
604 char *cp, buf[LegibleChecksumLen];
606 if ((cp = MD5File(tmp, buf)) != NULL) {
607 /* Mismatch? */
608 if (strcmp(cp, p->next->name + ChecksumHeaderLen) != 0) {
609 printf("original MD5 checksum failed, %s: %s\n",
610 Force ? "deleting anyway" : "not deleting", tmp);
611 if (!Force) {
612 fail = FAIL;
613 goto pkgdb_cleanup;
617 } else if (strncmp(p->next->name, SYMLINK_HEADER, SymlinkHeaderLen) == 0) {
618 char buf[MaxPathSize + SymlinkHeaderLen];
619 int cc;
621 (void) strlcpy(buf, SYMLINK_HEADER,
622 sizeof(buf));
623 if ((cc = readlink(tmp, &buf[SymlinkHeaderLen],
624 sizeof(buf) - SymlinkHeaderLen - 1)) < 0) {
625 warn("can't readlink `%s'", tmp);
626 goto pkgdb_cleanup;
628 buf[SymlinkHeaderLen + cc] = 0x0;
629 if (strcmp(buf, p->next->name) != 0) {
630 if ((cc = readlink(&buf[SymlinkHeaderLen], &buf[SymlinkHeaderLen],
631 sizeof(buf) - SymlinkHeaderLen)) < 0) {
632 printf("symlink %s is not same as recorded value, %s: %s\n",
633 buf, Force ? "deleting anyway" : "not deleting", tmp);
634 if (!Force) {
635 fail = FAIL;
636 goto pkgdb_cleanup;
639 buf[SymlinkHeaderLen + cc] = 0x0;
640 if (strcmp(buf, p->next->name) != 0) {
641 printf("symlink %s is not same as recorded value, %s: %s\n",
642 buf, Force ? "deleting anyway" : "not deleting", tmp);
643 if (!Force) {
644 fail = FAIL;
645 goto pkgdb_cleanup;
651 if (Verbose && !NoDeleteFiles)
652 printf("Delete file %s\n", tmp);
653 if (!Fake && !NoDeleteFiles) {
654 if (delete_with_parents(tmp, ign_err, FALSE))
655 fail = FAIL;
656 if (preserve && name) {
657 char tmp2[MaxPathSize];
659 if (make_preserve_name(tmp2, MaxPathSize, name, tmp)) {
660 if (fexists(tmp2)) {
661 if (rename(tmp2, tmp))
662 warn("preserve: unable to restore %s as %s",
663 tmp2, tmp);
664 else
665 restored = 1;
671 pkgdb_cleanup:
672 if (!Fake) {
673 if (!restored) {
674 errno = 0;
675 if (pkgdb_remove(tmp) && errno)
676 perror("pkgdb_remove");
680 break;
681 default:
682 break;
685 pkgdb_close();
686 return fail;
690 * Selectively delete a hierarchy
691 * Returns 1 on error, 0 else.
693 static int
694 delete_with_parents(const char *fname, Boolean ign_err, Boolean ign_nonempty)
696 char *cp, *cp2;
698 if (remove(fname)) {
699 if (!ign_err && (!ign_nonempty || errno != ENOTEMPTY))
700 warnx("Couldn't remove %s", fname);
701 return 0;
703 cp = xstrdup(fname);
704 while (*cp) {
705 if ((cp2 = strrchr(cp, '/')) != NULL)
706 *cp2 = '\0';
707 if (!isemptydir(cp))
708 break;
709 if (has_pkgdir(cp))
710 break;
711 if (rmdir(cp))
712 break;
714 free(cp);
716 return 0;
719 void
720 add_pkgdir(const char *pkg, const char *prefix, const char *path)
722 char *fullpath, *oldvalue, *newvalue;
724 fullpath = xasprintf("%s/%s", prefix, path);
725 oldvalue = pkgdb_retrieve(fullpath);
726 if (oldvalue) {
727 if (strncmp(oldvalue, "@pkgdir ", 8) != 0)
728 errx(EXIT_FAILURE, "Internal error while processing pkgdb, run pkg_admin rebuild");
729 newvalue = xasprintf("%s %s", oldvalue, pkg);
730 pkgdb_remove(fullpath);
731 } else {
732 newvalue = xasprintf("@pkgdir %s", pkg);
734 pkgdb_store(fullpath, newvalue);
736 free(fullpath);
737 free(newvalue);
740 void
741 delete_pkgdir(const char *pkg, const char *prefix, const char *path)
743 size_t pkg_len, len;
744 char *fullpath, *oldvalue, *newvalue, *iter;
746 fullpath = xasprintf("%s/%s", prefix, path);
747 oldvalue = pkgdb_retrieve(fullpath);
748 if (oldvalue && strncmp(oldvalue, "@pkgdir ", 8) == 0) {
749 newvalue = xstrdup(oldvalue);
750 iter = newvalue + 8;
751 pkg_len = strlen(pkg);
752 while (*iter) {
753 if (strncmp(iter, pkg, pkg_len) == 0 &&
754 (iter[pkg_len] == ' ' || iter[pkg_len] == '\0')) {
755 len = strlen(iter + pkg_len);
756 memmove(iter, iter + pkg_len + 1, len);
757 if (len == 0)
758 *iter = '\0';
759 } else {
760 iter += strcspn(iter, " ");
761 iter += strspn(iter, " ");
764 pkgdb_remove(fullpath);
765 if (iter != newvalue + 8)
766 pkgdb_store(fullpath, newvalue);
767 free(newvalue);
769 free(fullpath);
773 has_pkgdir(const char *path)
775 const char *value;
777 value = pkgdb_retrieve(path);
779 if (value && strncmp(value, "@pkgdir ", 8) == 0)
780 return 1;
781 else
782 return 0;