perform.c revision 8083
1327Sjkh#ifndef lint 28083Sjkhstatic const char *rcsid = "$Id: perform.c,v 1.21 1995/04/26 07:43:30 jkh Exp $"; 3327Sjkh#endif 4327Sjkh 5327Sjkh/* 6327Sjkh * FreeBSD install - a package for the installation and maintainance 7327Sjkh * of non-core utilities. 8327Sjkh * 9327Sjkh * Redistribution and use in source and binary forms, with or without 10327Sjkh * modification, are permitted provided that the following conditions 11327Sjkh * are met: 12327Sjkh * 1. Redistributions of source code must retain the above copyright 13327Sjkh * notice, this list of conditions and the following disclaimer. 14327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 15327Sjkh * notice, this list of conditions and the following disclaimer in the 16327Sjkh * documentation and/or other materials provided with the distribution. 17327Sjkh * 18327Sjkh * Jordan K. Hubbard 19327Sjkh * 18 July 1993 20327Sjkh * 21327Sjkh * This is the main body of the add module. 22327Sjkh * 23327Sjkh */ 24327Sjkh 25327Sjkh#include "lib.h" 26327Sjkh#include "add.h" 27327Sjkh 28327Sjkh#include <signal.h> 294996Sjkh#include <sys/wait.h> 30327Sjkh 31327Sjkhstatic int pkg_do(char *); 32327Sjkhstatic int sanity_check(char *); 33327Sjkhstatic char LogDir[FILENAME_MAX]; 34327Sjkh 35327Sjkh 36327Sjkhint 37327Sjkhpkg_perform(char **pkgs) 38327Sjkh{ 39327Sjkh int i, err_cnt = 0; 40327Sjkh 41327Sjkh signal(SIGINT, cleanup); 42327Sjkh signal(SIGHUP, cleanup); 43327Sjkh 44382Sjkh if (AddMode == SLAVE) 45382Sjkh err_cnt = pkg_do(NULL); 46382Sjkh else { 47382Sjkh for (i = 0; pkgs[i]; i++) 48382Sjkh err_cnt += pkg_do(pkgs[i]); 49382Sjkh } 50327Sjkh return err_cnt; 51327Sjkh} 52327Sjkh 53327Sjkhstatic Package Plist; 54327Sjkh 558083Sjkh/* 568083Sjkh * This is seriously ugly code following. Written very fast! 578083Sjkh * [And subsequently made even worse.. Sigh! This code was just born 588083Sjkh * to be hacked, I guess.. :) -jkh] 598083Sjkh */ 60327Sjkhstatic int 61327Sjkhpkg_do(char *pkg) 62327Sjkh{ 63327Sjkh char pkg_fullname[FILENAME_MAX]; 643576Sjkh char home[FILENAME_MAX]; 657998Sjkh char extract_contents[FILENAME_MAX]; 667998Sjkh char *where_to, *tmp; 67327Sjkh FILE *cfile; 68327Sjkh int code = 0; 691545Sjkh PackingList p; 703364Sjkh struct stat sb; 718083Sjkh char *isTMP = NULL; 72327Sjkh 73327Sjkh /* Reset some state */ 74327Sjkh if (Plist.head) 75327Sjkh free_plist(&Plist); 76327Sjkh LogDir[0] = '\0'; 778075Sjkh 788083Sjkh /* Are we coming in for a second pass, everything already extracted? */ 79382Sjkh if (AddMode == SLAVE) { 80382Sjkh char tmp_dir[FILENAME_MAX]; 81382Sjkh 82382Sjkh fgets(tmp_dir, FILENAME_MAX, stdin); 83382Sjkh tmp_dir[strlen(tmp_dir) - 1] = '\0'; /* pesky newline! */ 84382Sjkh if (chdir(tmp_dir) == FAIL) { 85382Sjkh whinge("pkg_add in SLAVE mode can't chdir to %s.", tmp_dir); 86382Sjkh return 1; 87382Sjkh } 88382Sjkh read_plist(&Plist, stdin); 89327Sjkh } 908083Sjkh /* Nope - do it now */ 91382Sjkh else { 923574Sjkh if (!getcwd(home, FILENAME_MAX)) 933574Sjkh upchuck("getcwd"); 943574Sjkh 958083Sjkh if (isURL(pkg)) { 968083Sjkh char *newname = fileGetURL(pkg); 978083Sjkh 988083Sjkh if (!newname) { 998083Sjkh whinge("Unable to fetch `%s' by URL.", pkg); 1008083Sjkh return 1; 1018083Sjkh } 1028083Sjkh strcpy(pkg_fullname, newname); 1038083Sjkh isTMP = pkg_fullname; 104382Sjkh } 1058083Sjkh else { 1068083Sjkh if (pkg[0] == '/') /* full pathname? */ 1078083Sjkh strcpy(pkg_fullname, pkg); 1088083Sjkh else 1098083Sjkh sprintf(pkg_fullname, "%s/%s", home, pkg); 1108083Sjkh if (!fexists(pkg_fullname)) { 1118083Sjkh char *tmp = fileFindByPath(pkg); 1128083Sjkh 1138083Sjkh if (!tmp) { 1148083Sjkh whinge("Can't find package `%s'.", pkg); 1158083Sjkh return 1; 1168083Sjkh } 1178083Sjkh strcpy(pkg_fullname, tmp); 1188083Sjkh } 1198083Sjkh } 1207998Sjkh Home = make_playpen(PlayPen, 0); 1217998Sjkh sprintf(extract_contents, "--fast-read %s", CONTENTS_FNAME); 1227998Sjkh if (unpack(pkg_fullname, extract_contents)) { 1237998Sjkh whinge("Unable to extract table of contents file from `%s' - not a package?.", pkg_fullname); 1247998Sjkh goto bomb; 1257998Sjkh } 1267998Sjkh cfile = fopen(CONTENTS_FNAME, "r"); 1277998Sjkh if (!cfile) { 1287998Sjkh whinge("Unable to open table of contents file `%s' - not a package?", CONTENTS_FNAME); 1297998Sjkh goto bomb; 1307998Sjkh } 1317998Sjkh read_plist(&Plist, cfile); 1327998Sjkh fclose(cfile); 1337998Sjkh 1343364Sjkh /* 1357998Sjkh * If we have a prefix, delete the first one we see and add this 1367998Sjkh * one in place of it. 1377998Sjkh */ 1387998Sjkh if (Prefix) { 1397998Sjkh delete_plist(&Plist, FALSE, PLIST_CWD, NULL); 1407998Sjkh add_plist_top(&Plist, PLIST_CWD, Prefix); 1417998Sjkh } 1427998Sjkh 1437998Sjkh /* Extract directly rather than moving? Oh goodie! */ 1447998Sjkh if (find_plist_option(&Plist, "extract-in-place")) { 1457998Sjkh if (Verbose) 1467998Sjkh printf("Doing in-place extraction for %s\n", pkg_fullname); 1477998Sjkh p = find_plist(&Plist, PLIST_CWD); 1487998Sjkh if (p) { 1498075Sjkh if (!isdir(p->name) && !Fake) { 1507998Sjkh if (Verbose) 1517998Sjkh printf("Desired prefix of %s does not exist, creating..\n", p->name); 1527998Sjkh vsystem("mkdir -p %s", p->name); 1537998Sjkh if (chdir(p->name)) { 1547998Sjkh whinge("Unable to change directory to `%s' - no permission?", p->name); 1557998Sjkh perror("chdir"); 1568083Sjkh goto bomb; 1577998Sjkh } 1587998Sjkh } 1597998Sjkh where_to = p->name; 1607998Sjkh } 1617998Sjkh else { 1627998Sjkh whinge("No prefix specified in `%s' - this is a bad package!", 1637998Sjkh pkg_fullname); 1648083Sjkh goto bomb; 1657998Sjkh } 1667998Sjkh } 1677998Sjkh else 1687998Sjkh where_to = PlayPen; 1697998Sjkh /* 1703364Sjkh * Apply a crude heuristic to see how much space the package will 1713364Sjkh * take up once it's unpacked. I've noticed that most packages 1723574Sjkh * compress an average of 75%, so multiply by 4 for good measure. 1733364Sjkh */ 1743364Sjkh if (stat(pkg_fullname, &sb) == FAIL) { 1753364Sjkh whinge("Can't stat package file '%s'.", pkg_fullname); 1768083Sjkh goto bomb; 1773364Sjkh } 1787998Sjkh 1797998Sjkh if (min_free(where_to) < sb.st_size * 4) { 1807998Sjkh whinge("Projected size of %d exceeds free space in %s.", 1817998Sjkh sb.st_size * 4, where_to); 1827998Sjkh whinge("Not extracting %s, sorry!", pkg_fullname); 1837998Sjkh goto bomb; 1847996Sjkh } 185327Sjkh 1867998Sjkh setenv(PKG_PREFIX_VNAME, 1877998Sjkh (p = find_plist(&Plist, PLIST_CWD)) ? p->name : NULL, 1); 1887998Sjkh /* Protect against old packages with bogus @name fields */ 1897998Sjkh PkgName = (p = find_plist(&Plist, PLIST_NAME)) ? p->name : "anonymous"; 1907998Sjkh 1917998Sjkh /* See if we're already registered */ 1927998Sjkh sprintf(LogDir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, 1937998Sjkh basename_of(PkgName)); 1947998Sjkh if (isdir(LogDir)) { 1957998Sjkh char tmp[FILENAME_MAX]; 1967998Sjkh 1977998Sjkh whinge("Package `%s' already recorded as installed.\n", PkgName); 1987998Sjkh code = 1; 1997998Sjkh goto success; /* close enough for government work */ 2007998Sjkh } 2017998Sjkh 2028075Sjkh /* Now check the packing list for dependencies */ 2038075Sjkh for (p = Plist.head; p ; p = p->next) { 2048083Sjkh char *isTMP = NULL; /* local copy for depends only */ 2058083Sjkh 2068075Sjkh if (p->type != PLIST_PKGDEP) 2078075Sjkh continue; 2088075Sjkh if (Verbose) 2098075Sjkh printf("Package `%s' depends on `%s'", pkg, p->name); 2108075Sjkh if (!Fake && vsystem("pkg_info -e %s", p->name)) { 2118083Sjkh char path[FILENAME_MAX], *cp = NULL; 2128075Sjkh 2138075Sjkh if (Verbose) 2148075Sjkh printf(" which is not currently loaded"); 2158083Sjkh if (!isURL(p->name)) { 2168083Sjkh snprintf(path, FILENAME_MAX, "%s/%s", Home, p->name); 2178083Sjkh if (fexists(path)) 2188083Sjkh cp = path; 2198083Sjkh else 2208083Sjkh cp = fileFindByPath(p->name); 2218075Sjkh } 2228083Sjkh else { 2238083Sjkh cp = fileGetURL(p->name); 2248083Sjkh isTMP = cp; 2258083Sjkh } 2268083Sjkh if (cp) { 2278075Sjkh if (Verbose) 2288075Sjkh printf(" but was found - loading:\n"); 2298083Sjkh if (!Fake && vsystem("pkg_add %s", cp)) { 2308083Sjkh whinge("Autoload of dependency `%s' failed%s", 2318083Sjkh p->name, Force ? " (proceeding anyway)" : "!"); 2328075Sjkh if (!Force) 2338075Sjkh ++code; 2348075Sjkh } 2358075Sjkh else if (Verbose) 2368075Sjkh printf("\t`%s' loaded successfully.\n", p->name); 2378083Sjkh /* Nuke the temporary URL copy */ 2388083Sjkh if (isTMP) { 2398083Sjkh unlink(isTMP); 2408083Sjkh isTMP = NULL; 2418083Sjkh } 2428075Sjkh } 2438075Sjkh else { 2448075Sjkh if (Verbose) 2458075Sjkh printf("and was not found%s.\n", 2468075Sjkh Force ? " (proceeding anyway)" : ""); 2478075Sjkh else 2488075Sjkh printf("Package dependency %s for %s not found%s\n", 2498075Sjkh p->name, pkg, 2508083Sjkh Force ? " (proceeding anyway)" : "!"); 2518075Sjkh if (!Force) 2528075Sjkh ++code; 2538075Sjkh } 2548075Sjkh } 2558075Sjkh else if (Verbose) 2568075Sjkh printf(" - already installed.\n"); 2578075Sjkh } 2588075Sjkh 2598083Sjkh /* If this is a direct extract and we didn't want it, stop now */ 2608083Sjkh if (where_to != PlayPen && Fake) 2618083Sjkh goto success; 2628083Sjkh 2637998Sjkh /* Finally unpack the whole mess */ 2647998Sjkh if (unpack(pkg_fullname, NULL)) { 2657998Sjkh whinge("Unable to extract `%s'!", pkg_fullname); 2667998Sjkh goto bomb; 2677996Sjkh } 268327Sjkh 2698075Sjkh /* Check for sanity and dependencies */ 2707998Sjkh if (sanity_check(pkg_fullname)) 2717998Sjkh goto bomb; 2727998Sjkh 273382Sjkh /* If we're running in MASTER mode, just output the plist and return */ 274382Sjkh if (AddMode == MASTER) { 275382Sjkh printf("%s\n", where_playpen()); 276382Sjkh write_plist(&Plist, stdout); 277573Sjkh return 0; 278382Sjkh } 279327Sjkh } 2807713Sjkh 2818075Sjkh /* Look for the requirements file */ 282327Sjkh if (fexists(REQUIRE_FNAME)) { 283327Sjkh vsystem("chmod +x %s", REQUIRE_FNAME); /* be sure */ 284327Sjkh if (Verbose) 285327Sjkh printf("Running requirements file first for %s..\n", PkgName); 286545Sjkh if (!Fake && vsystem("./%s %s INSTALL", REQUIRE_FNAME, PkgName)) { 2874996Sjkh whinge("Package %s fails requirements %s", 2884996Sjkh pkg_fullname, 2894996Sjkh Force ? "installing anyway" : "- not installed."); 2904996Sjkh if (!Force) { 2914996Sjkh code = 1; 2924996Sjkh goto success; /* close enough for government work */ 2934996Sjkh } 294327Sjkh } 295327Sjkh } 2968075Sjkh 2978075Sjkh /* If we're really installing, and have an installation file, run it */ 298327Sjkh if (!NoInstall && fexists(INSTALL_FNAME)) { 299327Sjkh vsystem("chmod +x %s", INSTALL_FNAME); /* make sure */ 300327Sjkh if (Verbose) 301327Sjkh printf("Running install with PRE-INSTALL for %s..\n", PkgName); 302545Sjkh if (!Fake && vsystem("./%s %s PRE-INSTALL", INSTALL_FNAME, PkgName)) { 303327Sjkh whinge("Install script returned error status."); 3047998Sjkh unlink(INSTALL_FNAME); 3054996Sjkh code = 1; 3064996Sjkh goto success; /* nothing to uninstall yet */ 307327Sjkh } 308327Sjkh } 3098075Sjkh 3108075Sjkh /* Now finally extract the entire show if we're not going direct */ 3118075Sjkh if (where_to == PlayPen && !Fake) 3128075Sjkh extract_plist(home, &Plist); 3138075Sjkh 3148075Sjkh if (!Fake && fexists(MTREE_FNAME)) { 3154996Sjkh if (Verbose) 3164996Sjkh printf("Running mtree for %s..\n", PkgName); 3174996Sjkh p = find_plist(&Plist, PLIST_CWD); 3184996Sjkh if (Verbose) 3194996Sjkh printf("mtree -u -f %s -d -e -p %s\n", MTREE_FNAME, 3204996Sjkh p ? p->name : "/"); 3214996Sjkh if (!Fake) { 3227938Sjkh if (vsystem("/usr/sbin/mtree -u -f %s -d -e -p %s", 3237938Sjkh MTREE_FNAME, p ? p->name : "/")) { 3247938Sjkh perror("error in the execution of mtree"); 3257998Sjkh unlink(MTREE_FNAME); 3264996Sjkh goto fail; 3274996Sjkh } 3284996Sjkh } 3297998Sjkh unlink(MTREE_FNAME); 3304996Sjkh } 3318075Sjkh 3328083Sjkh /* Run the installation script one last time? */ 333327Sjkh if (!NoInstall && fexists(INSTALL_FNAME)) { 334327Sjkh if (Verbose) 335327Sjkh printf("Running install with POST-INSTALL for %s..\n", PkgName); 336545Sjkh if (!Fake && vsystem("./%s %s POST-INSTALL", INSTALL_FNAME, PkgName)) { 337327Sjkh whinge("Install script returned error status."); 3387998Sjkh unlink(INSTALL_FNAME); 3394996Sjkh code = 1; 340327Sjkh goto fail; 341327Sjkh } 3427998Sjkh unlink(INSTALL_FNAME); 343327Sjkh } 3448075Sjkh 3458083Sjkh /* Time to record the deed? */ 346327Sjkh if (!NoRecord && !Fake) { 347382Sjkh char contents[FILENAME_MAX]; 348382Sjkh FILE *cfile; 349382Sjkh 3504996Sjkh umask(022); 351327Sjkh if (getuid() != 0) 352327Sjkh whinge("Not running as root - trying to record install anyway."); 353327Sjkh if (!PkgName) { 354327Sjkh whinge("No package name! Can't record package, sorry."); 355327Sjkh code = 1; 356327Sjkh goto success; /* well, partial anyway */ 357327Sjkh } 3587937Sjkh sprintf(LogDir, "%s/%s", 3597937Sjkh (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, 3607937Sjkh basename_of(PkgName)); 361327Sjkh if (Verbose) 362327Sjkh printf("Attempting to record package into %s..\n", LogDir); 363327Sjkh if (make_hierarchy(LogDir)) { 364327Sjkh whinge("Can't record package into '%s', you're on your own!", 365327Sjkh LogDir); 366327Sjkh bzero(LogDir, FILENAME_MAX); 367327Sjkh code = 1; 368327Sjkh goto success; /* close enough for government work */ 369327Sjkh } 370477Sjkh /* Make sure pkg_info can read the entry */ 371477Sjkh vsystem("chmod a+rx %s", LogDir); 372327Sjkh if (fexists(DEINSTALL_FNAME)) 3737998Sjkh move_file(".", DEINSTALL_FNAME, LogDir); 374327Sjkh if (fexists(REQUIRE_FNAME)) 3757998Sjkh move_file(".", REQUIRE_FNAME, LogDir); 376382Sjkh sprintf(contents, "%s/%s", LogDir, CONTENTS_FNAME); 377382Sjkh cfile = fopen(contents, "w"); 378382Sjkh if (!cfile) { 379382Sjkh whinge("Can't open new contents file '%s'! Can't register pkg.", 380382Sjkh contents); 381382Sjkh goto success; /* can't log, but still keep pkg */ 382382Sjkh } 383382Sjkh write_plist(&Plist, cfile); 384382Sjkh fclose(cfile); 3857998Sjkh move_file(".", DESC_FNAME, LogDir); 3867998Sjkh move_file(".", COMMENT_FNAME, LogDir); 3874996Sjkh if (fexists(DISPLAY_FNAME)) 3887998Sjkh move_file(".", DISPLAY_FNAME, LogDir); 3894996Sjkh for (p = Plist.head; p ; p = p->next) { 3904996Sjkh if (p->type != PLIST_PKGDEP) 3914996Sjkh continue; 3924996Sjkh if (Verbose) 3934996Sjkh printf("Attempting to record dependency on package `%s'\n", 3944996Sjkh p->name); 3957937Sjkh sprintf(contents, "%s/%s/%s", 3967937Sjkh (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, 3977937Sjkh basename_of(p->name), REQUIRED_BY_FNAME); 3984996Sjkh cfile = fopen(contents, "a"); 3994996Sjkh if (!cfile) { 4004996Sjkh whinge("Can't open dependency file '%s'!\n\tDependency registration incomplete.", 4014996Sjkh contents); 4024996Sjkh continue; 4034996Sjkh } 4044996Sjkh fprintf(cfile, "%s\n", basename_of(PkgName)); 4054996Sjkh if (fclose(cfile) == EOF) 4064996Sjkh warn("Cannot properly close file %s", contents); 4074996Sjkh } 408327Sjkh if (Verbose) 409327Sjkh printf("Package %s registered in %s\n", PkgName, LogDir); 410327Sjkh } 4114996Sjkh 4124996Sjkh if (p = find_plist(&Plist, PLIST_DISPLAY)) { 4134996Sjkh FILE *fp; 4144996Sjkh char buf[BUFSIZ]; 4154996Sjkh fp = fopen(p->name, "r"); 4164996Sjkh if (fp) { 4174996Sjkh putc('\n', stdout); 4184996Sjkh while (fgets(buf, sizeof(buf), fp)) 4194996Sjkh fputs(buf, stdout); 4204996Sjkh putc('\n', stdout); 4214996Sjkh (void) fclose(fp); 4224996Sjkh } else 4234996Sjkh warn("Cannot open display file `%s'.", p->name); 4244996Sjkh } 4254996Sjkh 426327Sjkh goto success; 427327Sjkh 4287998Sjkh bomb: 4297998Sjkh code = 1; 4307998Sjkh goto success; 4317998Sjkh 432327Sjkh fail: 4334996Sjkh /* Nuke the whole (installed) show, XXX but don't clean directories */ 434327Sjkh if (!Fake) 4354996Sjkh delete_package(FALSE, FALSE, &Plist); 436327Sjkh 437327Sjkh success: 438327Sjkh /* delete the packing list contents */ 439327Sjkh leave_playpen(); 4408083Sjkh if (isTMP) 4418083Sjkh unlink(isTMP); 442327Sjkh return code; 443327Sjkh} 444327Sjkh 445327Sjkhstatic int 446327Sjkhsanity_check(char *pkg) 447327Sjkh{ 4488075Sjkh PackingList p; 4498075Sjkh int code = 0; 4508075Sjkh 451327Sjkh if (!fexists(CONTENTS_FNAME)) { 452327Sjkh whinge("Package %s has no CONTENTS file!", pkg); 4538075Sjkh code = 1; 454327Sjkh } 4558075Sjkh else if (!fexists(COMMENT_FNAME)) { 456327Sjkh whinge("Package %s has no COMMENT file!", pkg); 4578075Sjkh code = 1; 458327Sjkh } 4598075Sjkh else if (!fexists(DESC_FNAME)) { 460327Sjkh whinge("Package %s has no DESC file!", pkg); 4618075Sjkh code = 1; 462327Sjkh } 4638075Sjkh return code; 464327Sjkh} 465327Sjkh 466327Sjkhvoid 467327Sjkhcleanup(int signo) 468327Sjkh{ 469382Sjkh if (signo) 470382Sjkh printf("Signal %d received, cleaning up..\n", signo); 471327Sjkh if (Plist.head) { 472327Sjkh if (!Fake) 4734996Sjkh delete_package(FALSE, FALSE, &Plist); 474327Sjkh free_plist(&Plist); 475327Sjkh } 476327Sjkh if (!Fake && LogDir[0]) 477327Sjkh vsystem("%s -rf %s", REMOVE_CMD, LogDir); 478327Sjkh leave_playpen(); 479327Sjkh} 480