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.
19 * $FreeBSD: src/usr.sbin/pkg_install/lib/plist.c,v 1.48 2004/07/28 07:19:15 kan Exp $
20 * $DragonFly: src/usr.sbin/pkg_install/lib/Attic/plist.c,v 1.5 2005/08/28 16:56:12 corecode Exp $
27 /* Add an item to a packing list */
29 add_plist(Package *p, plist_t type, const char *arg)
33 tmp = new_plist_entry();
34 tmp->name = copy_string(arg);
38 p->head = p->tail = tmp;
50 p->origin = tmp->name;
59 add_plist_top(Package *p, plist_t type, const char *arg)
63 tmp = new_plist_entry();
64 tmp->name = copy_string(arg);
68 p->head = p->tail = tmp;
76 /* Return the last (most recent) entry in a packing list */
78 last_plist(Package *p)
83 /* Mark all items in a packing list to prevent iteration over them */
85 mark_plist(Package *pkg)
87 PackingList p = pkg->head;
95 /* Find a given item in a packing list and, if so, return it (else NULL) */
97 find_plist(Package *pkg, plist_t type)
99 PackingList p = pkg->head;
109 /* Look for a specific boolean option argument in the list */
111 find_plist_option(Package *pkg, const char *name)
113 PackingList p = pkg->head;
116 if (p->type == PLIST_OPTION && !strcmp(p->name, name))
124 * Delete plist item 'type' in the list (if 'name' is non-null, match it
125 * too.) If 'all' is set, delete all items, not just the first occurance.
128 delete_plist(Package *pkg, Boolean all, plist_t type, const char *name)
130 PackingList p = pkg->head;
133 PackingList pnext = p->next;
135 if (p->type == type && (!name || !strcmp(name, p->name))) {
138 p->prev->next = pnext;
142 pnext->prev = p->prev;
155 /* Allocate a new packing list entry */
157 new_plist_entry(void)
161 ret = (PackingList)malloc(sizeof(struct _plist));
162 bzero(ret, sizeof(struct _plist));
166 /* Free an entire packing list */
168 free_plist(Package *pkg)
170 PackingList p = pkg->head;
173 PackingList p1 = p->next;
179 pkg->head = pkg->tail = NULL;
183 * For an ascii string denoting a plist command, return its code and
184 * optionally its argument(s)
187 plist_cmd(const char *s, char **arg)
189 char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */
200 while (isspace(*sp)) /* Never sure if macro, increment later */
208 if (!strcmp(cmd, "cwd"))
210 else if (!strcmp(cmd, "srcdir"))
212 else if (!strcmp(cmd, "cd"))
214 else if (!strcmp(cmd, "exec"))
216 else if (!strcmp(cmd, "unexec"))
218 else if (!strcmp(cmd, "mode"))
220 else if (!strcmp(cmd, "owner"))
222 else if (!strcmp(cmd, "group"))
224 else if (!strcmp(cmd, "comment")) {
225 if (!strncmp(*arg, "ORIGIN:", 7)) {
228 } else if (!strncmp(*arg, "DEPORIGIN:", 10)) {
230 return PLIST_DEPORIGIN;
232 return PLIST_COMMENT;
233 } else if (!strcmp(cmd, "ignore"))
235 else if (!strcmp(cmd, "ignore_inst"))
236 return PLIST_IGNORE_INST;
237 else if (!strcmp(cmd, "name"))
239 else if (!strcmp(cmd, "display"))
240 return PLIST_DISPLAY;
241 else if (!strcmp(cmd, "pkgdep"))
243 else if (!strcmp(cmd, "conflicts"))
244 return PLIST_CONFLICTS;
245 else if (!strcmp(cmd, "mtree"))
247 else if (!strcmp(cmd, "dirrm"))
249 else if (!strcmp(cmd, "option"))
255 /* Read a packing list from a file */
257 read_plist(Package *pkg, FILE *fp)
259 char *cp, pline[FILENAME_MAX];
260 int cmd, major, minor;
265 while (fgets(pline, FILENAME_MAX, fp)) {
266 int len = strlen(pline);
268 while (len && isspace(pline[len - 1]))
273 if (pline[0] != CMD_CHAR) {
277 cmd = plist_cmd(pline + 1, &cp);
279 warnx("%s: unknown command '%s' (package tools out of date?)",
287 if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
288 &major, &minor) == 2) {
289 pkg->fmtver_maj = major;
290 pkg->fmtver_mnr = minor;
291 if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0)
294 warnx("plist format revision (%d.%d) is higher than supported"
295 "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr,
296 PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR);
297 if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) {
303 add_plist(pkg, cmd, cp);
307 /* Write a packing list to a file, converting commands to ascii equivs */
309 write_plist(Package *pkg, FILE *fp)
311 PackingList plist = pkg->head;
314 switch(plist->type) {
316 fprintf(fp, "%s\n", plist->name);
320 fprintf(fp, "%ccwd %s\n", CMD_CHAR, plist->name);
324 fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
328 fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
332 fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
336 fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : "");
340 fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : "");
344 fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : "");
348 fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
352 case PLIST_IGNORE_INST: /* a one-time non-ignored file */
353 fprintf(fp, "%cignore\n", CMD_CHAR);
357 fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
361 fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name);
365 fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name);
368 case PLIST_CONFLICTS:
369 fprintf(fp, "%cconflicts %s\n", CMD_CHAR, plist->name);
373 fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name);
377 fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name);
381 fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name);
385 fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name);
388 case PLIST_DEPORIGIN:
389 fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name);
394 errx(2, "%s: unknown command type %d (%s)", __func__,
395 plist->type, plist->name);
403 * Delete the results of a package installation.
405 * This is here rather than in the pkg_delete code because pkg_add needs to
406 * run it too in cases of failure.
409 delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg)
413 const char *Where = ".", *last_file = "";
414 Boolean fail = SUCCESS;
416 char tmp[FILENAME_MAX], *name = NULL;
418 preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
419 for (p = pkg->head; p; p = p->next) {
432 Where = dn = fake_chroot(p->name);
434 printf("Change working directory to %s\n", Where);
438 format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file);
440 printf("Execute '%s'\n", tmp);
441 if (!Fake && system(tmp)) {
442 warnx("unexec command for '%s' failed", tmp);
449 sprintf(tmp, "%s/%s", Where, p->name);
450 if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) {
451 warnx("cannot delete specified file '%s' - it is a directory!\n"
452 "this packing list is incorrect - ignoring delete request", tmp);
455 if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) {
456 char *cp = NULL, buf[33];
459 * For packing lists whose version is 1.1 or greater, the md5
460 * hash for a symlink is calculated on the string returned
463 if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) {
465 char linkbuf[FILENAME_MAX];
467 if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
468 cp = MD5Data((unsigned char *)linkbuf, len, buf);
469 } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0)
470 cp = MD5File(tmp, buf);
474 if (strcmp(cp, p->next->name + 4)) {
475 warnx("'%s' fails original MD5 checksum - %s",
476 tmp, Force ? "deleted anyway." : "not deleted.");
485 printf("Delete file %s\n", tmp);
487 if (delete_hierarchy(tmp, ign_err, nukedirs))
489 if (preserve && name) {
490 char tmp2[FILENAME_MAX];
492 if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) {
494 if (rename(tmp2, tmp))
495 warn("preserve: unable to restore %s as %s",
505 sprintf(tmp, "%s/%s", Where, p->name);
506 if (!isdir(tmp) && fexists(tmp)) {
507 warnx("cannot delete specified directory '%s' - it is a file!\n"
508 "this packing list is incorrect - ignoring delete request", tmp);
512 printf("Delete directory %s\n", tmp);
513 if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) {
514 warnx("unable to completely remove directory '%s'", tmp);
530 #define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir)
531 #define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir)
534 #define REMOVE(file,ie) (remove(file) && !(ie))
537 /* Selectively delete a hierarchy */
539 delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
543 cp1 = cp2 = strdup(dir);
546 warnx("%s '%s' doesn't really exist",
547 isdir(dir) ? "directory" : "file", dir);
551 if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
554 else if (isdir(dir) && !issymlink(dir)) {
555 if (RMDIR(dir) && !ign_err)
559 if (REMOVE(dir, ign_err))
566 if ((cp2 = strrchr(cp1, '/')) != NULL)
568 if (!isemptydir(dir))
570 if (RMDIR(dir) && !ign_err) {
572 warnx("directory '%s' doesn't really exist", dir);
576 /* back up the pathname one component */