perform.c revision 93520
1161304Snetchild/* 2161304Snetchild * FreeBSD install - a package for the installation and maintainance 3161304Snetchild * of non-core utilities. 4161304Snetchild * 5161304Snetchild * Redistribution and use in source and binary forms, with or without 6161304Snetchild * modification, are permitted provided that the following conditions 7161304Snetchild * are met: 8161304Snetchild * 1. Redistributions of source code must retain the above copyright 9161304Snetchild * notice, this list of conditions and the following disclaimer. 10161304Snetchild * 2. Redistributions in binary form must reproduce the above copyright 11161304Snetchild * notice, this list of conditions and the following disclaimer in the 12161304Snetchild * documentation and/or other materials provided with the distribution. 13161304Snetchild * 14161304Snetchild * Jordan K. Hubbard 15161304Snetchild * 23 Aug 1993 16161304Snetchild * 17161304Snetchild * This is the main body of the info module. 18161304Snetchild * 19161304Snetchild */ 20161304Snetchild 21161304Snetchild#include <sys/cdefs.h> 22161304Snetchild__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 93520 2002-04-01 09:39:07Z obrien $"); 23161304Snetchild 24161304Snetchild#include "lib.h" 25161304Snetchild#include "info.h" 26161304Snetchild#include <err.h> 27161304Snetchild#include <signal.h> 28161304Snetchild 29161304Snetchildstatic int pkg_do(char *); 30161304Snetchildstatic int find_pkg(const char *, struct which_head *); 31161304Snetchildstatic int cmp_path(const char *, const char *, const char *); 32161304Snetchildstatic char *abspath(const char *); 33161304Snetchild 34161304Snetchildint 35161304Snetchildpkg_perform(char **pkgs) 36161304Snetchild{ 37161304Snetchild char **matched; 38161304Snetchild const char *tmp; 39235063Snetchild int err_cnt = 0; 40161304Snetchild int i, errcode; 41161304Snetchild 42235063Snetchild signal(SIGINT, cleanup); 43161304Snetchild 44161304Snetchild tmp = LOG_DIR; 45235063Snetchild 46161304Snetchild /* Overriding action? */ 47161304Snetchild if (CheckPkg) { 48161304Snetchild char buf[FILENAME_MAX]; 49161304Snetchild 50161304Snetchild snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); 51161304Snetchild return abs(access(buf, R_OK)); 52161304Snetchild /* Not reached */ 53161304Snetchild } else if (!TAILQ_EMPTY(whead)) { 54161304Snetchild return find_pkg(tmp, whead); 55161304Snetchild } 56161304Snetchild 57161304Snetchild if (MatchType != MATCH_EXACT) { 58161304Snetchild matched = matchinstalled(MatchType, pkgs, &errcode); 59161304Snetchild if (errcode != 0) 60161304Snetchild return 1; 61161304Snetchild /* Not reached */ 62235063Snetchild 63246085Sjhb if (matched != NULL) 64235063Snetchild pkgs = matched; 65235063Snetchild else switch (MatchType) { 66235063Snetchild case MATCH_GLOB: 67235063Snetchild break; 68235063Snetchild case MATCH_ALL: 69235063Snetchild warnx("no packages installed"); 70235063Snetchild return 0; 71235063Snetchild /* Not reached */ 72235063Snetchild case MATCH_REGEX: 73235063Snetchild warnx("no packages match pattern(s)"); 74235063Snetchild return 1; 75235063Snetchild /* Not reached */ 76235063Snetchild default: 77235063Snetchild break; 78235063Snetchild } 79235063Snetchild } 80235063Snetchild 81235063Snetchild for (i = 0; pkgs[i]; i++) 82235063Snetchild err_cnt += pkg_do(pkgs[i]); 83235063Snetchild 84235063Snetchild return err_cnt; 85235063Snetchild} 86235063Snetchild 87235063Snetchildstatic char *Home; 88235063Snetchild 89235063Snetchildstatic int 90235063Snetchildpkg_do(char *pkg) 91235063Snetchild{ 92235063Snetchild Boolean installed = FALSE, isTMP = FALSE; 93235063Snetchild char log_dir[FILENAME_MAX]; 94235063Snetchild char fname[FILENAME_MAX]; 95235063Snetchild Package plist; 96235063Snetchild FILE *fp; 97235063Snetchild struct stat sb; 98235063Snetchild char *cp = NULL; 99235063Snetchild int code = 0; 100235063Snetchild 101235063Snetchild if (isURL(pkg)) { 102235063Snetchild if ((cp = fileGetURL(NULL, pkg)) != NULL) { 103235063Snetchild strcpy(fname, cp); 104235063Snetchild isTMP = TRUE; 105235063Snetchild } 106235063Snetchild } 107235063Snetchild else if (fexists(pkg) && isfile(pkg)) { 108235063Snetchild int len; 109235063Snetchild 110235063Snetchild if (*pkg != '/') { 111235063Snetchild if (!getcwd(fname, FILENAME_MAX)) 112235063Snetchild upchuck("getcwd"); 113235063Snetchild len = strlen(fname); 114235063Snetchild snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); 115235063Snetchild } 116235063Snetchild else 117235063Snetchild strcpy(fname, pkg); 118235063Snetchild cp = fname; 119235063Snetchild } 120161304Snetchild else { 121161304Snetchild if ((cp = fileFindByPath(NULL, pkg)) != NULL) 122165408Sjkim strncpy(fname, cp, FILENAME_MAX); 123161304Snetchild } 124161304Snetchild if (cp) { 125161304Snetchild /* 126161304Snetchild * Apply a crude heuristic to see how much space the package will 127161304Snetchild * take up once it's unpacked. I've noticed that most packages 128161304Snetchild * compress an average of 75%, but we're only unpacking the + files so 129235063Snetchild * be very optimistic. 130235063Snetchild */ 131235063Snetchild if (stat(fname, &sb) == FAIL) { 132161304Snetchild warnx("can't stat package file '%s'", fname); 133161304Snetchild code = 1; 134235063Snetchild goto bail; 135235063Snetchild } 136161304Snetchild Home = make_playpen(PlayPen, sb.st_size / 2); 137161304Snetchild if (unpack(fname, "+*")) { 138165408Sjkim warnx("error during unpacking, no info for '%s' available", pkg); 139161304Snetchild code = 1; 140161304Snetchild goto bail; 141235063Snetchild } 142235063Snetchild } 143235063Snetchild /* It's not an ininstalled package, try and find it among the installed */ 144235063Snetchild else { 145235063Snetchild sprintf(log_dir, "%s/%s", LOG_DIR, pkg); 146165408Sjkim if (!fexists(log_dir)) { 147235063Snetchild warnx("can't find package '%s' installed or in a file!", pkg); 148161304Snetchild return 1; 149161304Snetchild } 150165408Sjkim if (chdir(log_dir) == FAIL) { 151235063Snetchild warnx("can't change directory to '%s'!", log_dir); 152165408Sjkim return 1; 153161304Snetchild } 154161304Snetchild installed = TRUE; 155161304Snetchild } 156161304Snetchild 157161304Snetchild /* Suck in the contents list */ 158235063Snetchild plist.head = plist.tail = NULL; 159235063Snetchild fp = fopen(CONTENTS_FNAME, "r"); 160235063Snetchild if (!fp) { 161161304Snetchild warnx("unable to open %s file", CONTENTS_FNAME); 162161304Snetchild code = 1; 163161304Snetchild goto bail; 164161304Snetchild } 165161304Snetchild /* If we have a prefix, add it now */ 166161304Snetchild read_plist(&plist, fp); 167161304Snetchild fclose(fp); 168161304Snetchild 169161304Snetchild /* 170161304Snetchild * Index is special info type that has to override all others to make 171161304Snetchild * any sense. 172235063Snetchild */ 173235063Snetchild if (Flags & SHOW_INDEX) { 174235063Snetchild char tmp[FILENAME_MAX]; 175235063Snetchild 176235063Snetchild snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); 177165408Sjkim show_index(tmp, COMMENT_FNAME); 178235063Snetchild } 179235063Snetchild else { 180235063Snetchild /* Start showing the package contents */ 181165408Sjkim if (!Quiet) 182165408Sjkim printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 183161304Snetchild if (Flags & SHOW_COMMENT) 184161304Snetchild show_file("Comment:\n", COMMENT_FNAME); 185235063Snetchild if (Flags & SHOW_REQUIRE) 186165408Sjkim show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE); 187161304Snetchild if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) 188161304Snetchild show_file("Required by:\n", REQUIRED_BY_FNAME); 189161304Snetchild if (Flags & SHOW_DESC) 190161304Snetchild show_file("Description:\n", DESC_FNAME); 191161304Snetchild if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) 192161304Snetchild show_file("Install notice:\n", DISPLAY_FNAME); 193161304Snetchild if (Flags & SHOW_PLIST) 194161304Snetchild show_plist("Packing list:\n", &plist, (plist_t)0, TRUE); 195161304Snetchild if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) 196161304Snetchild show_file("Install script:\n", INSTALL_FNAME); 197235063Snetchild if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME)) 198235063Snetchild show_file("Post-Install script:\n", POST_INSTALL_FNAME); 199161304Snetchild if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) 200235063Snetchild show_file("De-Install script:\n", DEINSTALL_FNAME); 201235063Snetchild if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME)) 202235063Snetchild show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME); 203235063Snetchild if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) 204165408Sjkim show_file("mtree file:\n", MTREE_FNAME); 205235063Snetchild if (Flags & SHOW_PREFIX) 206161304Snetchild show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE); 207235063Snetchild if (Flags & SHOW_FILES) 208235063Snetchild show_files("Files:\n", &plist); 209235063Snetchild if ((Flags & SHOW_SIZE) && installed) 210165408Sjkim show_size("Package Size:\n", &plist); 211235063Snetchild if ((Flags & SHOW_CKSUM) && installed) 212161304Snetchild show_cksum("Mismatched Checksums:\n", &plist); 213161304Snetchild if (Flags & SHOW_ORIGIN) 214235063Snetchild show_origin("Origin:\n", &plist); 215235063Snetchild if (Flags & SHOW_FMTREV) 216235063Snetchild show_fmtrev("Packing list format revision:\n", &plist); 217235063Snetchild if (!Quiet) 218235063Snetchild puts(InfoPrefix); 219235063Snetchild } 220161304Snetchild free_plist(&plist); 221161304Snetchild bail: 222161304Snetchild leave_playpen(); 223161304Snetchild if (isTMP) 224161304Snetchild unlink(fname); 225161304Snetchild return code; 226161304Snetchild} 227161304Snetchild 228161304Snetchildvoid 229161304Snetchildcleanup(int sig) 230235063Snetchild{ 231235063Snetchild static int in_cleanup = 0; 232161304Snetchild 233235063Snetchild if (!in_cleanup) { 234235063Snetchild in_cleanup = 1; 235235063Snetchild leave_playpen(); 236235063Snetchild } 237165408Sjkim if (sig) 238235063Snetchild exit(1); 239161304Snetchild} 240235063Snetchild 241235063Snetchild/* 242235063Snetchild * Return an absolute path, additionally removing all .'s, ..'s, and extraneous 243165408Sjkim * /'s, as realpath() would, but without resolving symlinks, because that can 244235063Snetchild * potentially screw up our comparisons later. 245165408Sjkim */ 246235063Snetchildstatic char * 247235063Snetchildabspath(const char *pathname) 248235063Snetchild{ 249235063Snetchild char *tmp, *tmp1, *resolved_path; 250165408Sjkim char *cwd = NULL; 251235063Snetchild int len; 252161304Snetchild 253235063Snetchild if (pathname[0] != '/') { 254235063Snetchild cwd = getcwd(NULL, MAXPATHLEN); 255235063Snetchild asprintf(&resolved_path, "%s/%s/", cwd, pathname); 256235063Snetchild } else 257235063Snetchild asprintf(&resolved_path, "%s/", pathname); 258235063Snetchild 259161304Snetchild if (resolved_path == NULL) 260161304Snetchild errx(2, NULL); 261161304Snetchild 262161304Snetchild if (cwd != NULL) 263161304Snetchild free(cwd); 264161304Snetchild 265161304Snetchild while ((tmp = strstr(resolved_path, "//")) != NULL) 266161304Snetchild strcpy(tmp, tmp + 1); 267161304Snetchild 268161304Snetchild while ((tmp = strstr(resolved_path, "/./")) != NULL) 269235063Snetchild strcpy(tmp, tmp + 2); 270235063Snetchild 271235063Snetchild while ((tmp = strstr(resolved_path, "/../")) != NULL) { 272235063Snetchild *tmp = '\0'; 273235063Snetchild if ((tmp1 = strrchr(resolved_path, '/')) == NULL) 274165408Sjkim tmp1 = resolved_path; 275235063Snetchild strcpy(tmp1, tmp + 3); 276161304Snetchild } 277161304Snetchild 278235063Snetchild len = strlen(resolved_path); 279235063Snetchild if (len > 1 && resolved_path[len - 1] == '/') 280235063Snetchild resolved_path[len - 1] = '\0'; 281235063Snetchild 282165408Sjkim return resolved_path; 283235063Snetchild} 284161304Snetchild 285235063Snetchild/* 286235063Snetchild * Comparison to see if the path we're on matches the 287235063Snetchild * one we are looking for. 288165408Sjkim */ 289235063Snetchildstatic int 290165408Sjkimcmp_path(const char *target, const char *current, const char *cwd) 291161304Snetchild{ 292235063Snetchild char *resolved, *temp; 293235063Snetchild int rval; 294235063Snetchild 295235063Snetchild asprintf(&temp, "%s/%s", cwd, current); 296235063Snetchild if (temp == NULL) 297235063Snetchild errx(2, NULL); 298161304Snetchild 299161304Snetchild /* 300161304Snetchild * Make sure there's no multiple /'s or other weird things in the PLIST, 301165408Sjkim * since some plists seem to have them and it could screw up our strncmp. 302165408Sjkim */ 303165408Sjkim resolved = abspath(temp); 304165408Sjkim 305165408Sjkim if (strcmp(target, resolved) == 0) 306165408Sjkim rval = 1; 307165408Sjkim else 308235063Snetchild rval = 0; 309235063Snetchild 310165408Sjkim free(temp); 311235063Snetchild free(resolved); 312235063Snetchild return rval; 313235063Snetchild} 314165408Sjkim 315235063Snetchild/* 316165408Sjkim * Look through package dbs in db_dir and find which 317165408Sjkim * packages installed the files in which_list. 318165408Sjkim */ 319165408Sjkimstatic int 320165408Sjkimfind_pkg(const char *db_dir, struct which_head *which_list) 321165408Sjkim{ 322165408Sjkim char **installed; 323235063Snetchild int errcode, i; 324235063Snetchild struct which_entry *wp; 325235063Snetchild 326165408Sjkim TAILQ_FOREACH(wp, which_list, next) { 327235063Snetchild const char *msg = "file cannot be found"; 328165408Sjkim char *tmp; 329235063Snetchild 330235063Snetchild wp->skip = TRUE; 331235063Snetchild /* If it's not a file, we'll see if it's an executable. */ 332165408Sjkim if (isfile(wp->file) == FALSE) { 333235063Snetchild if (strchr(wp->file, '/') == NULL) { 334165408Sjkim tmp = vpipe("/usr/bin/which %s", wp->file); 335165408Sjkim if (tmp != NULL) { 336165408Sjkim strlcpy(wp->file, tmp, PATH_MAX); 337165408Sjkim wp->skip = FALSE; 338235063Snetchild free(tmp); 339235063Snetchild } else 340235063Snetchild msg = "file is not in PATH"; 341235063Snetchild } 342165408Sjkim } else { 343235063Snetchild tmp = abspath(wp->file); 344165408Sjkim if (isfile(tmp)) { 345165408Sjkim strlcpy(wp->file, tmp, PATH_MAX); 346235063Snetchild wp->skip = FALSE; 347165408Sjkim } 348165408Sjkim free(tmp); 349165408Sjkim } 350165408Sjkim if (wp->skip == TRUE) 351161304Snetchild warnx("%s: %s", wp->file, msg); 352161304Snetchild } 353161304Snetchild 354161304Snetchild installed = matchinstalled(MATCH_ALL, NULL, &errcode); 355161304Snetchild if (installed == NULL) 356161304Snetchild return errcode; 357161304Snetchild 358235063Snetchild for (i = 0; installed[i] != NULL; i++) { 359235063Snetchild FILE *fp; 360235063Snetchild Package pkg; 361235063Snetchild PackingList itr; 362235063Snetchild char *cwd = NULL; 363235063Snetchild char tmp[PATH_MAX]; 364235063Snetchild 365235063Snetchild snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 366165408Sjkim CONTENTS_FNAME); 367235063Snetchild fp = fopen(tmp, "r"); 368161304Snetchild if (fp == NULL) { 369235063Snetchild warn("%s", tmp); 370235063Snetchild return 1; 371235063Snetchild } 372235063Snetchild 373165408Sjkim pkg.head = pkg.tail = NULL; 374235063Snetchild read_plist(&pkg, fp); 375161304Snetchild fclose(fp); 376161304Snetchild for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { 377235063Snetchild if (itr->type == PLIST_CWD) { 378235063Snetchild cwd = itr->name; 379235063Snetchild } else if (itr->type == PLIST_FILE) { 380235063Snetchild TAILQ_FOREACH(wp, which_list, next) { 381165408Sjkim if (wp->skip == TRUE) 382235063Snetchild continue; 383161304Snetchild if (!cmp_path(wp->file, itr->name, cwd)) 384161304Snetchild continue; 385161304Snetchild if (wp->package[0] != '\0') { 386161304Snetchild warnx("both %s and %s claim to have installed %s\n", 387161304Snetchild wp->package, installed[i], wp->file); 388161304Snetchild } else { 389165408Sjkim strlcpy(wp->package, installed[i], PATH_MAX); 390235063Snetchild } 391235063Snetchild } 392235063Snetchild } 393235063Snetchild } 394165408Sjkim free_plist(&pkg); 395235063Snetchild } 396161304Snetchild 397235063Snetchild TAILQ_FOREACH(wp, which_list, next) { 398235063Snetchild if (wp->package[0] != '\0') { 399235063Snetchild if (Quiet) 400235063Snetchild puts(wp->package); 401165408Sjkim else 402235063Snetchild printf("%s was installed by package %s\n", \ 403165408Sjkim wp->file, wp->package); 404161304Snetchild } 405161304Snetchild } 406161304Snetchild while (!TAILQ_EMPTY(which_list)) { 407235063Snetchild wp = TAILQ_FIRST(which_list); 408235063Snetchild TAILQ_REMOVE(which_list, wp, next); 409235063Snetchild free(wp); 410235063Snetchild } 411165408Sjkim 412235063Snetchild free(which_list); 413161304Snetchild return 0; 414161304Snetchild} 415235063Snetchild