perform.c revision 84745
1327Sjkh#ifndef lint 230221Scharnierstatic const char rcsid[] = 350479Speter "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 84745 2001-10-10 06:58:42Z sobomax $"; 4327Sjkh#endif 5327Sjkh 6327Sjkh/* 7327Sjkh * FreeBSD install - a package for the installation and maintainance 8327Sjkh * of non-core utilities. 9327Sjkh * 10327Sjkh * Redistribution and use in source and binary forms, with or without 11327Sjkh * modification, are permitted provided that the following conditions 12327Sjkh * are met: 13327Sjkh * 1. Redistributions of source code must retain the above copyright 14327Sjkh * notice, this list of conditions and the following disclaimer. 15327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 16327Sjkh * notice, this list of conditions and the following disclaimer in the 17327Sjkh * documentation and/or other materials provided with the distribution. 18327Sjkh * 19327Sjkh * Jordan K. Hubbard 20327Sjkh * 23 Aug 1993 21327Sjkh * 22327Sjkh * This is the main body of the info module. 23327Sjkh * 24327Sjkh */ 25327Sjkh 26327Sjkh#include "lib.h" 27327Sjkh#include "info.h" 2872174Ssobomax#include <err.h> 29327Sjkh#include <signal.h> 30327Sjkh 31327Sjkhstatic int pkg_do(char *); 3284745Ssobomaxstatic int find_pkg(const char *, struct which_head *); 3374699Ssobomaxstatic int cmp_path(const char *, const char *, const char *); 3484745Ssobomaxstatic char *abspath(const char *); 35327Sjkh 36327Sjkhint 37327Sjkhpkg_perform(char **pkgs) 38327Sjkh{ 3973134Ssobomax char **matched; 4084745Ssobomax const char *tmp; 4173134Ssobomax int err_cnt = 0; 4273134Ssobomax int i, errcode; 43327Sjkh 44327Sjkh signal(SIGINT, cleanup); 45327Sjkh 4681049Ssobomax tmp = LOG_DIR; 4774699Ssobomax 48327Sjkh /* Overriding action? */ 4916404Sjkh if (CheckPkg) { 5016404Sjkh char buf[FILENAME_MAX]; 51327Sjkh 5216404Sjkh snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); 5316404Sjkh return abs(access(buf, R_OK)); 5472174Ssobomax /* Not reached */ 5574699Ssobomax } else if (!TAILQ_EMPTY(whead)) { 5674699Ssobomax return find_pkg(tmp, whead); 5716404Sjkh } 588857Srgrimes 5973134Ssobomax if (MatchType != MATCH_EXACT) { 6073134Ssobomax matched = matchinstalled(MatchType, pkgs, &errcode); 6173134Ssobomax if (errcode != 0) 6273134Ssobomax return 1; 6373134Ssobomax /* Not reached */ 6472174Ssobomax 6573134Ssobomax if (matched != NULL) 6673134Ssobomax pkgs = matched; 6773134Ssobomax else switch (MatchType) { 6873134Ssobomax case MATCH_GLOB: 6973134Ssobomax break; 7073134Ssobomax case MATCH_ALL: 7173134Ssobomax warnx("no packages installed"); 7273134Ssobomax return 0; 7373134Ssobomax /* Not reached */ 7473134Ssobomax case MATCH_REGEX: 7573134Ssobomax warnx("no packages match pattern(s)"); 7672174Ssobomax return 1; 7773134Ssobomax /* Not reached */ 7873134Ssobomax default: 7973134Ssobomax break; 8016404Sjkh } 8173134Ssobomax } 8272174Ssobomax 8373134Ssobomax for (i = 0; pkgs[i]; i++) 8473134Ssobomax err_cnt += pkg_do(pkgs[i]); 8572174Ssobomax 86327Sjkh return err_cnt; 87327Sjkh} 88327Sjkh 8911780Sjkhstatic char *Home; 9011780Sjkh 91327Sjkhstatic int 92327Sjkhpkg_do(char *pkg) 93327Sjkh{ 948086Sjkh Boolean installed = FALSE, isTMP = FALSE; 95327Sjkh char log_dir[FILENAME_MAX]; 968086Sjkh char fname[FILENAME_MAX]; 97327Sjkh Package plist; 98327Sjkh FILE *fp; 998086Sjkh struct stat sb; 1008142Sjkh char *cp = NULL; 1018086Sjkh int code = 0; 102327Sjkh 1038086Sjkh if (isURL(pkg)) { 10411780Sjkh if ((cp = fileGetURL(NULL, pkg)) != NULL) { 1058086Sjkh strcpy(fname, cp); 1068086Sjkh isTMP = TRUE; 1078086Sjkh } 1088086Sjkh } 1099782Sache else if (fexists(pkg) && isfile(pkg)) { 1108086Sjkh int len; 111327Sjkh 1128423Sjkh if (*pkg != '/') { 1138423Sjkh if (!getcwd(fname, FILENAME_MAX)) 1148423Sjkh upchuck("getcwd"); 1158423Sjkh len = strlen(fname); 1168423Sjkh snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); 1178423Sjkh } 1188423Sjkh else 1198423Sjkh strcpy(fname, pkg); 1208086Sjkh cp = fname; 1218086Sjkh } 1228086Sjkh else { 12311780Sjkh if ((cp = fileFindByPath(NULL, pkg)) != NULL) 1248086Sjkh strncpy(fname, cp, FILENAME_MAX); 1258086Sjkh } 1268086Sjkh if (cp) { 1273364Sjkh /* 1283364Sjkh * Apply a crude heuristic to see how much space the package will 1293364Sjkh * take up once it's unpacked. I've noticed that most packages 1303577Sjkh * compress an average of 75%, but we're only unpacking the + files so 1313577Sjkh * be very optimistic. 1323364Sjkh */ 1333364Sjkh if (stat(fname, &sb) == FAIL) { 13430221Scharnier warnx("can't stat package file '%s'", fname); 1358086Sjkh code = 1; 1368086Sjkh goto bail; 1373364Sjkh } 13811780Sjkh Home = make_playpen(PlayPen, sb.st_size / 2); 139327Sjkh if (unpack(fname, "+*")) { 14030221Scharnier warnx("error during unpacking, no info for '%s' available", pkg); 1418086Sjkh code = 1; 1428086Sjkh goto bail; 143327Sjkh } 144327Sjkh } 1458086Sjkh /* It's not an ininstalled package, try and find it among the installed */ 146327Sjkh else { 14781049Ssobomax sprintf(log_dir, "%s/%s", LOG_DIR, pkg); 148327Sjkh if (!fexists(log_dir)) { 14981046Ssobomax warnx("can't find package '%s' installed or in a file!", pkg); 150327Sjkh return 1; 151327Sjkh } 152327Sjkh if (chdir(log_dir) == FAIL) { 15330221Scharnier warnx("can't change directory to '%s'!", log_dir); 154327Sjkh return 1; 155327Sjkh } 156327Sjkh installed = TRUE; 157327Sjkh } 158327Sjkh 159327Sjkh /* Suck in the contents list */ 160327Sjkh plist.head = plist.tail = NULL; 161327Sjkh fp = fopen(CONTENTS_FNAME, "r"); 162327Sjkh if (!fp) { 16330221Scharnier warnx("unable to open %s file", CONTENTS_FNAME); 1648086Sjkh code = 1; 1658086Sjkh goto bail; 166327Sjkh } 167327Sjkh /* If we have a prefix, add it now */ 168327Sjkh read_plist(&plist, fp); 169327Sjkh fclose(fp); 170327Sjkh 171327Sjkh /* 172327Sjkh * Index is special info type that has to override all others to make 173327Sjkh * any sense. 174327Sjkh */ 175327Sjkh if (Flags & SHOW_INDEX) { 1768086Sjkh char tmp[FILENAME_MAX]; 177327Sjkh 1788086Sjkh snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); 1798086Sjkh show_index(tmp, COMMENT_FNAME); 180327Sjkh } 181327Sjkh else { 182327Sjkh /* Start showing the package contents */ 183411Sjkh if (!Quiet) 184411Sjkh printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 185327Sjkh if (Flags & SHOW_COMMENT) 186379Sjkh show_file("Comment:\n", COMMENT_FNAME); 18766339Smarko if (Flags & SHOW_REQUIRE) 18884745Ssobomax show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE); 1894996Sjkh if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) 1904996Sjkh show_file("Required by:\n", REQUIRED_BY_FNAME); 191327Sjkh if (Flags & SHOW_DESC) 192379Sjkh show_file("Description:\n", DESC_FNAME); 1934996Sjkh if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) 1944996Sjkh show_file("Install notice:\n", DISPLAY_FNAME); 195327Sjkh if (Flags & SHOW_PLIST) 19684745Ssobomax show_plist("Packing list:\n", &plist, (plist_t)0, TRUE); 197327Sjkh if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) 198379Sjkh show_file("Install script:\n", INSTALL_FNAME); 19941866Sjkh if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME)) 20041866Sjkh show_file("Post-Install script:\n", POST_INSTALL_FNAME); 201327Sjkh if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) 202379Sjkh show_file("De-Install script:\n", DEINSTALL_FNAME); 20341866Sjkh if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME)) 20441866Sjkh show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME); 2054996Sjkh if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) 2064996Sjkh show_file("mtree file:\n", MTREE_FNAME); 207327Sjkh if (Flags & SHOW_PREFIX) 20884745Ssobomax show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE); 209411Sjkh if (Flags & SHOW_FILES) 210411Sjkh show_files("Files:\n", &plist); 21162775Ssobomax if ((Flags & SHOW_SIZE) && installed) 21262775Ssobomax show_size("Package Size:\n", &plist); 21371965Sjkh if ((Flags & SHOW_CKSUM) && installed) 21471965Sjkh show_cksum("Mismatched Checksums:\n", &plist); 21567454Ssobomax if (Flags & SHOW_ORIGIN) 21667454Ssobomax show_origin("Origin:\n", &plist); 217411Sjkh if (!Quiet) 218411Sjkh puts(InfoPrefix); 219327Sjkh } 220327Sjkh free_plist(&plist); 2218086Sjkh bail: 22233427Sjkh leave_playpen(); 2238086Sjkh if (isTMP) 2248086Sjkh unlink(fname); 2258086Sjkh return code; 226327Sjkh} 227327Sjkh 228327Sjkhvoid 229327Sjkhcleanup(int sig) 230327Sjkh{ 23133427Sjkh static int in_cleanup = 0; 23233427Sjkh 23333427Sjkh if (!in_cleanup) { 23433427Sjkh in_cleanup = 1; 23572174Ssobomax leave_playpen(); 23633427Sjkh } 23739068Sjkh if (sig) 23839068Sjkh exit(1); 239327Sjkh} 24049300Sjdp 24174699Ssobomax/* 24274808Ssobomax * Return an absolute path, additionally removing all .'s, ..'s, and extraneous 24374808Ssobomax * /'s, as realpath() would, but without resolving symlinks, because that can 24474808Ssobomax * potentially screw up our comparisons later. 24574808Ssobomax */ 24684745Ssobomaxstatic char * 24774808Ssobomaxabspath(const char *pathname) 24874808Ssobomax{ 24974808Ssobomax char *tmp, *tmp1, *resolved_path; 25074808Ssobomax char *cwd = NULL; 25174808Ssobomax int len; 25274808Ssobomax 25374808Ssobomax if (pathname[0] != '/') { 25474808Ssobomax cwd = getcwd(NULL, MAXPATHLEN); 25574808Ssobomax asprintf(&resolved_path, "%s/%s/", cwd, pathname); 25674808Ssobomax } else 25774808Ssobomax asprintf(&resolved_path, "%s/", pathname); 25874808Ssobomax 25974808Ssobomax if (resolved_path == NULL) 26074808Ssobomax errx(2, NULL); 26174808Ssobomax 26274808Ssobomax if (cwd != NULL) 26374808Ssobomax free(cwd); 26474808Ssobomax 26574808Ssobomax while ((tmp = strstr(resolved_path, "//")) != NULL) 26674808Ssobomax strcpy(tmp, tmp + 1); 26774808Ssobomax 26874808Ssobomax while ((tmp = strstr(resolved_path, "/./")) != NULL) 26974808Ssobomax strcpy(tmp, tmp + 2); 27074808Ssobomax 27174808Ssobomax while ((tmp = strstr(resolved_path, "/../")) != NULL) { 27274808Ssobomax *tmp = '\0'; 27374808Ssobomax if ((tmp1 = strrchr(resolved_path, '/')) == NULL) 27474808Ssobomax tmp1 = resolved_path; 27574808Ssobomax strcpy(tmp1, tmp + 3); 27674808Ssobomax } 27774808Ssobomax 27874808Ssobomax len = strlen(resolved_path); 27974808Ssobomax if (len > 1 && resolved_path[len - 1] == '/') 28074808Ssobomax resolved_path[len - 1] = '\0'; 28174808Ssobomax 28274808Ssobomax return resolved_path; 28374808Ssobomax} 28474808Ssobomax 28574808Ssobomax/* 28674699Ssobomax * Comparison to see if the path we're on matches the 28774699Ssobomax * one we are looking for. 28874699Ssobomax */ 28974699Ssobomaxstatic int 29074699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd) 29174699Ssobomax{ 29274808Ssobomax char *resolved, *temp; 29374699Ssobomax int rval; 29474699Ssobomax 29574699Ssobomax asprintf(&temp, "%s/%s", cwd, current); 29674699Ssobomax if (temp == NULL) 29774699Ssobomax errx(2, NULL); 29874699Ssobomax 29974699Ssobomax /* 30074808Ssobomax * Make sure there's no multiple /'s or other weird things in the PLIST, 30174808Ssobomax * since some plists seem to have them and it could screw up our strncmp. 30274699Ssobomax */ 30374808Ssobomax resolved = abspath(temp); 30474699Ssobomax 30574808Ssobomax if (strcmp(target, resolved) == 0) 30674699Ssobomax rval = 1; 30774699Ssobomax else 30874699Ssobomax rval = 0; 30974699Ssobomax 31074699Ssobomax free(temp); 31174808Ssobomax free(resolved); 31274699Ssobomax return rval; 31374699Ssobomax} 31474699Ssobomax 31574699Ssobomax/* 31674699Ssobomax * Look through package dbs in db_dir and find which 31774699Ssobomax * packages installed the files in which_list. 31874699Ssobomax */ 31974699Ssobomaxstatic int 32084745Ssobomaxfind_pkg(const char *db_dir, struct which_head *which_list) 32174699Ssobomax{ 32274699Ssobomax char **installed; 32374699Ssobomax int errcode, i; 32474699Ssobomax struct which_entry *wp; 32574699Ssobomax 32674699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 32784745Ssobomax const char *msg = "file cannot be found"; 32874808Ssobomax char *tmp; 32974808Ssobomax 33074808Ssobomax wp->skip = TRUE; 33174699Ssobomax /* If it's not a file, we'll see if it's an executable. */ 33274699Ssobomax if (isfile(wp->file) == FALSE) { 33374699Ssobomax if (strchr(wp->file, '/') == NULL) { 33474699Ssobomax tmp = vpipe("/usr/bin/which %s", wp->file); 33574808Ssobomax if (tmp != NULL) { 33674808Ssobomax strlcpy(wp->file, tmp, PATH_MAX); 33774808Ssobomax wp->skip = FALSE; 33874808Ssobomax free(tmp); 33974699Ssobomax } else 34074808Ssobomax msg = "file is not in PATH"; 34174699Ssobomax } 34274808Ssobomax } else { 34374808Ssobomax tmp = abspath(wp->file); 34474808Ssobomax if (isfile(tmp)) { 34574808Ssobomax strlcpy(wp->file, tmp, PATH_MAX); 34674808Ssobomax wp->skip = FALSE; 34774808Ssobomax } 34874699Ssobomax free(tmp); 34974699Ssobomax } 35074808Ssobomax if (wp->skip == TRUE) 35174808Ssobomax warnx("%s: %s", wp->file, msg); 35274699Ssobomax } 35374699Ssobomax 35474699Ssobomax installed = matchinstalled(MATCH_ALL, NULL, &errcode); 35574699Ssobomax if (installed == NULL) 35674699Ssobomax return errcode; 35774699Ssobomax 35874699Ssobomax for (i = 0; installed[i] != NULL; i++) { 35974699Ssobomax FILE *fp; 36074699Ssobomax Package pkg; 36174699Ssobomax PackingList itr; 36274699Ssobomax char *cwd = NULL; 36374699Ssobomax char tmp[PATH_MAX]; 36474699Ssobomax 36574699Ssobomax snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 36674699Ssobomax CONTENTS_FNAME); 36774699Ssobomax fp = fopen(tmp, "r"); 36874699Ssobomax if (fp == NULL) { 36974699Ssobomax warn("%s", tmp); 37074699Ssobomax return 1; 37174699Ssobomax } 37274699Ssobomax 37374699Ssobomax pkg.head = pkg.tail = NULL; 37474699Ssobomax read_plist(&pkg, fp); 37574699Ssobomax fclose(fp); 37674699Ssobomax for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { 37774699Ssobomax if (itr->type == PLIST_CWD) { 37874699Ssobomax cwd = itr->name; 37974699Ssobomax } else if (itr->type == PLIST_FILE) { 38074699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 38174699Ssobomax if (wp->skip == TRUE) 38274699Ssobomax continue; 38374699Ssobomax if (!cmp_path(wp->file, itr->name, cwd)) 38474699Ssobomax continue; 38574699Ssobomax if (wp->package[0] != '\0') { 38674809Ssobomax warnx("both %s and %s claim to have installed %s\n", 38774699Ssobomax wp->package, installed[i], wp->file); 38874699Ssobomax } else { 38974699Ssobomax strlcpy(wp->package, installed[i], PATH_MAX); 39074699Ssobomax } 39174699Ssobomax } 39274699Ssobomax } 39374699Ssobomax } 39474699Ssobomax free_plist(&pkg); 39574699Ssobomax } 39674699Ssobomax 39774699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 39874699Ssobomax if (wp->package[0] != '\0') { 39974699Ssobomax if (Quiet) 40074699Ssobomax puts(wp->package); 40174699Ssobomax else 40274699Ssobomax printf("%s was installed by package %s\n", \ 40374699Ssobomax wp->file, wp->package); 40474699Ssobomax } 40574699Ssobomax } 40674699Ssobomax while (!TAILQ_EMPTY(which_list)) { 40774699Ssobomax wp = TAILQ_FIRST(which_list); 40874699Ssobomax TAILQ_REMOVE(which_list, wp, next); 40974699Ssobomax free(wp); 41074699Ssobomax } 41174699Ssobomax 41274699Ssobomax free(which_list); 41374699Ssobomax return 0; 41474699Ssobomax} 415