2 * FreeBSD install - a package for the installation and maintenance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
17 * General packing list routines.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
28 /* Add an item to a packing list */
30 add_plist(Package *p, plist_t type, const char *arg)
34 tmp = new_plist_entry();
35 tmp->name = copy_string(arg);
39 p->head = p->tail = tmp;
51 p->origin = tmp->name;
60 add_plist_top(Package *p, plist_t type, const char *arg)
64 tmp = new_plist_entry();
65 tmp->name = copy_string(arg);
69 p->head = p->tail = tmp;
77 /* Return the last (most recent) entry in a packing list */
79 last_plist(Package *p)
84 /* Mark all items in a packing list to prevent iteration over them */
86 mark_plist(Package *pkg)
88 PackingList p = pkg->head;
96 /* Find a given item in a packing list and, if so, return it (else NULL) */
98 find_plist(Package *pkg, plist_t type)
100 PackingList p = pkg->head;
110 /* Look for a specific boolean option argument in the list */
112 find_plist_option(Package *pkg, const char *name)
114 PackingList p = pkg->head;
117 if (p->type == PLIST_OPTION && !strcmp(p->name, name))
125 * Delete plist item 'type' in the list (if 'name' is non-null, match it
126 * too.) If 'all' is set, delete all items, not just the first occurrence.
129 delete_plist(Package *pkg, Boolean all, plist_t type, const char *name)
131 PackingList p = pkg->head;
134 PackingList pnext = p->next;
136 if (p->type == type && (!name || !strcmp(name, p->name))) {
139 p->prev->next = pnext;
143 pnext->prev = p->prev;
156 /* Allocate a new packing list entry */
158 new_plist_entry(void)
162 ret = (PackingList)malloc(sizeof(struct _plist));
163 bzero(ret, sizeof(struct _plist));
167 /* Free an entire packing list */
169 free_plist(Package *pkg)
171 PackingList p = pkg->head;
174 PackingList p1 = p->next;
180 pkg->head = pkg->tail = NULL;
184 * For an ascii string denoting a plist command, return its code and
185 * optionally its argument(s)
188 plist_cmd(const char *s, char **arg)
190 char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */
201 while (isspace(*sp)) /* Never sure if macro, increment later */
209 if (!strcmp(cmd, "cwd"))
211 else if (!strcmp(cmd, "srcdir"))
213 else if (!strcmp(cmd, "cd"))
215 else if (!strcmp(cmd, "exec"))
217 else if (!strcmp(cmd, "unexec"))
219 else if (!strcmp(cmd, "mode"))
221 else if (!strcmp(cmd, "owner"))
223 else if (!strcmp(cmd, "group"))
225 else if (!strcmp(cmd, "noinst"))
227 else if (!strcmp(cmd, "comment")) {
228 if (!strncmp(*arg, "ORIGIN:", 7)) {
231 } else if (!strncmp(*arg, "DEPORIGIN:", 10)) {
233 return PLIST_DEPORIGIN;
235 return PLIST_COMMENT;
236 } else if (!strcmp(cmd, "ignore"))
238 else if (!strcmp(cmd, "ignore_inst"))
239 return PLIST_IGNORE_INST;
240 else if (!strcmp(cmd, "name"))
242 else if (!strcmp(cmd, "display"))
243 return PLIST_DISPLAY;
244 else if (!strcmp(cmd, "pkgdep"))
246 else if (!strcmp(cmd, "conflicts"))
247 return PLIST_CONFLICTS;
248 else if (!strcmp(cmd, "mtree"))
250 else if (!strcmp(cmd, "dirrm"))
252 else if (!strcmp(cmd, "option"))
258 /* Read a packing list from a file */
260 read_plist(Package *pkg, FILE *fp)
262 char *cp, pline[FILENAME_MAX];
263 int cmd, major, minor;
268 while (fgets(pline, FILENAME_MAX, fp)) {
269 int len = strlen(pline);
271 while (len && isspace(pline[len - 1]))
276 if (pline[0] != CMD_CHAR) {
280 cmd = plist_cmd(pline + 1, &cp);
282 warnx("%s: unknown command '%s' (package tools out of date?)",
288 if (cmd == PLIST_PKGDEP) {
289 warnx("corrupted record for package %s (pkgdep line without "
290 "argument), ignoring", pkg->name);
295 if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
296 &major, &minor) == 2) {
297 pkg->fmtver_maj = major;
298 pkg->fmtver_mnr = minor;
299 if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0)
302 warnx("plist format revision (%d.%d) is higher than supported"
303 "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr,
304 PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR);
305 if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) {
311 add_plist(pkg, cmd, cp);
315 /* Write a packing list to a file, converting commands to ascii equivs */
317 write_plist(Package *pkg, FILE *fp)
319 PackingList plist = pkg->head;
322 switch(plist->type) {
324 fprintf(fp, "%s\n", plist->name);
328 fprintf(fp, "%ccwd %s\n", CMD_CHAR, (plist->name == NULL) ? "" : plist->name);
332 fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
336 fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
340 fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
344 fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : "");
348 fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : "");
352 fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : "");
356 fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
360 fprintf(fp, "%cnoinst %s\n", CMD_CHAR, plist->name);
364 case PLIST_IGNORE_INST: /* a one-time non-ignored file */
365 fprintf(fp, "%cignore\n", CMD_CHAR);
369 fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
373 fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name);
377 fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name);
380 case PLIST_CONFLICTS:
381 fprintf(fp, "%cconflicts %s\n", CMD_CHAR, plist->name);
385 fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name);
389 fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name);
393 fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name);
397 fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name);
400 case PLIST_DEPORIGIN:
401 fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name);
406 errx(2, "%s: unknown command type %d (%s)", __func__,
407 plist->type, plist->name);
415 * Delete the results of a package installation.
417 * This is here rather than in the pkg_delete code because pkg_add needs to
418 * run it too in cases of failure.
421 delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg)
424 const char *Where = ".", *last_file = "";
425 Boolean fail = SUCCESS;
427 char tmp[FILENAME_MAX], *name = NULL;
430 preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
431 for (p = pkg->head; p; p = p->next) {
444 Where = (p->name == NULL) ? prefix : p->name;
446 printf("Change working directory to %s\n", Where);
450 format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file);
452 printf("Execute '%s'\n", tmp);
453 if (!Fake && system(tmp)) {
454 warnx("unexec command for '%s' failed", tmp);
462 strlcpy(tmp, p->name, FILENAME_MAX);
464 sprintf(tmp, "%s/%s", Where, p->name);
465 if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) {
466 warnx("cannot delete specified file '%s' - it is a directory!\n"
467 "this packing list is incorrect - ignoring delete request", tmp);
470 if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) {
471 char *cp = NULL, buf[33];
474 * For packing lists whose version is 1.1 or greater, the md5
475 * hash for a symlink is calculated on the string returned
478 if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) {
480 char linkbuf[FILENAME_MAX];
482 if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
483 cp = MD5Data((unsigned char *)linkbuf, len, buf);
484 } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0)
485 cp = MD5File(tmp, buf);
489 if (strcmp(cp, p->next->name + 4)) {
490 warnx("'%s' fails original MD5 checksum - %s",
491 tmp, Force ? "deleted anyway." : "not deleted.");
500 printf("Delete file %s\n", tmp);
502 if (delete_hierarchy(tmp, ign_err, nukedirs))
504 if (preserve && name) {
505 char tmp2[FILENAME_MAX];
507 if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) {
509 if (rename(tmp2, tmp))
510 warn("preserve: unable to restore %s as %s",
520 sprintf(tmp, "%s/%s", Where, p->name);
521 if (!isdir(tmp) && fexists(tmp)) {
522 warnx("cannot delete specified directory '%s' - it is a file!\n"
523 "this packing list is incorrect - ignoring delete request", tmp);
527 printf("Delete directory %s\n", tmp);
528 if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) {
529 warnx("unable to completely remove directory '%s'", tmp);
544 #define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir)
545 #define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir)
548 #define REMOVE(file,ie) (remove(file) && !(ie))
551 /* Selectively delete a hierarchy */
553 delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
557 cp1 = cp2 = strdup(dir);
558 if (!fexists(dir) && !issymlink(dir)) {
560 warnx("%s '%s' doesn't exist",
561 isdir(dir) ? "directory" : "file", dir);
565 if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
568 else if (isdir(dir) && !issymlink(dir)) {
569 if (RMDIR(dir) && !ign_err)
573 if (REMOVE(dir, ign_err))
580 if ((cp2 = strrchr(cp1, '/')) != NULL)
582 if (!isemptydir(dir))
584 if (RMDIR(dir) && !ign_err) {
586 warnx("directory '%s' doesn't exist", dir);
590 /* back up the pathname one component */