2 * FreeBSD install - a package for the installation and maintainance
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: src/usr.sbin/pkg_install/lib/plist.c,v 1.29.2.10 2002/08/31 19:38:55 obrien Exp $");
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 occurance.
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 */
208 (const char *)*arg = sp;
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, "comment")) {
226 if (!strncmp(*arg, "ORIGIN:", 7)) {
229 } else if (!strncmp(*arg, "DEPORIGIN:", 10)) {
231 return PLIST_DEPORIGIN;
233 return PLIST_COMMENT;
234 } else if (!strcmp(cmd, "ignore"))
236 else if (!strcmp(cmd, "ignore_inst"))
237 return PLIST_IGNORE_INST;
238 else if (!strcmp(cmd, "name"))
240 else if (!strcmp(cmd, "display"))
241 return PLIST_DISPLAY;
242 else if (!strcmp(cmd, "pkgdep"))
244 else if (!strcmp(cmd, "mtree"))
246 else if (!strcmp(cmd, "dirrm"))
248 else if (!strcmp(cmd, "option"))
254 /* Read a packing list from a file */
256 read_plist(Package *pkg, FILE *fp)
258 char *cp, pline[FILENAME_MAX];
259 int cmd, major, minor;
264 while (fgets(pline, FILENAME_MAX, fp)) {
265 int len = strlen(pline);
267 while (len && isspace(pline[len - 1]))
272 if (pline[0] != CMD_CHAR) {
276 cmd = plist_cmd(pline + 1, &cp);
279 errx(2, "%s: bad command '%s'", __func__, pline);
285 if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
286 &major, &minor) == 2) {
287 pkg->fmtver_maj = major;
288 pkg->fmtver_mnr = minor;
289 if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0)
292 warnx("plist format revision (%d.%d) is higher than supported"
293 "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr,
294 PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR);
295 if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) {
301 add_plist(pkg, cmd, cp);
305 /* Write a packing list to a file, converting commands to ascii equivs */
307 write_plist(Package *pkg, FILE *fp)
309 PackingList plist = pkg->head;
312 switch(plist->type) {
314 fprintf(fp, "%s\n", plist->name);
318 fprintf(fp, "%ccwd %s\n", CMD_CHAR, plist->name);
322 fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
326 fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
330 fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
334 fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : "");
338 fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : "");
342 fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : "");
346 fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
350 case PLIST_IGNORE_INST: /* a one-time non-ignored file */
351 fprintf(fp, "%cignore\n", CMD_CHAR);
355 fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
359 fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name);
363 fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name);
367 fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name);
371 fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name);
375 fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name);
379 fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name);
382 case PLIST_DEPORIGIN:
383 fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name);
388 errx(2, "%s: unknown command type %d (%s)", __func__,
389 plist->type, plist->name);
397 * Delete the results of a package installation.
399 * This is here rather than in the pkg_delete code because pkg_add needs to
400 * run it too in cases of failure.
403 delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg)
406 const char *Where = ".", *last_file = "";
407 Boolean fail = SUCCESS;
409 char tmp[FILENAME_MAX], *name = NULL;
411 preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
412 for (p = pkg->head; p; p = p->next) {
425 printf("Change working directory to %s\n", Where);
429 format_cmd(tmp, p->name, Where, last_file);
431 printf("Execute '%s'\n", tmp);
432 if (!Fake && system(tmp)) {
433 warnx("unexec command for '%s' failed", tmp);
440 sprintf(tmp, "%s/%s", Where, p->name);
441 if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) {
442 warnx("cannot delete specified file '%s' - it is a directory!\n"
443 "this packing list is incorrect - ignoring delete request", tmp);
446 if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) {
447 char *cp = NULL, buf[33];
450 * For packing lists whose version is 1.1 or greater, the md5
451 * hash for a symlink is calculated on the string returned
454 if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) {
456 char linkbuf[FILENAME_MAX];
458 if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
459 cp = MD5Data((unsigned char *)linkbuf, len, buf);
460 } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0)
461 cp = MD5File(tmp, buf);
465 if (strcmp(cp, p->next->name + 4)) {
466 warnx("'%s' fails original MD5 checksum - %s",
467 tmp, Force ? "deleted anyway." : "not deleted.");
476 printf("Delete file %s\n", tmp);
478 if (delete_hierarchy(tmp, ign_err, nukedirs))
480 if (preserve && name) {
481 char tmp2[FILENAME_MAX];
483 if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) {
485 if (rename(tmp2, tmp))
486 warn("preserve: unable to restore %s as %s",
496 sprintf(tmp, "%s/%s", Where, p->name);
497 if (!isdir(tmp) && fexists(tmp)) {
498 warnx("cannot delete specified directory '%s' - it is a file!\n"
499 "this packing list is incorrect - ignoring delete request", tmp);
503 printf("Delete directory %s\n", tmp);
504 if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) {
505 warnx("unable to completely remove directory '%s'", tmp);
520 #define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir)
521 #define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir)
524 #define REMOVE(file,ie) (remove(file) && !(ie))
527 /* Selectively delete a hierarchy */
529 delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
533 cp1 = cp2 = strdup(dir);
536 warnx("%s '%s' doesn't really exist",
537 isdir(dir) ? "directory" : "file", dir);
541 if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
544 else if (isdir(dir) && !issymlink(dir)) {
545 if (RMDIR(dir) && !ign_err)
549 if (REMOVE(dir, ign_err))
556 if ((cp2 = strrchr(cp1, '/')) != NULL)
558 if (!isemptydir(dir))
560 if (RMDIR(dir) && !ign_err) {
562 warnx("directory '%s' doesn't really exist", dir);
566 /* back up the pathname one component */