diff options
-rw-r--r-- | usr.sbin/pkg_install/README | 4 | ||||
-rw-r--r-- | usr.sbin/pkg_install/add/perform.c | 159 | ||||
-rw-r--r-- | usr.sbin/pkg_install/add/pkg_add.1 | 55 | ||||
-rw-r--r-- | usr.sbin/pkg_install/create/perform.c | 16 |
4 files changed, 165 insertions, 69 deletions
diff --git a/usr.sbin/pkg_install/README b/usr.sbin/pkg_install/README index dabd52a..a5a517d 100644 --- a/usr.sbin/pkg_install/README +++ b/usr.sbin/pkg_install/README @@ -4,5 +4,5 @@ for each individual command. This code was written by Jordan Hubbard for FreeBSD, snatched and mildly reshaped by John Kohl in NetBSD and the changes taken back into -FreeBSD again by Jordan. Whee! :-) - +FreeBSD again by Jordan, who then proceeded to add another couple +of dozen features on top. Whee! :-) diff --git a/usr.sbin/pkg_install/add/perform.c b/usr.sbin/pkg_install/add/perform.c index aa5058c..1218c75 100644 --- a/usr.sbin/pkg_install/add/perform.c +++ b/usr.sbin/pkg_install/add/perform.c @@ -1,5 +1,5 @@ #ifndef lint -static const char *rcsid = "$Id: perform.c,v 1.17 1995/04/19 14:54:25 jkh Exp $"; +static const char *rcsid = "$Id: perform.c,v 1.18 1995/04/22 07:40:54 jkh Exp $"; #endif /* @@ -58,7 +58,8 @@ pkg_do(char *pkg) { char pkg_fullname[FILENAME_MAX]; char home[FILENAME_MAX]; - char *tmp; + char extract_contents[FILENAME_MAX]; + char *where_to, *tmp; FILE *cfile; int code = 0; PackingList p; @@ -91,6 +92,57 @@ pkg_do(char *pkg) whinge("Can't find package '%s'.", pkg_fullname); return 1; } + Home = make_playpen(PlayPen, 0); + sprintf(extract_contents, "--fast-read %s", CONTENTS_FNAME); + if (unpack(pkg_fullname, extract_contents)) { + whinge("Unable to extract table of contents file from `%s' - not a package?.", pkg_fullname); + goto bomb; + } + cfile = fopen(CONTENTS_FNAME, "r"); + if (!cfile) { + whinge("Unable to open table of contents file `%s' - not a package?", CONTENTS_FNAME); + goto bomb; + } + read_plist(&Plist, cfile); + fclose(cfile); + + /* + * If we have a prefix, delete the first one we see and add this + * one in place of it. + */ + if (Prefix) { + delete_plist(&Plist, FALSE, PLIST_CWD, NULL); + add_plist_top(&Plist, PLIST_CWD, Prefix); + } + + /* Extract directly rather than moving? Oh goodie! */ + if (find_plist_option(&Plist, "extract-in-place")) { + if (Verbose) + printf("Doing in-place extraction for %s\n", pkg_fullname); + p = find_plist(&Plist, PLIST_CWD); + if (p) { + if (!isdir(p->name) && !NoInstall) { + if (Verbose) + printf("Desired prefix of %s does not exist, creating..\n", p->name); + vsystem("mkdir -p %s", p->name); + if (chdir(p->name)) { + whinge("Unable to change directory to `%s' - no permission?", p->name); + perror("chdir"); + leave_playpen(); + return 1; + } + } + where_to = p->name; + } + else { + whinge("No prefix specified in `%s' - this is a bad package!", + pkg_fullname); + leave_playpen(); + return 1; + } + } + else + where_to = PlayPen; /* * Apply a crude heuristic to see how much space the package will * take up once it's unpacked. I've noticed that most packages @@ -100,33 +152,43 @@ pkg_do(char *pkg) whinge("Can't stat package file '%s'.", pkg_fullname); return 1; } - sb.st_size *= 4; - Home = make_playpen(PlayPen, sb.st_size); - if (unpack(pkg_fullname, NULL)) { - leave_playpen(); - return 1; - } - if (sanity_check(pkg_fullname)) { - leave_playpen(); - return 1; + if (min_free(where_to) < sb.st_size * 4) { + whinge("Projected size of %d exceeds free space in %s.", + sb.st_size * 4, where_to); + whinge("Not extracting %s, sorry!", pkg_fullname); + goto bomb; } - cfile = fopen(CONTENTS_FNAME, "r"); - if (!cfile) { - whinge("Unable to open %s file.", CONTENTS_FNAME); - goto fail; - } - read_plist(&Plist, cfile); - fclose(cfile); - if (Prefix) { - /* - * If we have a prefix, delete the first one we see and add this - * one in place of it. - */ - delete_plist(&Plist, FALSE, PLIST_CWD, NULL); - add_plist_top(&Plist, PLIST_CWD, Prefix); + /* If this is a direct extract and we didn't want it, stop now */ + if (where_to != PlayPen && NoInstall) + goto success; + + setenv(PKG_PREFIX_VNAME, + (p = find_plist(&Plist, PLIST_CWD)) ? p->name : NULL, 1); + /* Protect against old packages with bogus @name fields */ + PkgName = (p = find_plist(&Plist, PLIST_NAME)) ? p->name : "anonymous"; + + /* See if we're already registered */ + sprintf(LogDir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, + basename_of(PkgName)); + if (isdir(LogDir)) { + char tmp[FILENAME_MAX]; + + whinge("Package `%s' already recorded as installed.\n", PkgName); + code = 1; + goto success; /* close enough for government work */ + } + + /* Finally unpack the whole mess */ + if (unpack(pkg_fullname, NULL)) { + whinge("Unable to extract `%s'!", pkg_fullname); + goto bomb; } + + if (sanity_check(pkg_fullname)) + goto bomb; + /* If we're running in MASTER mode, just output the plist and return */ if (AddMode == MASTER) { printf("%s\n", where_playpen()); @@ -134,28 +196,28 @@ pkg_do(char *pkg) return 0; } } - setenv(PKG_PREFIX_VNAME, - (p = find_plist(&Plist, PLIST_CWD)) ? p->name : NULL, 1); - /* Protect against old packages with bogus @name fields */ - PkgName = (p = find_plist(&Plist, PLIST_NAME)) ? p->name : "anonymous"; - sprintf(LogDir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR, - basename_of(PkgName)); - if (isdir(LogDir)) { - whinge("Package `%s' already recorded as installed.\n", PkgName); - code = 1; - goto success; /* close enough for government work */ - } for (p = Plist.head; p ; p = p->next) { if (p->type != PLIST_PKGDEP) continue; if (Verbose) printf("Package `%s' depends on `%s'", PkgName, p->name); if (!Fake && vsystem("pkg_info -e %s", p->name)) { - char tmp[120]; + char *cp, tmp[FILENAME_MAX], path[FILENAME_MAX*2]; if (Verbose) printf(" which is not currently loaded"); - sprintf(tmp, "%s/%s.tgz", Home, p->name); + cp = getenv("PKG_PATH"); + if (!cp) + cp = Home; + strcpy(path, cp); + cp = path; + while (cp) { + char *cp2 = strsep(&cp, ":"); + + sprintf(tmp, "%s/%s.tgz", cp2 ? cp2 : cp, p->name); + if (fexists(tmp)) + break; + } if (fexists(tmp)) { if (Verbose) printf(" but was found - loading:\n"); @@ -169,7 +231,7 @@ pkg_do(char *pkg) printf("\t`%s' loaded successfully.\n", p->name); } else { - whinge("and was not found%s.", p->name, + printf("and was not found%s.\n", Force ? " (proceeding anyway)" : ""); if (!Force) code++; @@ -201,6 +263,7 @@ pkg_do(char *pkg) printf("Running install with PRE-INSTALL for %s..\n", PkgName); if (!Fake && vsystem("./%s %s PRE-INSTALL", INSTALL_FNAME, PkgName)) { whinge("Install script returned error status."); + unlink(INSTALL_FNAME); code = 1; goto success; /* nothing to uninstall yet */ } @@ -217,18 +280,22 @@ pkg_do(char *pkg) if (vsystem("/usr/sbin/mtree -u -f %s -d -e -p %s", MTREE_FNAME, p ? p->name : "/")) { perror("error in the execution of mtree"); + unlink(MTREE_FNAME); goto fail; } } + unlink(MTREE_FNAME); } if (!NoInstall && fexists(INSTALL_FNAME)) { if (Verbose) printf("Running install with POST-INSTALL for %s..\n", PkgName); if (!Fake && vsystem("./%s %s POST-INSTALL", INSTALL_FNAME, PkgName)) { whinge("Install script returned error status."); + unlink(INSTALL_FNAME); code = 1; goto fail; } + unlink(INSTALL_FNAME); } if (!NoRecord && !Fake) { char contents[FILENAME_MAX]; @@ -257,9 +324,9 @@ pkg_do(char *pkg) /* Make sure pkg_info can read the entry */ vsystem("chmod a+rx %s", LogDir); if (fexists(DEINSTALL_FNAME)) - copy_file(".", DEINSTALL_FNAME, LogDir); + move_file(".", DEINSTALL_FNAME, LogDir); if (fexists(REQUIRE_FNAME)) - copy_file(".", REQUIRE_FNAME, LogDir); + move_file(".", REQUIRE_FNAME, LogDir); sprintf(contents, "%s/%s", LogDir, CONTENTS_FNAME); cfile = fopen(contents, "w"); if (!cfile) { @@ -269,10 +336,10 @@ pkg_do(char *pkg) } write_plist(&Plist, cfile); fclose(cfile); - copy_file(".", DESC_FNAME, LogDir); - copy_file(".", COMMENT_FNAME, LogDir); + move_file(".", DESC_FNAME, LogDir); + move_file(".", COMMENT_FNAME, LogDir); if (fexists(DISPLAY_FNAME)) - copy_file(".", DISPLAY_FNAME, LogDir); + move_file(".", DISPLAY_FNAME, LogDir); for (p = Plist.head; p ; p = p->next) { if (p->type != PLIST_PKGDEP) continue; @@ -312,6 +379,10 @@ pkg_do(char *pkg) goto success; + bomb: + code = 1; + goto success; + fail: /* Nuke the whole (installed) show, XXX but don't clean directories */ if (!Fake) diff --git a/usr.sbin/pkg_install/add/pkg_add.1 b/usr.sbin/pkg_install/add/pkg_add.1 index 5dba67c..682a1d5 100644 --- a/usr.sbin/pkg_install/add/pkg_add.1 +++ b/usr.sbin/pkg_install/add/pkg_add.1 @@ -92,17 +92,18 @@ Sets .Ar prefix as the directory in which to extract files from a package. If a package has set its default directory, it will be overridden -by this flag. Note that only the first directory default will -be replaced, since +by this flag. Note that only the first +.Cm @cwd +directive will be replaced, since .Nm has no way of knowing which directory settings are relative and -which are absolute. It is rare, in any case, that more than one -directory transition is made, but when such is the case then you -may wish to look into the use of +which are absolute. It is rare, in any case, to see more than one +directory transition made, but when such is the case you +may then wish to look into the use of the .Cm MASTER and .Cm SLAVE -mode (see the +modes (see the .Fl M and .Fl S @@ -166,27 +167,40 @@ and the contents then acted on as normal. .El .Sh TECHNICAL DETAILS .Nm -is fairly simple. It simply extracts the requested packages into -a ``staging area'' directory and then performs the following steps: +is fairly simple. It extracts each packages' "packing list" +into a special staging directory in /tmp (or $PKG_TMPDIR), parses it, +then runs through the following sequence to fully extract the contents: .Bl -enum -indent indent .It -It checks whether the package is already recorded as installed; if so, -the installation terminates. +Check if the package is already recorded as installed. If so, +terminate installation. .It -It checks whether all the package dependencies (from +Scan all the package dependencies (from .Cm @pkgdep directives, see .Xr pkg_create 8 ) -are met; if not, the missing dependencies are printed and the -installation terminates. +and make sure each one is met. If not, print the missing dependencies and +terminate the installation. +.It +Search for any +.Cm @option +directives which control how the package is added to the system. +At the time of this writing, the only currently implemented option is +.Cm @option extract-in-place +which will cause the package to be extracted direcly into its +prefix directory without moving through a staging area in /tmp. +.It +If +.Cm @option extract-in-place +is enabled, the package is now extracted directly into its +final location, otherwise it is extracted into the staging area. .It If the package contains a .Ar require file (see .Xr pkg_create 8 ), -then this is executed first as +then execute it with the following arguments: .Bd -filled -offset indent -compact -.Cm require .Ar <pkg-name> .Ar INSTALL .Ed @@ -194,13 +208,12 @@ where .Ar <pkg-name> is the name of the package in question and .Ar INSTALL -is a keyword denoting that this is an installation requirements check. +is simply a keyword denoting that this is an installation requirements check. .It If an .Ar install -script exists for the package, it is then executed as +script exists for the package, it is then executed with the following arguments: .Bd -filled -offset indent -compact -.Cm install .Ar <pkg-name> .Ar PRE-INSTALL .Ed @@ -210,9 +223,11 @@ is the name of the package in question and .Ar PRE-INSTALL is a keyword denoting that this is the preinstallation phase. .It -Using the packing list (the +If +.Cm @option extract-in-place +is not used, then the packing list (this is the .Pa +CONTENTS -file) as a guide, files are then moved (or copied, as necessary) from +file) is now used as a guide for moving (or copying, as necessary) files from the staging area into their final locations. .It If the package contains an diff --git a/usr.sbin/pkg_install/create/perform.c b/usr.sbin/pkg_install/create/perform.c index 54c7fce..951ccce 100644 --- a/usr.sbin/pkg_install/create/perform.c +++ b/usr.sbin/pkg_install/create/perform.c @@ -1,5 +1,5 @@ #ifndef lint -static const char *rcsid = "$Id: perform.c,v 1.18 1995/04/22 00:59:33 jkh Exp $"; +static const char *rcsid = "$Id: perform.c,v 1.19 1995/04/22 01:20:13 jkh Exp $"; #endif /* @@ -174,6 +174,15 @@ pkg_perform(char **pkgs) return TRUE; /* Success */ } +/* + * This is evil. It is the command executed inline on tar's command line + * to presort file arguments in such a way as to put the all-important + * +* files at the front. I'm sure there's a way of doing this that's + * a hundred times more efficient, but I'm in a hurry right now and I don't + * have the time to think more about it.. -jkh + */ +#define SORTED_NAMES "`find . | sed -e 's/^\\.\\///' -e '/^\\.$/D' | sort`" + static void make_dist(char *home, char *pkg, char *suffix, Package *plist) { @@ -194,9 +203,10 @@ make_dist(char *home, char *pkg, char *suffix, Package *plist) printf("Creating gzip'd tar ball in '%s'\n", tball); strcat(args, "cf"); if (ExcludeFrom) - ret = vsystem("tar %sX %s %s .", args, tball, ExcludeFrom); + ret = vsystem("tar %sX %s %s %s", args, tball, ExcludeFrom, + SORTED_NAMES); else - ret = vsystem("tar %s %s .", args, tball); + ret = vsystem("tar %s %s %s", args, tball, SORTED_NAMES); if (ret) barf("tar command failed with code %d", ret); } |