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.29.2.10 2002/08/31 19:38:55 obrien Exp $
20 * $DragonFly: src/usr.sbin/pkg_install/lib/Attic/plist.c,v 1.2 2003/06/17 04:29:59 dillon 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 */
207 (const char *)*arg = sp;
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, "mtree"))
245 else if (!strcmp(cmd, "dirrm"))
247 else if (!strcmp(cmd, "option"))
253 /* Read a packing list from a file */
255 read_plist(Package *pkg, FILE *fp)
257 char *cp, pline[FILENAME_MAX];
258 int cmd, major, minor;
263 while (fgets(pline, FILENAME_MAX, fp)) {
264 int len = strlen(pline);
266 while (len && isspace(pline[len - 1]))
271 if (pline[0] != CMD_CHAR) {
275 cmd = plist_cmd(pline + 1, &cp);
278 errx(2, "%s: bad command '%s'", __func__, pline);
284 if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
285 &major, &minor) == 2) {
286 pkg->fmtver_maj = major;
287 pkg->fmtver_mnr = minor;
288 if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0)
291 warnx("plist format revision (%d.%d) is higher than supported"
292 "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr,
293 PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR);
294 if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) {
300 add_plist(pkg, cmd, cp);
304 /* Write a packing list to a file, converting commands to ascii equivs */
306 write_plist(Package *pkg, FILE *fp)
308 PackingList plist = pkg->head;
311 switch(plist->type) {
313 fprintf(fp, "%s\n", plist->name);
317 fprintf(fp, "%ccwd %s\n", CMD_CHAR, plist->name);
321 fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
325 fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
329 fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
333 fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : "");
337 fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : "");
341 fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : "");
345 fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
349 case PLIST_IGNORE_INST: /* a one-time non-ignored file */
350 fprintf(fp, "%cignore\n", CMD_CHAR);
354 fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
358 fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name);
362 fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name);
366 fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name);
370 fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name);
374 fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name);
378 fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name);
381 case PLIST_DEPORIGIN:
382 fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name);
387 errx(2, "%s: unknown command type %d (%s)", __func__,
388 plist->type, plist->name);
396 * Delete the results of a package installation.
398 * This is here rather than in the pkg_delete code because pkg_add needs to
399 * run it too in cases of failure.
402 delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg)
405 const char *Where = ".", *last_file = "";
406 Boolean fail = SUCCESS;
408 char tmp[FILENAME_MAX], *name = NULL;
410 preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
411 for (p = pkg->head; p; p = p->next) {
424 printf("Change working directory to %s\n", Where);
428 format_cmd(tmp, p->name, Where, last_file);
430 printf("Execute '%s'\n", tmp);
431 if (!Fake && system(tmp)) {
432 warnx("unexec command for '%s' failed", tmp);
439 sprintf(tmp, "%s/%s", Where, p->name);
440 if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) {
441 warnx("cannot delete specified file '%s' - it is a directory!\n"
442 "this packing list is incorrect - ignoring delete request", tmp);
445 if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) {
446 char *cp = NULL, buf[33];
449 * For packing lists whose version is 1.1 or greater, the md5
450 * hash for a symlink is calculated on the string returned
453 if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) {
455 char linkbuf[FILENAME_MAX];
457 if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
458 cp = MD5Data((unsigned char *)linkbuf, len, buf);
459 } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0)
460 cp = MD5File(tmp, buf);
464 if (strcmp(cp, p->next->name + 4)) {
465 warnx("'%s' fails original MD5 checksum - %s",
466 tmp, Force ? "deleted anyway." : "not deleted.");
475 printf("Delete file %s\n", tmp);
477 if (delete_hierarchy(tmp, ign_err, nukedirs))
479 if (preserve && name) {
480 char tmp2[FILENAME_MAX];
482 if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) {
484 if (rename(tmp2, tmp))
485 warn("preserve: unable to restore %s as %s",
495 sprintf(tmp, "%s/%s", Where, p->name);
496 if (!isdir(tmp) && fexists(tmp)) {
497 warnx("cannot delete specified directory '%s' - it is a file!\n"
498 "this packing list is incorrect - ignoring delete request", tmp);
502 printf("Delete directory %s\n", tmp);
503 if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) {
504 warnx("unable to completely remove directory '%s'", tmp);
519 #define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir)
520 #define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir)
523 #define REMOVE(file,ie) (remove(file) && !(ie))
526 /* Selectively delete a hierarchy */
528 delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
532 cp1 = cp2 = strdup(dir);
535 warnx("%s '%s' doesn't really exist",
536 isdir(dir) ? "directory" : "file", dir);
540 if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
543 else if (isdir(dir) && !issymlink(dir)) {
544 if (RMDIR(dir) && !ign_err)
548 if (REMOVE(dir, ign_err))
555 if ((cp2 = strrchr(cp1, '/')) != NULL)
557 if (!isemptydir(dir))
559 if (RMDIR(dir) && !ign_err) {
561 warnx("directory '%s' doesn't really exist", dir);
565 /* back up the pathname one component */