Subject: bin/13699: pkg_install fixes for binary packages and exclusive use of pax
To: None <gnats-bugs@gnats.netbsd.org>
From: Greg A. Woods <woods@weird.com>
List: netbsd-bugs
Date: 08/12/2001 20:27:15
>Number:         13699
>Category:       bin
>Synopsis:       pkg_install fixes for binary packages and exclusive use of pax
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Aug 12 18:38:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Greg A. Woods
>Release:        2001/06/24
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:

System: NetBSD 1.5W

>Description:

	Two factors combine to trigger the problems noted in this PR.
	One is that I'm using binary packages exclusively in a number of
	scenarios now, and the other is that at a couple of of sites
	I've eliminated GNU Tar in favour of (a slightly beefed up
	version of) pax (with its tar front-end).

	I was quite surprised to find the root cause of a couple of
	annoyances in these scenarios that had been preventing
	completely smooth automated use of binary packages.  It turns
	out there were several misconceptions in the implementation of
	pkg_create and pkg_add where it they did not appear to follow
	the documentation or implied design.

	The first and most glaring problem was that sometimes (and only
	sometimes) were setuid flags being lost on installed binaries.
	It seems that GNU Tar gratuitiously copies setuid bits when run
	as the superuser (i.e. when '-p' is not specified).  [[that's
	probably a separate bug that should be fixed in GNU Tar, but I
	no longer care much about fixing GNU Tar of course]]

	The second and far more subtle problem was that it seemed 'tar'
	was being used to "accidentally" create directories for packages
	(which was sometimes causing the setuid problem to occur too if
	a setuid file happened to be in a new package-specific sub-
	directory).  Package installation should explicitly create any
	special directories needed beyond what's in the common package
	system mtree file.

	Given the way pkgsrc works with this common system-wide mtree
	file for all packages it would seem best to simply allow
	multiple mtree files (and why not multiple display files too,
	while we're at it).  This will ensure that packages can create
	cusom hierarchies without relying on the internal fall-back tar
	command to do it for them (though of course @dirrm directives
	will still be needed to clean them up).

	The following patches fix these problems (and provide a few
	other minor fixes and internal improvments).

>How-To-Repeat:

	migrate from GNU Tar to the 'tar' front-end of pax and then try
	to use binary packages exclusively....

>Fix:

	The primary fix to the first problem is to simply explicitly
	give the '-p' flag to the "tar" command used to copy from
	PKG_TMPDIR to PREFIX, and to ensure in other places that GNU Tar
	features are not abused.

	The fix to the second problem involves adding explicit handling
	for PLIST_DISPLAY and PLIST_MTREE entries, as well as to move
	the invocation of the primary package-common MTREE file up to
	the beginning of process (and to be more explicit about handling
	the package-commong DISPLAY file too of course).

	To support the new explicit handling of PLIST_MTREE (and
	PLIST_DISPLAY) entries in pkg_add it's also necessary to fix
	pkg_create so that it "hides" the package-common MTREE and
	DISPLAY files from per-entry handling.  These could instead
	simply be omitted, but they're handy documentation and I suppose
	even good for backwareds compatability too.  Note that if the
	package supplies the mtree file(s) itself (as it is likely it
	will do) it(they) must be extracted prior to being used, and as
	such it(they) should be uniquely named and placed in a directory
	created by the package common +MTREE_DIRS file, such as
	PREFIX/etc/mtree which of course means that directory must be
	added to the pkgsrc/mk/*.dist files too.

	NOTE:  the very last change will only be necessary when /bin/tar
	(which will of course be a hard link to /bin/pax) finally
	replaces the GNU Tar presently installed in /usr/bin/tar on
	NetBSD, but it should not be applied until that link is made (I
	suspect backwards compatability insanity will drive someone to
	put a symlink in place of /usr/bin/tar, but of course native
	utilities should never use such compatability features and so it
	really should be applied then).

	WARNING:  these patches may kill support for package archives
	compressed with bzip2 (".tbz"), however this shouldn't matter
	because:  a) pkgsrc doesn't use it yet; and b) the correct fix
	is to make 'tar' transparent to handle any form of decompression.

	Note that I also clean up a few coding uglies, including
	collapsing some duplicated code (which was potentially wrong in
	one instance)

Index: add/extract.c
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/add/extract.c,v
retrieving revision 1.1.1.5
diff -c -r1.1.1.5 extract.c
*** add/extract.c	2001/03/25 06:44:06	1.1.1.5
--- add/extract.c	2001/08/13 00:21:01
***************
*** 30,40 ****
   */
  
  #include <err.h>
  #include "lib.h"
  #include "add.h"
  
  #define TAR_ARGS	" cf - "
! #define TARX_CMD	"|" TAR_CMD " xf - -C "
  
  /* 
   * This macro is used to determine if the 'where_args'  buffer is big enough to add the
--- 30,41 ----
   */
  
  #include <err.h>
+ #include <errno.h>
  #include "lib.h"
  #include "add.h"
  
  #define TAR_ARGS	" cf - "
! #define TARX_CMD	"|" TAR_CMD " -xpf - -C "
  
  /* 
   * This macro is used to determine if the 'where_args'  buffer is big enough to add the
***************
*** 43,49 ****
   * 
   * The string " 'str'" will be added so we need room for the string plus 3 chars plus the other arguments.
   * 
!  * In addition, we will add " 'srt'" to the perm_args buffer so we need to ensure that there is room
   * for that.
   */
  #define TOOBIG(str) ((strlen(str) + 3 + strlen(TARX_CMD) + strlen(Directory) + where_count  >= maxargs) \
--- 44,50 ----
   * 
   * The string " 'str'" will be added so we need room for the string plus 3 chars plus the other arguments.
   * 
!  * In addition, we will add "'str' " to the perm_args buffer so we need to ensure that there is room
   * for that.
   */
  #define TOOBIG(str) ((strlen(str) + 3 + strlen(TARX_CMD) + strlen(Directory) + where_count  >= maxargs) \
***************
*** 53,65 ****
          if (where_count > sizeof(TAR_CMD) + sizeof(TAR_ARGS)-1) {	\
  		    strcat(where_args, TARX_CMD);			\
  		    strcat(where_args, todir);				\
! 		    if (system(where_args)) {				\
  			cleanup(0);					\
  			errx(2, "can not invoke %lu byte %s pipeline: %s", \
  				(u_long)strlen(where_args), TAR_CMD,	\
  				where_args);				\
  		    }							\
! 		    strcpy(where_args, TAR_CMD TAR_ARGS);		\
  		    where_count = strlen(where_args);			\
  	}								\
  	if (perm_count) {						\
--- 54,66 ----
          if (where_count > sizeof(TAR_CMD) + sizeof(TAR_ARGS)-1) {	\
  		    strcat(where_args, TARX_CMD);			\
  		    strcat(where_args, todir);				\
! 		    if (vsystem("%s", where_args)) {			\
  			cleanup(0);					\
  			errx(2, "can not invoke %lu byte %s pipeline: %s", \
  				(u_long)strlen(where_args), TAR_CMD,	\
  				where_args);				\
  		    }							\
! 		    sprintf(where_args, "%s%s", TAR_CMD, TAR_ARGS);	\
  		    where_count = strlen(where_args);			\
  	}								\
  	if (perm_count) {						\
***************
*** 118,124 ****
  		cleanup(0);
  		errx(2, "can't get argument list space");
  	}
! 	strcpy(where_args, TAR_CMD TAR_ARGS);
  	/*
  	 * we keep track of how many characters are stored in 'where_args' with 'where_count'.
  	 * Note this doesn't include the trailing null character.
--- 119,125 ----
  		cleanup(0);
  		errx(2, "can't get argument list space");
  	}
! 	sprintf(where_args, "%s%s", TAR_CMD, TAR_ARGS);
  	/*
  	 * we keep track of how many characters are stored in 'where_args' with 'where_count'.
  	 * Note this doesn't include the trailing null character.
***************
*** 127,133 ****
  
  	perm_args[0] = 0;
  	/*
! 	 * we keep track of how many characters are stored in 'perm__args' with 'perm_count'.
  	 * Note this doesn't include the trailing null character.
  	 */
  	perm_count = 0;
--- 128,134 ----
  
  	perm_args[0] = 0;
  	/*
! 	 * we keep track of how many characters are stored in 'perm_args' with 'perm_count'.
  	 * Note this doesn't include the trailing null character.
  	 */
  	perm_count = 0;
***************
*** 165,171 ****
  			if (!Fake) {
  				char    try[FILENAME_MAX];
  
! 				if (strrchr(p->name, '\'')) {
  					cleanup(0);
  					errx(2, "Bogus filename \"%s\"", p->name);
  				}
--- 166,172 ----
  			if (!Fake) {
  				char    try[FILENAME_MAX];
  
! 				if (strrchr(p->name, '\'')) { /* ???? */
  					cleanup(0);
  					errx(2, "Bogus filename \"%s\"", p->name);
  				}
***************
*** 189,228 ****
  					}
  				}
  				if (rename(p->name, try) == 0) {
- 					/* note in pkgdb */
- 					{
- 						char   *s, t[FILENAME_MAX];
- 						int     rc;
- 
- 						(void) snprintf(t, sizeof(t), "%s/%s", Directory, p->name);
- 
- 						s = pkgdb_retrieve(t);
- #ifdef PKGDB_DEBUG
- 						printf("pkgdb_retrieve(\"%s\")=\"%s\"\n", t, s);	/* pkgdb-debug - HF */
- #endif
- 						if (s)
- 							warnx("Overwriting %s - pkg %s bogus/conflicting?", t, s);
- 						else {
- 							rc = pkgdb_store(t, PkgName);
- #ifdef PKGDB_DEBUG
- 							printf("pkgdb_store(\"%s\", \"%s\") = %d\n", t, PkgName, rc);	/* pkgdb-debug - HF */
- #endif
- 
- 						}
- 					}
- 
- 					/* try to add to list of perms to be changed and run in bulk. */
  					if (p->name[0] == '/' || TOOBIG(p->name)) {
  						PUSHOUT(Directory);
  					}
- 					/* note, if the following line is modified, TOOBIG must be adjusted accordingly */
- 					add_count = snprintf(&perm_args[perm_count], maxargs - perm_count, "'%s' ", p->name);
- 					if (add_count > maxargs - perm_count) {
- 						cleanup(0);
- 						errx(2, "oops, miscounted strings!");
- 					}
- 					perm_count += add_count;
  				} else {
  					/* rename failed, try copying with a big tar command */
  					if (last_chdir != Directory) {
  						PUSHOUT(last_chdir);
--- 190,203 ----
  					}
  				}
  				if (rename(p->name, try) == 0) {
  					if (p->name[0] == '/' || TOOBIG(p->name)) {
  						PUSHOUT(Directory);
  					}
  				} else {
+ 					if (Verbose && errno != EXDEV) {
+ 						warn("rename(%s, %s) failed", p->name, try);
+ 					} else if (Verbose)
+ 						warnx("using tar pipeline to install %s across filesystems", try);
  					/* rename failed, try copying with a big tar command */
  					if (last_chdir != Directory) {
  						PUSHOUT(last_chdir);
***************
*** 237,280 ****
  						errx(2, "oops, miscounted strings!");
  					}
  					where_count += add_count;
! 					/* note, if the following line is modified, TOOBIG must be adjusted accordingly */
! 					add_count = snprintf(&perm_args[perm_count],
! 					    maxargs - perm_count,
! 					    "'%s' ", p->name);
! 					if (add_count > maxargs - perm_count) {
! 						cleanup(0);
! 						errx(2, "oops, miscounted strings!");
  					}
! 					perm_count += add_count;
! 
! 					/* note in pkgdb */
! 					/* XXX would be better to store in PUSHOUT, but
! 					 * that would probably affect too much code I prefer
! 					 * not to touch - HF */
! 					{
! 						char   *s, t[FILENAME_MAX], *u;
! 						int     rc;
! 
! 						if (p->name[0] == '/')
! 							u = p->name;
! 						else {
! 							(void) snprintf(t, sizeof(t), "%s/%s", Directory, p->name);
! 							u = t;
! 						}
! 
! 						s = pkgdb_retrieve(t);
  #ifdef PKGDB_DEBUG
! 						printf("pkgdb_retrieve(\"%s\")=\"%s\"\n", t, s);	/* pkgdb-debug - HF */
  #endif
! 						if (s)
! 							warnx("Overwriting %s - pkg %s bogus/conflicting?", t, s);
! 						else {
! 							rc = pkgdb_store(t, PkgName);
  #ifdef PKGDB_DEBUG
! 							printf("pkgdb_store(\"%s\", \"%s\") = %d\n", t, PkgName, rc);	/* pkgdb-debug - HF */
  #endif
- 						}
- 					}
  				}
  			}
  			break;
--- 212,248 ----
  						errx(2, "oops, miscounted strings!");
  					}
  					where_count += add_count;
