perform.c revision 84750
150472Speter#ifndef lint 237Srgrimesstatic const char rcsid[] = 378822Snik "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 84750 2001-10-10 08:21:41Z sobomax $"; 450203Srgrimes#endif 537Srgrimes 639161Sobrien/* 739490Sobrien * FreeBSD install - a package for the installation and maintainance 88571Srgrimes * of non-core utilities. 92878Srgrimes * 1039490Sobrien * Redistribution and use in source and binary forms, with or without 112878Srgrimes * modification, are permitted provided that the following conditions 128571Srgrimes * are met: 132878Srgrimes * 1. Redistributions of source code must retain the above copyright 148571Srgrimes * notice, this list of conditions and the following disclaimer. 1550296Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 1650296Srgrimes * notice, this list of conditions and the following disclaimer in the 1750296Srgrimes * documentation and/or other materials provided with the distribution. 1850296Srgrimes * 1950296Srgrimes * Jordan K. Hubbard 2050296Srgrimes * 23 Aug 1993 21160945Sjb * 22160945Sjb * This is the main body of the info module. 23160822Ssimon * 24160822Ssimon */ 25248979Semaste 26248979Semaste#include "lib.h" 27255384Sdes#include "info.h" 28255384Sdes#include <err.h> 292878Srgrimes#include <signal.h> 30219019Sgabor 31248979Semastestatic int pkg_do(char *); 32248979Semastestatic int find_pkg(const char *, struct which_head *); 33248979Semastestatic int cmp_path(const char *, const char *, const char *); 34248979Semastestatic char *abspath(const char *); 35255384Sdes 36255384Sdesint 37219019Sgaborpkg_perform(char **pkgs) 3814796Spaul{ 39127383Sobrien char **matched; 40127383Sobrien const char *tmp; 4150296Srgrimes int err_cnt = 0; 4250296Srgrimes int i, errcode; 4350296Srgrimes 4450296Srgrimes signal(SIGINT, cleanup); 45253637Srpaulo 46253637Srpaulo tmp = LOG_DIR; 4714796Spaul 488571Srgrimes /* Overriding action? */ 49255036Sdelphij if (CheckPkg) { 50255036Sdelphij char buf[FILENAME_MAX]; 51255036Sdelphij 52255036Sdelphij snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg); 53255036Sdelphij return abs(access(buf, R_OK)); 54255036Sdelphij /* Not reached */ 55255036Sdelphij } else if (!TAILQ_EMPTY(whead)) { 56255036Sdelphij return find_pkg(tmp, whead); 57255036Sdelphij } 58255036Sdelphij 59255036Sdelphij if (MatchType != MATCH_EXACT) { 60255036Sdelphij matched = matchinstalled(MatchType, pkgs, &errcode); 61255036Sdelphij if (errcode != 0) 62255036Sdelphij return 1; 63255036Sdelphij /* Not reached */ 64255036Sdelphij 65255036Sdelphij if (matched != NULL) 66255036Sdelphij pkgs = matched; 67255036Sdelphij else switch (MatchType) { 68255036Sdelphij case MATCH_GLOB: 69255036Sdelphij break; 70255036Sdelphij case MATCH_ALL: 71255036Sdelphij warnx("no packages installed"); 72255036Sdelphij return 0; 73255036Sdelphij /* Not reached */ 74255036Sdelphij case MATCH_REGEX: 75255036Sdelphij warnx("no packages match pattern(s)"); 76255036Sdelphij return 1; 77255036Sdelphij /* Not reached */ 78255036Sdelphij default: 79255036Sdelphij break; 80255036Sdelphij } 81255036Sdelphij } 82255036Sdelphij 83255036Sdelphij for (i = 0; pkgs[i]; i++) 84255036Sdelphij err_cnt += pkg_do(pkgs[i]); 85255036Sdelphij 86255036Sdelphij return err_cnt; 87255036Sdelphij} 88255036Sdelphij 89255036Sdelphijstatic char *Home; 90255036Sdelphij 91255036Sdelphijstatic int 92255036Sdelphijpkg_do(char *pkg) 93255036Sdelphij{ 94255036Sdelphij Boolean installed = FALSE, isTMP = FALSE; 95255036Sdelphij char log_dir[FILENAME_MAX]; 96255036Sdelphij char fname[FILENAME_MAX]; 97255036Sdelphij Package plist; 98255036Sdelphij FILE *fp; 99255036Sdelphij struct stat sb; 100255036Sdelphij char *cp = NULL; 101255036Sdelphij int code = 0; 102255036Sdelphij 103255036Sdelphij if (isURL(pkg)) { 104269399Semaste if ((cp = fileGetURL(NULL, pkg)) != NULL) { 105269399Semaste strcpy(fname, cp); 106269399Semaste isTMP = TRUE; 107269399Semaste } 108255036Sdelphij } 109248979Semaste else if (fexists(pkg) && isfile(pkg)) { 110248979Semaste int len; 111272322Sdelphij 112272322Sdelphij if (*pkg != '/') { 1138571Srgrimes if (!getcwd(fname, FILENAME_MAX)) 11450296Srgrimes upchuck("getcwd"); 11550296Srgrimes len = strlen(fname); 1162878Srgrimes snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg); 11755797Srgrimes } 11855797Srgrimes else 11950296Srgrimes strcpy(fname, pkg); 12050296Srgrimes cp = fname; 1212878Srgrimes } 12239490Sobrien else { 1232878Srgrimes if ((cp = fileFindByPath(NULL, pkg)) != NULL) 12472515Sru strncpy(fname, cp, FILENAME_MAX); 1252878Srgrimes } 1268571Srgrimes if (cp) { 1272878Srgrimes /* 1288571Srgrimes * Apply a crude heuristic to see how much space the package will 129255036Sdelphij * take up once it's unpacked. I've noticed that most packages 130255036Sdelphij * compress an average of 75%, but we're only unpacking the + files so 131255036Sdelphij * be very optimistic. 132255036Sdelphij */ 133255036Sdelphij if (stat(fname, &sb) == FAIL) { 134255036Sdelphij warnx("can't stat package file '%s'", fname); 135255036Sdelphij code = 1; 136255036Sdelphij goto bail; 137255036Sdelphij } 138255036Sdelphij Home = make_playpen(PlayPen, sb.st_size / 2); 139255036Sdelphij if (unpack(fname, "+*")) { 140255036Sdelphij warnx("error during unpacking, no info for '%s' available", pkg); 141255036Sdelphij code = 1; 142255036Sdelphij goto bail; 143255036Sdelphij } 144255036Sdelphij } 1458571Srgrimes /* It's not an ininstalled package, try and find it among the installed */ 146255035Sdelphij else { 147255035Sdelphij sprintf(log_dir, "%s/%s", LOG_DIR, pkg); 14878045Sache if (!fexists(log_dir)) { 14950296Srgrimes warnx("can't find package '%s' installed or in a file!", pkg); 15095753Sdwmalone return 1; 15195688Sdwmalone } 15278045Sache if (chdir(log_dir) == FAIL) { 15350296Srgrimes warnx("can't change directory to '%s'!", log_dir); 154133833Sdwmalone return 1; 155133833Sdwmalone } 156255035Sdelphij installed = TRUE; 157255035Sdelphij } 158255035Sdelphij 159255035Sdelphij /* Suck in the contents list */ 16059949Sphantom plist.head = plist.tail = NULL; 16150296Srgrimes fp = fopen(CONTENTS_FNAME, "r"); 162255035Sdelphij if (!fp) { 163255035Sdelphij warnx("unable to open %s file", CONTENTS_FNAME); 164151825Sru code = 1; 165151825Sru goto bail; 1662878Srgrimes } 1678571Srgrimes /* If we have a prefix, add it now */ 1688571Srgrimes read_plist(&plist, fp); 1698571Srgrimes fclose(fp); 17057522Sshin 17157522Sshin /* 172118825Sharti * Index is special info type that has to override all others to make 173118825Sharti * any sense. 174167165Sflz */ 175167169Sflz if (Flags & SHOW_INDEX) { 176167169Sflz char tmp[FILENAME_MAX]; 177167169Sflz 178167169Sflz snprintf(tmp, FILENAME_MAX, "%-19s ", pkg); 179173491Sbenjsc show_index(tmp, COMMENT_FNAME); 180173491Sbenjsc } 181167165Sflz else { 182225880Sdim /* Start showing the package contents */ 183225880Sdim if (!Quiet) 184225880Sdim printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 185225880Sdim if (Flags & SHOW_COMMENT) 18655797Srgrimes show_file("Comment:\n", COMMENT_FNAME); 18755797Srgrimes if (Flags & SHOW_REQUIRE) 18855797Srgrimes show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE); 189290000Sglebius if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME)) 190290000Sglebius show_file("Required by:\n", REQUIRED_BY_FNAME); 191290000Sglebius if (Flags & SHOW_DESC) 192290000Sglebius show_file("Description:\n", DESC_FNAME); 193290000Sglebius if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME)) 194290000Sglebius show_file("Install notice:\n", DISPLAY_FNAME); 195290000Sglebius if (Flags & SHOW_PLIST) 196290000Sglebius show_plist("Packing list:\n", &plist, (plist_t)0, TRUE); 19755797Srgrimes if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME)) 1988571Srgrimes show_file("Install script:\n", INSTALL_FNAME); 1998571Srgrimes if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME)) 2008571Srgrimes show_file("Post-Install script:\n", POST_INSTALL_FNAME); 20197098Sru if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME)) 20297098Sru show_file("De-Install script:\n", DEINSTALL_FNAME); 20397098Sru if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME)) 20497098Sru show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME); 20597098Sru if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME)) 20697098Sru show_file("mtree file:\n", MTREE_FNAME); 20797098Sru if (Flags & SHOW_PREFIX) 20897098Sru show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE); 20918022Sbde if (Flags & SHOW_FILES) 21018022Sbde show_files("Files:\n", &plist); 21197098Sru if ((Flags & SHOW_SIZE) && installed) 21297098Sru show_size("Package Size:\n", &plist); 2138571Srgrimes if ((Flags & SHOW_CKSUM) && installed) 2148571Srgrimes show_cksum("Mismatched Checksums:\n", &plist); 21523379Swosch if (Flags & SHOW_ORIGIN) 21623379Swosch show_origin("Origin:\n", &plist); 21797098Sru if (Flags & SHOW_FMTREV) 21897098Sru show_fmtrev("Packing list format revision:\n", &plist); 21997098Sru if (!Quiet) 22097098Sru puts(InfoPrefix); 22197098Sru } 22297098Sru free_plist(&plist); 2238571Srgrimes bail: 2248571Srgrimes leave_playpen(); 2258571Srgrimes if (isTMP) 2268571Srgrimes unlink(fname); 2278571Srgrimes return code; 2288571Srgrimes} 2298571Srgrimes 2308571Srgrimesvoid 2318571Srgrimescleanup(int sig) 2328571Srgrimes{ 2338571Srgrimes static int in_cleanup = 0; 2348571Srgrimes 2358571Srgrimes if (!in_cleanup) { 2368571Srgrimes in_cleanup = 1; 2378571Srgrimes leave_playpen(); 2388571Srgrimes } 2398571Srgrimes if (sig) 2408571Srgrimes exit(1); 2418571Srgrimes} 2428571Srgrimes 2438571Srgrimes/* 2448571Srgrimes * Return an absolute path, additionally removing all .'s, ..'s, and extraneous 2458571Srgrimes * /'s, as realpath() would, but without resolving symlinks, because that can 2468571Srgrimes * potentially screw up our comparisons later. 2478571Srgrimes */ 2488571Srgrimesstatic char * 2498571Srgrimesabspath(const char *pathname) 2508571Srgrimes{ 2518571Srgrimes char *tmp, *tmp1, *resolved_path; 2528571Srgrimes char *cwd = NULL; 2538571Srgrimes int len; 2548571Srgrimes 2558571Srgrimes if (pathname[0] != '/') { 2568571Srgrimes cwd = getcwd(NULL, MAXPATHLEN); 2578571Srgrimes asprintf(&resolved_path, "%s/%s/", cwd, pathname); 2588571Srgrimes } else 2598571Srgrimes asprintf(&resolved_path, "%s/", pathname); 2608571Srgrimes 2618571Srgrimes if (resolved_path == NULL) 2628571Srgrimes errx(2, NULL); 2638571Srgrimes 2648571Srgrimes if (cwd != NULL) 2658571Srgrimes free(cwd); 2668571Srgrimes 2678571Srgrimes while ((tmp = strstr(resolved_path, "//")) != NULL) 2688571Srgrimes strcpy(tmp, tmp + 1); 269202843Sdelphij 270202843Sdelphij while ((tmp = strstr(resolved_path, "/./")) != NULL) 271202843Sdelphij strcpy(tmp, tmp + 2); 272202843Sdelphij 2738571Srgrimes while ((tmp = strstr(resolved_path, "/../")) != NULL) { 2748571Srgrimes *tmp = '\0'; 2758571Srgrimes if ((tmp1 = strrchr(resolved_path, '/')) == NULL) 2768571Srgrimes tmp1 = resolved_path; 2778571Srgrimes strcpy(tmp1, tmp + 3); 2788571Srgrimes } 2798571Srgrimes 2808571Srgrimes len = strlen(resolved_path); 2818571Srgrimes if (len > 1 && resolved_path[len - 1] == '/') 2828571Srgrimes resolved_path[len - 1] = '\0'; 2838571Srgrimes 2848571Srgrimes return resolved_path; 2858571Srgrimes} 2868571Srgrimes 2878571Srgrimes/* 2888571Srgrimes * Comparison to see if the path we're on matches the 28997098Sru * one we are looking for. 29097098Sru */ 29197098Srustatic int 29297098Srucmp_path(const char *target, const char *current, const char *cwd) 2938571Srgrimes{ 2948571Srgrimes char *resolved, *temp; 295235613Sgnn int rval; 296235613Sgnn 297235613Sgnn asprintf(&temp, "%s/%s", cwd, current); 298248979Semaste if (temp == NULL) 2998571Srgrimes errx(2, NULL); 30072636Sphk 30172636Sphk /* 3022878Srgrimes * Make sure there's no multiple /'s or other weird things in the PLIST, 3032878Srgrimes * since some plists seem to have them and it could screw up our strncmp. 30457522Sshin */ 30557522Sshin resolved = abspath(temp); 306248484Sneel 307248484Sneel if (strcmp(target, resolved) == 0) 30842006Sjkh rval = 1; 30942006Sjkh else 310255036Sdelphij rval = 0; 311255036Sdelphij 312235203Seadler free(temp); 313235203Seadler free(resolved); 31450296Srgrimes return rval; 31550296Srgrimes} 31622240Sjdp 31722240Sjdp/* 3188571Srgrimes * Look through package dbs in db_dir and find which 31950296Srgrimes * packages installed the files in which_list. 32050296Srgrimes */ 3212878Srgrimesstatic int 32250296Srgrimesfind_pkg(const char *db_dir, struct which_head *which_list) 32350296Srgrimes{ 324204080Sdelphij char **installed; 325204080Sdelphij int errcode, i; 326173532Ssam struct which_entry *wp; 327173532Ssam 3283831Ssos TAILQ_FOREACH(wp, which_list, next) { 3292878Srgrimes const char *msg = "file cannot be found"; 330206996Savg char *tmp; 331206996Savg 33285484Sru wp->skip = TRUE; 33385484Sru /* If it's not a file, we'll see if it's an executable. */ 33477825Sdcs if (isfile(wp->file) == FALSE) { 33577825Sdcs if (strchr(wp->file, '/') == NULL) { 336171584Sscottl tmp = vpipe("/usr/bin/which %s", wp->file); 337171584Sscottl if (tmp != NULL) { 338214308Sjulian strlcpy(wp->file, tmp, PATH_MAX); 339214308Sjulian wp->skip = FALSE; 34041682Sdfr free(tmp); 34141682Sdfr } else 34241682Sdfr msg = "file is not in PATH"; 34341682Sdfr } 34441682Sdfr } else { 34541682Sdfr tmp = abspath(wp->file); 34641682Sdfr if (isfile(tmp)) { 34763211Sabial strlcpy(wp->file, tmp, PATH_MAX); 34863211Sabial wp->skip = FALSE; 349200440Santoine } 350200440Santoine free(tmp); 351200440Santoine } 352200440Santoine if (wp->skip == TRUE) 353200440Santoine warnx("%s: %s", wp->file, msg); 354200440Santoine } 355218914Slstewart 356218914Slstewart installed = matchinstalled(MATCH_ALL, NULL, &errcode); 35742449Sjdp if (installed == NULL) 35841682Sdfr return errcode; 35941682Sdfr 36041682Sdfr for (i = 0; installed[i] != NULL; i++) { 36141682Sdfr FILE *fp; 36241682Sdfr Package pkg; 36341682Sdfr PackingList itr; 364238618Sjoerg char *cwd = NULL; 365238618Sjoerg char tmp[PATH_MAX]; 36630488Sjkh 36730488Sjkh snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i], 36855797Srgrimes CONTENTS_FNAME); 36955797Srgrimes fp = fopen(tmp, "r"); 37055797Srgrimes if (fp == NULL) { 371121616Semax warn("%s", tmp); 372121616Semax return 1; 37355797Srgrimes } 374209513Simp 375209513Simp pkg.head = pkg.tail = NULL; 37650296Srgrimes read_plist(&pkg, fp); 37750296Srgrimes fclose(fp); 378135184Smlaier for (itr = pkg.head; itr != pkg.tail; itr = itr->next) { 379135184Smlaier if (itr->type == PLIST_CWD) { 38050296Srgrimes cwd = itr->name; 38150296Srgrimes } else if (itr->type == PLIST_FILE) { 38250296Srgrimes TAILQ_FOREACH(wp, which_list, next) { 38350296Srgrimes if (wp->skip == TRUE) 38450296Srgrimes continue; 38550296Srgrimes if (!cmp_path(wp->file, itr->name, cwd)) 38655797Srgrimes continue; 38755797Srgrimes if (wp->package[0] != '\0') { 38856114Sphk warnx("both %s and %s claim to have installed %s\n", 38957611Sbillf wp->package, installed[i], wp->file); 39057611Sbillf } else { 39157611Sbillf strlcpy(wp->package, installed[i], PATH_MAX); 39257611Sbillf } 39357611Sbillf } 39457611Sbillf } 39557611Sbillf } 39657611Sbillf free_plist(&pkg); 39757611Sbillf } 39857611Sbillf 39956114Sphk TAILQ_FOREACH(wp, which_list, next) { 400252356Sdavide if (wp->package[0] != '\0') { 401252356Sdavide if (Quiet) 402252356Sdavide puts(wp->package); 403252356Sdavide else 4048571Srgrimes printf("%s was installed by package %s\n", \ 4058571Srgrimes wp->file, wp->package); 4068571Srgrimes } 4078571Srgrimes } 4088571Srgrimes while (!TAILQ_EMPTY(which_list)) { 4098571Srgrimes wp = TAILQ_FIRST(which_list); 4108571Srgrimes TAILQ_REMOVE(which_list, wp, next); 4118571Srgrimes free(wp); 41290559Smp } 41390559Smp 4142878Srgrimes free(which_list); 41539695Sobrien return 0; 4168571Srgrimes} 4172878Srgrimes