perform.c revision 96030
1327Sjkh/* 2327Sjkh * FreeBSD install - a package for the installation and maintainance 3327Sjkh * of non-core utilities. 4327Sjkh * 5327Sjkh * Redistribution and use in source and binary forms, with or without 6327Sjkh * modification, are permitted provided that the following conditions 7327Sjkh * are met: 8327Sjkh * 1. Redistributions of source code must retain the above copyright 9327Sjkh * notice, this list of conditions and the following disclaimer. 10327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 11327Sjkh * notice, this list of conditions and the following disclaimer in the 12327Sjkh * documentation and/or other materials provided with the distribution. 13327Sjkh * 14327Sjkh * Jordan K. Hubbard 15327Sjkh * 23 Aug 1993 16327Sjkh * 17327Sjkh * This is the main body of the info module. 18327Sjkh * 19327Sjkh */ 20327Sjkh 2193520Sobrien#include <sys/cdefs.h> 2293520Sobrien__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 96030 2002-05-04 14:49:49Z sobomax $"); 2393520Sobrien 24327Sjkh#include "lib.h" 25327Sjkh#include "info.h" 2672174Ssobomax#include <err.h> 27327Sjkh#include <signal.h> 28327Sjkh 29327Sjkhstatic int pkg_do(char *); 3084745Ssobomaxstatic int find_pkg(const char *, struct which_head *); 3174699Ssobomaxstatic int cmp_path(const char *, const char *, const char *); 3284745Ssobomaxstatic char *abspath(const char *); 3396030Ssobomaxstatic int find_pkgs_by_origin(const char *, const char *); 34327Sjkh 35327Sjkhint 36327Sjkhpkg_perform(char **pkgs) 37327Sjkh{ 3873134Ssobomax char **matched; 3984745Ssobomax const char *tmp; 4073134Ssobomax int err_cnt = 0; 4173134Ssobomax int i, errcode; 42327Sjkh 43327Sjkh signal(SIGINT, cleanup); 44327Sjkh 4581049Ssobomax tmp = LOG_DIR; 4674699Ssobomax 47327Sjkh /* Overriding action? */ 4816404Sjkh if (CheckPkg) { 4916404Sjkh char buf[FILENAME_MAX]; 50327Sjkh 5116404Sjkh snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); 5216404Sjkh return abs(access(buf, R_OK)); 5372174Ssobomax /* Not reached */ 5474699Ssobomax } else if (!TAILQ_EMPTY(whead)) { 5574699Ssobomax return find_pkg(tmp, whead); 5696030Ssobomax } else if (LookUpOrigin != NULL) { 5796030Ssobomax return find_pkgs_by_origin(tmp, LookUpOrigin); 5816404Sjkh } 598857Srgrimes 6073134Ssobomax if (MatchType != MATCH_EXACT) { 6173134Ssobomax matched = matchinstalled(MatchType, pkgs, &errcode); 6273134Ssobomax if (errcode != 0) 6373134Ssobomax return 1; 6473134Ssobomax /* Not reached */ 6572174Ssobomax 6673134Ssobomax if (matched != NULL) 6773134Ssobomax pkgs = matched; 6873134Ssobomax else switch (MatchType) { 6973134Ssobomax case MATCH_GLOB: 7073134Ssobomax break; 7173134Ssobomax case MATCH_ALL: 7273134Ssobomax warnx("no packages installed"); 7373134Ssobomax return 0; 7473134Ssobomax /* Not reached */ 7573134Ssobomax case MATCH_REGEX: 7673134Ssobomax warnx("no packages match pattern(s)"); 7772174Ssobomax return 1; 7873134Ssobomax /* Not reached */ 7973134Ssobomax default: 8073134Ssobomax break; 8116404Sjkh } 8273134Ssobomax } 8372174Ssobomax 8473134Ssobomax for (i = 0; pkgs[i]; i++) 8573134Ssobomax err_cnt += pkg_do(pkgs[i]); 8672174Ssobomax 87327Sjkh return err_cnt; 88327Sjkh} 89327Sjkh 9011780Sjkhstatic char *Home; 9111780Sjkh 92327Sjkhstatic int 93327Sjkhpkg_do(char *pkg) 94327Sjkh{ 958086Sjkh Boolean installed = FALSE, isTMP = FALSE; 96327Sjkh char log_dir[FILENAME_MAX]; 978086Sjkh char fname[FILENAME_MAX]; 98327Sjkh Package plist; 99327Sjkh FILE *fp; 1008086Sjkh struct stat sb; 1018142Sjkh char *cp = NULL; 1028086Sjkh int code = 0; 103327Sjkh 1048086Sjkh if (isURL(pkg)) { 10511780Sjkh if ((cp = fileGetURL(NULL, pkg)) != NULL) { 1068086Sjkh strcpy(fname, cp); 1078086Sjkh isTMP = TRUE; 1088086Sjkh } 1098086Sjkh } 1109782Sache else if (fexists(pkg) && isfile(pkg)) { 1118086Sjkh int len; 112327Sjkh 1138423Sjkh if (*pkg != '/') { 1148423Sjkh if (!getcwd(fname, FILENAME_MAX)) 1158423Sjkh upchuck("getcwd"); 1168423Sjkh len = strlen(fname); 1178423Sjkh snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); 1188423Sjkh } 1198423Sjkh else 1208423Sjkh strcpy(fname, pkg); 1218086Sjkh cp = fname; 1228086Sjkh } 1238086Sjkh else { 12411780Sjkh if ((cp = fileFindByPath(NULL, pkg)) != NULL) 1258086Sjkh strncpy(fname, cp, FILENAME_MAX); 1268086Sjkh } 1278086Sjkh if (cp) { 1283364Sjkh /* 1293364Sjkh * Apply a crude heuristic to see how much space the package will 1303364Sjkh * take up once it's unpacked. I've noticed that most packages 1313577Sjkh * compress an average of 75%, but we're only unpacking the + files so 1323577Sjkh * be very optimistic. 1333364Sjkh */ 1343364Sjkh if (stat(fname, &sb) == FAIL) { 13530221Scharnier warnx("can't stat package file '%s'", fname); 1368086Sjkh code = 1; 1378086Sjkh goto bail; 1383364Sjkh } 13911780Sjkh Home = make_playpen(PlayPen, sb.st_size / 2); 140327Sjkh if (unpack(fname, "+*")) { 14130221Scharnier warnx("error during unpacking, no info for '%s' available", pkg); 1428086Sjkh code = 1; 1438086Sjkh goto bail; 144327Sjkh } 145327Sjkh } 1468086Sjkh /* It's not an ininstalled package, try and find it among the installed */ 147327Sjkh else { 14881049Ssobomax sprintf(log_dir, "%s/%s", LOG_DIR, pkg); 149327Sjkh if (!fexists(log_dir)) { 15081046Ssobomax warnx("can't find package '%s' installed or in a file!", pkg); 151327Sjkh return 1; 152327Sjkh } 153327Sjkh if (chdir(log_dir) == FAIL) { 15430221Scharnier warnx("can't change directory to '%s'!", log_dir); 155327Sjkh return 1; 156327Sjkh } 157327Sjkh installed = TRUE; 158327Sjkh } 159327Sjkh 160327Sjkh /* Suck in the contents list */ 161327Sjkh plist.head = plist.tail = NULL; 162327Sjkh fp = fopen(CONTENTS_FNAME, "r"); 163327Sjkh if (!fp) { 16430221Scharnier warnx("unable to open %s file", CONTENTS_FNAME); 1658086Sjkh code = 1; 1668086Sjkh goto bail; 167327Sjkh } 168327Sjkh /* If we have a prefix, add it now */ 169327Sjkh read_plist(&plist, fp); 170327Sjkh fclose(fp); 171327Sjkh 172327Sjkh /* 173327Sjkh * Index is special info type that has to override all others to make 174327Sjkh * any sense. 175327Sjkh */ 176327Sjkh if (Flags & SHOW_INDEX) { 1778086Sjkh char tmp[FILENAME_MAX]; 178327Sjkh 1798086Sjkh snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); 1808086Sjkh show_index(tmp, COMMENT_FNAME); 181327Sjkh } 182327Sjkh else { 183327Sjkh /* Start showing the package contents */ 184411Sjkh if (!Quiet) 185411Sjkh printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 186327Sjkh if (Flags & SHOW_COMMENT) 187379Sjkh show_file("Comment:\n", COMMENT_FNAME); 18866339Smarko if (Flags & SHOW_REQUIRE) 18984745Ssobomax show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE); 1904996Sjkh if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) 1914996Sjkh show_file("Required by:\n", REQUIRED_BY_FNAME); 192327Sjkh if (Flags & SHOW_DESC) 193379Sjkh show_file("Description:\n", DESC_FNAME); 1944996Sjkh if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) 1954996Sjkh show_file("Install notice:\n", DISPLAY_FNAME); 196327Sjkh if (Flags & SHOW_PLIST) 19784745Ssobomax show_plist("Packing list:\n", &plist, (plist_t)0, TRUE); 198327Sjkh if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) 199379Sjkh show_file("Install script:\n", INSTALL_FNAME); 20041866Sjkh if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME)) 20141866Sjkh show_file("Post-Install script:\n", POST_INSTALL_FNAME); 202327Sjkh if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) 203379Sjkh show_file("De-Install script:\n", DEINSTALL_FNAME); 20441866Sjkh if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME)) 20541866Sjkh show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME); 2064996Sjkh if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) 2074996Sjkh show_file("mtree file:\n", MTREE_FNAME); 208327Sjkh if (Flags & SHOW_PREFIX) 20984745Ssobomax show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE); 210411Sjkh if (Flags & SHOW_FILES) 211411Sjkh show_files("Files:\n", &plist); 21262775Ssobomax if ((Flags & SHOW_SIZE) && installed) 21362775Ssobomax show_size("Package Size:\n", &plist); 21471965Sjkh if ((Flags & SHOW_CKSUM) && installed) 21571965Sjkh show_cksum("Mismatched Checksums:\n", &plist); 21667454Ssobomax if (Flags & SHOW_ORIGIN) 21767454Ssobomax show_origin("Origin:\n", &plist); 21884750Ssobomax if (Flags & SHOW_FMTREV) 21984750Ssobomax show_fmtrev("Packing list format revision:\n", &plist); 220411Sjkh if (!Quiet) 221411Sjkh puts(InfoPrefix); 222327Sjkh } 223327Sjkh free_plist(&plist); 2248086Sjkh bail: 22533427Sjkh leave_playpen(); 2268086Sjkh if (isTMP) 2278086Sjkh unlink(fname); 2288086Sjkh return code; 229327Sjkh} 230327Sjkh 231327Sjkhvoid 232327Sjkhcleanup(int sig) 233327Sjkh{ 23433427Sjkh static int in_cleanup = 0; 23533427Sjkh 23633427Sjkh if (!in_cleanup) { 23733427Sjkh in_cleanup = 1; 23872174Ssobomax leave_playpen(); 23933427Sjkh } 24039068Sjkh if (sig) 24139068Sjkh exit(1); 242327Sjkh} 24349300Sjdp 24474699Ssobomax/* 24574808Ssobomax * Return an absolute path, additionally removing all .'s, ..'s, and extraneous 24674808Ssobomax * /'s, as realpath() would, but without resolving symlinks, because that can 24774808Ssobomax * potentially screw up our comparisons later. 24874808Ssobomax */ 24984745Ssobomaxstatic char * 25074808Ssobomaxabspath(const char *pathname) 25174808Ssobomax{ 25274808Ssobomax char *tmp, *tmp1, *resolved_path; 25374808Ssobomax char *cwd = NULL; 25474808Ssobomax int len; 25574808Ssobomax 25674808Ssobomax if (pathname[0] != '/') { 25774808Ssobomax cwd = getcwd(NULL, MAXPATHLEN); 25874808Ssobomax asprintf(&resolved_path, "%s/%s/", cwd, pathname); 25974808Ssobomax } else 26074808Ssobomax asprintf(&resolved_path, "%s/", pathname); 26174808Ssobomax 26274808Ssobomax if (resolved_path == NULL) 26374808Ssobomax errx(2, NULL); 26474808Ssobomax 26574808Ssobomax if (cwd != NULL) 26674808Ssobomax free(cwd); 26774808Ssobomax 26874808Ssobomax while ((tmp = strstr(resolved_path, "//")) != NULL) 26974808Ssobomax strcpy(tmp, tmp + 1); 27074808Ssobomax 27174808Ssobomax while ((tmp = strstr(resolved_path, "/./")) != NULL) 27274808Ssobomax strcpy(tmp, tmp + 2); 27374808Ssobomax 27474808Ssobomax while ((tmp = strstr(resolved_path, "/../")) != NULL) { 27574808Ssobomax *tmp = '\0'; 27674808Ssobomax if ((tmp1 = strrchr(resolved_path, '/')) == NULL) 27774808Ssobomax tmp1 = resolved_path; 27874808Ssobomax strcpy(tmp1, tmp + 3); 27974808Ssobomax } 28074808Ssobomax 28174808Ssobomax len = strlen(resolved_path); 28274808Ssobomax if (len > 1 && resolved_path[len - 1] == '/') 28374808Ssobomax resolved_path[len - 1] = '\0'; 28474808Ssobomax 28574808Ssobomax return resolved_path; 28674808Ssobomax} 28774808Ssobomax 28874808Ssobomax/* 28974699Ssobomax * Comparison to see if the path we're on matches the 29074699Ssobomax * one we are looking for. 29174699Ssobomax */ 29274699Ssobomaxstatic int 29374699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd) 29474699Ssobomax{ 29574808Ssobomax char *resolved, *temp; 29674699Ssobomax int rval; 29774699Ssobomax 29874699Ssobomax asprintf(&temp, "%s/%s", cwd, current); 29974699Ssobomax if (temp == NULL) 30074699Ssobomax errx(2, NULL); 30174699Ssobomax 30274699Ssobomax /* 30374808Ssobomax * Make sure there's no multiple /'s or other weird things in the PLIST, 30474808Ssobomax * since some plists seem to have them and it could screw up our strncmp. 30574699Ssobomax */ 30674808Ssobomax resolved = abspath(temp); 30774699Ssobomax 30874808Ssobomax if (strcmp(target, resolved) == 0) 30974699Ssobomax rval = 1; 31074699Ssobomax else 31174699Ssobomax rval = 0; 31274699Ssobomax 31374699Ssobomax free(temp); 31474808Ssobomax free(resolved); 31574699Ssobomax return rval; 31674699Ssobomax} 31774699Ssobomax 31874699Ssobomax/* 31974699Ssobomax * Look through package dbs in db_dir and find which 32074699Ssobomax * packages installed the files in which_list. 32174699Ssobomax */ 32274699Ssobomaxstatic int 32384745Ssobomaxfind_pkg(const char *db_dir, struct which_head *which_list) 32474699Ssobomax{ 32574699Ssobomax char **installed; 32674699Ssobomax int errcode, i; 32774699Ssobomax struct which_entry *wp; 32874699Ssobomax 32974699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 33084745Ssobomax const char *msg = "file cannot be found"; 33174808Ssobomax char *tmp; 33274808Ssobomax 33374808Ssobomax wp->skip = TRUE; 33474699Ssobomax /* If it's not a file, we'll see if it's an executable. */ 33574699Ssobomax if (isfile(wp->file) == FALSE) { 33674699Ssobomax if (strchr(wp->file, '/') == NULL) { 33774699Ssobomax tmp = vpipe("/usr/bin/which %s", wp->file); 33874808Ssobomax if (tmp != NULL) { 33974808Ssobomax strlcpy(wp->file, tmp, PATH_MAX); 34074808Ssobomax wp->skip = FALSE; 34174808Ssobomax free(tmp); 34274699Ssobomax } else 34374808Ssobomax msg = "file is not in PATH"; 34474699Ssobomax } 34574808Ssobomax } else { 34674808Ssobomax tmp = abspath(wp->file); 34774808Ssobomax if (isfile(tmp)) { 34874808Ssobomax strlcpy(wp->file, tmp, PATH_MAX); 34974808Ssobomax wp->skip = FALSE; 35074808Ssobomax } 35174699Ssobomax free(tmp); 35274699Ssobomax } 35374808Ssobomax if (wp->skip == TRUE) 35474808Ssobomax warnx("%s: %s", wp->file, msg); 35574699Ssobomax } 35674699Ssobomax 35774699Ssobomax installed = matchinstalled(MATCH_ALL, NULL, &errcode); 35874699Ssobomax if (installed == NULL) 35974699Ssobomax return errcode; 36074699Ssobomax 36174699Ssobomax for (i = 0; installed[i] != NULL; i++) { 36274699Ssobomax FILE *fp; 36374699Ssobomax Package pkg; 36474699Ssobomax PackingList itr; 36574699Ssobomax char *cwd = NULL; 36674699Ssobomax char tmp[PATH_MAX]; 36774699Ssobomax 36874699Ssobomax snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 36974699Ssobomax CONTENTS_FNAME); 37074699Ssobomax fp = fopen(tmp, "r"); 37174699Ssobomax if (fp == NULL) { 37274699Ssobomax warn("%s", tmp); 37374699Ssobomax return 1; 37474699Ssobomax } 37574699Ssobomax 37674699Ssobomax pkg.head = pkg.tail = NULL; 37774699Ssobomax read_plist(&pkg, fp); 37874699Ssobomax fclose(fp); 37974699Ssobomax for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { 38074699Ssobomax if (itr->type == PLIST_CWD) { 38174699Ssobomax cwd = itr->name; 38274699Ssobomax } else if (itr->type == PLIST_FILE) { 38374699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 38474699Ssobomax if (wp->skip == TRUE) 38574699Ssobomax continue; 38674699Ssobomax if (!cmp_path(wp->file, itr->name, cwd)) 38774699Ssobomax continue; 38874699Ssobomax if (wp->package[0] != '\0') { 38974809Ssobomax warnx("both %s and %s claim to have installed %s\n", 39074699Ssobomax wp->package, installed[i], wp->file); 39174699Ssobomax } else { 39274699Ssobomax strlcpy(wp->package, installed[i], PATH_MAX); 39374699Ssobomax } 39474699Ssobomax } 39574699Ssobomax } 39674699Ssobomax } 39774699Ssobomax free_plist(&pkg); 39874699Ssobomax } 39974699Ssobomax 40074699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 40174699Ssobomax if (wp->package[0] != '\0') { 40274699Ssobomax if (Quiet) 40374699Ssobomax puts(wp->package); 40474699Ssobomax else 40574699Ssobomax printf("%s was installed by package %s\n", \ 40674699Ssobomax wp->file, wp->package); 40774699Ssobomax } 40874699Ssobomax } 40974699Ssobomax while (!TAILQ_EMPTY(which_list)) { 41074699Ssobomax wp = TAILQ_FIRST(which_list); 41174699Ssobomax TAILQ_REMOVE(which_list, wp, next); 41274699Ssobomax free(wp); 41374699Ssobomax } 41474699Ssobomax 41574699Ssobomax free(which_list); 41674699Ssobomax return 0; 41774699Ssobomax} 41896030Ssobomax 41996030Ssobomax/* 42096030Ssobomax * Look through package dbs in db_dir and find which 42196030Ssobomax * packages have the given origin. Don't use read_plist() 42296030Ssobomax * because this increases time necessary for lookup by 40 42396030Ssobomax * times, as we don't really have to parse all plist to 42496030Ssobomax * get origin. 42596030Ssobomax */ 42696030Ssobomaxstatic int 42796030Ssobomaxfind_pkgs_by_origin(const char *db_dir, const char *origin) 42896030Ssobomax{ 42996030Ssobomax char **installed; 43096030Ssobomax int errcode, i; 43196030Ssobomax 43296030Ssobomax installed = matchinstalled(MATCH_ALL, NULL, &errcode); 43396030Ssobomax if (installed == NULL) 43496030Ssobomax return errcode; 43596030Ssobomax 43696030Ssobomax if (!Quiet) 43796030Ssobomax printf("The following installed package(s) has %s origin:\n", origin); 43896030Ssobomax for (i = 0; installed[i] != NULL; i++) { 43996030Ssobomax FILE *fp; 44096030Ssobomax char *cp, tmp[PATH_MAX]; 44196030Ssobomax int cmd; 44296030Ssobomax 44396030Ssobomax snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 44496030Ssobomax CONTENTS_FNAME); 44596030Ssobomax fp = fopen(tmp, "r"); 44696030Ssobomax if (fp == NULL) { 44796030Ssobomax warn("%s", tmp); 44896030Ssobomax return 1; 44996030Ssobomax } 45096030Ssobomax 45196030Ssobomax cmd = -1; 45296030Ssobomax while (fgets(tmp, sizeof(tmp), fp)) { 45396030Ssobomax int len = strlen(tmp); 45496030Ssobomax 45596030Ssobomax while (len && isspace(tmp[len - 1])) 45696030Ssobomax tmp[--len] = '\0'; 45796030Ssobomax if (!len) 45896030Ssobomax continue; 45996030Ssobomax cp = tmp; 46096030Ssobomax if (tmp[0] != CMD_CHAR) 46196030Ssobomax continue; 46296030Ssobomax cmd = plist_cmd(tmp + 1, &cp); 46396030Ssobomax if (cmd == PLIST_ORIGIN) { 46496030Ssobomax if (strcmp(origin, cp) == 0) 46596030Ssobomax puts(installed[i]); 46696030Ssobomax break; 46796030Ssobomax } 46896030Ssobomax } 46996030Ssobomax if (cmd != PLIST_ORIGIN) 47096030Ssobomax warnx("package %s has no origin recorded", installed[i]); 47196030Ssobomax fclose(fp); 47296030Ssobomax } 47396030Ssobomax 47496030Ssobomax return 0; 47596030Ssobomax} 476