perform.c revision 74699
1327Sjkh#ifndef lint 230221Scharnierstatic const char rcsid[] = 350479Speter "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 74699 2001-03-23 18:45:24Z 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 *); 3274699Ssobomaxstatic int find_pkg(char *, struct which_head *); 3374699Ssobomaxstatic int cmp_path(const char *, const char *, const char *); 34327Sjkh 35327Sjkhint 36327Sjkhpkg_perform(char **pkgs) 37327Sjkh{ 3873134Ssobomax char **matched; 397937Sjkh char *tmp; 4073134Ssobomax int err_cnt = 0; 4173134Ssobomax int i, errcode; 42327Sjkh 43327Sjkh signal(SIGINT, cleanup); 44327Sjkh 4574699Ssobomax tmp = getenv(PKG_DBDIR); 4674699Ssobomax if (!tmp) 4774699Ssobomax tmp = DEF_LOG_DIR; 4874699Ssobomax 49327Sjkh /* Overriding action? */ 5016404Sjkh if (CheckPkg) { 5116404Sjkh char buf[FILENAME_MAX]; 52327Sjkh 5316404Sjkh snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); 5416404Sjkh return abs(access(buf, R_OK)); 5572174Ssobomax /* Not reached */ 5674699Ssobomax } else if (!TAILQ_EMPTY(whead)) { 5774699Ssobomax return find_pkg(tmp, whead); 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 { 1487937Sjkh char *tmp; 1497937Sjkh 1507937Sjkh sprintf(log_dir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, 1517937Sjkh pkg); 152327Sjkh if (!fexists(log_dir)) { 15330221Scharnier warnx("can't find package `%s' installed or in a file!", pkg); 154327Sjkh return 1; 155327Sjkh } 156327Sjkh if (chdir(log_dir) == FAIL) { 15730221Scharnier warnx("can't change directory to '%s'!", log_dir); 158327Sjkh return 1; 159327Sjkh } 160327Sjkh installed = TRUE; 161327Sjkh } 162327Sjkh 163327Sjkh /* Suck in the contents list */ 164327Sjkh plist.head = plist.tail = NULL; 165327Sjkh fp = fopen(CONTENTS_FNAME, "r"); 166327Sjkh if (!fp) { 16730221Scharnier warnx("unable to open %s file", CONTENTS_FNAME); 1688086Sjkh code = 1; 1698086Sjkh goto bail; 170327Sjkh } 171327Sjkh /* If we have a prefix, add it now */ 172327Sjkh read_plist(&plist, fp); 173327Sjkh fclose(fp); 174327Sjkh 175327Sjkh /* 176327Sjkh * Index is special info type that has to override all others to make 177327Sjkh * any sense. 178327Sjkh */ 179327Sjkh if (Flags & SHOW_INDEX) { 1808086Sjkh char tmp[FILENAME_MAX]; 181327Sjkh 1828086Sjkh snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); 1838086Sjkh show_index(tmp, COMMENT_FNAME); 184327Sjkh } 185327Sjkh else { 186327Sjkh /* Start showing the package contents */ 187411Sjkh if (!Quiet) 188411Sjkh printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 189327Sjkh if (Flags & SHOW_COMMENT) 190379Sjkh show_file("Comment:\n", COMMENT_FNAME); 19166339Smarko if (Flags & SHOW_REQUIRE) 19266339Smarko show_plist("Depends on:\n", &plist, PLIST_PKGDEP); 1934996Sjkh if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) 1944996Sjkh show_file("Required by:\n", REQUIRED_BY_FNAME); 195327Sjkh if (Flags & SHOW_DESC) 196379Sjkh show_file("Description:\n", DESC_FNAME); 1974996Sjkh if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) 1984996Sjkh show_file("Install notice:\n", DISPLAY_FNAME); 199327Sjkh if (Flags & SHOW_PLIST) 200379Sjkh show_plist("Packing list:\n", &plist, (plist_t)-1); 201327Sjkh if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) 202379Sjkh show_file("Install script:\n", INSTALL_FNAME); 20341866Sjkh if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME)) 20441866Sjkh show_file("Post-Install script:\n", POST_INSTALL_FNAME); 205327Sjkh if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) 206379Sjkh show_file("De-Install script:\n", DEINSTALL_FNAME); 20741866Sjkh if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME)) 20841866Sjkh show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME); 2094996Sjkh if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) 2104996Sjkh show_file("mtree file:\n", MTREE_FNAME); 211327Sjkh if (Flags & SHOW_PREFIX) 212379Sjkh show_plist("Prefix(s):\n", &plist, PLIST_CWD); 213411Sjkh if (Flags & SHOW_FILES) 214411Sjkh show_files("Files:\n", &plist); 21562775Ssobomax if ((Flags & SHOW_SIZE) && installed) 21662775Ssobomax show_size("Package Size:\n", &plist); 21771965Sjkh if ((Flags & SHOW_CKSUM) && installed) 21871965Sjkh show_cksum("Mismatched Checksums:\n", &plist); 21967454Ssobomax if (Flags & SHOW_ORIGIN) 22067454Ssobomax show_origin("Origin:\n", &plist); 221411Sjkh if (!Quiet) 222411Sjkh puts(InfoPrefix); 223327Sjkh } 224327Sjkh free_plist(&plist); 2258086Sjkh bail: 22633427Sjkh leave_playpen(); 2278086Sjkh if (isTMP) 2288086Sjkh unlink(fname); 2298086Sjkh return code; 230327Sjkh} 231327Sjkh 232327Sjkhvoid 233327Sjkhcleanup(int sig) 234327Sjkh{ 23533427Sjkh static int in_cleanup = 0; 23633427Sjkh 23733427Sjkh if (!in_cleanup) { 23833427Sjkh in_cleanup = 1; 23972174Ssobomax leave_playpen(); 24033427Sjkh } 24139068Sjkh if (sig) 24239068Sjkh exit(1); 243327Sjkh} 24449300Sjdp 24574699Ssobomax/* 24674699Ssobomax * Comparison to see if the path we're on matches the 24774699Ssobomax * one we are looking for. 24874699Ssobomax */ 24974699Ssobomaxstatic int 25074699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd) 25174699Ssobomax{ 25274699Ssobomax char *loc, *temp; 25374699Ssobomax int rval; 25474699Ssobomax 25574699Ssobomax asprintf(&temp, "%s/%s", cwd, current); 25674699Ssobomax if (temp == NULL) 25774699Ssobomax errx(2, NULL); 25874699Ssobomax 25974699Ssobomax /* 26074699Ssobomax * Make sure there's no multiple /'s, since some plists 26174699Ssobomax * seem to have them and it could screw up our strncmp. 26274699Ssobomax */ 26374699Ssobomax while ((loc = strstr(temp, "//")) != NULL) 26474699Ssobomax strcpy(loc, loc + 1); 26574699Ssobomax 26674699Ssobomax if (strcmp(target, temp) == 0) 26774699Ssobomax rval = 1; 26874699Ssobomax else 26974699Ssobomax rval = 0; 27074699Ssobomax 27174699Ssobomax free(temp); 27274699Ssobomax return rval; 27374699Ssobomax} 27474699Ssobomax 27574699Ssobomax/* 27674699Ssobomax * Look through package dbs in db_dir and find which 27774699Ssobomax * packages installed the files in which_list. 27874699Ssobomax */ 27974699Ssobomaxstatic int 28074699Ssobomaxfind_pkg(char *db_dir, struct which_head *which_list) 28174699Ssobomax{ 28274699Ssobomax char **installed; 28374699Ssobomax int errcode, i; 28474699Ssobomax struct which_entry *wp; 28574699Ssobomax 28674699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 28774699Ssobomax /* If it's not a file, we'll see if it's an executable. */ 28874699Ssobomax if (isfile(wp->file) == FALSE) { 28974699Ssobomax if (strchr(wp->file, '/') == NULL) { 29074699Ssobomax char *tmp; 29174699Ssobomax tmp = vpipe("/usr/bin/which %s", wp->file); 29274699Ssobomax if (tmp == NULL) { 29374699Ssobomax warnx("%s: file is not in PATH", wp->file); 29474699Ssobomax wp->skip = TRUE; 29574699Ssobomax } else 29674699Ssobomax strlcpy(wp->file, tmp, PATH_MAX); 29774699Ssobomax free(tmp); 29874699Ssobomax } else { 29974699Ssobomax warnx("%s: file cannot be found", wp->file); 30074699Ssobomax wp->skip = TRUE; 30174699Ssobomax } 30274699Ssobomax } else if (wp->file[0] != '/') { 30374699Ssobomax /* 30474699Ssobomax * If it is a file, and it doesn't start with a /, then it's a 30574699Ssobomax * relative path. in order to give us some chance of getting a 30674699Ssobomax * successful match, tack the current working directory on the 30774699Ssobomax * beginning. this won't work for filenames that include .. or . 30874699Ssobomax * or extra /'s, but it's better than nothing). 30974699Ssobomax */ 31074699Ssobomax char *curdir, *tmp; 31174699Ssobomax 31274699Ssobomax curdir = getcwd(NULL, PATH_MAX); 31374699Ssobomax if (curdir == NULL) 31474699Ssobomax err(2, NULL); 31574699Ssobomax 31674699Ssobomax asprintf(&tmp, "%s/%s", curdir, wp->file); 31774699Ssobomax if (tmp == NULL) 31874699Ssobomax err(2, NULL); 31974699Ssobomax 32074699Ssobomax if (!isfile(tmp)) { 32174699Ssobomax warnx("%s: file cannot be found", tmp); 32274699Ssobomax wp->skip = TRUE; 32374699Ssobomax } else 32474699Ssobomax strlcpy(wp->file, tmp, PATH_MAX); 32574699Ssobomax 32674699Ssobomax free(tmp); 32774699Ssobomax free(curdir); 32874699Ssobomax } 32974699Ssobomax } 33074699Ssobomax 33174699Ssobomax installed = matchinstalled(MATCH_ALL, NULL, &errcode); 33274699Ssobomax if (installed == NULL) 33374699Ssobomax return errcode; 33474699Ssobomax 33574699Ssobomax for (i = 0; installed[i] != NULL; i++) { 33674699Ssobomax FILE *fp; 33774699Ssobomax Package pkg; 33874699Ssobomax PackingList itr; 33974699Ssobomax char *cwd = NULL; 34074699Ssobomax char tmp[PATH_MAX]; 34174699Ssobomax 34274699Ssobomax snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 34374699Ssobomax CONTENTS_FNAME); 34474699Ssobomax fp = fopen(tmp, "r"); 34574699Ssobomax if (fp == NULL) { 34674699Ssobomax warn("%s", tmp); 34774699Ssobomax return 1; 34874699Ssobomax } 34974699Ssobomax 35074699Ssobomax pkg.head = pkg.tail = NULL; 35174699Ssobomax read_plist(&pkg, fp); 35274699Ssobomax fclose(fp); 35374699Ssobomax for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { 35474699Ssobomax if (itr->type == PLIST_CWD) { 35574699Ssobomax cwd = itr->name; 35674699Ssobomax } else if (itr->type == PLIST_FILE) { 35774699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 35874699Ssobomax if (wp->skip == TRUE) 35974699Ssobomax continue; 36074699Ssobomax if (!cmp_path(wp->file, itr->name, cwd)) 36174699Ssobomax continue; 36274699Ssobomax if (wp->package[0] != '\0') { 36374699Ssobomax warnx("Both %s and %s claim to have installed %s\n", 36474699Ssobomax wp->package, installed[i], wp->file); 36574699Ssobomax } else { 36674699Ssobomax strlcpy(wp->package, installed[i], PATH_MAX); 36774699Ssobomax } 36874699Ssobomax } 36974699Ssobomax } 37074699Ssobomax } 37174699Ssobomax free_plist(&pkg); 37274699Ssobomax } 37374699Ssobomax 37474699Ssobomax TAILQ_FOREACH(wp, which_list, next) { 37574699Ssobomax if (wp->package[0] != '\0') { 37674699Ssobomax if (Quiet) 37774699Ssobomax puts(wp->package); 37874699Ssobomax else 37974699Ssobomax printf("%s was installed by package %s\n", \ 38074699Ssobomax wp->file, wp->package); 38174699Ssobomax } 38274699Ssobomax } 38374699Ssobomax while (!TAILQ_EMPTY(which_list)) { 38474699Ssobomax wp = TAILQ_FIRST(which_list); 38574699Ssobomax TAILQ_REMOVE(which_list, wp, next); 38674699Ssobomax free(wp); 38774699Ssobomax } 38874699Ssobomax 38974699Ssobomax free(which_list); 39074699Ssobomax return 0; 39174699Ssobomax} 392