! 				}
! 				/* try to add to list of perms to be changed and run in bulk. */
! 				/* note, if the following line is modified, TOOBIG must be adjusted accordingly */
! 				add_count = snprintf(&perm_args[perm_count], maxargs - perm_count, "'%s' ", p->name);
! 				if (add_count > maxargs - perm_count) {
! 					cleanup(0);
! 					errx(2, "oops, miscounted strings!");
! 				}
! 				perm_count += add_count;
! 				/* note in pkgdb */
! 				{
! 					char   *s, t[FILENAME_MAX], *u;
! 					int     rc;
! 					
! 					if (p->name[0] == '/')
! 						u = p->name;
! 					else {
! 						(void) snprintf(t, sizeof(t), "%s/%s", Directory, p->name);
! 						u = t;
  					}
! 					
! 					s = pkgdb_retrieve(u);
  #ifdef PKGDB_DEBUG
! 					printf("pkgdb_retrieve(\"%s\")=\"%s\"\n", u, s);	/* pkgdb-debug - HF */
  #endif
! 					if (s)
! 						warnx("Overwrote %s - pkg %s bogus/conflicting?", u, s);
! 					rc = pkgdb_store(u, PkgName); /* XXX error checking!!!!! */
  #ifdef PKGDB_DEBUG
! 					printf("pkgdb_store(\"%s\", \"%s\") = %d\n", u, PkgName, rc);	/* pkgdb-debug - HF */
  #endif
  				}
  			}
  			break;
