Second round:

1. Make paths work correctly.
2. Make pkg_add generally more robust in the face of failure.
3. Make the depend messages come out on stderr or stdout, but not both
   interspersed! :-)
This commit is contained in:
jkh 1995-04-22 13:58:24 +00:00
parent 07a6a76523
commit c63844d550
4 changed files with 165 additions and 69 deletions

View File

@ -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! :-)

View File

@ -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 (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;
}
/* 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)) {
leave_playpen();
return 1;
whinge("Unable to extract `%s'!", pkg_fullname);
goto bomb;
}
if (sanity_check(pkg_fullname)) {
leave_playpen();
return 1;
}
if (sanity_check(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 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)

View File

@ -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

View File

@ -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);
}