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$");
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 */
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, "conflicts"))
245 return PLIST_CONFLICTS;
246 else if (!strcmp(cmd, "mtree"))
248 else if (!strcmp(cmd, "dirrm"))
250 else if (!strcmp(cmd, "option"))
256 /* Read a packing list from a file */
258 read_plist(Package *pkg, FILE *fp)
260 char *cp, pline[FILENAME_MAX];
261 int cmd, major, minor;
266 while (fgets(pline, FILENAME_MAX, fp)) {
267 int len = strlen(pline);
269 while (len && isspace(pline[len - 1]))
274 if (pline[0] != CMD_CHAR) {
278 cmd = plist_cmd(pline + 1, &cp);
280 warnx("%s: unknown command '%s' (package tools out of date?)",
288 if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
289 &major, &minor) == 2) {
290 pkg->fmtver_maj = major;
291 pkg->fmtver_mnr = minor;
292 if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0)
295 warnx("plist format revision (%d.%d) is higher than supported"
296 "(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr,
297 PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR);
298 if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) {
304 add_plist(pkg, cmd, cp);
308 /* Write a packing list to a file, converting commands to ascii equivs */
310 write_plist(Package *pkg, FILE *fp)
312 PackingList plist = pkg->head;
315 switch(plist->type) {
317 fprintf(fp, "%s\n", plist->name);
321 fprintf(fp, "%ccwd %s\n", CMD_CHAR, plist->name);
325 fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
329 fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
333 fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
337 fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : "");
341 fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : "");
345 fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : "");
349 fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
353 case PLIST_IGNORE_INST: /* a one-time non-ignored file */
354 fprintf(fp, "%cignore\n", CMD_CHAR);
358 fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
362 fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name);
366 fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name);
369 case PLIST_CONFLICTS:
370 fprintf(fp, "%cconflicts %s\n", CMD_CHAR, plist->name);
374 fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name);
378 fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name);
382 fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name);
386 fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name);
389 case PLIST_DEPORIGIN:
390 fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name);
395 errx(2, "%s: unknown command type %d (%s)", __func__,
396 plist->type, plist->name);
404 * Delete the results of a package installation.
406 * This is here rather than in the pkg_delete code because pkg_add needs to
407 * run it too in cases of failure.
410 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 printf("Change working directory to %s\n", Where);
436 format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file);
438 printf("Execute '%s'\n", tmp);
439 if (!Fake && system(tmp)) {
440 warnx("unexec command for '%s' failed", tmp);
447 sprintf(tmp, "%s/%s", Where, p->name);
448 if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) {
449 warnx("cannot delete specified file '%s' - it is a directory!\n"
450 "this packing list is incorrect - ignoring delete request", tmp);
453 if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) {
454 char *cp = NULL, buf[33];
457 * For packing lists whose version is 1.1 or greater, the md5
458 * hash for a symlink is calculated on the string returned
461 if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) {
463 char linkbuf[FILENAME_MAX];
465 if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
466 cp = MD5Data((unsigned char *)linkbuf, len, buf);
467 } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0)
468 cp = MD5File(tmp, buf);
472 if (strcmp(cp, p->next->name + 4)) {
473 warnx("'%s' fails original MD5 checksum - %s",
474 tmp, Force ? "deleted anyway." : "not deleted.");
483 printf("Delete file %s\n", tmp);
485 if (delete_hierarchy(tmp, ign_err, nukedirs))
487 if (preserve && name) {
488 char tmp2[FILENAME_MAX];
490 if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) {
492 if (rename(tmp2, tmp))
493 warn("preserve: unable to restore %s as %s",
503 sprintf(tmp, "%s/%s", Where, p->name);
504 if (!isdir(tmp) && fexists(tmp)) {
505 warnx("cannot delete specified directory '%s' - it is a file!\n"
506 "this packing list is incorrect - ignoring delete request", tmp);
510 printf("Delete directory %s\n", tmp);
511 if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) {
512 warnx("unable to completely remove directory '%s'", tmp);
527 #define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir)
528 #define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir)
531 #define REMOVE(file,ie) (remove(file) && !(ie))
534 /* Selectively delete a hierarchy */
536 delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
540 cp1 = cp2 = strdup(dir);
543 warnx("%s '%s' doesn't really exist",
544 isdir(dir) ? "directory" : "file", dir);
548 if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
551 else if (isdir(dir) && !issymlink(dir)) {
552 if (RMDIR(dir) && !ign_err)
556 if (REMOVE(dir, ign_err))
563 if ((cp2 = strrchr(cp1, '/')) != NULL)
565 if (!isemptydir(dir))
567 if (RMDIR(dir) && !ign_err) {
569 warnx("directory '%s' doesn't really exist", dir);
573 /* back up the pathname one component */