***************
*** 328,334 ****
--- 296,344 ----
  			p = p->next;
  			break;
  
+ 		case PLIST_DISPLAY: {		/* XXX we should do these last with +DISPLAY.... */
+ 			FILE   *fp;
+ 			char    buf[BUFSIZ];
+ 
+ 			fp = fopen(p->name, "r");
+ 			if (fp) {
+ 				putc('\n', stdout);
+ 				while (fgets(buf, sizeof(buf), fp))
+ 					fputs(buf, stdout);
+ 				putc('\n', stdout);
+ 				(void) fclose(fp);
+ 			} else
+ 				warnx("cannot open %s as display file", p->name);
+ 
+ 			break;
+ 		}
+ 
+ 		case PLIST_MTREE:
+ 			/*
+ 			 * make sure that if p->name is from within the package
+ 			 * then it has already been successfully extracted
+ 			 */
+ 			PUSHOUT(Directory);
+ 			if (Verbose)
+ 				printf("mtree -U -f %s/%s -d -e -p %s\n", *(p->name) == '/' ? "" : Directory, p->name, Directory);
+ 			if (!Fake) {
+ 				if (vsystem("%s/mtree -U -f %s/%s -d -e -p %s", BINDIR, *(p->name) == '/' ? "" : Directory, p->name, Directory))
+ 					warnx("mtree returned a non-zero status - continuing");
+ 			}
+ 			break;
+ 
+ 		case PLIST_SRC:			/*  */
+ 		case PLIST_UNEXEC:		/* only for pkg_delete */
+ 		case PLIST_IGNORE_INST:		/*  */
+ 		case PLIST_PKGDEP:		/* handled in perform.c */
+ 		case PLIST_PKGCFL:		/* handled in perform.c */
+ 		case PLIST_DIR_RM:		/* only for pkg_delete */
+ 		case PLIST_OPTION:		/*  */
+ 			break;
+ 
  		default:
+ 			if (Verbose)
+ 				printf("unknown type of plist entry: %d\n", p->type);
  			break;
  		}
  		p = p->next;
Index: add/futil.c
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/add/futil.c,v
retrieving revision 1.1.1.5
diff -c -r1.1.1.5 futil.c
*** add/futil.c	2001/03/25 06:44:07	1.1.1.5
--- add/futil.c	2001/08/12 16:32:29
***************
*** 83,89 ****
  		if (vsystem("cd %s && %s -R %s %s", cd_to, CHMOD, Mode, arg))
  			warnx("couldn't change modes of '%s' to '%s'", arg, Mode);
  	if (Owner && Group) {
! 		if (vsystem("cd %s && %s -R %s.%s %s", cd_to, CHOWN, Owner, Group, arg))
  			warnx("couldn't change owner/group of '%s' to '%s.%s'",
  			    arg, Owner, Group);
  		return;
--- 83,89 ----
  		if (vsystem("cd %s && %s -R %s %s", cd_to, CHMOD, Mode, arg))
  			warnx("couldn't change modes of '%s' to '%s'", arg, Mode);
  	if (Owner && Group) {
! 		if (vsystem("cd %s && %s -R %s:%s %s", cd_to, CHOWN, Owner, Group, arg))
  			warnx("couldn't change owner/group of '%s' to '%s.%s'",
  			    arg, Owner, Group);
  		return;
Index: add/perform.c
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/add/perform.c,v
retrieving revision 1.1.1.8
diff -c -r1.1.1.8 perform.c
*** add/perform.c	2001/06/12 21:27:06	1.1.1.8
--- add/perform.c	2001/08/12 22:40:06
***************
*** 210,216 ****
  					warnx("can't stat package file '%s'", pkg_fullname);
  					goto bomb;
  				}
! 				(void) snprintf(extract_contents, sizeof(extract_contents), "--fast-read %s", CONTENTS_FNAME);
  				extract = extract_contents;
  			} else {
  			        /* some values for stdin */
--- 210,216 ----
  					warnx("can't stat package file '%s'", pkg_fullname);
  					goto bomb;
  				}
! 				(void) snprintf(extract_contents, sizeof(extract_contents), "%s", CONTENTS_FNAME);
  				extract = extract_contents;
  			} else {
  			        /* some values for stdin */
***************
*** 342,354 ****
  						printf("Upgrading %s to %s.\n", installed, PkgName);
  
  					if (fexists(upgrade_from)) {
- 						if (0 && Verbose)
- 							printf("HF: mv %s %s\n", upgrade_from, upgrade_via);
  						rc = rename(upgrade_from, upgrade_via);
! 						assert(rc == 0);
  
- 						if (0 && Verbose)
- 							printf("HF: pkg_delete '%s'\n", installed);
  						vsystem("pkg_delete '%s'\n", installed);
  
  						upgrading = 1;
--- 342,350 ----
  						printf("Upgrading %s to %s.\n", installed, PkgName);
  
  					if (fexists(upgrade_from)) {
  						rc = rename(upgrade_from, upgrade_via);
! 						assert(rc == 0); /* XXX this should be more gentle!!!! */
  
  						vsystem("pkg_delete '%s'\n", installed);
  
  						upgrading = 1;
***************
*** 372,379 ****
  		if (Verbose)
  			printf("Package `%s' conflicts with `%s'.\n", PkgName, p->name);
  
- 		/* was: */
- 		/* if (!vsystem("/usr/sbin/pkg_info -qe '%s'", p->name)) { */
  		if (findmatchingname(dbdir, p->name, note_whats_installed, installed) > 0) {
  			warnx("Conflicting package `%s'installed, please use\n"
  			      "\t\"pkg_delete %s\" first to remove it!\n", installed, installed);
--- 368,373 ----
***************
*** 391,397 ****
  			continue;
  		if (Verbose)
  			printf("Depends pre-scan: `%s' required.\n", p->name);
- 		/* if (vsystem("/usr/sbin/pkg_info -qe '%s'", p->name)) { */
  		if (findmatchingname(dbdir, p->name, note_whats_installed, installed) <= 0) {
  			/* 
  			 * required pkg not found. look if it's available with a more liberal
--- 385,390 ----
***************
*** 451,457 ****
  			continue;
  		if (Verbose)
  			printf("Package `%s' depends on `%s'.\n", PkgName, p->name);
- 		/* if (vsystem("/usr/sbin/pkg_info -qe '%s'", p->name)) { */
  		if (findmatchingname(dbdir, p->name, note_whats_installed, installed) != 1) {
  			/* required pkg not found - need to pull in */
  
--- 444,449 ----
***************
*** 523,529 ****
  
  					if ((cp = fileGetURL(new_pkg, new_name)) != NULL) {
  							if (Verbose)
! 							printf("Finished loading %s over FTP.\n", new_name);
  							if (!fexists(CONTENTS_FNAME)) {
  								warnx("autoloaded package %s has no %s file?",
  								    p->name, CONTENTS_FNAME);
--- 515,521 ----
  
  					if ((cp = fileGetURL(new_pkg, new_name)) != NULL) {
  							if (Verbose)
! 								printf("Finished loading %s over FTP.\n", new_name);
  							if (!fexists(CONTENTS_FNAME)) {
  								warnx("autoloaded package %s has no %s file?",
  								    p->name, CONTENTS_FNAME);
***************
*** 570,575 ****
--- 562,584 ----
  	if (code != 0)
  		goto bomb;
  
+ 	/*
+ 	 * If we have a main mtree file then we need to run it first,
+ 	 * potentially to the hierarchy in the base directory
+ 	 */
+ 	if (!Fake && fexists(MTREE_FNAME)) {
+ 		if (Verbose)
+ 			printf("Running mtree for %s.\n", PkgName);
+ 		p = find_plist(&Plist, PLIST_CWD);
+ 		if (Verbose && Fake)
+ 			printf("mtree -U -f %s -d -e -p %s\n", MTREE_FNAME, p ? p->name : "/");
+ 		if (!Fake) {
+ 			if (vsystem("%s/mtree -U -f %s -d -e -p %s", BINDIR, MTREE_FNAME, p ? p->name : "/"))
+ 				warnx("mtree returned a non-zero status - continuing");
+ 		}
+ 		unlink(MTREE_FNAME); /* remove this line to tar up pkg later  - HF  (????) */
+ 	}
+ 
  	/* Look for the requirements file */
  	if (fexists(REQUIRE_FNAME)) {
  		vsystem("%s +x %s", CHMOD, REQUIRE_FNAME);	/* be sure */
***************
*** 604,622 ****
  		goto fail;
  	    }
  
- 	if (!Fake && fexists(MTREE_FNAME)) {
- 		if (Verbose)
- 			printf("Running mtree for %s.\n", PkgName);
- 		p = find_plist(&Plist, PLIST_CWD);
- 		if (Verbose)
- 			printf("mtree -U -f %s -d -e -p %s\n", MTREE_FNAME, p ? p->name : "/");
- 		if (!Fake) {
- 			if (vsystem("%s/mtree -U -f %s -d -e -p %s", BINDIR, MTREE_FNAME, p ? p->name : "/"))
- 				warnx("mtree returned a non-zero status - continuing");
- 		}
- 		unlink(MTREE_FNAME); /* remove this line to tar up pkg later  - HF */
- 	}
- 
  	/* Run the installation script one last time? */
  	if (!NoInstall && fexists(INSTALL_FNAME)) {
  		if (Verbose)
--- 613,618 ----
***************
*** 631,637 ****
  	/* Time to record the deed? */
  	if (!NoRecord && !Fake) {
  		char    contents[FILENAME_MAX];
! 		FILE   *cfile;
  
  		umask(022);
  		if (getuid() != 0)
--- 627,634 ----
  	/* Time to record the deed? */
  	if (!NoRecord && !Fake) {
  		char    contents[FILENAME_MAX];
! 		char    dfile[FILENAME_MAX];
! 		FILE   *fp;
  
  		umask(022);
  		if (getuid() != 0)
***************
*** 663,676 ****
  		if (fexists(SIZE_ALL_FNAME))
  			move_file(".", SIZE_ALL_FNAME, LogDir);
  		(void) snprintf(contents, sizeof(contents), "%s/%s", LogDir, CONTENTS_FNAME);
! 		cfile = fopen(contents, "w");
! 		if (!cfile) {
  			warnx("can't open new contents file '%s'! can't register pkg",
  			    contents);
  			goto success;	/* can't log, but still keep pkg */
  		}
! 		write_plist(&Plist, cfile, NULL);
! 		fclose(cfile);
  		move_file(".", DESC_FNAME, LogDir);
  		move_file(".", COMMENT_FNAME, LogDir);
  		if (fexists(BUILD_VERSION_FNAME))
--- 660,673 ----
  		if (fexists(SIZE_ALL_FNAME))
  			move_file(".", SIZE_ALL_FNAME, LogDir);
  		(void) snprintf(contents, sizeof(contents), "%s/%s", LogDir, CONTENTS_FNAME);
! 		fp = fopen(contents, "w");
! 		if (!fp) {
  			warnx("can't open new contents file '%s'! can't register pkg",
  			    contents);
  			goto success;	/* can't log, but still keep pkg */
  		}
! 		write_plist(&Plist, fp, NULL);
! 		fclose(fp);
  		move_file(".", DESC_FNAME, LogDir);
  		move_file(".", COMMENT_FNAME, LogDir);
  		if (fexists(BUILD_VERSION_FNAME))
***************
*** 707,742 ****
  			strcat(contents, "/");
  			strcat(contents, REQUIRED_BY_FNAME);
  
! 			cfile = fopen(contents, "a");
! 			if (!cfile)
  				warnx("can't open dependency file '%s'!\n"
  				    "dependency registration is incomplete", contents);
  			else {
! 				fprintf(cfile, "%s\n", PkgName);
! 				if (fclose(cfile) == EOF)
  					warnx("cannot properly close file %s", contents);
  			}
  		}
  		if (Verbose)
  			printf("Package %s registered in %s\n", PkgName, LogDir);
- 	}
  
! 	if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) {
! 		FILE   *fp;
! 		char    buf[BUFSIZ];
! 
! 		(void) snprintf(buf, sizeof(buf), "%s/%s", LogDir, p->name);
! 		fp = fopen(buf, "r");
! 		if (fp) {
! 			putc('\n', stdout);
! 			while (fgets(buf, sizeof(buf), fp))
! 				fputs(buf, stdout);
! 			putc('\n', stdout);
! 			(void) fclose(fp);
! 		} else
! 			warnx("cannot open %s as display file", buf);
  	}
- 
  	goto success;
  
  bomb:
--- 704,737 ----
  			strcat(contents, "/");
  			strcat(contents, REQUIRED_BY_FNAME);
  
! 			fp = fopen(contents, "a");
! 			if (!fp)
  				warnx("can't open dependency file '%s'!\n"
  				    "dependency registration is incomplete", contents);
  			else {
! 				fprintf(fp, "%s\n", PkgName);
! 				if (fclose(fp) == EOF)
  					warnx("cannot properly close file %s", contents);
  			}
  		}
  		if (Verbose)
  			printf("Package %s registered in %s\n", PkgName, LogDir);
  
! 		(void) snprintf(dfile, sizeof(dfile), "%s/%s", LogDir, DISPLAY_FNAME);
! 		if (fexists(dfile)) {
! 			fp = fopen(dfile, "r");
! 			if (fp) {
! 				char buf[BUFSIZ];
! 
! 				putc('\n', stdout);
! 				while (fgets(buf, sizeof(buf), fp))
! 					fputs(buf, stdout);
! 				putc('\n', stdout);
! 				(void) fclose(fp);
! 			} else
! 				warnx("cannot open %s as display file", dfile);
! 		}
  	}
  	goto success;
  
  bomb:
Index: pkg_add.1
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/add/pkg_add.1,v
retrieving revision 1.1.1.7
diff -c -c -r1.1.1.7 pkg_add.1
*** pkg_add.1	2001/06/12 21:27:06	1.1.1.7
--- pkg_add.1	2001/08/13 00:05:48
***************
*** 269,277 ****
--- 269,308 ----
  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 an
+ .Ar mtreefile
+ (see
+ .Fl m
+ in
+ .Xr pkg_create 1 ) ,
+ then
+ .Xr mtree 8
+ is invoked as
+ .Bd -filled -offset indent -compact
+ .Cm mtree
+ .Fl u
+ .Fl f
+ .Ar mtreefile
+ .Fl d
+ .Fl e
+ .Fl p
+ .Pa prefix
+ .Ed
+ where
+ .Pa prefix
+ is either the prefix specified with the
+ .Fl p
+ flag or, if no
+ .Fl p
+ flag was specified, the name of the first directory named by a
+ .Cm @cwd
+ directive within this package.
+ .It
  If the package contains a
  .Ar require
  script (see
+ .Fl r
+ in
  .Xr pkg_create 1 ) ,
  it is executed with the following arguments:
  .Bl -tag -width indentindent
***************
*** 289,295 ****
  .It
  If the package contains an
  .Ar install
! script, it is executed with the following arguments:
  .Bl -tag -width indentindent
  .It Ar pkg-name
  The name of the package being installed.
--- 320,331 ----
  .It
  If the package contains an
  .Ar install
! script
!  (see
! .Fl i
! in
! .Xr pkg_create 1 ) ,
! it is executed with the following arguments:
  .Bl -tag -width indentindent
  .It Ar pkg-name
  The name of the package being installed.
***************
*** 308,338 ****
  then it is 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
- .Ar mtreefile
- file (see
- .Xr pkg_create 1 ) ,
- then mtree is invoked as:
- .Bd -filled -offset indent -compact
- .Cm mtree
- .Fl u
- .Fl f
- .Ar mtreefile
- .Fl d
- .Fl e
- .Fl p
- .Pa prefix
- .Ed
- where
- .Pa prefix
- is either the prefix specified with the
- .Fl p
- flag or, if no
- .Fl p
- flag was specified, the name of the first directory named by a
- .Cm @cwd
- directive within this package.
- .It
  If an
  .Ar install
  script exists for the package, it is executed with the following arguments:
--- 344,349 ----
***************
*** 346,352 ****
  .It
  After installation is complete, a copy of the packing list,
  .Ar deinstall
! script, description, and display files are copied into
  .Pa /var/db/pkg/<pkg-name>
  for subsequent possible use by
  .Xr pkg_delete 1 .
--- 357,363 ----
  .It
  After installation is complete, a copy of the packing list,
  .Ar deinstall
! script, description, and main display files are copied into
  .Pa /var/db/pkg/<pkg-name>
  for subsequent possible use by
  .Xr pkg_delete 1 .
***************
*** 460,465 ****
--- 471,483 ----
  invocations due to exec argument-space limitations--this depends on the
  value returned by
  .Fn sysconf _SC_ARG_MAX ) .
+ .Pp
+ The
+ .Ar install
+ and
+ .Ar require
+ scripts should be copied to PKG_DBDIR so that binary packages can be
+ re-created after they are installed.
  .Pp
  Pkg upgrading needs a lot more work to be really universal.
  .Pp
Index: create/perform.c
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/create/perform.c,v
retrieving revision 1.1.1.7
diff -c -r1.1.1.7 perform.c
*** create/perform.c	2001/06/12 21:27:07	1.1.1.7
--- create/perform.c	2001/08/12 21:04:14
***************
*** 61,70 ****
  	args[nargs++] = "-c";
  	args[nargs++] = "-f";
  	args[nargs++] = tball;
  	if (strstr(suffix, "bz")) {
  		args[nargs++] = "--use-compress-program";
  		args[nargs++] = "bzip2";
! 	} else if (strchr(suffix, 'z'))/* Compress/gzip? */
  		args[nargs++] = "-z";
  	if (Dereference)
  		args[nargs++] = "-h";
--- 61,78 ----
  	args[nargs++] = "-c";
  	args[nargs++] = "-f";
  	args[nargs++] = tball;
+ #ifdef DEBUG
+ 	if (Verbose)
+ 		args[nargs++] = "-v";
+ #endif
+ 	if (strchr(suffix, 'z'))/* Compress/gzip? */
+ #if 0 /* GNU tar-ism */
  	if (strstr(suffix, "bz")) {
  		args[nargs++] = "--use-compress-program";
  		args[nargs++] = "bzip2";
! 	} else
! #endif
! 	if (strchr(suffix, 'z'))/* Compress/gzip? */
  		args[nargs++] = "-z";
  	if (Dereference)
  		args[nargs++] = "-h";
***************
*** 79,84 ****
--- 87,103 ----
  	if (Verbose)
  		printf("Creating gzip'd %s ball in '%s'\n", TAR_CMD, tball);
  
+ #ifdef DEBUG
+ 	if (Verbose) {
+ 		int i;
+ 
+ 		printf("    with the following command:\n");
+ 		printf("%s ", TAR_FULLPATHNAME);
+ 		for (i = 1; i < nargs; i++)
+ 			printf(" %s", args[i]);
+ 		printf("\n");
+ 	}
+ #endif
  	/* Set up a pipe for passing the filenames, and fork off a tar process. */
  	if (pipe(pipefds) == -1) {
  		cleanup(0);
***************
*** 140,146 ****
  		if (p->type == PLIST_FILE)
  			fprintf(totar, "%s\n", p->name);
  		else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
! 			fprintf(totar, "-C\n%s\n", p->name);
  		else if (p->type == PLIST_IGNORE)
  			p = p->next;
  	}
--- 159,165 ----
  		if (p->type == PLIST_FILE)
  			fprintf(totar, "%s\n", p->name);
  		else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
! 			fprintf(totar, "-C %s\n", p->name);
  		else if (p->type == PLIST_IGNORE)
  			p = p->next;
  	}
***************
*** 292,299 ****
  	}
  
  	/*
!          * We're just here for to dump out a revised plist for the FreeBSD ports
!          * hack.  It's not a real create in progress.
           */
  	if (PlistOnly) {
  		check_list(home, &plist, basename_of(pkg));
--- 311,318 ----
  	}
  
  	/*
!          * We're just here for to dump out a revised plist for the
!          * install-from-source hack.  It's not a real create in progress.
           */
  	if (PlistOnly) {
  		check_list(home, &plist, basename_of(pkg));
***************
*** 339,350 ****
--- 358,371 ----
  		copy_file(home, Display, DISPLAY_FNAME);
  		add_plist(&plist, PLIST_IGNORE, NULL);
  		add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
+ 		add_plist(&plist, PLIST_IGNORE, NULL);
  		add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
  	}
  	if (Mtree) {
  		copy_file(home, Mtree, MTREE_FNAME);
  		add_plist(&plist, PLIST_IGNORE, NULL);
  		add_plist(&plist, PLIST_FILE, MTREE_FNAME);
+ 		add_plist(&plist, PLIST_IGNORE, NULL);
  		add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
  	}
  	if (BuildVersion) {
Index: pkg_create.1
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/create/pkg_create.1,v
retrieving revision 1.1.1.7
diff -c -c -r1.1.1.7 pkg_create.1
*** pkg_create.1	2001/06/12 21:27:07	1.1.1.7
--- pkg_create.1	2001/08/13 00:06:10
***************
*** 172,190 ****
  .Ar iscript
  to be the install procedure for the package.  This can be any
  executable program (or shell script).  It will be invoked automatically
! when the package is later installed.
  .It Fl k Ar dscript
  Set
  .Ar dscript
  to be the de-install procedure for the package.  This can be any
  executable program (or shell script).  It will be invoked automatically
! when the package is later (if ever) de-installed.
  .It Fl L Ar SrcDir
  This sets the package's @src directive; see below for a description
  of what this does.
  .It Fl l
  Check that any symbolic links which are to be placed in the package are
! relative to the current prefix. This means using
  .Xr unlink 2
  and
  .Xr symlink 2
--- 172,194 ----
  .Ar iscript
  to be the install procedure for the package.  This can be any
  executable program (or shell script).  It will be invoked automatically
! when the package is later installed.  See
! .Xr pkg_add 8
! for details on how and when it is invoked.
  .It Fl k Ar dscript
  Set
  .Ar dscript
  to be the de-install procedure for the package.  This can be any
  executable program (or shell script).  It will be invoked automatically
! when the package is later (if ever) de-installed.  See
! .Xr pkg_delete 8
! for details on how and when it is invoked.
  .It Fl L Ar SrcDir
  This sets the package's @src directive; see below for a description
  of what this does.
  .It Fl l
  Check that any symbolic links which are to be placed in the package are
! relative to the current prefix.  This means using
  .Xr unlink 2
  and
  .Xr symlink 2
***************
*** 193,200 ****
  .It Fl m Ar mtreefile
  Run
  .Xr mtree 8
! with input from mtreefile before the package is installed.
! Mtree is invoked as
  .Cm mtree
  .Fl u
  .Fl f
--- 197,217 ----
  .It Fl m Ar mtreefile
  Run
  .Xr mtree 8
! with input from
! .Ar mtreefile
! before the package is installed.
! It is indended that this file contain specifications for creating the
! directory hierarchy used by all packages in common.  Package specific
! directories that might be removed when the package is de-installed can
! be created by a package-specific
! .Nm mtree
! file specified by an
! .Cm @mtree
! directive as described below.
! To process this file
! .Nm mtree
! is invoked as
! .Bd -filled -offset indent -compact
  .Cm mtree
  .Fl u
  .Fl f
***************
*** 202,208 ****
  .Fl d
  .Fl e
  .Fl p
! .Pa prefix ,
  where
  .Pa prefix
  is the name of the first directory named by a
--- 219,226 ----
  .Fl d
  .Fl e
  .Fl p
! .Pa prefix
! .Ed
  where
  .Pa prefix
  is the name of the first directory named by a
***************
*** 235,241 ****
  to be the ``requirements'' procedure for the package.  This can be any
  executable program (or shell script).  It will be invoked automatically
  at installation/deinstallation time to determine whether or not
! installation/deinstallation should proceed.
  .It Fl S Ar size-all-file
  Store the given file for later querying with the
  .Xr pkg_info 1
--- 253,263 ----
  to be the ``requirements'' procedure for the package.  This can be any
  executable program (or shell script).  It will be invoked automatically
  at installation/deinstallation time to determine whether or not
! installation/deinstallation should proceed.  See
! .Xr pkg_add 8
! and
! .Xr pkg_delete 8
! for details on how and when it is invoked.
  .It Fl S Ar size-all-file
  Store the given file for later querying with the
  .Xr pkg_info 1
***************
*** 406,413 ****
  makes it possible to use this directive in the
  .Ar packinglist
  file, so you can pack a
! specialized datafile in with a distribution for your install script (or
! something) yet have the installer ignore it.
  .It Cm @name Ar name
  Set the name of the package.  This is mandatory and is usually
  put at the top.  This name is potentially different than the name of
--- 428,436 ----
  makes it possible to use this directive in the
  .Ar packinglist
  file, so you can pack a
! specialized datafile in with a distribution for your
! .Ar install
! script (or something) yet have the installer ignore it.
  .It Cm @name Ar name
  Set the name of the package.  This is mandatory and is usually
  put at the top.  This name is potentially different than the name of
***************
*** 435,447 ****
  .Xr mtree 8
  input file to be used at install time (see
  .Fl m
! above).  Only the first
! .Cm @mtree
! directive is honored.
  .It Cm @display Ar name
  Declare
  .Pa name
! as the file to be displayed at install time (see
  .Fl D
  above).
  .It Cm @pkgdep Ar pkgname
--- 458,479 ----
  .Xr mtree 8
  input file to be used at install time (see
  .Fl m
! above).  Note that if the file is part of the package then it must be
! listed prior to this directive, and the directory it is extracted into
! must exist prior to the package extraction taking place (it could be
! created either by the main package system
! .Nm mtree
! file given by
! .Fl m ,
! or it could be created by the
! .Ar install
! script in the
! .Ar PRE-INSTALL
! phase).
  .It Cm @display Ar name
  Declare
  .Pa name
! as a file to be displayed to the user at install time (see also
  .Fl D
  above).
  .It Cm @pkgdep Ar pkgname
Index: lib/exec.c
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/lib/exec.c,v
retrieving revision 1.1.1.5
diff -c -r1.1.1.5 exec.c
*** lib/exec.c	2001/03/25 06:44:15	1.1.1.5
--- lib/exec.c	2001/08/12 22:35:16
***************
*** 56,64 ****
  		warnx("vsystem args are too long");
  		return 1;
  	}
! #ifdef VSYSTEM_DEBUG
! 	printf("vsystem(\"%s\")\n", cmd);
! #endif
  	ret = system(cmd);
  	va_end(args);
  	free(cmd);
--- 56,63 ----
  		warnx("vsystem args are too long");
  		return 1;
  	}
! 	if (Verbose)
! 		printf("system(\"%s\")\n", cmd);
  	ret = system(cmd);
  	va_end(args);
  	free(cmd);
Index: lib/lib.h
===================================================================
RCS file: /cvs/NetBSD/src/usr.sbin/pkg_install/lib/lib.h,v
retrieving revision 1.1.1.7
diff -c -r1.1.1.7 lib.h
*** lib/lib.h	2001/06/12 21:27:09	1.1.1.7
--- lib/lib.h	2001/06/13 15:47:56
***************
*** 58,69 ****
  
  /* Define tar as a string, in case it's called gtar or something */
  #ifndef TAR_CMD
! #define TAR_CMD	"tar"
  #endif
  
  /* Full path name of TAR_CMD */
  #ifndef TAR_FULLPATHNAME
! #define TAR_FULLPATHNAME	"/usr/bin/tar"
  #endif
  
  /* Where we put logging information by default, else ${PKG_DBDIR} if set */
--- 58,69 ----
  
  /* Define tar as a string, in case it's called gtar or something */
  #ifndef TAR_CMD
! # define TAR_CMD	"tar"
  #endif
  
  /* Full path name of TAR_CMD */
  #ifndef TAR_FULLPATHNAME
! # define TAR_FULLPATHNAME	"/bin/tar"
  #endif
  
  /* Where we put logging information by default, else ${PKG_DBDIR} if set */
>Release-Note:
>Audit-Trail:
>Unformatted: