Sat Apr 26 17:40:01 2008 UTC ()
Revert last change, it was not intended to go into HEAD.


(joerg)
diff -r1.17 -r1.18 pkgsrc/pkgtools/pkg_install/files/add/Makefile.in
diff -r1.11 -r1.12 pkgsrc/pkgtools/pkg_install/files/add/add.h
diff -r0 -r1.18 pkgsrc/pkgtools/pkg_install/files/add/extract.c
diff -r0 -r1.11 pkgsrc/pkgtools/pkg_install/files/add/futil.c
diff -r1.15 -r1.16 pkgsrc/pkgtools/pkg_install/files/add/main.c
diff -r1.71 -r1.72 pkgsrc/pkgtools/pkg_install/files/add/perform.c
diff -r1.29 -r1.30 pkgsrc/pkgtools/pkg_install/files/add/pkg_add.1
diff -r1.20 -r1.21 pkgsrc/pkgtools/pkg_install/files/create/perform.c
diff -r1.15 -r1.16 pkgsrc/pkgtools/pkg_install/files/info/Makefile.in
diff -r1.47 -r1.48 pkgsrc/pkgtools/pkg_install/files/info/perform.c
diff -r1.22 -r1.23 pkgsrc/pkgtools/pkg_install/files/lib/Makefile.in
diff -r1.5 -r1.6 pkgsrc/pkgtools/pkg_install/files/lib/conflicts.c
diff -r1.24 -r1.25 pkgsrc/pkgtools/pkg_install/files/lib/file.c
diff -r0 -r1.28 pkgsrc/pkgtools/pkg_install/files/lib/ftpio.c
diff -r1.43 -r1.44 pkgsrc/pkgtools/pkg_install/files/lib/lib.h
diff -r0 -r1.24 pkgsrc/pkgtools/pkg_install/files/lib/pen.c
diff -r0 -r1.5 pkgsrc/pkgtools/pkg_install/files/lib/pexec.c
diff -r1.2 -r1.3 pkgsrc/pkgtools/pkg_install/files/lib/pkg_io.c
diff -r1.18 -r1.19 pkgsrc/pkgtools/pkg_install/files/lib/plist.c
diff -r1.23 -r1.24 pkgsrc/pkgtools/pkg_install/files/lib/str.c

cvs diff -r1.17 -r1.18 pkgsrc/pkgtools/pkg_install/files/add/Makefile.in (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/add/Makefile.in 2008/04/26 14:56:33 1.17
+++ pkgsrc/pkgtools/pkg_install/files/add/Makefile.in 2008/04/26 17:40:01 1.18
@@ -1,39 +1,39 @@ @@ -1,39 +1,39 @@
1# $NetBSD: Makefile.in,v 1.17 2008/04/26 14:56:33 joerg Exp $ 1# $NetBSD: Makefile.in,v 1.18 2008/04/26 17:40:01 joerg Exp $
2 2
3srcdir= @srcdir@ 3srcdir= @srcdir@
4 4
5prefix= @prefix@ 5prefix= @prefix@
6exec_prefix= @exec_prefix@ 6exec_prefix= @exec_prefix@
7sbindir= @sbindir@ 7sbindir= @sbindir@
8mandir= @mandir@ 8mandir= @mandir@
9datarootdir= @datarootdir@ 9datarootdir= @datarootdir@
10 10
11man1dir= $(mandir)/man1 11man1dir= $(mandir)/man1
12cat1dir= $(mandir)/cat1 12cat1dir= $(mandir)/cat1
13 13
14CC= @CC@ 14CC= @CC@
15CCLD= $(CC) 15CCLD= $(CC)
16LIBS= -linstall -lfetch -larchive -lbz2 -lz @LIBS@ 16LIBS= -linstall @LIBS@
17CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib 17CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib
18DEFS= @DEFS@ -DOPSYS_NAME=\"$(OPSYS)\" -DMACHINE_ARCH=\"$(MACHINE_ARCH)\" -DBINDIR=\"$(sbindir)\" 18DEFS= @DEFS@ -DOPSYS_NAME=\"$(OPSYS)\" -DMACHINE_ARCH=\"$(MACHINE_ARCH)\" -DBINDIR=\"$(sbindir)\" -DTAR_CMD=\"@tar@\" -DPAX_CMD=\"@pax@\"
19CFLAGS= @CFLAGS@ 19CFLAGS= @CFLAGS@
20LDFLAGS= @LDFLAGS@ -L../lib 20LDFLAGS= @LDFLAGS@ -L../lib
21 21
22INSTALL= @INSTALL@ 22INSTALL= @INSTALL@
23 23
24PROG= pkg_add 24PROG= pkg_add
25 25
26OBJS= main.o perform.o verify.o 26OBJS= main.o perform.o futil.o extract.o verify.o
27 27
28all: $(PROG) 28all: $(PROG)
29 29
30.c.o: 30.c.o:
31 $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< 31 $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
32 32
33$(PROG): $(OBJS) 33$(PROG): $(OBJS)
34 $(CCLD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) 34 $(CCLD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
35 35
36clean: 36clean:
37 rm -f $(OBJS) $(PROG) 37 rm -f $(OBJS) $(PROG)
38 38
39install: 39install:

cvs diff -r1.11 -r1.12 pkgsrc/pkgtools/pkg_install/files/add/add.h (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/add/add.h 2008/04/26 14:56:33 1.11
+++ pkgsrc/pkgtools/pkg_install/files/add/add.h 2008/04/26 17:40:01 1.12
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: add.h,v 1.11 2008/04/26 14:56:33 joerg Exp $ */ 1/* $NetBSD: add.h,v 1.12 2008/04/26 17:40:01 joerg Exp $ */
2 2
3/* from FreeBSD Id: add.h,v 1.8 1997/02/22 16:09:15 peter Exp */ 3/* from FreeBSD Id: add.h,v 1.8 1997/02/22 16:09:15 peter Exp */
4 4
5/* 5/*
6 * FreeBSD install - a package for the installation and maintainance 6 * FreeBSD install - a package for the installation and maintainance
7 * of non-core utilities. 7 * of non-core utilities.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
@@ -25,20 +25,27 @@ @@ -25,20 +25,27 @@
25#ifndef _INST_ADD_H_INCLUDE 25#ifndef _INST_ADD_H_INCLUDE
26#define _INST_ADD_H_INCLUDE 26#define _INST_ADD_H_INCLUDE
27 27
28extern char *OverrideMachine; 28extern char *OverrideMachine;
29extern char *Prefix; 29extern char *Prefix;
30extern char *View; 30extern char *View;
31extern char *Viewbase; 31extern char *Viewbase;
32extern Boolean NoView; 32extern Boolean NoView;
33extern Boolean NoInstall; 33extern Boolean NoInstall;
34extern Boolean NoRecord; 34extern Boolean NoRecord;
35extern Boolean Force; 35extern Boolean Force;
36extern Boolean Automatic; 36extern Boolean Automatic;
37extern int Replace; 37extern int Replace;
 38extern char *Mode;
 39extern char *Owner;
 40extern char *Group;
 41extern char *Directory;
 42extern char *PkgName;
 43extern char FirstPen[];
38 44
39int make_hierarchy(char *); 45int make_hierarchy(char *);
 46int extract_plist(char *, package_t *);
40void apply_perms(char *, char **, int); 47void apply_perms(char *, char **, int);
41 48
42int pkg_perform(lpkg_head_t *); 49int pkg_perform(lpkg_head_t *);
43 50
44#endif /* _INST_ADD_H_INCLUDE */ 51#endif /* _INST_ADD_H_INCLUDE */

File Added: pkgsrc/pkgtools/pkg_install/files/add/Attic/extract.c
/*	$NetBSD: extract.c,v 1.18 2008/04/26 17:40:01 joerg Exp $	*/

#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#ifndef lint
#if 0
static const char *rcsid = "FreeBSD - Id: extract.c,v 1.17 1997/10/08 07:45:35 charnier Exp";
#else
__RCSID("$NetBSD: extract.c,v 1.18 2008/04/26 17:40:01 joerg Exp $");
#endif
#endif

/*
 * FreeBSD install - a package for the installation and maintainance
 * of non-core utilities.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Jordan K. Hubbard
 * 18 July 1993
 *
 * This is the package extraction code for the add module.
 *
 */

#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#include "add.h"

lfile_head_t files;
lfile_head_t perms;

/* 
 * Copy files from staging area to todir.
 * This is only used when the files cannot be directory rename()ed.
 */
static void
pushout(char *todir)
{
	pipe_to_system_t	*pipe_to;
	char			*file_args[4];
	char			**perm_argv;
	int			perm_argc = 1;
	lfile_t			*lfp;
	int			count;

	/* set up arguments to run "pax -r -w -p e" */
	file_args[0] = (char *)strrchr(PAX_CMD, '/');
	if (file_args[0] == NULL)
		file_args[0] = PAX_CMD;
	else
		file_args[0]++;
	file_args[1] = "-rwpe";
	file_args[2] = todir;
	file_args[3] = NULL;

	/* count entries for files */
	count = 0;
	TAILQ_FOREACH(lfp, &files, lf_link)
		count++;

	if (count > 0)  {
		/* open pipe, feed it files, close pipe */
		pipe_to = pipe_to_system_begin(PAX_CMD, file_args, NULL);
		while ((lfp = TAILQ_FIRST(&files)) != NULL) {
			fprintf(pipe_to->fp, "%s\n", lfp->lf_name);
			TAILQ_REMOVE(&files, lfp, lf_link);
			free(lfp);
		}
		pipe_to_system_end(pipe_to);
        }
 
	/* count entries for permissions */
	count = 0;
	TAILQ_FOREACH(lfp, &perms, lf_link)
		count++;

	if (count > 0) {
		perm_argv = malloc((count + 1) * sizeof(char *));
		perm_argc = 0;
		TAILQ_FOREACH(lfp, &perms, lf_link)
			perm_argv[perm_argc++] = lfp->lf_name;
		perm_argv[perm_argc] = NULL;
		apply_perms(todir, perm_argv, perm_argc);

		/* empty the perm list */
		while ((lfp = TAILQ_FIRST(&perms)) != NULL) {
			TAILQ_REMOVE(&perms, lfp, lf_link);
			free(lfp);
		}
		free(perm_argv);
	}
}

static void
rollback(char *name, char *home, plist_t *start, plist_t *stop)
{
	plist_t *q;
	char    try[MaxPathSize], bup[MaxPathSize], *dir;

	dir = home;
	for (q = start; q != stop; q = q->next) {
		if (q->type == PLIST_FILE) {
			(void) snprintf(try, sizeof(try), "%s/%s", dir, q->name);
			if (make_preserve_name(bup, sizeof(bup), name, try) && fexists(bup)) {
#if HAVE_CHFLAGS
				(void) chflags(try, 0);
#endif
				(void) unlink(try);
				if (rename(bup, try))
					warnx("rollback: unable to rename %s back to %s", bup, try);
			}
		} else if (q->type == PLIST_CWD) {
			if (strcmp(q->name, "."))
				dir = q->name;
			else
				dir = home;
		}
	}
}


/*
 * Return 0 on error, 1 for success.
 */
int
extract_plist(char *home, package_t *pkg)
{
	plist_t *p = pkg->head;
	char   *last_file;
	char	*last_chdir;
	Boolean preserve;
	lfile_t	*lfp;

	TAILQ_INIT(&files);
	TAILQ_INIT(&perms);

	last_chdir = 0;
	preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;

	/* Reset the world */
	Owner = NULL;
	Group = NULL;
	Mode = NULL;
	last_file = NULL;
	Directory = home;

	if (!NoRecord) {
		/* Open Package Database for writing */
		if (!pkgdb_open(ReadWrite)) {
			cleanup(0);
			err(EXIT_FAILURE, "can't open pkgdb");
		}
	}
	/* Do it */
	while (p) {
		char    cmd[MaxPathSize];

		switch (p->type) {
		case PLIST_NAME:
			PkgName = p->name;
			if (Verbose)
				printf("extract: Package name is %s\n", p->name);
			break;

		case PLIST_FILE:
			last_file = p->name;
			if (Verbose)
				printf("extract: %s/%s\n", Directory, p->name);
			if (!Fake) {
				char    try[MaxPathSize];

				if (strrchr(p->name, '\'')) {
					cleanup(0);
					errx(2, "Bogus filename \"%s\"", p->name);
				}

				/* first try to rename it into place */
				(void) snprintf(try, sizeof(try), "%s/%s", Directory, p->name);
				if (fexists(try)) {
#if HAVE_CHFLAGS
					(void) chflags(try, 0);	/* XXX hack - if truly immutable, rename fails */
#endif
					if (preserve && PkgName) {
						char    pf[MaxPathSize];

						if (make_preserve_name(pf, sizeof(pf), PkgName, try)) {
							if (rename(try, pf)) {
								warnx(
								    "unable to back up %s to %s, aborting pkg_add",
								    try, pf);
								rollback(PkgName, home, pkg->head, p);
								return 0;
							}
						}
					}
				}
				if (rename(p->name, try) == 0) {
					if (!NoRecord) {
						/* note in pkgdb */
						char   *s, t[MaxPathSize];
						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] == '/')
						pushout(Directory);

					LFILE_ADD(&perms, lfp, p->name);
				} else {
					/* rename failed, try copying with a big tar command */
					if (last_chdir != Directory) {
						if (last_chdir != NULL)
							pushout(last_chdir);
						last_chdir = Directory;
					} else if (p->name[0] == '/') {
						pushout(Directory);
					}

					if (!NoRecord) {
						/* 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[MaxPathSize];
						int     rc;

						LFILE_ADD(&files, lfp, p->name);
						LFILE_ADD(&perms, lfp, p->name);
						if (p->name[0] == '/')
							errx(EXIT_FAILURE, "File names must not be absolute (%s).", p->name);
						else {
							(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
						}
					}
				}
			}
			break;

		case PLIST_CWD:
			if (Verbose)
				printf("extract: CWD to %s\n", p->name);
			pushout(Directory);
			if (strcmp(p->name, ".")) {
				if (!Fake && make_hierarchy(p->name) == FAIL) {
					cleanup(0);
					errx(2, "unable to make directory '%s'", p->name);
				}
				Directory = p->name;
			} else
				Directory = home;
			break;

		case PLIST_CMD:
			format_cmd(cmd, sizeof(cmd), p->name, Directory, last_file);
			pushout(Directory);
			printf("Executing '%s'\n", cmd);
			if (!Fake && system(cmd))
				warnx("command '%s' failed", cmd);
			break;

		case PLIST_CHMOD:
			pushout(Directory);
			Mode = p->name;
			break;

		case PLIST_CHOWN:
			pushout(Directory);
			Owner = p->name;
			break;

		case PLIST_CHGRP:
			pushout(Directory);
			Group = p->name;
			break;

		case PLIST_COMMENT:
			break;

		case PLIST_IGNORE:
			p = p->next;
			break;

		default:
			break;
		}
		p = p->next;
	}
	pushout(Directory);
	if (!NoRecord)
		pkgdb_close();
	return 1;
}

File Added: pkgsrc/pkgtools/pkg_install/files/add/Attic/futil.c
/*	$NetBSD: futil.c,v 1.11 2008/04/26 17:40:01 joerg Exp $	*/

#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: futil.c,v 1.7 1997/10/08 07:45:39 charnier Exp";
#else
__RCSID("$NetBSD: futil.c,v 1.11 2008/04/26 17:40:01 joerg Exp $");
#endif
#endif

/*
 * FreeBSD install - a package for the installation and maintainance
 * of non-core utilities.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Jordan K. Hubbard
 * 18 July 1993
 *
 * Miscellaneous file access utilities.
 *
 */

#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#include "add.h"

/*
 * Assuming dir is a desired directory name, make it and all intervening
 * directories necessary.
 */
int
make_hierarchy(char *dir)
{
	char   *cp1, *cp2;
	char   *argv[2];

	argv[0] = dir;
	argv[1] = NULL;

	if (dir[0] == '/')
		cp1 = cp2 = dir + 1;
	else
		cp1 = cp2 = dir;
	while (cp2) {
		if ((cp2 = strchr(cp1, '/')) != NULL)
			*cp2 = '\0';
		if (fexists(dir)) {
			if (!(isdir(dir) || islinktodir(dir)))
				return FAIL;
		} else {
			if (fexec("mkdir", dir, NULL))
				return FAIL;
			apply_perms(NULL, argv, 1);
		}
		/* Put it back */
		if (cp2) {
			*cp2 = '/';
			cp1 = cp2 + 1;
		}
	}
	return SUCCESS;
}

/*
 * Using permission defaults, apply them as necessary
 */
void
apply_perms(char *dir, char **args, int nargs)
{
	char   *cd_to;
	char	owner_group[128];
	const char	**argv;
	int	i;

	argv = malloc((nargs + 4) * sizeof(char *));
	/*
	 * elements 0..2 are set later depending on Mode.
	 * args is a NULL terminated list of file names.
	 * by appending them to argv, argv becomes NULL terminated also.
	 */
	for (i = 0; i <= nargs; i++)
		argv[i + 3] = args[i];

	if (!dir || args[0][0] == '/') /* absolute path? */
		cd_to = "/";
	else
		cd_to = dir;

	if (Mode) {
		argv[0] = CHMOD_CMD;
		argv[1] = "-R";
		argv[2] = Mode;
		if (pfcexec(cd_to, argv[0], argv))
			warnx("couldn't change modes of '%s' ... to '%s'",
			    args[0], Mode);
	}
	if (Owner != NULL && Group != NULL) {
		if (snprintf(owner_group, sizeof(owner_group),
			     "%s:%s", Owner, Group) > sizeof(owner_group)) {
			warnx("'%s:%s' is too long (%lu max)",
			      Owner, Group, (unsigned long) sizeof(owner_group));
			free(argv);
			return;
		}
		argv[0] = CHOWN_CMD;
		argv[1] = "-R";
		argv[2] = owner_group;
		if (pfcexec(cd_to, argv[0], argv))
			warnx("couldn't change owner/group of '%s' ... to '%s:%s'",
				args[0], Owner, Group);
		free(argv);
		return;
	}
	if (Owner != NULL) {
		argv[0] = CHOWN_CMD;
		argv[1] = "-R";
		argv[2] = Owner;
		if (pfcexec(cd_to, argv[0], argv))
			warnx("couldn't change owner of '%s' ... to '%s'",
				args[0], Owner);
		free(argv);

		return;
	}
	if (Group != NULL) {
		argv[0] = CHGRP_CMD;
		argv[1] = "-R";
		argv[2] = Group;
		if (pfcexec(cd_to, argv[0], argv))
			warnx("couldn't change group of '%s' ... to '%s'",
				args[0], Group);
	}
	free(argv);
}

cvs diff -r1.15 -r1.16 pkgsrc/pkgtools/pkg_install/files/add/main.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/add/main.c 2008/04/26 14:56:34 1.15
+++ pkgsrc/pkgtools/pkg_install/files/add/main.c 2008/04/26 17:40:01 1.16
@@ -1,27 +1,27 @@ @@ -1,27 +1,27 @@
1/* $NetBSD: main.c,v 1.15 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: main.c,v 1.16 2008/04/26 17:40:01 joerg Exp $ */
2 2
3#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
4#include "config.h" 4#include "config.h"
5#endif 5#endif
6#include <nbcompat.h> 6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#endif 9#endif
10#ifndef lint 10#ifndef lint
11#if 0 11#if 0
12static char *rcsid = "from FreeBSD Id: main.c,v 1.16 1997/10/08 07:45:43 charnier Exp"; 12static char *rcsid = "from FreeBSD Id: main.c,v 1.16 1997/10/08 07:45:43 charnier Exp";
13#else 13#else
14__RCSID("$NetBSD: main.c,v 1.15 2008/04/26 14:56:34 joerg Exp $"); 14__RCSID("$NetBSD: main.c,v 1.16 2008/04/26 17:40:01 joerg Exp $");
15#endif 15#endif
16#endif 16#endif
17 17
18/* 18/*
19 * 19 *
20 * FreeBSD install - a package for the installation and maintainance 20 * FreeBSD install - a package for the installation and maintainance
21 * of non-core utilities. 21 * of non-core utilities.
22 * 22 *
23 * Redistribution and use in source and binary forms, with or without 23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions 24 * modification, are permitted provided that the following conditions
25 * are met: 25 * are met:
26 * 1. Redistributions of source code must retain the above copyright 26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer. 27 * notice, this list of conditions and the following disclaimer.
@@ -50,34 +50,40 @@ __RCSID("$NetBSD: main.c,v 1.15 2008/04/ @@ -50,34 +50,40 @@ __RCSID("$NetBSD: main.c,v 1.15 2008/04/
50#include "verify.h" 50#include "verify.h"
51 51
52static char Options[] = "AIK:LRVW:fhm:np:s:t:uvw:"; 52static char Options[] = "AIK:LRVW:fhm:np:s:t:uvw:";
53 53
54char *OverrideMachine = NULL; 54char *OverrideMachine = NULL;
55char *Prefix = NULL; 55char *Prefix = NULL;
56char *View = NULL; 56char *View = NULL;
57char *Viewbase = NULL; 57char *Viewbase = NULL;
58Boolean NoView = FALSE; 58Boolean NoView = FALSE;
59Boolean NoInstall = FALSE; 59Boolean NoInstall = FALSE;
60Boolean NoRecord = FALSE; 60Boolean NoRecord = FALSE;
61Boolean Automatic = FALSE; 61Boolean Automatic = FALSE;
62 62
 63char *Mode = NULL;
 64char *Owner = NULL;
 65char *Group = NULL;
 66char *PkgName = NULL;
 67char *Directory = NULL;
 68char FirstPen[MaxPathSize];
63int Replace = 0; 69int Replace = 0;
64 70
65static void 71static void
66usage(void) 72usage(void)
67{ 73{
68 (void) fprintf(stderr, "%s\n%s\n%s\n", 74 (void) fprintf(stderr, "%s\n%s\n%s\n",
69 "usage: pkg_add [-AfhILnRuVv] [-K pkg_dbdir] [-m machine] [-p prefix]", 75 "usage: pkg_add [-AfhILnRuVv] [-K pkg_dbdir] [-m machine] [-p prefix]",
70 " [-s verification-type] [-W viewbase] [-w view]", 76 " [-s verification-type] [-t template] [-W viewbase] [-w view]",
71 " [[ftp|http]://[user[:password]@]host[:port]][/path/]pkg-name ..."); 77 " [[ftp|http]://[user[:password]@]host[:port]][/path/]pkg-name ...");
72 exit(1); 78 exit(1);
73} 79}
74 80
75int 81int
76main(int argc, char **argv) 82main(int argc, char **argv)
77{ 83{
78 int ch, error=0; 84 int ch, error=0;
79 lpkg_head_t pkgs; 85 lpkg_head_t pkgs;
80 struct rlimit rlim; 86 struct rlimit rlim;
81 int rc; 87 int rc;
82 88
83 setprogname(argv[0]); 89 setprogname(argv[0]);
@@ -110,31 +116,33 @@ main(int argc, char **argv) @@ -110,31 +116,33 @@ main(int argc, char **argv)
110 case 'm': 116 case 'm':
111 OverrideMachine = optarg; 117 OverrideMachine = optarg;
112 break; 118 break;
113 119
114 case 'n': 120 case 'n':
115 Fake = TRUE; 121 Fake = TRUE;
116 Verbose = TRUE; 122 Verbose = TRUE;
117 break; 123 break;
118 124
119 case 'p': 125 case 'p':
120 Prefix = optarg; 126 Prefix = optarg;
121 break; 127 break;
122 128
123#if 0 
124 case 's': 129 case 's':
125 set_verification(optarg); 130 set_verification(optarg);
126 break; 131 break;
127#endif 132
 133 case 't':
 134 strlcpy(FirstPen, optarg, sizeof(FirstPen));
 135 break;
128 136
129 case 'u': 137 case 'u':
130 Replace++; 138 Replace++;
131 break; 139 break;
132 140
133 case 'V': 141 case 'V':
134 show_version(); 142 show_version();
135 /* NOTREACHED */ 143 /* NOTREACHED */
136 144
137 case 'v': 145 case 'v':
138 Verbose = TRUE; 146 Verbose = TRUE;
139 break; 147 break;
140 148

cvs diff -r1.71 -r1.72 pkgsrc/pkgtools/pkg_install/files/add/perform.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/add/perform.c 2008/04/26 14:56:34 1.71
+++ pkgsrc/pkgtools/pkg_install/files/add/perform.c 2008/04/26 17:40:01 1.72
@@ -1,1228 +1,1053 @@ @@ -1,1228 +1,1053 @@
1/* $NetBSD: perform.c,v 1.71 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: perform.c,v 1.72 2008/04/26 17:40:01 joerg Exp $ */
 2
2#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
3#include "config.h" 4#include "config.h"
4#endif 5#endif
5#include <nbcompat.h> 6#include <nbcompat.h>
6#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
7#include <sys/cdefs.h> 8#include <sys/cdefs.h>
8#endif 9#endif
9__RCSID("$NetBSD: perform.c,v 1.71 2008/04/26 14:56:34 joerg Exp $"); 10#if HAVE_SYS_QUEUE_H
 11#include <sys/queue.h>
 12#endif
 13#ifndef lint
 14#if 0
 15static const char *rcsid = "from FreeBSD Id: perform.c,v 1.44 1997/10/13 15:03:46 jkh Exp";
 16#else
 17__RCSID("$NetBSD: perform.c,v 1.72 2008/04/26 17:40:01 joerg Exp $");
 18#endif
 19#endif
10 20
11/*- 21/*
12 * Copyright (c) 2003 Grant Beattie <grant@NetBSD.org> 22 * FreeBSD install - a package for the installation and maintainance
13 * Copyright (c) 2005 Dieter Baron <dillo@NetBSD.org> 23 * of non-core utilities.
14 * Copyright (c) 2007 Roland Illig <rillig@NetBSD.org> 
15 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org> 
16 * All rights reserved. 
17 * 24 *
18 * Redistribution and use in source and binary forms, with or without 25 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions 26 * modification, are permitted provided that the following conditions
20 * are met: 27 * are met:
21 * 
22 * 1. Redistributions of source code must retain the above copyright 28 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer. 29 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright 30 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in 31 * notice, this list of conditions and the following disclaimer in the
26 * the documentation and/or other materials provided with the 32 * documentation and/or other materials provided with the distribution.
27 * distribution. 33 *
 34 * Jordan K. Hubbard
 35 * 18 July 1993
 36 *
 37 * This is the main body of the add module.
28 * 38 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
32 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
33 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 
35 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
36 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
37 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
38 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
39 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
40 * SUCH DAMAGE. 
41 */ 39 */
42 40
43#include <sys/utsname.h> 41#if HAVE_ASSERT_H
44#include <archive.h> 42#include <assert.h>
45#include <archive_entry.h> 43#endif
 44#if HAVE_ERR_H
46#include <err.h> 45#include <err.h>
 46#endif
 47#if HAVE_ERRNO_H
47#include <errno.h> 48#include <errno.h>
48#include <stdlib.h> 49#endif
49#include <string.h> 50#include "defs.h"
50#include <unistd.h> 
51 
52#include "lib.h" 51#include "lib.h"
53#include "add.h" 52#include "add.h"
 53#include "verify.h"
54 54
55struct pkg_meta { 55#if HAVE_INTTYPES_H
56 char *meta_contents; 56#include <inttypes.h>
57 char *meta_comment; 57#endif
58 char *meta_desc; 58#if HAVE_SIGNAL_H
59 char *meta_mtree; 59#include <signal.h>
60 char *meta_build_version; 60#endif
61 char *meta_build_info; 61#if HAVE_STRING_H
62 char *meta_size_pkg; 62#include <string.h>
63 char *meta_size_all; 63#endif
64 char *meta_required_by; 64#if HAVE_STDLIB_H
65 char *meta_display; 65#include <stdlib.h>
66 char *meta_install; 66#endif
67 char *meta_deinstall; 67#if HAVE_SYS_UTSNAME_H
68 char *meta_preserve; 68#include <sys/utsname.h>
69 char *meta_views; 69#endif
70 char *meta_installed_info; 
71}; 
72 
73struct pkg_task { 
74 const char *pkgname; 
75 
76 const char *prefix; 
77 const char *install_prefix; 
78 
79 char *logdir; 
80 char *other_version; 
81 
82 package_t plist; 
83 
84 struct pkg_meta meta_data; 
85 70
86 struct archive *archive; 71static char LogDir[MaxPathSize];
87 struct archive_entry *entry; 72static int zapLogDir; /* Should we delete LogDir? */
88 73
89 char *buildinfo[BI_ENUM_COUNT]; 74static package_t Plist;
 75static char *Home;
90 76
91 size_t dep_length, dep_allocated; 77static lfile_head_t files;
92 char **dependencies; 
93}; 
94 78
95static const struct pkg_meta_desc { 79/* used in build information */
96 size_t entry_offset; 80enum {
97 const char *entry_filename; 81 Good,
98 int required_file; 82 Missing,
99 mode_t perm; 83 Warning,
100} pkg_meta_descriptors[] = { 84 Fatal
101 { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 1, 0644 }, 
102 { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 1, 0444}, 
103 { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 1, 0444}, 
104 { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 0, 0555 }, 
105 { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 0, 0555 }, 
106 { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 0, 0444 }, 
107 { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 0, 0444 }, 
108 { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME, 0, 0444 }, 
109 { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME, 0, 0444 }, 
110 { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME, 0, 0444 }, 
111 { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME, 0, 0444 }, 
112 { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME, 0, 0444 }, 
113 { offsetof(struct pkg_meta, meta_views), VIEWS_FNAME, 0, 0444 }, 
114 { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME, 0, 0644 }, 
115 { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME, 0, 0644 }, 
116 { 0, NULL, 0 }, 
117}; 85};
118 86
119static int pkg_do(const char *, int); 87static void
120 88normalise_platform(struct utsname *host_name)
121static int 
122mkdir_p(const char *path) 
123{ 89{
124 return fexec(MKDIR_CMD, "-p", path, (void *)NULL);  90#ifdef NUMERIC_VERSION_ONLY
 91 size_t span;
 92
 93 span = strspn(host_name->release, "0123456789.");
 94 host_name->release[span] = '\0';
 95#endif
125} 96}
126 97
127/* 98/* Read package build information */
128 * Read meta data from archive. 
129 * Bail out if a required entry is missing or entries are in the wrong order. 
130 */ 
131static int 99static int
132read_meta_data(struct pkg_task *pkg) 100read_buildinfo(char **buildinfo)
133{ 101{
134 const struct pkg_meta_desc *descr, *last_descr; 102 char *key;
135 const char *fname; 103 char *line;
136 char **target; 104 size_t len;
137 int64_t size; 105 FILE *fp;
138 int r, found_required; 
139 
140 found_required = 0; 
141 106
142 last_descr = 0; 107 if ((fp = fopen(BUILD_INFO_FNAME, "r")) == NULL) {
143 while ((r = archive_read_next_header(pkg->archive, &pkg->entry)) == 108 warnx("unable to open %s file.", BUILD_INFO_FNAME);
144 ARCHIVE_OK) { 109 return 0;
145 fname = archive_entry_pathname(pkg->entry); 
146 
147 for (descr = pkg_meta_descriptors; descr->entry_filename; 
148 ++descr) { 
149 if (strcmp(descr->entry_filename, fname) == 0) 
150 break; 
151 } 
152 if (descr->entry_filename == NULL) 
153 break; 
154 
155 if (descr->required_file) 
156 ++found_required; 
157 
158 target = (char **)((char *)&pkg->meta_data + 
159 descr->entry_offset); 
160 if (*target) { 
161 warnx("duplicate entry, package corrupt"); 
162 return -1; 
163 } 
164 if (descr < last_descr) { 
165 warnx("misordered package"); 
166 return -1; 
167 } 
168 last_descr = descr; 
169 
170 size = archive_entry_size(pkg->entry); 
171 if (size > SSIZE_MAX - 1) { 
172 warnx("package meta data too large to process"); 
173 return -1; 
174 } 
175 if ((*target = malloc(size + 1)) == NULL) 
176 err(2, "cannot allocate meta data"); 
177 if (archive_read_data(pkg->archive, *target, size) != size) { 
178 warn("cannot read package meta data"); 
179 return -1; 
180 } 
181 (*target)[size] = '\0'; 
182 } 110 }
183 111
184 if (r != ARCHIVE_OK) 112 while ((line = fgetln(fp, &len)) != NULL) {
185 pkg->entry = NULL; 113 if (line[len - 1] == '\n')
 114 line[len - 1] = '\0';
186 115
187 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { 116 if ((key = strsep(&line, "=")) == NULL)
188 if (descr->required_file) 117 continue;
189 --found_required; 
190 } 
191 
192 return !found_required ? 0 : -1; 
193} 
194 118
195/* 119 /*
196 * Free meta data. 120 * pkgsrc used to create the BUILDINFO file using
197 */ 121 * "key= value", so skip the space if it's there.
198static void 122 */
199free_meta_data(struct pkg_task *pkg) 123 if (line == NULL)
200{ 124 continue;
201 const struct pkg_meta_desc *descr; 125 if (line[0] == ' ')
202 char **target; 126 line += sizeof(char);
203 127
204 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { 128 /*
205 target = (char **)((char *)&pkg->meta_data + 129 * we only care about opsys, arch, version, and
206 descr->entry_offset); 130 * dependency recommendations
207 free(*target); 131 */
208 *target = NULL; 132 if (line[0] != '\0') {
 133 if (strcmp(key, "OPSYS") == 0)
 134 buildinfo[BI_OPSYS] = strdup(line);
 135 else if (strcmp(key, "OS_VERSION") == 0)
 136 buildinfo[BI_OS_VERSION] = strdup(line);
 137 else if (strcmp(key, "MACHINE_ARCH") == 0)
 138 buildinfo[BI_MACHINE_ARCH] = strdup(line);
 139 else if (strcmp(key, "IGNORE_RECOMMENDED") == 0)
 140 buildinfo[BI_IGNORE_RECOMMENDED] = strdup(line);
 141 else if (strcmp(key, "USE_ABI_DEPENDS") == 0)
 142 buildinfo[BI_USE_ABI_DEPENDS] = strdup(line);
 143 }
 144 }
 145 (void) fclose(fp);
 146 if (buildinfo[BI_OPSYS] == NULL ||
 147 buildinfo[BI_OS_VERSION] == NULL ||
 148 buildinfo[BI_MACHINE_ARCH] == NULL) {
 149 warnx("couldn't extract build information from package.");
 150 return 0;
209 } 151 }
 152 return 1;
210} 153}
211 154
212/* 
213 * Parse PLIST and populate pkg. 
214 */ 
215static int 155static int
216pkg_parse_plist(struct pkg_task *pkg) 156sanity_check(const char *pkg)
217{ 157{
218 plist_t *p; 158 int errc = 0;
219 159
220 parse_plist(&pkg->plist, pkg->meta_data.meta_contents); 160 if (!fexists(CONTENTS_FNAME)) {
221 if ((p = find_plist(&pkg->plist, PLIST_NAME)) == NULL) { 161 warnx("package %s has no CONTENTS file!", pkg);
222 warnx("Invalid PLIST: missing @name"); 162 errc = 1;
223 return -1; 163 } else if (!fexists(COMMENT_FNAME)) {
 164 warnx("package %s has no COMMENT file!", pkg);
 165 errc = 1;
 166 } else if (!fexists(DESC_FNAME)) {
 167 warnx("package %s has no DESC file!", pkg);
 168 errc = 1;
224 } 169 }
225 pkg->pkgname = p->name; 170 return errc;
226 if ((p = find_plist(&pkg->plist, PLIST_CWD)) == NULL) { 
227 warnx("Invalid PLIST: missing @cwd"); 
228 return -1; 
229 } 
230 /* XXX change first @cwd in PLIST? */ 
231 pkg->prefix = p->name; 
232 pkg->install_prefix = Prefix != NULL ? Prefix : pkg->prefix; 
233 
234 return 0; 
235} 
236 
237/* 
238 * Helper function to extract value from a string of the 
239 * form key=value ending at eol. 
240 */ 
241static char * 
242dup_value(const char *line, const char *eol) 
243{ 
244 const char *key; 
245 char *val; 
246 
247 key = strchr(line, '='); 
248 val = malloc(eol - key); 
249 if (val == NULL) 
250 err(2, "malloc failed"); 
251 memcpy(val, key + 1, eol - key - 1); 
252 val[eol - key - 1] = '\0'; 
253 return val; 
254} 171}
255 172
 173/* install a pre-requisite package. Returns 1 if it installed it */
256static int 174static int
257check_already_installed(struct pkg_task *pkg) 175installprereq(const char *name, int *errc, int doupdate)
258{ 176{
259 char *filename; 177 int ret;
260 int fd; 178 ret = 0;
261 
262 if (Force) 
263 return -1; 
264 179
265 filename = pkgdb_pkg_file(pkg->pkgname, CONTENTS_FNAME); 180 if (Verbose)
266 fd = open(filename, O_RDONLY); 181 printf("Loading it from %s.\n", name);
267 free(filename); 182 path_setenv("PKG_PATH");
268 if (fd == -1) 
269 return -1; 
270 183
271 /* We can only arrive here for explicitly requested packages. */ 184 if (fexec_skipempty(BINDIR "/pkg_add", "-K", _pkgdb_getPKGDB_DIR(),
272 if (!Automatic && is_automatic_installed(pkg->pkgname)) { 185 "-s", get_verification(),
273 if (Fake || 186 doupdate > 1 ? "-uu" : (doupdate ? "-u" : ""),
274 mark_as_automatic_installed(pkg->pkgname, 0) == 0) 187 Fake ? "-n" : "",
275 warnx("package `%s' was already installed as " 188 NoView ? "-L" : "",
276 "dependency, now marked as installed " 189 View ? "-w" : "", View ? View : "",
277 "manually", pkg->pkgname); 190 Viewbase ? "-W" : "", Viewbase ? Viewbase : "",
 191 Force ? "-f" : "",
 192 Prefix ? "-p" : "", Prefix ? Prefix : "",
 193 Verbose ? "-v" : "",
 194 OverrideMachine ? "-m" : "",
 195 OverrideMachine ? OverrideMachine : "",
 196 NoInstall ? "-I" : "",
 197 "-A", name, NULL)) {
 198 warnx("autoload of dependency `%s' failed%s",
 199 name, Force ? " (proceeding anyway)" : "!");
 200 if (!Force)
 201 ++(*errc);
278 } else { 202 } else {
279 warnx("package `%s' already recorded as installed", 203 ret = 1;
280 pkg->pkgname); 
281 } 204 }
282 return 0; 
283 205
 206 return ret;
284} 207}
285 208
286static int 209static int
287check_other_installed(struct pkg_task *pkg) 210pkg_do_installed(int *replacing, char replace_via[MaxPathSize], char replace_to[MaxPathSize],
 211 Boolean is_depoted_pkg, const char *dbdir)
288{ 212{
289 FILE *f, *f_pkg; 213 char replace_from[MaxPathSize];
290 size_t len; 214 char *s;
291 char *pkgbase, *iter, *filename; 215 char buf[MaxPathSize];
292 package_t plist; 216 char *best_installed;
293 plist_t *p; 
294 int status; 
295 
296 if ((pkgbase = strdup(pkg->pkgname)) == NULL) { 
297 warnx("strdup failed"); 
298 return -1; 
299 } 
300 if ((iter = strrchr(pkgbase, '-')) == NULL) { 
301 free(pkgbase); 
302 warnx("Invalid package name %s", pkg->pkgname); 
303 return -1; 
304 } 
305 *iter = '\0'; 
306 pkg->other_version = find_best_matching_installed_pkg(pkgbase); 
307 free(pkgbase); 
308 if (pkg->other_version == NULL) 
309 return 0; 
310 217
311 if (!Replace) { 218 const size_t replace_via_size = MaxPathSize;
312 /* XXX This is redundant to the implicit conflict check. */ 219 const size_t replace_to_size = MaxPathSize;
313 warnx("A different version of %s is already installed: %s", 
314 pkg->pkgname, pkg->other_version); 
315 return -1; 
316 } 
317 220
318 filename = pkgdb_pkg_file(pkg->other_version, REQUIRED_BY_FNAME); 221 if ((s = strrchr(PkgName, '-')) == NULL) {
319 errno = 0; 222 warnx("Package name %s does not contain a version, bailing out", PkgName);
320 f = fopen(filename, "r"); 
321 free(filename); 
322 if (f == NULL) { 
323 if (errno == ENOENT) { 
324 /* No packages depend on this, so everything is well. */ 
325 return 0;  
326 } 
327 warnx("Can't open +REQUIRED_BY of %s", pkg->other_version); 
328 return -1; 223 return -1;
329 } 224 }
 225
 226 /*
 227 * See if the pkg is already installed. If so, we might want to
 228 * upgrade/replace it. Otherwise, just return and let pkg_do work.
 229 */
 230 (void) snprintf(buf, sizeof(buf), "%.*s[0-9]*",
 231 (int)(s - PkgName) + 1, PkgName);
 232 best_installed = find_best_matching_installed_pkg(buf);
 233 if (best_installed == NULL)
 234 return 0;
330 235
331 status = 0; 236 if (!Replace || Fake) {
332 237 if (is_depoted_pkg) {
333 while ((iter = fgetln(f, &len)) != NULL) { 238 free(best_installed);
334 if (iter[len - 1] == '\n') 239 return 0;
335 iter[len - 1] = '\0'; 240 } else {
336 filename = pkgdb_pkg_file(iter, CONTENTS_FNAME); 241 warnx("other version '%s' already installed", best_installed);
337 if ((f_pkg = fopen(filename, "r")) == NULL) { 242 free(best_installed);
338 warnx("Can't open +CONTENTS of depending package %s", 243 return 1; /* close enough for government work */
339 iter); 
340 fclose(f); 
341 return -1; 
342 } 
343 plist.head = plist.tail = NULL; 
344 read_plist(&plist, f_pkg); 
345 fclose(f_pkg); 
346 for (p = plist.head; p != NULL; p = p->next) { 
347 if (p->type == PLIST_IGNORE) { 
348 p = p->next; 
349 continue; 
350 } else if (p->type != PLIST_PKGDEP) 
351 continue; 
352 /* 
353 * XXX This is stricter than necessary. 
354 * XXX One pattern might be fulfilled by 
355 * XXX a different package and still need this 
356 * XXX one for a different pattern. 
357 */ 
358 if (pkg_match(p->name, pkg->other_version) == 0) 
359 continue; 
360 if (pkg_match(p->name, pkg->pkgname) == 1) 
361 continue; /* Both match, ok. */ 
362 warnx("Dependency of %s fulfilled by %s, but not by %s", 
363 iter, pkg->other_version, pkg->pkgname); 
364 if (!Force) 
365 status = -1; 
366 break; 
367 } 244 }
368 free_plist(&plist);  
369 } 245 }
370 246
371 fclose(f); 247 /* XXX Should list the steps in Fake mode */
 248 snprintf(replace_from, sizeof(replace_from), "%s/%s/" REQUIRED_BY_FNAME,
 249 dbdir, best_installed);
 250 snprintf(replace_via, replace_via_size, "%s/.%s." REQUIRED_BY_FNAME,
 251 dbdir, best_installed);
 252 snprintf(replace_to, replace_to_size, "%s/%s/" REQUIRED_BY_FNAME,
 253 dbdir, PkgName);
372 254
373 return status; 255 if (Verbose)
374} 256 printf("Upgrading %s to %s.\n", best_installed, PkgName);
375 257
376/* 258 if (fexists(replace_from)) { /* Are there any dependencies? */
377 * Read package build information from meta data. 259 /*
378 */ 260 * Upgrade step 1/4: Check if the new version is ok with all pkgs
379static int 261 * (from +REQUIRED_BY) that require this pkg
380read_buildinfo(struct pkg_task *pkg) 262 */
381{ 263 FILE *rb; /* +REQUIRED_BY file */
382 const char *data, *eol, *next_line; 264 char pkg2chk[MaxPathSize];
383 265
384 data = pkg->meta_data.meta_build_info; 266 rb = fopen(replace_from, "r");
 267 if (! rb) {
 268 warnx("Cannot open '%s' for reading%s", replace_from,
 269 Force ? " (proceeding anyways)" : "");
 270 if (Force)
 271 goto ignore_replace_depends_check;
 272 else
 273 return -1;
 274 }
 275 while (fgets(pkg2chk, sizeof(pkg2chk), rb)) {
 276 package_t depPlist;
 277 FILE *depf;
 278 plist_t *depp;
 279 char depC[MaxPathSize];
 280
 281 depPlist.head = depPlist.tail = NULL;
 282
 283 s = strrchr(pkg2chk, '\n');
 284 if (s)
 285 *s = '\0'; /* strip trailing '\n' */
 286
 287 /*
 288 * step into pkg2chk, read it's +CONTENTS file and see if
 289 * all @pkgdep lines agree with PkgName (using pkg_match())
 290 */
 291 snprintf(depC, sizeof(depC), "%s/%s/%s", dbdir, pkg2chk, CONTENTS_FNAME);
 292 depf = fopen(depC , "r");
 293 if (depf == NULL) {
 294 warnx("Cannot check depends in '%s'%s", depC,
 295 Force ? " (proceeding anyways)" : "!" );
 296 if (Force)
 297 goto ignore_replace_depends_check;
 298 else
 299 return -1;
 300 }
 301 read_plist(&depPlist, depf);
 302 fclose(depf);
 303
 304 for (depp = depPlist.head; depp; depp = depp->next) {
 305 char base_new[MaxPathSize];
 306 char base_exist[MaxPathSize];
 307 char *s2;
 308
 309 if (depp->type != PLIST_PKGDEP)
 310 continue;
 311
 312 /*
 313 * Prepare basename (no versions) of both pkgs,
 314 * to see if we want to compare against that
 315 * one at all.
 316 */
 317 strlcpy(base_new, PkgName, sizeof(base_new));
 318 s2 = strpbrk(base_new, "<>[]?*{"); /* } */
 319 if (s2)
 320 *s2 = '\0';
 321 else {
 322 s2 = strrchr(base_new, '-');
 323 if (s2)
 324 *s2 = '\0';
 325 }
 326 strlcpy(base_exist, depp->name, sizeof(base_exist));
 327 s2 = strpbrk(base_exist, "<>[]?*{"); /* } */
 328 if (s2)
 329 *s2 = '\0';
 330 else {
 331 s2 = strrchr(base_exist, '-');
 332 if (s2)
 333 *s2 = '\0';
 334 }
 335 if (strcmp(base_new, base_exist) == 0) {
 336 /* Same pkg, so do the interesting compare */
 337 if (pkg_match(depp->name, PkgName)) {
 338 if (Verbose)
 339 printf("@pkgdep check: %s is ok for %s (in %s pkg)\n",
 340 PkgName, depp->name, pkg2chk);
 341 } else {
 342 printf("Package %s requires %s, \n\tCannot replace with %s%s\n",
 343 pkg2chk, depp->name, PkgName,
 344 Force? " (proceeding anyways)" : "!");
 345 if (! Force)
 346 return -1;
 347 }
 348 }
 349 }
 350 }
 351 fclose(rb);
385 352
386 for (; *data != '\0'; data = next_line) { 353ignore_replace_depends_check:
387 if ((eol = strchr(data, '\n')) == NULL) { 354 /*
388 eol = data + strlen(data); 355 * Upgrade step 2/4: Do the actual update by moving aside
389 next_line = eol; 356 * the +REQUIRED_BY file, deinstalling the old pkg, adding
390 } else 357 * the new one and moving the +REQUIRED_BY file back
391 next_line = eol + 1; 358 * into place (finished in step 3/4)
 359 */
 360 if (Verbose)
 361 printf("mv %s %s\n", replace_from, replace_via);
 362 if (rename(replace_from, replace_via) != 0)
 363 err(EXIT_FAILURE, "renaming \"%s\" to \"%s\" failed", replace_from, replace_via);
392 364
393 if (strncmp(data, "OPSYS=", 6) == 0) 365 *replacing = 1;
394 pkg->buildinfo[BI_OPSYS] = dup_value(data, eol); 
395 else if (strncmp(data, "OS_VERSION=", 11) == 0) 
396 pkg->buildinfo[BI_OS_VERSION] = dup_value(data, eol); 
397 else if (strncmp(data, "MACHINE_ARCH=", 13) == 0) 
398 pkg->buildinfo[BI_MACHINE_ARCH] = dup_value(data, eol); 
399 else if (strncmp(data, "IGNORE_RECOMMENDED=", 19) == 0) 
400 pkg->buildinfo[BI_IGNORE_RECOMMENDED] = dup_value(data, 
401 eol); 
402 else if (strncmp(data, "USE_ABI_DEPENDS=", 16) == 0) 
403 pkg->buildinfo[BI_USE_ABI_DEPENDS] = dup_value(data, 
404 eol); 
405 } 
406 if (pkg->buildinfo[BI_OPSYS] == NULL || 
407 pkg->buildinfo[BI_OS_VERSION] == NULL || 
408 pkg->buildinfo[BI_MACHINE_ARCH] == NULL) { 
409 warnx("Not all required build information are present."); 
410 return -1; 
411 } 366 }
412 367
413 if ((pkg->buildinfo[BI_USE_ABI_DEPENDS] != NULL && 368 if (Verbose) {
414 strcasecmp(pkg->buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) || 369 printf("%s/pkg_delete -K %s '%s'\n",
415 (pkg->buildinfo[BI_IGNORE_RECOMMENDED] != NULL && 370 BINDIR, dbdir, best_installed);
416 strcasecmp(pkg->buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) { 
417 warnx("%s was built to ignore ABI dependencies", pkg->pkgname); 
418 } 371 }
 372 fexec(BINDIR "/pkg_delete", "-K", dbdir, best_installed, NULL);
419 373
420 return 0; 374 free(best_installed);
421} 
422 375
423/* 376 return 0;
424 * Free buildinfo. 
425 */ 
426static void 
427free_buildinfo(struct pkg_task *pkg) 
428{ 
429 size_t i; 
430 
431 for (i = 0; i < BI_ENUM_COUNT; ++i) { 
432 free(pkg->buildinfo[i]); 
433 pkg->buildinfo[i] = NULL; 
434 } 
435} 377}
436 378
437/* 379/*
438 * Write meta data files to pkgdb after creating the directory. 380 * Install a single package
 381 * Returns 0 if everything is ok, >0 else
439 */ 382 */
440static int 383static int
441write_meta_data(struct pkg_task *pkg) 384pkg_do(const char *pkg, lpkg_head_t *pkgs)
442{ 385{
443 const struct pkg_meta_desc *descr; 386 char playpen[MaxPathSize];
444 char *filename, **target; 387 char replace_via[MaxPathSize];
445 size_t len; 388 char replace_to[MaxPathSize];
446 ssize_t ret; 389 char *buildinfo[BI_ENUM_COUNT];
447 int fd; 390 int replacing = 0;
448 391 char dbdir[MaxPathSize];
449 if (Fake) 392 const char *tmppkg;
450 return 0; 393 FILE *cfile;
451 394 int errc, err_prescan;
452 if (mkdir_p(pkg->logdir)) { 395 plist_t *p;
453 warn("Can't create pkgdb entry: %s", pkg->logdir); 396 struct stat sb;
454 return -1; 397 struct utsname host_uname;
455 } 398 uint64_t needed;
456 399 Boolean is_depoted_pkg = FALSE;
457 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { 400 lfile_t *lfp;
458 target = (char **)((char *)&pkg->meta_data + 401 int result;
459 descr->entry_offset); 402
460 if (*target == NULL) 403 errc = 0;
461 continue; 404 zapLogDir = 0;
462 if (asprintf(&filename, "%s/%s", pkg->logdir, 405 LogDir[0] = '\0';
463 descr->entry_filename) == -1) { 406 strlcpy(playpen, FirstPen, sizeof(playpen));
464 warn("asprintf failed"); 407 memset(buildinfo, '\0', sizeof(buildinfo));
465 return -1; 408
466 } 409 umask(DEF_UMASK);
467 (void)unlink(filename); 410
468 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, descr->perm); 411 tmppkg = fileFindByPath(pkg);
469 if (fd == -1) { 412 if (tmppkg == NULL) {
470 warn("Can't open meta data file: %s", filename); 413 warnx("no pkg found for '%s', sorry.", pkg);
471 return -1; 414 return 1;
472 } 415 }
473 len = strlen(*target); 416
474 do { 417 pkg = tmppkg;
475 ret = write(fd, *target, len); 418
476 if (ret == -1) { 419 if (IS_URL(pkg)) {
477 warn("Can't write meta data file: %s", 420 Home = fileGetURL(pkg);
478 filename); 421 if (Home == NULL) {
479 free(filename); 422 warnx("unable to fetch `%s' by URL", pkg);
480 return -1; 423 }
 424
 425 /* make sure the pkg is verified */
 426 if (!verify(pkg)) {
 427 warnx("Package %s will not be extracted", pkg);
 428 goto bomb;
 429 }
 430 } else { /* local */
 431 if (!IS_STDIN(pkg)) {
 432 /* not stdin */
 433 if (!ispkgpattern(pkg)) {
 434 if (stat(pkg, &sb) == FAIL) {
 435 warnx("can't stat package file '%s'", pkg);
 436 goto bomb;
 437 }
 438 /* make sure the pkg is verified */
 439 if (!verify(pkg)) {
 440 warnx("Package %s will not be extracted", pkg);
 441 goto bomb;
 442 }
481 } 443 }
482 len -= ret; 444 LFILE_ADD(&files, lfp, CONTENTS_FNAME);
483 } while (ret > 0); 445 } else {
484 if (close(fd) == -1) { 446 /* some values for stdin */
485 warn("Can't close meta data file: %s", filename); 447 sb.st_size = 100000; /* Make up a plausible average size */
486 free(filename); 
487 return -1; 
488 } 448 }
489 free(filename); 449 Home = make_playpen(playpen, sizeof(playpen), sb.st_size * 4);
490 } 450 if (!Home)
491 451 warnx("unable to make playpen for %ld bytes",
492 return 0; 452 (long) (sb.st_size * 4));
493} 453 result = unpack(pkg, &files);
494 454 while ((lfp = TAILQ_FIRST(&files)) != NULL) {
495/* 455 TAILQ_REMOVE(&files, lfp, lf_link);
496 * Helper function for extract_files. 456 free(lfp);
497 */ 457 }
498static int 458 if (result) {
499copy_data_to_disk(struct archive *reader, struct archive *writer, 459 warnx("unable to extract table of contents file from `%s' - not a package?",
500 const char *filename) 460 pkg);
501{ 461 goto bomb;
502 int r; 
503 const void *buff; 
504 size_t size; 
505 off_t offset; 
506 
507 for (;;) { 
508 r = archive_read_data_block(reader, &buff, &size, &offset); 
509 if (r == ARCHIVE_EOF) 
510 return 0; 
511 if (r != ARCHIVE_OK) { 
512 warnx("Read error for %s: %s", filename, 
513 archive_error_string(reader)); 
514 return -1; 
515 } 
516 r = archive_write_data_block(writer, buff, size, offset); 
517 if (r != ARCHIVE_OK) { 
518 warnx("Write error for %s: %s", filename, 
519 archive_error_string(writer)); 
520 return -1; 
521 } 462 }
522 } 463 }
523} 
524 
525/* 
526 * Extract package. 
527 * Any misordered, missing or unlisted file in the package is an error. 
528 */ 
529 
530static const int extract_flags = /* ARCHIVE_EXTRACT_OWNER | */ 
531 ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | 
532 ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR; 
533 
534static int 
535extract_files(struct pkg_task *pkg) 
536{ 
537 char cmd[MaxPathSize]; 
538 const char *owner, *group, *permissions; 
539 struct archive *writer; 
540 int r; 
541 plist_t *p; 
542 const char *last_file; 
543 char *fullpath; 
544 464
545 if (Fake) 465 cfile = fopen(CONTENTS_FNAME, "r");
546 return 0; 466 if (!cfile) {
547 467 warnx("unable to open table of contents file `%s' - not a package?",
548 if (mkdir_p(pkg->install_prefix)) { 468 CONTENTS_FNAME);
549 warn("Can't create prefix: %s", pkg->install_prefix); 469 goto bomb;
550 return -1; 
551 } 
552 
553 if (chdir(pkg->install_prefix) == -1) { 
554 warn("Can't change into prefix: %s", pkg->install_prefix); 
555 return -1; 
556 } 470 }
 471 read_plist(&Plist, cfile);
 472 fclose(cfile);
557 473
558 if (!NoRecord && !pkgdb_open(ReadWrite)) { 474 if (!IS_URL(pkg)) {
559 warn("Can't open pkgdb for writing"); 475 /*
560 return -1; 476 * Apply a crude heuristic to see how much space the package will
561 } 477 * take up once it's unpacked. I've noticed that most packages
562 478 * compress an average of 75%, so multiply by 4 for good measure.
563 writer = archive_write_disk_new(); 479 */
564 archive_write_disk_set_options(writer, extract_flags); 
565 archive_write_disk_set_standard_lookup(writer); 
566 
567 owner = NULL; 
568 group = NULL; 
569 permissions = NULL; 
570 last_file = NULL; 
571 
572 r = -1; 
573 
574 for (p = pkg->plist.head; p != NULL; p = p->next) { 
575 switch (p->type) { 
576 case PLIST_FILE: 
577 last_file = p->name; 
578 if (pkg->entry == NULL) { 
579 warnx("PLIST entry not in package (%s)", 
580 archive_entry_pathname(pkg->entry)); 
581 goto out; 
582 } 
583 if (strcmp(p->name, archive_entry_pathname(pkg->entry))) { 
584 warnx("PLIST entry and package don't match (%s vs %s)", 
585 p->name, archive_entry_pathname(pkg->entry)); 
586 goto out; 
587 } 
588 if (asprintf(&fullpath, "%s/%s", pkg->install_prefix, p->name) == -1) { 
589 warnx("asprintf failed"); 
590 goto out; 
591 } 
592 pkgdb_store(fullpath, pkg->pkgname); 
593 free(fullpath); 
594 if (Verbose) 
595 printf("%s", p->name); 
596 break; 
597 
598 case PLIST_CMD: 
599 if (format_cmd(cmd, sizeof(cmd), p->name, pkg->install_prefix, last_file)) 
600 return -1; 
601 printf("Executing '%s'\n", cmd); 
602 if (!Fake && system(cmd)) 
603 warnx("command '%s' failed", cmd); /* XXX bail out? */ 
604 continue; 
605 
606 case PLIST_CHMOD: 
607 permissions = p->name; 
608 continue; 
609 
610 case PLIST_CHOWN: 
611 owner = p->name; 
612 continue; 
613 
614 case PLIST_CHGRP: 
615 group = p->name; 
616 continue; 
617 
618 case PLIST_IGNORE: 
619 p = p->next; 
620 continue; 
621 480
622 default: 481 needed = 4 * (uint64_t) sb.st_size;
623 continue; 482 if (min_free(playpen) < needed) {
 483 warnx("projected size of %" MY_PRIu64 " bytes exceeds available free space\n"
 484 "in %s. Please set your PKG_TMPDIR variable to point\n"
 485 "to a location with more free space and try again.",
 486 needed, playpen);
 487 goto bomb;
624 } 488 }
625 489
626 r = archive_write_header(writer, pkg->entry); 490 /* Finally unpack the whole mess */
627 if (r != ARCHIVE_OK) { 491 if (unpack(pkg, NULL)) {
628 warnx("Failed to write %s: %s", 492 warnx("unable to extract `%s'!", pkg);
629 archive_entry_pathname(pkg->entry), 493 goto bomb;
630 archive_error_string(writer)); 
631 goto out; 
632 } 
633 
634 if (owner != NULL) 
635 archive_entry_set_uname(pkg->entry, owner); 
636 if (group != NULL) 
637 archive_entry_set_uname(pkg->entry, group); 
638 if (permissions != NULL) { 
639 mode_t mode; 
640 
641 mode = archive_entry_mode(pkg->entry); 
642 mode = getmode(setmode(permissions), mode); 
643 archive_entry_set_mode(pkg->entry, mode); 
644 } 
645 
646 r = copy_data_to_disk(pkg->archive, writer, 
647 archive_entry_pathname(pkg->entry)); 
648 if (r) 
649 goto out; 
650 if (Verbose) 
651 printf("\n"); 
652 
653 r = archive_read_next_header(pkg->archive, &pkg->entry); 
654 if (r == ARCHIVE_EOF) { 
655 pkg->entry = NULL; 
656 continue; 
657 } 
658 if (r != ARCHIVE_OK) { 
659 warnx("Failed to read from archive: %s", 
660 archive_error_string(pkg->archive)); 
661 goto out; 
662 } 494 }
663 } 495 }
664 496
665 if (pkg->entry != NULL) { 497 /* Check for sanity */
666 warnx("Package contains entries not in PLIST: %s", 498 if (sanity_check(pkg))
667 archive_entry_pathname(pkg->entry)); 499 goto bomb;
668 goto out; 
669 } 
670 
671 r = 0; 
672 
673out: 
674 if (!NoRecord) 
675 pkgdb_close(); 
676 archive_write_close(writer); 
677 archive_write_finish(writer); 
678 500
679 return r; 501 /* Read the OS, version and architecture from BUILD_INFO file */
680} 502 if (!read_buildinfo(buildinfo)) {
681 503 warn("can't read build information from %s", BUILD_INFO_FNAME);
682/* 504 if (!Force) {
683 * Register dependencies after sucessfully installing the package. 505 warnx("aborting.");
684 */ 506 goto bomb;
685static void 507 }
686pkg_register_depends(struct pkg_task *pkg) 
687{ 
688 int fd; 
689 size_t text_len, i; 
690 char *required_by, *text; 
691 
692 if (Fake) 
693 return; 
694 
695 if (pkg->other_version != NULL) 
696 return; /* XXX It's using the old dependencies. */ 
697 
698 if (asprintf(&text, "%s\n", pkg->pkgname) == -1) 
699 err(2, "asprintf failed"); 
700 text_len = strlen(text); 
701 
702 for (i = 0; i < pkg->dep_length; ++i) { 
703 required_by = pkgdb_pkg_file(pkg->dependencies[i], REQUIRED_BY_FNAME); 
704 
705 fd = open(required_by, O_WRONLY | O_APPEND | O_CREAT, 644); 
706 if (fd == -1) 
707 warn("can't open dependency file '%s'," 
708 "registration is incomplete!", required_by); 
709 else if (write(fd, text, text_len) != text_len) 
710 warn("can't write to dependency file `%s'", required_by); 
711 else if (close(fd) == -1) 
712 warn("cannot close file %s", required_by); 
713 
714 free(required_by); 
715 } 508 }
716 509
717 free(text); 510 if (uname(&host_uname) < 0) {
718} 511 warnx("uname() failed.");
719 512 if (!Force) {
720/* 513 warnx("aborting.");
721 * Reduce the result from uname(3) to a canonical form. 514 goto bomb;
722 */ 515 }
723static void 516 } else {
724normalise_platform(struct utsname *host_name) 517 int status = Good;
725{ 
726#ifdef NUMERIC_VERSION_ONLY 
727 size_t span; 
728 518
729 span = strspn(host_name->release, "0123456789."); 519 normalise_platform(&host_uname);
730 host_name->release[span] = '\0'; 
731#endif 
732} 
733 520
734/* 521 /* check that we have read some values from buildinfo */
735 * Check build platform of the package against local host. 522 if (buildinfo[BI_OPSYS] == NULL) {
736 */ 523 warnx("Missing operating system value from build information");
737static int 524 status = Missing;
738check_platform(struct pkg_task *pkg) 525 }
739{ 526 if (buildinfo[BI_MACHINE_ARCH] == NULL) {
740 struct utsname host_uname; 527 warnx("Missing machine architecture value from build information");
741 const char *effective_arch; 528 status = Missing;
742 int fatal; 529 }
 530 if (buildinfo[BI_OS_VERSION] == NULL) {
 531 warnx("Missing operating system version value from build information");
 532 status = Missing;
 533 }
 534
 535 if (status == Good) {
 536 const char *effective_arch;
 537
 538 if (OverrideMachine != NULL)
 539 effective_arch = OverrideMachine;
 540 else
 541 effective_arch = MACHINE_ARCH;
 542
 543 /* If either the OS or arch are different, bomb */
 544 if (strcmp(OPSYS_NAME, buildinfo[BI_OPSYS]) != 0)
 545 status = Fatal;
 546 if (strcmp(effective_arch, buildinfo[BI_MACHINE_ARCH]) != 0)
 547 status = Fatal;
 548
 549 /* If OS and arch are the same, warn if version differs */
 550 if (status == Good &&
 551 strcmp(host_uname.release, buildinfo[BI_OS_VERSION]) != 0)
 552 status = Warning;
 553
 554 if (status != Good) {
 555 warnx("Warning: package `%s' was built for a different version of the OS:", pkg);
 556 warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)",
 557 buildinfo[BI_OPSYS],
 558 buildinfo[BI_MACHINE_ARCH],
 559 buildinfo[BI_OS_VERSION],
 560 OPSYS_NAME,
 561 effective_arch,
 562 host_uname.release);
 563 }
 564 }
743 565
744 if (uname(&host_uname) < 0) { 566 if (!Force && status == Fatal) {
745 if (Force) { 567 warnx("aborting.");
746 warnx("uname() failed, continuing."); 568 goto bomb;
747 return 0; 
748 } else { 
749 warnx("uname() failed, aborting."); 
750 return -1; 
751 } 569 }
752 } 570 }
753 571
754 normalise_platform(&host_uname); 572 /* Check if USE_ABI_DEPENDS or IGNORE_RECOMMENDED was set
755 573 * when this package was built. IGNORE_RECOMMENDED is historical. */
756 if (OverrideMachine != NULL) 574
757 effective_arch = OverrideMachine; 575 if ((buildinfo[BI_USE_ABI_DEPENDS] != NULL &&
758 else 576 strcasecmp(buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) ||
759 effective_arch = MACHINE_ARCH; 577 (buildinfo[BI_IGNORE_RECOMMENDED] != NULL &&
760 578 strcasecmp(buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) {
761 /* If either the OS or arch are different, bomb */ 579 warnx("%s was built", pkg);
762 if (strcmp(OPSYS_NAME, pkg->buildinfo[BI_OPSYS]) || 580 warnx("\tto ignore recommended ABI dependencies, this may cause problems!\n");
763 strcmp(effective_arch, pkg->buildinfo[BI_MACHINE_ARCH]) != 0) 581 }
764 fatal = 1; 582
765 else 583 /*
766 fatal = 0; 584 * If we have a prefix, delete the first one we see and add this
767 585 * one in place of it.
768 if (fatal || 586 */
769 strcmp(host_uname.release, pkg->buildinfo[BI_OS_VERSION]) != 0) { 587 if (Prefix) {
770 warnx("Warning: package `%s' was built for a platform:", 588 delete_plist(&Plist, FALSE, PLIST_CWD, NULL);
771 pkg->pkgname); 589 add_plist_top(&Plist, PLIST_CWD, Prefix);
772 warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)", 590 }
773 pkg->buildinfo[BI_OPSYS], 591
774 pkg->buildinfo[BI_MACHINE_ARCH], 592 /* Protect against old packages with bogus @name fields */
775 pkg->buildinfo[BI_OS_VERSION], 593 p = find_plist(&Plist, PLIST_NAME);
776 OPSYS_NAME, 594 if (p->name == NULL) {
777 effective_arch, 595 warnx("PLIST contains no @name field");
778 host_uname.release); 596 goto bomb;
779 if (!Force && fatal) 597 }
780 return -1; 598 PkgName = p->name;
 599
 600 if (fexists(VIEWS_FNAME))
 601 is_depoted_pkg = TRUE;
 602
 603 /*
 604 * Depoted packages' dbdir is the same as DEPOTBASE. Non-depoted
 605 * packages' dbdir comes from the command-line or the environment.
 606 */
 607 if (is_depoted_pkg) {
 608 p = find_plist(&Plist, PLIST_CWD);
 609 if (p == NULL) {
 610 warn("no @cwd in +CONTENTS file?! aborting.");
 611 goto bomb;
 612 }
 613 (void) strlcpy(dbdir, dirname_of(p->name), sizeof(dbdir));
 614 (void) strlcpy(LogDir, p->name, sizeof(LogDir));
 615 } else {
 616 (void) strlcpy(dbdir, _pkgdb_getPKGDB_DIR(), sizeof(dbdir));
 617 (void) snprintf(LogDir, sizeof(LogDir), "%s/%s", dbdir, PkgName);
781 } 618 }
782 return 0; 
783} 
784 619
785/* 620 /* Set environment variables expected by the +INSTALL script. */
786 * Run the install script. 621 setenv(PKG_PREFIX_VNAME, (p = find_plist(&Plist, PLIST_CWD)) ? p->name : ".", 1);
787 */ 622 setenv(PKG_METADATA_DIR_VNAME, LogDir, 1);
788static int 
789run_install_script(struct pkg_task *pkg, const char *argument) 
790{ 
791 int ret; 
792 char *filename; 
793 
794 if (pkg->meta_data.meta_install == NULL || NoInstall) 
795 return 0; 
796 
797 setenv(PKG_PREFIX_VNAME, pkg->install_prefix, 1); /* XXX or prefix? */ 
798 setenv(PKG_METADATA_DIR_VNAME, pkg->logdir, 1); 
799 setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1); 623 setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1);
800 624
801 filename = pkgdb_pkg_file(pkg->pkgname, INSTALL_FNAME); 625 /* make sure dbdir actually exists! */
802 if (Verbose) 626 if (!(isdir(dbdir) || islinktodir(dbdir))) {
803 printf("Running install with PRE-INSTALL for %s.\n", pkg->pkgname); 627 if (fexec("mkdir", "-p", dbdir, NULL)) {
804 if (Fake) { 628 errx(EXIT_FAILURE,
805 free(filename); 629 "Database-dir %s cannot be generated, aborting.",
806 return 0; 630 dbdir);
 631 }
807 } 632 }
808 633
809 ret = 0; 634 /* See if this package (exact version) is already registered */
810 635 if (isdir(LogDir) && !Force) {
811 if (chdir(pkg->logdir) == -1) { 636 if (!Automatic && is_automatic_installed(PkgName)) {
812 warn("Can't change to %s", pkg->logdir); 637 if (mark_as_automatic_installed(PkgName, 0) == 0)
813 ret = -1; 638 warnx("package `%s' was already installed as "
 639 "dependency, now marked as installed "
 640 "manually", PkgName);
 641 } else {
 642 warnx("package `%s' already recorded as installed",
 643 PkgName);
 644 }
 645 goto success; /* close enough for government work */
814 } 646 }
815 647
816 errno = 0; 648 /* See if some other version of us is already installed */
817 if (ret == 0 && fexec(filename, pkg->pkgname, argument, (void *)NULL)) { 649 switch (pkg_do_installed(&replacing, replace_via, replace_to, is_depoted_pkg, dbdir)) {
818 if (errno != 0) 650 case 0:
819 warn("exec of install script failed"); 651 break;
820 else 652 case 1:
821 warnx("install script returned error status"); 653 errc = 1;
822 ret = -1; 654 goto success;
 655 case -1:
 656 goto bomb;
823 } 657 }
824 658
825 free(filename); 659 /* See if there are conflicting packages installed */
826 return ret; 660 for (p = Plist.head; p; p = p->next) {
827} 661 char *best_installed;
828 662
829static int 663 if (p->type != PLIST_PKGCFL)
830check_explicit_conflict(struct pkg_task *pkg) 
831{ 
832 char *installed, *installed_pattern; 
833 plist_t *p; 
834 int status; 
835 
836 status = 0; 
837 
838 for (p = pkg->plist.head; p != NULL; p = p->next) { 
839 if (p->type == PLIST_IGNORE) { 
840 p = p->next; 
841 continue; 
842 } else if (p->type != PLIST_PKGCFL) 
843 continue; 664 continue;
844 installed = find_best_matching_installed_pkg(p->name); 665 if (Verbose)
845 if (installed) { 666 printf("Package `%s' conflicts with `%s'.\n", PkgName, p->name);
 667 best_installed = find_best_matching_installed_pkg(p->name);
 668 if (best_installed) {
846 warnx("Package `%s' conflicts with `%s', and `%s' is installed.", 669 warnx("Package `%s' conflicts with `%s', and `%s' is installed.",
847 pkg->pkgname, p->name, installed); 670 PkgName, p->name, best_installed);
848 free(installed); 671 free(best_installed);
849 status = -1; 672 ++errc;
850 } 673 }
851 } 674 }
852 675
853 if (some_installed_package_conflicts_with(pkg->pkgname, 676 /* See if any of the installed packages conflicts with this one. */
854 pkg->other_version, &installed, &installed_pattern)) { 677 {
855 warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.", 678 char *inst_pkgname, *inst_pattern;
856 installed, installed_pattern, pkg->pkgname); 
857 free(installed); 
858 free(installed_pattern); 
859 status = -1; 
860 } 
861 
862 return status; 
863} 
864 
865static int 
866check_implicit_conflict(struct pkg_task *pkg) 
867{ 
868 plist_t *p; 
869 char *fullpath, *existing; 
870 int status; 
871 679
872 if (!pkgdb_open(ReadOnly)) { 680 if (some_installed_package_conflicts_with(PkgName, &inst_pkgname, &inst_pattern)) {
873#if notyet /* XXX empty pkgdb without database? */ 681 warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.",
874 warn("Can't open pkgdb for reading"); 682 inst_pkgname, inst_pattern, PkgName);
875 return -1; 683 free(inst_pkgname);
876#else 684 free(inst_pattern);
877 return 0; 685 errc++;
878#endif 686 }
879 } 687 }
880 688
881 status = 0; 689 /* Quick pre-check if any conflicting dependencies are installed
882 690 * (e.g. version X is installed, but version Y is required)
883 for (p = pkg->plist.head; p != NULL; p = p->next) { 691 */
884 if (p->type == PLIST_IGNORE) { 692 err_prescan=0;
885 p = p->next; 693 for (p = Plist.head; p; p = p->next) {
886 continue; 694 char *best_installed;
887 } else if (p->type != PLIST_FILE) 695
888 continue; 696 if (p->type != PLIST_PKGDEP)
889 
890 if (asprintf(&fullpath, "%s/%s", pkg->install_prefix, p->name) == -1) { 
891 warnx("asprintf failed"); 
892 status = -1; 
893 break; 
894 } 
895 existing = pkgdb_retrieve(fullpath); 
896 free(fullpath); 
897 if (existing == NULL) 
898 continue; 
899 if (pkg->other_version != NULL && 
900 strcmp(pkg->other_version, existing) == 0) 
901 continue; 697 continue;
 698 if (Verbose)
 699 printf("Depends pre-scan: `%s' required.\n", p->name);
 700 best_installed = find_best_matching_installed_pkg(p->name);
 701 if (best_installed == NULL) {
 702 /*
 703 * required pkg not found. look if it's available with a more liberal
 704 * pattern. If so, this will lead to problems later (check on "some
 705 * other version of us is already installed" will fail, see above),
 706 * and we better stop right now.
 707 */
 708 char *s;
 709 int skip = -1;
902 710
903 warnx("Conflicting PLIST with %s: %s", existing, p->name); 711 /* doing this right required to parse the full version(s),
904 if (!Force) { 712 * do a 99% solution here for now */
905 status = -1; 713 if (strchr(p->name, '{'))
906 if (!Verbose) 714 continue; /* would remove trailing '}' else */
907 break; 715
 716 if ((s = strpbrk(p->name, "<>")) != NULL) {
 717 skip = 0;
 718 } else if (((s = strstr(p->name, "-[0-9]*")) != NULL) &&
 719 (*(s + sizeof("-[0-9]*") - 1) == '\0')) {
 720 /* -[0-9]* already present so no need to */
 721 /* add it a second time */
 722 skip = -1;
 723 } else if ((s = strrchr(p->name, '-')) != NULL) {
 724 skip = 1;
 725 }
 726
 727 if (skip >= 0) {
 728 char buf[MaxPathSize];
 729
 730 (void) snprintf(buf, sizeof(buf),
 731 skip ? "%.*s[0-9]*" : "%.*s-[0-9]*",
 732 (int)(s - p->name) + skip, p->name);
 733 best_installed = find_best_matching_installed_pkg(buf);
 734 if (best_installed) {
 735 int done = 0;
 736
 737 if (Replace > 1)
 738 {
 739 int errc0 = 0;
 740 char tmp[MaxPathSize];
 741
 742 warnx("Attempting to update `%s' using binary package\n", p->name);
 743 /* Yes, append .tgz after the version so the */
 744 /* pattern can match a filename. */
 745 snprintf(tmp, sizeof(tmp), "%s.tgz", p->name);
 746 done = installprereq(tmp, &errc0, 2);
 747 }
 748 else if (Replace)
 749 {
 750 warnx("To perform necessary upgrades on required packages specify -u twice.\n");
 751 }
 752
 753 if (!done)
 754 {
 755 warnx("pkg `%s' required, but `%s' found installed.",
 756 p->name, best_installed);
 757 if (Force) {
 758 warnx("Proceeding anyway.");
 759 } else {
 760 err_prescan++;
 761 }
 762 }
 763 free(best_installed);
 764 }
 765 }
 766 } else {
 767 free(best_installed);
908 } 768 }
909 } 769 }
 770 if (err_prescan > 0) {
 771 warnx("Please resolve this conflict!");
 772 errc += err_prescan;
 773 goto success; /* close enough */
 774 }
 775
 776
 777 /* Now check the packing list for dependencies */
 778 for (p = Plist.head; p; p = p->next) {
 779 char *best_installed;
910 780
911 pkgdb_close(); 781 if (p->type != PLIST_PKGDEP)
912 return status; 
913} 
914 
915static int 
916check_dependencies(struct pkg_task *pkg) 
917{ 
918 plist_t *p; 
919 char *best_installed; 
920 int status; 
921 size_t i; 
922 
923 status = 0; 
924 
925 for (p = pkg->plist.head; p != NULL; p = p->next) { 
926 if (p->type == PLIST_IGNORE) { 
927 p = p->next; 
928 continue; 
929 } else if (p->type != PLIST_PKGDEP) 
930 continue; 782 continue;
 783 if (Verbose)
 784 printf("Package `%s' depends on `%s'.\n", PkgName, p->name);
931 785
932 best_installed = find_best_matching_installed_pkg(p->name); 786 best_installed = find_best_matching_installed_pkg(p->name);
933 787
934 if (best_installed == NULL) { 788 if (best_installed == NULL) {
935 /* XXX check cyclic dependencies? */ 789 /* required pkg not found - need to pull in */
936 if (Fake || NoRecord) { 790
937 if (!Force) { 791 if (Fake) {
938 warnx("Missing dependency %s\n", 792 /* fake install (???) */
939 p->name); 793 if (Verbose)
940 status = -1; 794 printf("Package dependency %s for %s not installed%s\n", p->name, pkg,
941 break; 795 Force ? " (proceeding anyway)" : "!");
 796 } else {
 797 int done = 0;
 798 int errc0 = 0;
 799
 800 done = installprereq(p->name, &errc0, (Replace > 1) ? 2 : 0);
 801 if (!done && !Force) {
 802 errc += errc0;
942 } 803 }
943 warnx("Missing dependency %s, continuing", 
944 p->name); 
945 continue; 
946 } 
947 if (pkg_do(p->name, 1)) { 
948 warnx("Can't install dependency %s", p->name); 
949 status = -1; 
950 break; 
951 } 804 }
952 best_installed = find_best_matching_installed_pkg(p->name); 805 } else {
953 if (best_installed == NULL && Force) { 806 if (Verbose)
954 warnx("Missing dependency %s ignored", p->name); 807 printf(" - %s already installed.\n", best_installed);
955 continue; 
956 } else if (best_installed == NULL) { 
957 warnx("Just installed dependency %s disappeared", p->name); 
958 status = -1; 
959 break; 
960 } 
961 } 
962 for (i = 0; i < pkg->dep_length; ++i) { 
963 if (strcmp(best_installed, pkg->dependencies[i]) == 0) 
964 break; 
965 } 
966 if (i < pkg->dep_length) { 
967 /* Already used as dependency, so skip it. */ 
968 free(best_installed); 808 free(best_installed);
969 continue; 
970 } 809 }
971 if (pkg->dep_length + 1 >= pkg->dep_allocated) { 
972 char **tmp; 
973 pkg->dep_allocated = 2 * pkg->dep_allocated + 1; 
974 tmp = realloc(pkg->dependencies, 
975 pkg->dep_allocated * sizeof(*tmp)); 
976 if (tmp == NULL) { 
977 warnx("realloc failed"); 
978 free(pkg->dependencies); 
979 pkg->dependencies = NULL; 
980 pkg->dep_length = pkg->dep_allocated = 0; 
981 free(best_installed); 
982 return -1; 
983 } 
984 pkg->dependencies = tmp; 
985 } 
986 pkg->dependencies[pkg->dep_length++] = best_installed; 
987 } 810 }
988 811
989 return status; 812 if (errc != 0)
990} 813 goto bomb;
991 814
992/* 815 /* If we're really installing, and have an installation file, run it */
993 * If this package uses pkg_views, register it in the default view. 816 if (!NoInstall && fexists(INSTALL_FNAME)) {
994 */ 817 (void) fexec(CHMOD_CMD, "+x", INSTALL_FNAME, NULL); /* make sure */
995static void 818 if (Verbose)
996pkg_register_views(struct pkg_task *pkg) 819 printf("Running install with PRE-INSTALL for %s.\n", PkgName);
997{ 820 errno = 0;
998 if (Fake || NoView || pkg->meta_data.meta_views == NULL) 821 if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "PRE-INSTALL", NULL)) {
999 return; 822 if (errno != 0)
1000 823 warn("exec of install script failed");
1001 if (Verbose) { 824 else
1002 printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n", 825 warnx("install script returned error status");
1003 BINDIR, _pkgdb_getPKGDB_DIR(), 826 errc = 1;
1004 View ? "-w " : "", View ? View : "", 827 goto success; /* nothing to uninstall yet */
1005 Viewbase ? "-W " : "", Viewbase ? Viewbase : "", 828 }
1006 Verbose ? "-v " : "", pkg->pkgname); 
1007 } 829 }
1008 830
1009 fexec_skipempty(BINDIR "/pkg_view", "-d", _pkgdb_getPKGDB_DIR(), 831 /*
1010 View ? "-w " : "", View ? View : "", 832 * Now finally extract the entire show if we're not going direct.
1011 Viewbase ? "-W " : "", Viewbase ? Viewbase : "", 833 * We need to reset the package dbdir so that extract_plist()
1012 Verbose ? "-v " : "", "add", pkg->pkgname, 834 * updates the correct pkgdb.byfile.db database.
1013 (void *)NULL); 835 */
1014} 
1015 
1016static int 
1017start_replacing(struct pkg_task *pkg) 
1018{ 
1019 char *old_required_by, *new_required_by; 
1020 
1021 old_required_by = pkgdb_pkg_file(pkg->other_version, 
1022 REQUIRED_BY_FNAME); 
1023 new_required_by = pkgdb_pkg_file(pkg->pkgname, 
1024 REQUIRED_BY_FNAME); 
1025 
1026 if (!Fake) { 836 if (!Fake) {
1027 if (rename(old_required_by, new_required_by) == -1 && 837 _pkgdb_setPKGDB_DIR(dbdir);
1028 errno != ENOENT) { 838 if (!extract_plist(".", &Plist)) {
1029 warn("Can't move +REQUIRED_BY from %s to %s", 839 errc = 1;
1030 old_required_by, new_required_by); 840 goto fail;
1031 return -1;  
1032 } 841 }
1033 } 842 }
1034 843
1035 if (Verbose || Fake) { 844 if (!Fake && fexists(MTREE_FNAME)) {
1036 printf("%s/pkg_delete -K %s -p %s '%s'\n", 845 warnx("Mtree file ignored for package %s", PkgName);
1037 BINDIR, _pkgdb_getPKGDB_DIR(), pkg->install_prefix, 
1038 pkg->other_version); 
1039 } 846 }
1040 if (!Fake) 
1041 fexec(BINDIR "/pkg_delete", "-K", _pkgdb_getPKGDB_DIR(), 
1042 "-p", pkg->install_prefix, 
1043 pkg->other_version, NULL); 
1044 
1045 /* XXX Check return value and do what? */ 
1046 return 0; 
1047} 
1048 847
1049/* 848 /* Run the installation script one last time? */
1050 * Install a single package. 849 if (!NoInstall && fexists(INSTALL_FNAME)) {
1051 */ 850 if (Verbose)
1052static int 851 printf("Running install with POST-INSTALL for %s.\n", PkgName);
1053pkg_do(const char *pkgpath, int mark_automatic) 852 if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "POST-INSTALL", NULL)) {
1054{ 853 warnx("install script returned error status");
1055 int status; 854 errc = 1;
1056 void *archive_cookie; 855 goto fail;
1057 struct pkg_task *pkg; 856 }
1058 
1059 if ((pkg = calloc(1, sizeof(*pkg))) == NULL) 
1060 err(2, "malloc failed"); 
1061 
1062 status = -1; 
1063 
1064 if ((pkg->archive = find_archive(pkgpath, &archive_cookie)) == NULL) { 
1065 warnx("no pkg found for '%s', sorry.", pkgpath); 
1066 goto clean_memory; 
1067 } 857 }
1068 if (read_meta_data(pkg)) 
1069 goto clean_memory; 
1070 858
1071 /* Parse PLIST early, so that messages can use real package name. */ 859 /* Time to record the deed? */
1072 if (pkg_parse_plist(pkg)) 860 if (!NoRecord && !Fake) {
1073 goto clean_memory; 861 char contents[MaxPathSize];
1074 862
1075 if (pkg->meta_data.meta_mtree != NULL) 863 if (!PkgName) {
1076 warnx("mtree specification in pkg `%s' ignored", pkg->pkgname); 864 warnx("no package name! can't record package, sorry");
 865 errc = 1;
 866 goto success; /* well, partial anyway */
 867 }
 868 (void) snprintf(LogDir, sizeof(LogDir), "%s/%s", dbdir, PkgName);
 869 zapLogDir = 1; /* LogDir contains something valid now */
 870 if (Verbose)
 871 printf("Attempting to record package into %s.\n", LogDir);
 872 if (make_hierarchy(LogDir)) {
 873 warnx("can't record package into '%s', you're on your own!",
 874 LogDir);
 875 memset(LogDir, 0, sizeof(LogDir));
 876 errc = 1;
 877 goto success; /* close enough for government work */
 878 }
 879 /* Make sure pkg_info can read the entry */
 880 (void) fexec(CHMOD_CMD, "a+rx", LogDir, NULL);
 881
 882 /* Move all of the +-files into place */
 883 move_files(".", "+*", LogDir);
 884
 885 /* Generate the +CONTENTS file in-place from the Plist */
 886 (void) snprintf(contents, sizeof(contents), "%s/%s", LogDir, CONTENTS_FNAME);
 887 cfile = fopen(contents, "w");
 888 if (!cfile) {
 889 warnx("can't open new contents file '%s'! can't register pkg",
 890 contents);
 891 goto success; /* can't log, but still keep pkg */
 892 }
 893 write_plist(&Plist, cfile, NULL);
 894 fclose(cfile);
 895
 896 /* register dependencies */
 897 /* we could save some cycles here if we remembered what we
 898 * installed above (in case we got a wildcard dependency) */
 899 /* XXX remembering in p->name would NOT be good! */
 900 for (p = Plist.head; p; p = p->next) {
 901 if (p->type != PLIST_PKGDEP)
 902 continue;
 903 if (Verbose)
 904 printf("Attempting to record dependency on package `%s'\n", p->name);
 905 (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir,
 906 basename_of(p->name));
 907 if (ispkgpattern(p->name)) {
 908 char *s;
1077 909
1078 if (pkg->meta_data.meta_views != NULL) { 910 s = find_best_matching_installed_pkg(p->name);
1079 if ((pkg->logdir = strdup(pkg->install_prefix)) == NULL) 
1080 err(EXIT_FAILURE, "strdup failed"); 
1081 _pkgdb_setPKGDB_DIR(dirname_of(pkg->logdir)); 
1082 } else { 
1083 if (asprintf(&pkg->logdir, "%s/%s", _pkgdb_getPKGDB_DIR(), 
1084 pkg->pkgname) == -1) 
1085 err(EXIT_FAILURE, "asprintf failed"); 
1086 } 
1087 911
1088 if (NoRecord && !Fake) { 912 if (s == NULL)
1089 const char *tmpdir; 913 errx(EXIT_FAILURE, "Where did our dependency go?!");
1090 914
1091 tmpdir = getenv("TMPDIR"); 915 (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir, s);
1092 if (tmpdir == NULL) 916 free(s);
1093 tmpdir = "/tmp"; 917 }
 918 strlcat(contents, "/", sizeof(contents));
 919 strlcat(contents, REQUIRED_BY_FNAME, sizeof(contents));
1094 920
1095 free(pkg->logdir); 921 cfile = fopen(contents, "a");
1096 if (asprintf(&pkg->logdir, "%s/pkg_install.XXXXXX", tmpdir) == -1) 922 if (!cfile)
1097 err(EXIT_FAILURE, "asprintf failed"); 923 warnx("can't open dependency file '%s'!\n"
1098 /* XXX pkg_add -u... */ 924 "dependency registration is incomplete", contents);
1099 if (mkdtemp(pkg->logdir) == NULL) { 925 else {
1100 warn("mkdtemp failed"); 926 fprintf(cfile, "%s\n", PkgName);
1101 goto clean_memory; 927 if (fclose(cfile) == EOF)
 928 warnx("cannot properly close file %s", contents);
 929 }
1102 } 930 }
 931 if (Automatic)
 932 mark_as_automatic_installed(PkgName, 1);
 933 if (Verbose)
 934 printf("Package %s registered in %s\n", PkgName, LogDir);
1103 } 935 }
1104 936
1105 if (check_already_installed(pkg) == 0) { 937 if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) {
1106 status = 0; 938 FILE *fp;
1107 goto clean_memory; 939 char buf[BUFSIZ];
 940
 941 (void) snprintf(buf, sizeof(buf), "%s/%s", LogDir, p->name);
 942 fp = fopen(buf, "r");
 943 if (fp) {
 944 putc('\n', stdout);
 945 while (fgets(buf, sizeof(buf), fp))
 946 fputs(buf, stdout);
 947 putc('\n', stdout);
 948 (void) fclose(fp);
 949 } else
 950 warnx("cannot open %s as display file", buf);
1108 } 951 }
1109 952
1110 if (read_buildinfo(pkg)) 953 /* Add the package to a default view. */
1111 goto clean_memory; 954 if (!Fake && !NoView && is_depoted_pkg) {
 955 if (Verbose) {
 956 printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n",
 957 BINDIR, dbdir,
 958 View ? "-w " : "", View ? View : "",
 959 Viewbase ? "-W " : "", Viewbase ? Viewbase : "",
 960 Verbose ? "-v " : "", PkgName);
 961 }
1112 962
1113 if (check_platform(pkg)) 963 fexec_skipempty(BINDIR "/pkg_view", "-d", dbdir,
1114 goto clean_memory; 964 View ? "-w " : "", View ? View : "",
 965 Viewbase ? "-W " : "", Viewbase ? Viewbase : "",
 966 Verbose ? "-v " : "", "add", PkgName, NULL);
 967 }
 968
 969 goto success;
1115 970
1116 if (check_other_installed(pkg)) 971bomb:
1117 goto clean_memory;  972 errc = 1;
 973 goto success;
1118 974
1119 if (check_explicit_conflict(pkg)) 975fail:
1120 goto clean_memory; 976 /* Nuke the whole (installed) show, XXX but don't clean directories */
 977 if (!Fake)
 978 delete_package(FALSE, FALSE, &Plist, FALSE);
1121 979
1122 if (check_implicit_conflict(pkg)) 980success:
1123 goto clean_memory; 981 /* delete the packing list contents */
 982 free_plist(&Plist);
 983 leave_playpen(Home);
1124 984
1125 if (pkg->other_version != NULL) { 985 if (replacing) {
1126 /* 986 /*
1127 * Replacing an existing package. 987 * Upgrade step 3/4: move back +REQUIRED_BY file
1128 * Write meta-data, get rid of the old version, 988 * (see also step 2/4)
1129 * install/update dependencies and finally extract. 
1130 */ 989 */
1131 if (write_meta_data(pkg)) 990 if (rename(replace_via, replace_to) != 0)
1132 goto nuke_pkgdb; 991 err(EXIT_FAILURE, "renaming \"%s\" to \"%s\" failed", replace_via, replace_to);
1133 992
1134 if (start_replacing(pkg)) 
1135 goto nuke_pkgdb; 
1136 
1137 if (check_dependencies(pkg)) 
1138 goto nuke_pkgdb; 
1139 } else { 
1140 /* 993 /*
1141 * Normal installation. 994 * Upgrade step 4/4: Fix pkgs that depend on us to
1142 * Install/update dependencies first and 995 * depend on the new version instead of the old
1143 * write the current package to disk afterwards. 996 * one by fixing @pkgdep lines in +CONTENTS files.
1144 */  997 */
1145 if (check_dependencies(pkg)) 998 /* TODO */
1146 goto clean_memory; 
1147 
1148 if (write_meta_data(pkg)) 
1149 goto nuke_pkgdb; 
1150 } 999 }
1151 1000
1152 if (run_install_script(pkg, "PRE-INSTALL")) 1001 return errc;
1153 goto nuke_pkgdb; 1002}
1154 
1155 if (extract_files(pkg)) 
1156 goto nuke_pkg; 
1157 
1158 if (run_install_script(pkg, "POST-INSTALL")) 
1159 goto nuke_pkgdb; 
1160 
1161 /* XXX keep +INSTALL_INFO for updates? */ 
1162 /* XXX keep +PRESERVE for updates? */ 
1163 if (mark_automatic) 
1164 mark_as_automatic_installed(pkg->pkgname, 1); 
1165 
1166 pkg_register_depends(pkg); 
1167 
1168 if (Verbose) 
1169 printf("Package %s registered in %s\n", pkg->pkgname, pkg->logdir); 
1170 
1171 if (pkg->meta_data.meta_display != NULL) 
1172 fputs(pkg->meta_data.meta_display, stdout); 
1173 1003
1174 pkg_register_views(pkg); 1004void
 1005cleanup(int signo)
 1006{
 1007 static int alreadyCleaning;
 1008 void (*oldint) (int);
 1009 void (*oldhup) (int);
 1010 int saved_errno;
1175 1011
1176 status = 0; 1012 saved_errno = errno;
1177 goto clean_memory; 1013 oldint = signal(SIGINT, SIG_IGN);
 1014 oldhup = signal(SIGHUP, SIG_IGN);
1178 1015
1179nuke_pkg: 1016 if (!alreadyCleaning) {
1180 if (!Fake) { 1017 alreadyCleaning = 1;
1181 if (pkg->other_version) { 1018 if (signo)
1182 warnx("Updating of %s to %s failed.", 1019 printf("Signal %d received, cleaning up.\n", signo);
1183 pkg->other_version, pkg->pkgname); 1020 if (!Fake && zapLogDir && LogDir[0])
1184 warnx("Remember to run pkg_admin rebuild-tree after fixing this."); 1021 (void) fexec(REMOVE_CMD, "-fr", LogDir, NULL);
1185 } 1022 leave_playpen(Home);
1186 delete_package(FALSE, FALSE, &pkg->plist, FALSE); 1023 if (signo)
 1024 exit(1);
1187 } 1025 }
1188 1026 signal(SIGINT, oldint);
1189nuke_pkgdb: 1027 signal(SIGHUP, oldhup);
1190 if (!Fake) { 1028 errno = saved_errno;
1191 (void) fexec(REMOVE_CMD, "-fr", pkg->logdir, (void *)NULL); 
1192 free(pkg->logdir); 
1193 pkg->logdir = NULL; 
1194 } 
1195 
1196clean_memory: 
1197 if (pkg->logdir != NULL && NoRecord && !Fake) 
1198 (void) fexec(REMOVE_CMD, "-fr", pkg->logdir, (void *)NULL); 
1199 free(pkg->logdir); 
1200 free_buildinfo(pkg); 
1201 free_plist(&pkg->plist); 
1202 free_meta_data(pkg); 
1203 if (pkg->archive) { 
1204 archive_read_close(pkg->archive); 
1205 close_archive(archive_cookie); 
1206 } 
1207 free(pkg->other_version); 
1208 free(pkg); 
1209 return status; 
1210} 1029}
1211 1030
1212int 1031int
1213pkg_perform(lpkg_head_t *pkgs) 1032pkg_perform(lpkg_head_t *pkgs)
1214{ 1033{
1215 int errors = 0; 1034 int err_cnt = 0;
1216 lpkg_t *lpp; 1035 lpkg_t *lpp;
1217 1036
 1037 signal(SIGINT, cleanup);
 1038 signal(SIGHUP, cleanup);
 1039
 1040 TAILQ_INIT(&files);
 1041
1218 while ((lpp = TAILQ_FIRST(pkgs)) != NULL) { 1042 while ((lpp = TAILQ_FIRST(pkgs)) != NULL) {
1219 path_prepend_from_pkgname(lpp->lp_name); 1043 path_prepend_from_pkgname(lpp->lp_name);
1220 if (pkg_do(lpp->lp_name, Automatic)) 1044 err_cnt += pkg_do(lpp->lp_name, pkgs);
1221 ++errors; 
1222 path_prepend_clear(); 1045 path_prepend_clear();
1223 TAILQ_REMOVE(pkgs, lpp, lp_link); 1046 TAILQ_REMOVE(pkgs, lpp, lp_link);
1224 free_lpkg(lpp); 1047 free_lpkg(lpp);
1225 } 1048 }
1226 1049
1227 return errors; 1050 ftp_stop();
 1051
 1052 return err_cnt;
1228} 1053}

cvs diff -r1.29 -r1.30 pkgsrc/pkgtools/pkg_install/files/add/pkg_add.1 (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/add/pkg_add.1 2008/04/26 14:56:34 1.29
+++ pkgsrc/pkgtools/pkg_install/files/add/pkg_add.1 2008/04/26 17:40:01 1.30
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1.\" $NetBSD: pkg_add.1,v 1.29 2008/04/26 14:56:34 joerg Exp $ 1.\" $NetBSD: pkg_add.1,v 1.30 2008/04/26 17:40:01 joerg Exp $
2.\" 2.\"
3.\" FreeBSD install - a package for the installation and maintenance 3.\" FreeBSD install - a package for the installation and maintenance
4.\" of non-core utilities. 4.\" of non-core utilities.
5.\" 5.\"
6.\" Redistribution and use in source and binary forms, with or without 6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions 7.\" modification, are permitted provided that the following conditions
8.\" are met: 8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright 9.\" 1. Redistributions of source code must retain the above copyright
10.\" notice, this list of conditions and the following disclaimer. 10.\" notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\" notice, this list of conditions and the following disclaimer in the 12.\" notice, this list of conditions and the following disclaimer in the
13.\" documentation and/or other materials provided with the distribution. 13.\" documentation and/or other materials provided with the distribution.
14.\" 14.\"
@@ -20,26 +20,27 @@ @@ -20,26 +20,27 @@
20.Dd August 23, 2007 20.Dd August 23, 2007
21.Dt PKG_ADD 1 21.Dt PKG_ADD 1
22.Os 22.Os
23.Sh NAME 23.Sh NAME
24.Nm pkg_add 24.Nm pkg_add
25.Nd a utility for installing and upgrading software package distributions 25.Nd a utility for installing and upgrading software package distributions
26.Sh SYNOPSIS 26.Sh SYNOPSIS
27.Nm 27.Nm
28.Op Fl AfILnRuVv 28.Op Fl AfILnRuVv
29.Op Fl K Ar pkg_dbdir 29.Op Fl K Ar pkg_dbdir
30.Op Fl m Ar machine 30.Op Fl m Ar machine
31.Op Fl p Ar prefix 31.Op Fl p Ar prefix
32.Op Fl s Ar verification-type 32.Op Fl s Ar verification-type
 33.Op Fl t Ar template
33.Op Fl W Ar viewbase 34.Op Fl W Ar viewbase
34.Op Fl w Ar view 35.Op Fl w Ar view
35.Ar \fR[[ftp|http]://[\fIuser\fR[:\fIpassword]\fR@]\fIhost\fR[:\fIport\fR]][/\fIpath/\fR]pkg-name ... 36.Ar \fR[[ftp|http]://[\fIuser\fR[:\fIpassword]\fR@]\fIhost\fR[:\fIport\fR]][/\fIpath/\fR]pkg-name ...
36.Sh DESCRIPTION 37.Sh DESCRIPTION
37The 38The
38.Nm 39.Nm
39command is used to extract and upgrade packages that have been 40command is used to extract and upgrade packages that have been
40previously created with the 41previously created with the
41.Xr pkg_create 1 42.Xr pkg_create 1
42command. 43command.
43Packages are prepared collections of pre-built binaries, documentation, 44Packages are prepared collections of pre-built binaries, documentation,
44configurations, installation instructions and/or other files. 45configurations, installation instructions and/or other files.
45.Nm 46.Nm
@@ -149,51 +150,73 @@ as the directory in which to extract fil @@ -149,51 +150,73 @@ as the directory in which to extract fil
149If a package has set its default directory, it will be overridden 150If a package has set its default directory, it will be overridden
150by this flag. 151by this flag.
151Note that only the first 152Note that only the first
152.Cm @cwd 153.Cm @cwd
153directive will be replaced, since 154directive will be replaced, since
154.Nm 155.Nm
155has no way of knowing which directory settings are relative and 156has no way of knowing which directory settings are relative and
156which are absolute. 157which are absolute.
157Only one directory transition is supported and the second one is expected to go 158Only one directory transition is supported and the second one is expected to go
158into 159into
159.Ar pkgdb . 160.Ar pkgdb .
160.It Fl R 161.It Fl R
161Do not record the installation of a package. 162Do not record the installation of a package.
162This implies  
163.Fl I . 
164This means that you cannot deinstall it later, so only use this option if 163This means that you cannot deinstall it later, so only use this option if
165you know what you are doing! 164you know what you are doing!
166.It Fl s Ar verification-type 165.It Fl s Ar verification-type
167Use a callout to an external program to verify the binary package 166Use a callout to an external program to verify the binary package
168being installed against an existing detached signature file. 167being installed against an existing detached signature file.
169The signature file must reside in the same directory 168The signature file must reside in the same directory
170as the binary package. 169as the binary package.
171At the present time, the following verification types 170At the present time, the following verification types
172are defined: none, gpg and pgp5. 171are defined: none, gpg and pgp5.
173The signature will be verified at install time, and the results 172The signature will be verified at install time, and the results
174will be displayed. 173will be displayed.
175If the signature type is anything other than none, the user will be asked if 174If the signature type is anything other than none, the user will be asked if
176.Nm 175.Nm
177should proceed to install the binary package. 176should proceed to install the binary package.
178The user must then take the decision whether to proceed or not, depending 177The user must then take the decision whether to proceed or not, depending
179upon the amount of trust that is placed in the signatory of the binary 178upon the amount of trust that is placed in the signatory of the binary
180package. 179package.
181Please note that, at the current time, it is not possible to use 180Please note that, at the current time, it is not possible to use
182the verification feature when using 181the verification feature when using
183.Nm 182.Nm
184to add a binary package via a URL - the package, and the related 183to add a binary package via a URL - the package, and the related
185detached signature file, must be local 184detached signature file, must be local
186for the verification to work. 185for the verification to work.
 186.It Fl t Ar template
 187Use
 188.Ar template
 189as the input to
 190.Xr mktemp 3
 191when creating a
 192.Dq staging area .
 193By default, this is the string
 194.Pa /var/tmp/instmp.XXXXXX ,
 195but it may be necessary to override it in the situation where
 196space in your
 197.Pa /var/tmp
 198directory is limited.
 199Be sure to leave some number of
 200.Sq X
 201characters for
 202.Xr mktemp 3
 203to fill in with a unique ID.
 204.Pp
 205You can get a performance boost by setting the staging area
 206.Ar template
 207to reside on the same disk partition as target directories for package
 208file installation; often this is
 209.Pa /usr .
187.It Fl u 210.It Fl u
188If the package that's being installed is already installed, either 211If the package that's being installed is already installed, either
189in the same or a different version, an update is performed. 212in the same or a different version, an update is performed.
190If this is specified twice, then any dependant packages that are 213If this is specified twice, then any dependant packages that are
191too old will also be updated to fulfill the dependency. 214too old will also be updated to fulfill the dependency.
192See below for a more detailed description of the process. 215See below for a more detailed description of the process.
193.It Fl V 216.It Fl V
194Print version number and exit. 217Print version number and exit.
195.It Fl v 218.It Fl v
196Turn on verbose output. 219Turn on verbose output.
197.It Fl W Ar viewbase 220.It Fl W Ar viewbase
198Set 221Set
199.Ar viewbase 222.Ar viewbase
@@ -242,30 +265,31 @@ FTP_PASSIVE_MODE @@ -242,30 +265,31 @@ FTP_PASSIVE_MODE
242.Ef 265.Ef
243to some value in your environment. 266to some value in your environment.
244Otherwise, the more standard ACTIVE mode may be used. 267Otherwise, the more standard ACTIVE mode may be used.
245If 268If
246.Nm 269.Nm
247consistently fails to fetch a package from a site known to work, 270consistently fails to fetch a package from a site known to work,
248it may be because you have a firewall that demands the usage of 271it may be because you have a firewall that demands the usage of
249.Bf -emphasis 272.Bf -emphasis
250passive mode 273passive mode
251.Ef 274.Ef
252ftp. 275ftp.
253.Sh TECHNICAL DETAILS 276.Sh TECHNICAL DETAILS
254.Nm 277.Nm
255extracts each package's meta data (including the 278extracts each package's
256.Dq packing list ) 279.Dq packing list
257to memory and then runs through the following sequence to fully extract 280into a special staging directory in /var/tmp (or $PKG_TMPDIR if set)
258the contents of the package: 281and then runs through the following sequence to fully extract the contents
 282of the package:
259.Bl -enum -offset indent 283.Bl -enum -offset indent
260.It 284.It
261A check is made to determine if the package or another version of it 285A check is made to determine if the package or another version of it
262is already recorded as installed. 286is already recorded as installed.
263If it is, 287If it is,
264installation is terminated if the 288installation is terminated if the
265.Fl u 289.Fl u
266option is not given. 290option is not given.
267.Pp 291.Pp
268If the 292If the
269.Fl u 293.Fl u
270option is given, it's assumed the package should be replaced by the 294option is given, it's assumed the package should be replaced by the
271new version instead. 295new version instead.

cvs diff -r1.20 -r1.21 pkgsrc/pkgtools/pkg_install/files/create/perform.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/create/perform.c 2008/04/26 14:56:34 1.20
+++ pkgsrc/pkgtools/pkg_install/files/create/perform.c 2008/04/26 17:40:01 1.21
@@ -1,27 +1,27 @@ @@ -1,27 +1,27 @@
1/* $NetBSD: perform.c,v 1.20 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: perform.c,v 1.21 2008/04/26 17:40:01 joerg Exp $ */
2 2
3#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
4#include "config.h" 4#include "config.h"
5#endif 5#endif
6#include <nbcompat.h> 6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#endif 9#endif
10#ifndef lint 10#ifndef lint
11#if 0 11#if 0
12static const char *rcsid = "from FreeBSD Id: perform.c,v 1.38 1997/10/13 15:03:51 jkh Exp"; 12static const char *rcsid = "from FreeBSD Id: perform.c,v 1.38 1997/10/13 15:03:51 jkh Exp";
13#else 13#else
14__RCSID("$NetBSD: perform.c,v 1.20 2008/04/26 14:56:34 joerg Exp $"); 14__RCSID("$NetBSD: perform.c,v 1.21 2008/04/26 17:40:01 joerg Exp $");
15#endif 15#endif
16#endif 16#endif
17 17
18/* 18/*
19 * FreeBSD install - a package for the installation and maintainance 19 * FreeBSD install - a package for the installation and maintainance
20 * of non-core utilities. 20 * of non-core utilities.
21 * 21 *
22 * Redistribution and use in source and binary forms, with or without 22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions 23 * modification, are permitted provided that the following conditions
24 * are met: 24 * are met:
25 * 1. Redistributions of source code must retain the above copyright 25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer. 26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright 27 * 2. Redistributions in binary form must reproduce the above copyright
@@ -81,58 +81,26 @@ register_depends(package_t *plist, char  @@ -81,58 +81,26 @@ register_depends(package_t *plist, char
81 free(best_installed); 81 free(best_installed);
82 if (!build_only) { 82 if (!build_only) {
83 add_plist(plist, PLIST_PKGDEP, cp); 83 add_plist(plist, PLIST_PKGDEP, cp);
84 if (Verbose && !PlistOnly) 84 if (Verbose && !PlistOnly)
85 printf(" %s", cp); 85 printf(" %s", cp);
86 } 86 }
87 } 87 }
88 } 88 }
89 if (Verbose && !PlistOnly) 89 if (Verbose && !PlistOnly)
90 printf(".\n"); 90 printf(".\n");
91} 91}
92 92
93/* 93/*
94 * Expect "fname" to point at a file, and read it into 
95 * the buffer returned. 
96 */ 
97static char * 
98fileGetContents(char *fname) 
99{ 
100 char *contents; 
101 struct stat sb; 
102 int fd; 
103 
104 if (stat(fname, &sb) == FAIL) { 
105 cleanup(0); 
106 errx(2, "can't stat '%s'", fname); 
107 } 
108 
109 contents = (char *) malloc((size_t) (sb.st_size) + 1); 
110 fd = open(fname, O_RDONLY, 0); 
111 if (fd == FAIL) { 
112 cleanup(0); 
113 errx(2, "unable to open '%s' for reading", fname); 
114 } 
115 if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) { 
116 cleanup(0); 
117 errx(2, "short read on '%s' - did not get %lld bytes", 
118 fname, (long long) sb.st_size); 
119 } 
120 close(fd); 
121 contents[(size_t) sb.st_size] = '\0'; 
122 return contents; 
123} 
124 
125/* 
126 * Get a string parameter as a file spec or as a "contents follow -" spec 94 * Get a string parameter as a file spec or as a "contents follow -" spec
127 */ 95 */
128static void 96static void
129get_dash_string(char **s) 97get_dash_string(char **s)
130{ 98{
131 if (**s == '-') 99 if (**s == '-')
132 *s = strdup(*s + 1); 100 *s = strdup(*s + 1);
133 else 101 else
134 *s = fileGetContents(*s);  102 *s = fileGetContents(*s);
135} 103}
136 104
137int 105int
138pkg_perform(const char *pkg) 106pkg_perform(const char *pkg)

cvs diff -r1.15 -r1.16 pkgsrc/pkgtools/pkg_install/files/info/Makefile.in (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/info/Makefile.in 2008/04/26 14:56:34 1.15
+++ pkgsrc/pkgtools/pkg_install/files/info/Makefile.in 2008/04/26 17:40:01 1.16
@@ -1,32 +1,32 @@ @@ -1,32 +1,32 @@
1# $NetBSD: Makefile.in,v 1.15 2008/04/26 14:56:34 joerg Exp $ 1# $NetBSD: Makefile.in,v 1.16 2008/04/26 17:40:01 joerg Exp $
2 2
3srcdir= @srcdir@ 3srcdir= @srcdir@
4 4
5prefix= @prefix@ 5prefix= @prefix@
6exec_prefix= @exec_prefix@ 6exec_prefix= @exec_prefix@
7sbindir= @sbindir@ 7sbindir= @sbindir@
8mandir= @mandir@ 8mandir= @mandir@
9datarootdir= @datarootdir@ 9datarootdir= @datarootdir@
10 10
11man1dir= $(mandir)/man1 11man1dir= $(mandir)/man1
12cat1dir= $(mandir)/cat1 12cat1dir= $(mandir)/cat1
13 13
14BOOTSTRAP= @bootstrap@ 14BOOTSTRAP= @bootstrap@
15 15
16CC= @CC@ 16CC= @CC@
17CCLD= $(CC) 17CCLD= $(CC)
18.if empty(BOOTSTRAP) 18.if empty(BOOTSTRAP)
19LIBS= -linstall -larchive -lfetch -lbz2 -lz @LIBS@ 19LIBS= -linstall -larchive -lbz2 -lfetch -lz @LIBS@
20CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib 20CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib
21.else 21.else
22LIBS= -linstall @LIBS@ 22LIBS= -linstall @LIBS@
23CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib -DBOOTSTRAP 23CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib -DBOOTSTRAP
24.endif 24.endif
25DEFS= @DEFS@ 25DEFS= @DEFS@
26CFLAGS= @CFLAGS@ 26CFLAGS= @CFLAGS@
27LDFLAGS= @LDFLAGS@ -L../lib 27LDFLAGS= @LDFLAGS@ -L../lib
28 28
29INSTALL= @INSTALL@ 29INSTALL= @INSTALL@
30 30
31PROG= pkg_info 31PROG= pkg_info
32 32

cvs diff -r1.47 -r1.48 pkgsrc/pkgtools/pkg_install/files/info/perform.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/info/perform.c 2008/04/26 14:56:34 1.47
+++ pkgsrc/pkgtools/pkg_install/files/info/perform.c 2008/04/26 17:40:01 1.48
@@ -1,33 +1,33 @@ @@ -1,33 +1,33 @@
1/* $NetBSD: perform.c,v 1.47 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: perform.c,v 1.48 2008/04/26 17:40:01 joerg Exp $ */
2 2
3#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
4#include "config.h" 4#include "config.h"
5#endif 5#endif
6#include <nbcompat.h> 6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#endif 9#endif
10#if HAVE_SYS_QUEUE_H 10#if HAVE_SYS_QUEUE_H
11#include <sys/queue.h> 11#include <sys/queue.h>
12#endif 12#endif
13#if HAVE_SYS_WAIT_H 13#if HAVE_SYS_WAIT_H
14#include <sys/wait.h> 14#include <sys/wait.h>
15#endif 15#endif
16#ifndef lint 16#ifndef lint
17#if 0 17#if 0
18static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp"; 18static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp";
19#else 19#else
20__RCSID("$NetBSD: perform.c,v 1.47 2008/04/26 14:56:34 joerg Exp $"); 20__RCSID("$NetBSD: perform.c,v 1.48 2008/04/26 17:40:01 joerg Exp $");
21#endif 21#endif
22#endif 22#endif
23 23
24/*- 24/*-
25 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. 25 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
26 * All rights reserved. 26 * All rights reserved.
27 * 27 *
28 * Redistribution and use in source and binary forms, with or without 28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions 29 * modification, are permitted provided that the following conditions
30 * are met: 30 * are met:
31 * 31 *
32 * 1. Redistributions of source code must retain the above copyright 32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer. 33 * notice, this list of conditions and the following disclaimer.
@@ -116,27 +116,27 @@ __RCSID("$NetBSD: perform.c,v 1.47 2008/ @@ -116,27 +116,27 @@ __RCSID("$NetBSD: perform.c,v 1.47 2008/
116#define LOAD_SIZE_PKG (1 << 9) 116#define LOAD_SIZE_PKG (1 << 9)
117#define LOAD_SIZE_ALL (1 << 10) 117#define LOAD_SIZE_ALL (1 << 10)
118#define LOAD_PRESERVE (1 << 11) 118#define LOAD_PRESERVE (1 << 11)
119#define LOAD_VIEWS (1 << 12) 119#define LOAD_VIEWS (1 << 12)
120#define LOAD_REQUIRED_BY (1 << 13) 120#define LOAD_REQUIRED_BY (1 << 13)
121#define LOAD_INSTALLED_INFO (1 << 14) 121#define LOAD_INSTALLED_INFO (1 << 14)
122 122
123static const struct pkg_meta_desc { 123static const struct pkg_meta_desc {
124 size_t entry_offset; 124 size_t entry_offset;
125 const char *entry_filename; 125 const char *entry_filename;
126 int entry_mask; 126 int entry_mask;
127 int required_file; 127 int required_file;
128} pkg_meta_descriptors[] = { 128} pkg_meta_descriptors[] = {
129 { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 129 { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME ,
130 LOAD_CONTENTS, 1}, 130 LOAD_CONTENTS, 1},
131 { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 131 { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME,
132 LOAD_COMMENT, 1 }, 132 LOAD_COMMENT, 1 },
133 { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 133 { offsetof(struct pkg_meta, meta_desc), DESC_FNAME,
134 LOAD_DESC, 1 }, 134 LOAD_DESC, 1 },
135 { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 135 { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME,
136 LOAD_INSTALL, 0 }, 136 LOAD_INSTALL, 0 },
137 { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 137 { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME,
138 LOAD_DEINSTALL, 0 }, 138 LOAD_DEINSTALL, 0 },
139 { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 139 { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME,
140 LOAD_DISPLAY, 0 }, 140 LOAD_DISPLAY, 0 },
141 { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 141 { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME,
142 LOAD_MTREE, 0 }, 142 LOAD_MTREE, 0 },
@@ -292,39 +292,50 @@ read_meta_data_from_pkgdb(const char *pk @@ -292,39 +292,50 @@ read_meta_data_from_pkgdb(const char *pk
292 return meta; 292 return meta;
293} 293}
294 294
295static lfile_head_t files; 295static lfile_head_t files;
296 296
297static int 297static int
298pkg_do(const char *pkg) 298pkg_do(const char *pkg)
299{ 299{
300 struct pkg_meta *meta; 300 struct pkg_meta *meta;
301 char log_dir[MaxPathSize]; 301 char log_dir[MaxPathSize];
302 int code = 0; 302 int code = 0;
303 const char *binpkgfile = NULL; 303 const char *binpkgfile = NULL;
304 304
305 if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) { 305 if (IS_URL(pkg)) {
 306#ifdef BOOTSTRAP
 307 errx(2, "Remote access not supported during bootstrap");
 308#else
 309 struct archive *archive;
 310 void *remote_archive_cookie;
 311
 312 archive = open_remote_archive(pkg, &remote_archive_cookie);
 313
 314 meta = read_meta_data_from_archive(archive);
 315 close_remote_archive(remote_archive_cookie);
 316#endif
 317 } else if (fexists(pkg) && isfile(pkg)) {
306#ifdef BOOTSTRAP 318#ifdef BOOTSTRAP
307 errx(2, "Binary packages not supported during bootstrap"); 319 errx(2, "Binary packages not supported during bootstrap");
308#else 320#else
309 struct archive *archive; 321 struct archive *archive;
310 void *archive_cookie; 322 void *remote_archive_cookie;
311 323
312 archive = open_archive(pkg, &archive_cookie); 324 archive = open_local_archive(pkg, &remote_archive_cookie);
313 325
314 meta = read_meta_data_from_archive(archive); 326 meta = read_meta_data_from_archive(archive);
315 close_archive(archive_cookie); 327 close_local_archive(remote_archive_cookie);
316 if (!IS_URL(pkg)) 328 binpkgfile = pkg;
317 binpkgfile = pkg; 
318#endif 329#endif
319 } else { 330 } else {
320 /* 331 /*
321 * It's not an uninstalled package, try and find it among the 332 * It's not an uninstalled package, try and find it among the
322 * installed 333 * installed
323 */ 334 */
324 (void) snprintf(log_dir, sizeof(log_dir), "%s/%s", 335 (void) snprintf(log_dir, sizeof(log_dir), "%s/%s",
325 _pkgdb_getPKGDB_DIR(), pkg); 336 _pkgdb_getPKGDB_DIR(), pkg);
326 if (!fexists(log_dir) || !(isdir(log_dir) || islinktodir(log_dir))) { 337 if (!fexists(log_dir) || !(isdir(log_dir) || islinktodir(log_dir))) {
327 switch (add_installed_pkgs_by_basename(pkg, &pkgs)) { 338 switch (add_installed_pkgs_by_basename(pkg, &pkgs)) {
328 case 1: 339 case 1:
329 return 0; 340 return 0;
330 case 0: 341 case 0:

cvs diff -r1.22 -r1.23 pkgsrc/pkgtools/pkg_install/files/lib/Makefile.in (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/Makefile.in 2008/04/26 14:56:34 1.22
+++ pkgsrc/pkgtools/pkg_install/files/lib/Makefile.in 2008/04/26 17:40:01 1.23
@@ -1,45 +1,45 @@ @@ -1,45 +1,45 @@
1# $NetBSD: Makefile.in,v 1.22 2008/04/26 14:56:34 joerg Exp $ 1# $NetBSD: Makefile.in,v 1.23 2008/04/26 17:40:01 joerg Exp $
2 2
3srcdir= @srcdir@ 3srcdir= @srcdir@
4 4
5pkgdbdir= @pkgdbdir@ 5pkgdbdir= @pkgdbdir@
6mandir= @mandir@ 6mandir= @mandir@
7datarootdir= @datarootdir@ 7datarootdir= @datarootdir@
8 8
9cat5dir= $(mandir)/cat5 9cat5dir= $(mandir)/cat5
10cat7dir= $(mandir)/cat7 10cat7dir= $(mandir)/cat7
11man5dir= $(mandir)/man5 11man5dir= $(mandir)/man5
12man7dir= $(mandir)/man7 12man7dir= $(mandir)/man7
13 13
14tar= @tar@ 14tar= @tar@
15ftp= @ftp@ 15ftp= @ftp@
16 16
17BOOTSTRAP= @bootstrap@ 17BOOTSTRAP= @bootstrap@
18 18
19RANLIB= @RANLIB@ 19RANLIB= @RANLIB@
20AR= @AR@ 20AR= @AR@
21CC= @CC@ 21CC= @CC@
22CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) 22CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir)
23DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" 23DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" -DTAR_CMD=\"$(tar)\" -DFTP_CMD=\"$(ftp)\"
24CFLAGS= @CFLAGS@ 24CFLAGS= @CFLAGS@
25 25
26INSTALL= @INSTALL@ 26INSTALL= @INSTALL@
27 27
28LIB= libinstall.a 28LIB= libinstall.a
29 29
30OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \ 30OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \
31 global.o iterate.o lpkg.o opattern.o \ 31 ftpio.o global.o iterate.o lpkg.o opattern.o \
32 path.o pkgdb.o plist.o \ 32 path.o pen.o pexec.o pkgdb.o plist.o \
33 str.o var.o version.o vulnerabilities-file.o 33 str.o var.o version.o vulnerabilities-file.o
34 34
35.if !empty(BOOTSTRAP) 35.if !empty(BOOTSTRAP)
36CPPFLAGS+= -DBOOTSTRAP 36CPPFLAGS+= -DBOOTSTRAP
37.else 37.else
38OBJS+= pkg_io.o 38OBJS+= pkg_io.o
39.endif 39.endif
40 40
41all: $(LIB) 41all: $(LIB)
42 42
43.c.o: 43.c.o:
44 $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< 44 $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
45 45

cvs diff -r1.5 -r1.6 pkgsrc/pkgtools/pkg_install/files/lib/conflicts.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/conflicts.c 2008/04/26 14:56:34 1.5
+++ pkgsrc/pkgtools/pkg_install/files/lib/conflicts.c 2008/04/26 17:40:01 1.6
@@ -20,27 +20,26 @@ @@ -20,27 +20,26 @@
20#include "dewey.h" 20#include "dewey.h"
21#include "lib.h" 21#include "lib.h"
22 22
23/** 23/**
24 * Data structure to keep the intermediate result of the conflict 24 * Data structure to keep the intermediate result of the conflict
25 * search. ''pkgname'' is the package in question. The first 25 * search. ''pkgname'' is the package in question. The first
26 * installed package that conflicts is filled into 26 * installed package that conflicts is filled into
27 * ''conflicting_pkgname''. The pattern that leads to the conflict is 27 * ''conflicting_pkgname''. The pattern that leads to the conflict is
28 * also filled in to help the user in deciding what to do with the 28 * also filled in to help the user in deciding what to do with the
29 * conflict. 29 * conflict.
30 */ 30 */
31struct package_conflict { 31struct package_conflict {
32 const char *pkgname; 32 const char *pkgname;
33 const char *skip_pkgname; 
34 char **conflicting_pkgname; 33 char **conflicting_pkgname;
35 char **conflicting_pattern; 34 char **conflicting_pattern;
36}; 35};
37 36
38static void * 37static void *
39nonnull(void *p) 38nonnull(void *p)
40{ 39{
41 40
42 if (p == NULL) { 41 if (p == NULL) {
43 err(EXIT_FAILURE, "NullPointerException"); 42 err(EXIT_FAILURE, "NullPointerException");
44 /* NOTREACHED */ 43 /* NOTREACHED */
45 } 44 }
46 return p; 45 return p;
@@ -61,30 +60,26 @@ fopen_contents(const char *pkgname, cons @@ -61,30 +60,26 @@ fopen_contents(const char *pkgname, cons
61 return f; 60 return f;
62} 61}
63 62
64 63
65static int 64static int
66check_package_conflict(const char *pkgname, void *v) 65check_package_conflict(const char *pkgname, void *v)
67{ 66{
68 struct package_conflict *conflict = v; 67 struct package_conflict *conflict = v;
69 package_t pkg; 68 package_t pkg;
70 plist_t *p; 69 plist_t *p;
71 FILE *f; 70 FILE *f;
72 int rv; 71 int rv;
73 72
74 if (conflict->skip_pkgname != NULL && 
75 strcmp(conflict->skip_pkgname, pkgname) == 0) 
76 return 0; 
77 
78 rv = 0; 73 rv = 0;
79 pkg.head = NULL; 74 pkg.head = NULL;
80 pkg.tail = NULL; 75 pkg.tail = NULL;
81 76
82 f = fopen_contents(pkgname, "r"); 77 f = fopen_contents(pkgname, "r");
83 read_plist(&pkg, f); 78 read_plist(&pkg, f);
84 (void)fclose(f); 79 (void)fclose(f);
85 80
86 for (p = pkg.head; p; p = p->next) { 81 for (p = pkg.head; p; p = p->next) {
87 if (p->type != PLIST_PKGCFL) 82 if (p->type != PLIST_PKGCFL)
88 continue; 83 continue;
89 84
90 if (pkg_match(p->name, conflict->pkgname) == 1) { 85 if (pkg_match(p->name, conflict->pkgname) == 1) {
@@ -97,34 +92,32 @@ check_package_conflict(const char *pkgna @@ -97,34 +92,32 @@ check_package_conflict(const char *pkgna
97 92
98 free_plist(&pkg); 93 free_plist(&pkg);
99 return rv; 94 return rv;
100} 95}
101 96
102/** 97/**
103 * Checks if some installed package has a pkgcfl entry that matches 98 * Checks if some installed package has a pkgcfl entry that matches
104 * PkgName. If such an entry is found, the package name is returned in 99 * PkgName. If such an entry is found, the package name is returned in
105 * inst_pkgname, the matching pattern in inst_pattern, and the function 100 * inst_pkgname, the matching pattern in inst_pattern, and the function
106 * returns a non-zero value. Otherwise, zero is returned and the result 101 * returns a non-zero value. Otherwise, zero is returned and the result
107 * variables are set to NULL. 102 * variables are set to NULL.
108 */ 103 */
109int 104int
110some_installed_package_conflicts_with(const char *pkgname, 105some_installed_package_conflicts_with(const char *pkgname, char **inst_pkgname, char **inst_pattern)
111 const char *skip_pkgname, char **inst_pkgname, char **inst_pattern) 
112{ 106{
113 struct package_conflict cfl; 107 struct package_conflict cfl;
114 int rv; 108 int rv;
115 109
116 cfl.pkgname = pkgname; 110 cfl.pkgname = pkgname;
117 cfl.skip_pkgname = skip_pkgname; 
118 *inst_pkgname = NULL; 111 *inst_pkgname = NULL;
119 *inst_pattern = NULL; 112 *inst_pattern = NULL;
120 cfl.conflicting_pkgname = inst_pkgname; 113 cfl.conflicting_pkgname = inst_pkgname;
121 cfl.conflicting_pattern = inst_pattern; 114 cfl.conflicting_pattern = inst_pattern;
122 rv = iterate_pkg_db(check_package_conflict, &cfl); 115 rv = iterate_pkg_db(check_package_conflict, &cfl);
123 if (rv == -1) { 116 if (rv == -1) {
124 errx(EXIT_FAILURE, "Couldn't read list of installed packages."); 117 errx(EXIT_FAILURE, "Couldn't read list of installed packages.");
125 /* NOTREACHED */ 118 /* NOTREACHED */
126 } 119 }
127 return *inst_pkgname != NULL; 120 return *inst_pkgname != NULL;
128} 121}
129 122
130#if 0 123#if 0

cvs diff -r1.24 -r1.25 pkgsrc/pkgtools/pkg_install/files/lib/file.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/file.c 2008/04/26 14:56:34 1.24
+++ pkgsrc/pkgtools/pkg_install/files/lib/file.c 2008/04/26 17:40:01 1.25
@@ -1,33 +1,33 @@ @@ -1,33 +1,33 @@
1/* $NetBSD: file.c,v 1.24 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: file.c,v 1.25 2008/04/26 17:40:01 joerg Exp $ */
2 2
3#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
4#include "config.h" 4#include "config.h"
5#endif 5#endif
6#include <nbcompat.h> 6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#endif 9#endif
10#if HAVE_SYS_PARAM_H 10#if HAVE_SYS_PARAM_H
11#include <sys/param.h> 11#include <sys/param.h>
12#endif 12#endif
13#if HAVE_SYS_QUEUE_H 13#if HAVE_SYS_QUEUE_H
14#include <sys/queue.h> 14#include <sys/queue.h>
15#endif 15#endif
16#ifndef lint 16#ifndef lint
17#if 0 17#if 0
18static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp"; 18static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp";
19#else 19#else
20__RCSID("$NetBSD: file.c,v 1.24 2008/04/26 14:56:34 joerg Exp $"); 20__RCSID("$NetBSD: file.c,v 1.25 2008/04/26 17:40:01 joerg Exp $");
21#endif 21#endif
22#endif 22#endif
23 23
24/* 24/*
25 * FreeBSD install - a package for the installation and maintainance 25 * FreeBSD install - a package for the installation and maintainance
26 * of non-core utilities. 26 * of non-core utilities.
27 * 27 *
28 * Redistribution and use in source and binary forms, with or without 28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions 29 * modification, are permitted provided that the following conditions
30 * are met: 30 * are met:
31 * 1. Redistributions of source code must retain the above copyright 31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer. 32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright 33 * 2. Redistributions in binary form must reproduce the above copyright
@@ -208,26 +208,283 @@ URLlength(const char *fname) @@ -208,26 +208,283 @@ URLlength(const char *fname)
208 for (i = 0; isspace((unsigned char) *fname); i++) { 208 for (i = 0; isspace((unsigned char) *fname); i++) {
209 fname++; 209 fname++;
210 } 210 }
211 for (up = urls; up->u_s; up++) { 211 for (up = urls; up->u_s; up++) {
212 if (strncmp(fname, up->u_s, up->u_len) == 0) { 212 if (strncmp(fname, up->u_s, up->u_len) == 0) {
213 return i + up->u_len; /* ... + sizeof(up->u_s); - HF */ 213 return i + up->u_len; /* ... + sizeof(up->u_s); - HF */
214 } 214 }
215 } 215 }
216 } 216 }
217 return -1; 217 return -1;
218} 218}
219 219
220/* 220/*
 221 * Returns the host part of a URL
 222 */
 223const char *
 224fileURLHost(const char *fname, char *where, int max)
 225{
 226 const char *ret;
 227 int i;
 228
 229 assert(where != NULL);
 230 assert(max > 0);
 231
 232 if ((i = URLlength(fname)) < 0) { /* invalid URL? */
 233 errx(EXIT_FAILURE, "fileURLhost called with a bad URL: `%s'", fname);
 234 }
 235 fname += i;
 236 /* Do we have a place to stick our work? */
 237 ret = where;
 238 while (*fname && *fname != '/' && --max)
 239 *where++ = *fname++;
 240 *where = '\0';
 241
 242 return ret;
 243}
 244
 245/*
 246 * Returns the filename part of a URL
 247 */
 248const char *
 249fileURLFilename(const char *fname, char *where, int max)
 250{
 251 const char *ret;
 252 int i;
 253
 254 assert(where != NULL);
 255 assert(max > 0);
 256
 257 if ((i = URLlength(fname)) < 0) { /* invalid URL? */
 258 errx(EXIT_FAILURE, "fileURLFilename called with a bad URL: `%s'", fname);
 259 }
 260 fname += i;
 261 /* Do we have a place to stick our work? */
 262 ret = where;
 263 while (*fname && *fname != '/')
 264 ++fname;
 265 if (*fname == '/') {
 266 while (*fname && --max)
 267 *where++ = *fname++;
 268 }
 269 *where = '\0';
 270
 271 return ret;
 272}
 273
 274/*
 275 * Try and fetch a file by URL, returning the directory name for where
 276 * it's unpacked, if successful. To be handed to leave_playpen() later.
 277 */
 278char *
 279fileGetURL(const char *spec)
 280{
 281 char host[MAXHOSTNAMELEN], file[MaxPathSize];
 282 const char *cp;
 283 char *rp;
 284 char pen[MaxPathSize];
 285 int rc;
 286
 287 rp = NULL;
 288 if (!IS_URL(spec)) {
 289 errx(EXIT_FAILURE, "fileGetURL was called with non-URL arg '%s'", spec);
 290 }
 291
 292 /* Some sanity checks on the URL */
 293 cp = fileURLHost(spec, host, MAXHOSTNAMELEN);
 294 if (!*cp) {
 295 warnx("URL `%s' has bad host part!", spec);
 296 return NULL;
 297 }
 298 cp = fileURLFilename(spec, file, MaxPathSize);
 299 if (!*cp) {
 300 warnx("URL `%s' has bad filename part!", spec);
 301 return NULL;
 302 }
 303
 304 if (Verbose)
 305 printf("Trying to fetch %s.\n", spec);
 306
 307 pen[0] = '\0';
 308 rp = make_playpen(pen, sizeof(pen), 0);
 309 if (rp == NULL) {
 310 printf("Error: Unable to construct a new playpen for FTP!\n");
 311 return NULL;
 312 }
 313
 314 rp = strdup(pen);
 315 rc = unpackURL(spec, pen);
 316 if (rc < 0) {
 317 leave_playpen(rp); /* Don't leave dir hang around! */
 318
 319 printf("Error on unpackURL('%s', '%s')\n", spec, pen);
 320 return NULL;
 321 }
 322 return rp;
 323}
 324
 325static char *
 326resolvepattern1(const char *name)
 327{
 328 static char tmp[MaxPathSize];
 329 char *cp;
 330
 331 if (IS_URL(name)) {
 332 /* some package depends on a wildcard pkg */
 333 int rc;
 334
 335 rc = expandURL(tmp, name);
 336 if (rc < 0) {
 337 return NULL;
 338 }
 339 if (Verbose)
 340 printf("'%s' expanded to '%s'\n", name, tmp);
 341 return tmp; /* return expanded URL w/ corrent pkg */
 342 }
 343 else if (ispkgpattern(name)) {
 344 cp = find_best_matching_file(dirname_of(name), basename_of(name), 1, 0);
 345 if (cp) {
 346 snprintf(tmp, sizeof(tmp), "%s/%s", dirname_of(name), cp);
 347 free(cp);
 348 return tmp;
 349 }
 350 } else {
 351 if (isfile(name)) {
 352 strlcpy(tmp, name, sizeof(tmp));
 353 return tmp;
 354 }
 355 }
 356
 357 return NULL;
 358}
 359
 360static char *
 361resolvepattern(const char *name)
 362{
 363 char tmp[MaxPathSize];
 364 char *cp;
 365 const char *suf;
 366
 367 cp = resolvepattern1(name);
 368 if (cp != NULL)
 369 return cp;
 370
 371 if (ispkgpattern(name))
 372 return NULL;
 373
 374 suf = suffix_of(name);
 375 if (!strcmp(suf, "tbz") || !strcmp(suf, "tgz"))
 376 return NULL;
 377
 378 /* add suffix and try */
 379 snprintf(tmp, sizeof(tmp), "%s.tbz", name);
 380 cp = resolvepattern1(tmp);
 381 if (cp != NULL)
 382 return cp;
 383 snprintf(tmp, sizeof(tmp), "%s.tgz", name);
 384 cp = resolvepattern1(tmp);
 385 if (cp != NULL)
 386 return cp;
 387
 388 /* add version number wildcard and try */
 389 snprintf(tmp, sizeof(tmp), "%s-[0-9]*", name);
 390 return resolvepattern1(tmp);
 391}
 392
 393/*
 394 * Look for filename/pattern "fname" in
 395 * Returns a full path/URL where the pkg can be found
 396 */
 397char *
 398fileFindByPath(const char *fname)
 399{
 400 char tmp[MaxPathSize];
 401 struct path *path;
 402
 403 /*
 404 * 1. if fname is an absolute pathname or a URL,
 405 * just use it.
 406 */
 407 if (IS_FULLPATH(fname) || IS_URL(fname))
 408 return resolvepattern(fname);
 409
 410 /*
 411 * 2. otherwise, use PKG_PATH.
 412 */
 413 TAILQ_FOREACH(path, &PkgPath, pl_entry) {
 414 char *cp;
 415 const char *cp2 = path->pl_path;
 416
 417 if (Verbose)
 418 printf("trying PKG_PATH %s\n", cp2);
 419
 420 if (IS_FULLPATH(cp2) || IS_URL(cp2)) {
 421 snprintf(tmp, sizeof(tmp), "%s/%s", cp2, fname);
 422 }
 423 else {
 424 char cwdtmp[MaxPathSize];
 425 if (getcwd(cwdtmp, sizeof(cwdtmp)) == NULL)
 426 errx(EXIT_FAILURE, "getcwd");
 427 snprintf(tmp, sizeof(tmp), "%s/%s/%s", cwdtmp, cp2, fname);
 428 }
 429 cp = resolvepattern(tmp);
 430 if (cp)
 431 return cp;
 432 }
 433
 434#if 0
 435 /*
 436 * 3. finally, search current directory.
 437 */
 438 snprintf(tmp, sizeof(tmp), "./%s", fname);
 439 return resolvepattern(tmp);
 440#else
 441 return NULL;
 442#endif
 443}
 444
 445/*
 446 * Expect "fname" to point at a file, and read it into
 447 * the buffer returned.
 448 */
 449char *
 450fileGetContents(char *fname)
 451{
 452 char *contents;
 453 struct stat sb;
 454 int fd;
 455
 456 if (stat(fname, &sb) == FAIL) {
 457 cleanup(0);
 458 errx(2, "can't stat '%s'", fname);
 459 }
 460
 461 contents = (char *) malloc((size_t) (sb.st_size) + 1);
 462 fd = open(fname, O_RDONLY, 0);
 463 if (fd == FAIL) {
 464 cleanup(0);
 465 errx(2, "unable to open '%s' for reading", fname);
 466 }
 467 if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) {
 468 cleanup(0);
 469 errx(2, "short read on '%s' - did not get %lld bytes",
 470 fname, (long long) sb.st_size);
 471 }
 472 close(fd);
 473 contents[(size_t) sb.st_size] = '\0';
 474 return contents;
 475}
 476
 477/*
221 * Takes a filename and package name, returning (in "try") the canonical 478 * Takes a filename and package name, returning (in "try") the canonical
222 * "preserve" name for it. 479 * "preserve" name for it.
223 */ 480 */
224Boolean 481Boolean
225make_preserve_name(char *try, size_t max, char *name, char *file) 482make_preserve_name(char *try, size_t max, char *name, char *file)
226{ 483{
227 int len, i; 484 int len, i;
228 485
229 if ((len = strlen(file)) == 0) 486 if ((len = strlen(file)) == 0)
230 return FALSE; 487 return FALSE;
231 else 488 else
232 i = len - 1; 489 i = len - 1;
233 strncpy(try, file, max); 490 strncpy(try, file, max);
@@ -242,26 +499,117 @@ make_preserve_name(char *try, size_t max @@ -242,26 +499,117 @@ make_preserve_name(char *try, size_t max
242 } 499 }
243 if (!i) { 500 if (!i) {
244 try[0] = '.'; 501 try[0] = '.';
245 strncpy(try + 1, file, max - 1); 502 strncpy(try + 1, file, max - 1);
246 } 503 }
247 /* I should probably be called rude names for these inline assignments */ 504 /* I should probably be called rude names for these inline assignments */
248 strncat(try, ".", max -= strlen(try)); 505 strncat(try, ".", max -= strlen(try));
249 strncat(try, name, max -= strlen(name)); 506 strncat(try, name, max -= strlen(name));
250 strncat(try, ".", max--); 507 strncat(try, ".", max--);
251 strncat(try, "backup", max -= 6); 508 strncat(try, "backup", max -= 6);
252 return TRUE; 509 return TRUE;
253} 510}
254 511
 512/*
 513 * Write the contents of "str" to a file
 514 */
 515void
 516write_file(char *name, char *str)
 517{
 518 size_t len;
 519 FILE *fp;
 520
 521 if ((fp = fopen(name, "w")) == (FILE *) NULL) {
 522 cleanup(0);
 523 errx(2, "cannot fopen '%s' for writing", name);
 524 }
 525 len = strlen(str);
 526 if (fwrite(str, 1, len, fp) != len) {
 527 cleanup(0);
 528 errx(2, "short fwrite on '%s', tried to write %ld bytes",
 529 name, (long) len);
 530 }
 531 if (fclose(fp)) {
 532 cleanup(0);
 533 errx(2, "failure to fclose '%s'", name);
 534 }
 535}
 536
 537void
 538copy_file(char *dir, char *fname, char *to)
 539{
 540 char fpath[MaxPathSize];
 541
 542 (void) snprintf(fpath, sizeof(fpath), "%s%s%s",
 543 (fname[0] != '/') ? dir : "",
 544 (fname[0] != '/') ? "/" : "",
 545 fname);
 546 if (fexec("cp", "-r", fpath, to, NULL)) {
 547 cleanup(0);
 548 errx(2, "could not perform 'cp -r %s %s'", fpath, to);
 549 }
 550}
 551
 552void
 553move_file(char *dir, char *fname, char *to)
 554{
 555 char fpath[MaxPathSize];
 556
 557 (void) snprintf(fpath, sizeof(fpath), "%s%s%s",
 558 (fname[0] != '/') ? dir : "",
 559 (fname[0] != '/') ? "/" : "",
 560 fname);
 561 if (fexec("mv", fpath, to, NULL)) {
 562 cleanup(0);
 563 errx(2, "could not perform 'mv %s %s'", fpath, to);
 564 }
 565}
 566
 567void
 568move_files(const char *dir, const char *pattern, const char *to)
 569{
 570 char fpath[MaxPathSize];
 571 glob_t globbed;
 572 size_t i;
 573
 574 (void) snprintf(fpath, sizeof(fpath), "%s/%s", dir, pattern);
 575 if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) {
 576 switch(i) {
 577 case GLOB_NOMATCH:
 578 warn("no files matching ``%s'' found", fpath);
 579 break;
 580 case GLOB_ABORTED:
 581 warn("globbing aborted");
 582 break;
 583 case GLOB_NOSPACE:
 584 warn("out-of-memory during globbing");
 585 break;
 586 default:
 587 warn("unknown error during globbing");
 588 break;
 589 }
 590 return;
 591 }
 592
 593 /* Moving globbed files -- we just use mv(1) to do the job */
 594 for (i=0; i<globbed.gl_pathc; i++)
 595 if (fexec("mv", globbed.gl_pathv[i], to, NULL)) {
 596 cleanup(0);
 597 errx(2, "could not perform 'mv %s %s'", globbed.gl_pathv[i], to);
 598 }
 599
 600 return;
 601}
 602
255void 603void
256remove_files(const char *path, const char *pattern) 604remove_files(const char *path, const char *pattern)
257{ 605{
258 char fpath[MaxPathSize]; 606 char fpath[MaxPathSize];
259 glob_t globbed; 607 glob_t globbed;
260 int i; 608 int i;
261 609
262 (void) snprintf(fpath, sizeof(fpath), "%s/%s", path, pattern); 610 (void) snprintf(fpath, sizeof(fpath), "%s/%s", path, pattern);
263 if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) { 611 if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) {
264 switch(i) { 612 switch(i) {
265 case GLOB_NOMATCH: 613 case GLOB_NOMATCH:
266 warn("no files matching ``%s'' found", fpath); 614 warn("no files matching ``%s'' found", fpath);
267 break; 615 break;
@@ -277,47 +625,115 @@ remove_files(const char *path, const cha @@ -277,47 +625,115 @@ remove_files(const char *path, const cha
277 } 625 }
278 return; 626 return;
279 } 627 }
280 628
281 /* deleting globbed files */ 629 /* deleting globbed files */
282 for (i=0; i<globbed.gl_pathc; i++) 630 for (i=0; i<globbed.gl_pathc; i++)
283 if (unlink(globbed.gl_pathv[i]) < 0) 631 if (unlink(globbed.gl_pathv[i]) < 0)
284 warn("can't delete ``%s''", globbed.gl_pathv[i]); 632 warn("can't delete ``%s''", globbed.gl_pathv[i]);
285 633
286 return; 634 return;
287} 635}
288 636
289/* 637/*
 638 * Unpack a tar file
 639 */
 640int
 641unpack(const char *pkg, const lfile_head_t *filesp)
 642{
 643 const char *decompress_cmd = NULL;
 644 const char *suf;
 645 int count = 0;
 646 lfile_t *lfp;
 647 char **up_argv;
 648 int up_argc = 7;
 649 int i = 0;
 650 int result;
 651
 652 if (filesp != NULL)
 653 TAILQ_FOREACH(lfp, filesp, lf_link)
 654 count++;
 655 up_argc += count;
 656 up_argv = malloc((count + up_argc + 1) * sizeof(char *));
 657 if (!IS_STDIN(pkg)) {
 658 suf = suffix_of(pkg);
 659 if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2"))
 660 decompress_cmd = BZIP2_CMD;
 661 else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz"))
 662 decompress_cmd = GZIP_CMD;
 663 else if (!strcmp(suf, "tar"))
 664 ; /* do nothing */
 665 else
 666 errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg);
 667 } else
 668 decompress_cmd = GZIP_CMD;
 669
 670 up_argv[i] = (char *)strrchr(TAR_CMD, '/');
 671 if (up_argv[i] == NULL)
 672 up_argv[i] = TAR_CMD;
 673 else
 674 up_argv[i]++; /* skip / character */
 675 if (count > 0)
 676 up_argv[++i] = "--fast-read";
 677 if (decompress_cmd != NULL) {
 678 up_argv[++i] = "--use-compress-program";
 679 up_argv[++i] = (char *)decompress_cmd;
 680 }
 681 up_argv[++i] = "-xpf";
 682 up_argv[++i] = (char *)pkg;
 683 if (count > 0)
 684 TAILQ_FOREACH(lfp, filesp, lf_link)
 685 up_argv[++i] = lfp->lf_name;
 686 up_argv[++i] = NULL;
 687
 688 if (Verbose) {
 689 printf("running: %s", TAR_CMD);
 690 for (i = 1; up_argv[i] != NULL; i++)
 691 printf(" %s", up_argv[i]);
 692 printf("\n");
 693 }
 694
 695 result = pfcexec(NULL, TAR_CMD, (const char **)up_argv);
 696 free(up_argv);
 697 if (result != 0) {
 698 warnx("extract of %s failed", pkg);
 699 return 1;
 700 }
 701
 702 return 0;
 703}
 704
 705/*
290 * Using fmt, replace all instances of: 706 * Using fmt, replace all instances of:
291 * 707 *
292 * %F With the parameter "name" 708 * %F With the parameter "name"
293 * %D With the parameter "dir" 709 * %D With the parameter "dir"
294 * %B Return the directory part ("base") of %D/%F 710 * %B Return the directory part ("base") of %D/%F
295 * %f Return the filename part of %D/%F 711 * %f Return the filename part of %D/%F
296 * 712 *
297 * Check that no overflows can occur. 713 * Check that no overflows can occur.
298 */ 714 */
299int 715void
300format_cmd(char *buf, size_t size, const char *fmt, const char *dir, const char *name) 716format_cmd(char *buf, size_t size, char *fmt, char *dir, char *name)
301{ 717{
302 char scratch[MaxPathSize * 2]; 718 char scratch[MaxPathSize * 2];
303 char *bufp; 719 char *bufp;
304 char *cp; 720 char *cp;
305 721
306 for (bufp = buf; (int) (bufp - buf) < size && *fmt;) { 722 for (bufp = buf; (int) (bufp - buf) < size && *fmt;) {
307 if (*fmt == '%') { 723 if (*fmt == '%') {
308 if (*++fmt != 'D' && name == NULL) { 724 if (*++fmt != 'D' && name == NULL) {
309 warnx("no last file available for '%s' command", buf); 725 cleanup(0);
310 return -1; 726 errx(2, "no last file available for '%s' command", buf);
311 } 727 }
312 switch (*fmt) { 728 switch (*fmt) {
313 case 'F': 729 case 'F':
314 strlcpy(bufp, name, size - (int) (bufp - buf)); 730 strlcpy(bufp, name, size - (int) (bufp - buf));
315 bufp += strlen(bufp); 731 bufp += strlen(bufp);
316 break; 732 break;
317 733
318 case 'D': 734 case 'D':
319 strlcpy(bufp, dir, size - (int) (bufp - buf)); 735 strlcpy(bufp, dir, size - (int) (bufp - buf));
320 bufp += strlen(bufp); 736 bufp += strlen(bufp);
321 break; 737 break;
322 738
323 case 'B': 739 case 'B':
@@ -342,15 +758,14 @@ format_cmd(char *buf, size_t size, const @@ -342,15 +758,14 @@ format_cmd(char *buf, size_t size, const
342 break; 758 break;
343 759
344 default: 760 default:
345 *bufp++ = '%'; 761 *bufp++ = '%';
346 *bufp++ = *fmt; 762 *bufp++ = *fmt;
347 break; 763 break;
348 } 764 }
349 ++fmt; 765 ++fmt;
350 } else { 766 } else {
351 *bufp++ = *fmt++; 767 *bufp++ = *fmt++;
352 } 768 }
353 } 769 }
354 *bufp = '\0'; 770 *bufp = '\0';
355 return 0; 
356} 771}

File Added: pkgsrc/pkgtools/pkg_install/files/lib/Attic/ftpio.c
/*	$NetBSD: ftpio.c,v 1.28 2008/04/26 17:40:01 joerg Exp $	*/

#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#ifndef lint
__RCSID("$NetBSD: ftpio.c,v 1.28 2008/04/26 17:40:01 joerg Exp $");
#endif

/*-
 * Copyright (c) 1999-2008 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Hubert Feyrer <hubert@feyrer.de> and Thomas Klausner.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *        This product includes software developed by the NetBSD
 *        Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_REGEX_H
#include <regex.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_TERMCAP_H
#include <termcap.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "../lib/lib.h"

/*
 * Names of environment variables used to pass things to
 * subprocesses, for connection caching.
 */
#define PKG_FTPIO_COMMAND		"PKG_FTPIO_COMMAND"
#define PKG_FTPIO_ANSWER		"PKG_FTPIO_ANSWER"
#define PKG_FTPIO_CNT			"PKG_FTPIO_CNT"
#define PKG_FTPIO_CURRENTHOST		"PKG_FTPIO_CURRENTHOST"
#define PKG_FTPIO_CURRENTDIR		"PKG_FTPIO_CURRENTDIR"

#undef STANDALONE   /* define for standalone debugging */

/* File descriptors */
typedef struct {
    int command;
    int answer;
} fds;


static int	 needclose=0;
static int	 ftp_started=0;
static fds	 ftpio;
static int	 ftp_pid;
static char	 term[1024];
static char	 bold_on[1024];
static char	 bold_off[1024];

static char *ftp_expand_URL(const char *, char *);
static int hexvalue(char);
static char *http_expand_URL(const char *, char *);
static int http_extract_fn(char *, char *, size_t);
static void URL_decode(char *);

/*
 * expect "str" (a regular expression) on file descriptor "fd", storing
 * the FTP return code of the command in the integer "ftprc". The "str"
 * string is expected to match some FTP return codes after a '\n', e.g.
 * "\n(550|226).*\n" 
 */
static int
expect(int fd, const char *str, int *ftprc)
{
	int rc;
	char buf[256];  
	regex_t rstr;
	int done;
	struct pollfd set[1];
	int retval;
	regmatch_t match;
	int verbose_expect=0;

	if (regcomp(&rstr, str, REG_EXTENDED) != 0)
		err(EXIT_FAILURE, "expect: regcomp() failed");

	memset(buf, '\n', sizeof(buf));

	done=0;
	retval=0;
	set[0].fd = fd;
	set[0].events = POLLIN;
	while(!done) {
		rc = poll(set, 1, 60*60*1000);    /* seconds until next message from tar */
		switch (rc) {
		case -1:
			if (errno == EINTR)
				break;
			warn("expect: poll() failed (probably ftp died because of bad args)");
			done = 1;
			retval = -1;
			break;
		case 0:
			warnx("expect: poll() timeout");
			/* need to send ftp coprocess SIGINT to make it stop
			 * downloading into dir that we'll blow away in a second */
			kill(ftp_pid, SIGINT);

			/* Wait until ftp coprocess is responsive again 
			 * XXX Entering recursion here!
			 */
			rc = ftp_cmd("cd .\n", "\n(550|250).*\n");
			if (rc != 250) {
				/* now we have a really good reason to bail out ;) */
			}
			/* ftp is at command prompt again, and will wait for our
			 * next command. If we were downloading, we can now safely
			 * continue and remove the dir that the tar command was
			 * expanding to */
		    
			done = 1;	/* hope that's ok */
			retval = -1;
			break;
		default:
			if (set[0].revents & POLLHUP) {
				done = 1;
				retval = -1;
				break;
			}

			rc = read(fd, &buf[sizeof(buf) - 1], 1);
			if (rc <= 0) {
				done = 1;
				retval = -1;
				break;
			}

			if (verbose_expect)
				putchar(buf[sizeof(buf)-1]);

			if (regexec(&rstr, buf, 1, &match, 0) == 0) {
				if (ftprc && isdigit((unsigned char)buf[match.rm_so+1])) 
					*ftprc = atoi(buf+match.rm_so+1);

				done=1;
				retval=0;
			}
	    
			memmove(buf, buf+1, sizeof(buf)-1); /* yes, this is non-performant */
			break;
		}
	}

	return retval;
}

/*
 * send a certain ftp-command "cmd" to our FTP coprocess, and wait for
 * "expectstr" to be returned. Return numeric FTP return code or -1
 * in case of an error (usually expect() timeout) 
 */
int
ftp_cmd(const char *cmd, const char *expectstr)
{
	int rc=0, verbose_ftp=0;
	int len;

	if (Verbose)
		verbose_ftp=1;
    
	if (verbose_ftp)
		fprintf(stderr, "\n%sftp> %s%s", bold_on, cmd, bold_off);
    
	fflush(stdout);
	len = write(ftpio.command, cmd, strlen(cmd));
	if (len == strlen(cmd)) {
		if (expectstr) {
			/* set "rc" to the FTP error code: */
			if (expect(ftpio.answer, expectstr, &rc) == -1)
				rc = -1;	/* some error occurred */
		}
	} else {	
		if (Verbose)
			warn("short write");
	}

	return rc;
}


/*
 * Really fire up FTP coprocess
 */
static int
setupCoproc(const char *base)
{
	int command_pipe[2];
	int answer_pipe[2];
	int rc1, rc2;
	char buf[20];
	char *argv0 = (char *)strrchr(FTP_CMD, '/');
	if (argv0 == NULL)
		argv0 = FTP_CMD;
	else
		argv0++;

	rc1 = pipe(command_pipe);
	rc2 = pipe(answer_pipe);

	if(rc1==-1 || rc2==-1) {
		warn("setupCoproc: pipe() failed");
		return -1;
	}

	if (command_pipe[0] == -1 || command_pipe[1] == -1 ||
	    answer_pipe[0] == -1  || answer_pipe[1] == -1 ) {
		warn("setupCoproc: pipe() returned bogus descriptor");
		return -1;
	}

	rc1 = fork();
	switch (rc1) {
	case -1:
		/* Error */
	    
		warn("setupCoproc: fork() failed");
		return -1;
		break;

	case 0:
		/* Child */
	    
		(void) close(command_pipe[1]);
		rc1 = dup2(command_pipe[0], 0);
		if (rc1 == -1) {
			err(EXIT_FAILURE, "setupCoproc: dup2 failed (command_pipe[0])");
		}
		(void) close(command_pipe[0]);
	    
		(void) close(answer_pipe[0]);
		rc1 = dup2(answer_pipe[1], 1);
		if (rc1 == -1) {
			err(EXIT_FAILURE, "setupCoproc: dup2 failed (answer_pipe[1])");
		}
		(void) close(answer_pipe[1]);
	    
		setbuf(stdout, NULL);
	    
		if (Verbose)
			fprintf(stderr, "%sftp -detv %s%s\n", bold_on, base, bold_off);
		rc1 = execlp(FTP_CMD, argv0, "-detv", base, NULL);
		warn("setupCoproc: execlp() failed");
		exit(1);
		break;
	default: 
		/* Parent */
		(void) close(command_pipe[0]);
		(void) close(answer_pipe[1]);
	    
		(void) snprintf(buf, sizeof(buf), "%d", command_pipe[1]);
		setenv(PKG_FTPIO_COMMAND, buf, 1);
		(void) snprintf(buf, sizeof(buf), "%d", answer_pipe[0]);
		setenv(PKG_FTPIO_ANSWER, buf, 1);
	    
		ftpio.command = command_pipe[1];
		ftpio.answer  = answer_pipe[0];
		ftp_pid = rc1;			/* to ^C transfers */
	    
		fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
		fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
	    
		break;
	}

	return 0;
}


/*
 * Dummy signal handler to detect if the ftp(1) coprocess or
 * and of the processes of the tar/gzip pipeline dies. 
 */
static void
sigchld_handler (int n)
{
	/* Make poll(2) return EINTR */
}


/*
 * SIGPIPE only happens when there's something wrong with the FTP
 * coprocess. In that case, set mark to not try to close shut down
 * the coprocess.
 */
static void
sigpipe_handler(int n)
{
	/* aparently our ftp companion died */
	if (Verbose)
		fprintf(stderr, "SIGPIPE!\n");
	needclose = 0;
}


/*
 * Close the FTP coprocess' current connection, but
 * keep the process itself alive. 
 */
void 
ftp_stop(void)
{
#if defined(__svr4__) && defined(__sun__)
	char	env[BUFSIZ];
#endif
	const char *tmp1, *tmp2;
	
	if (!ftp_started)
		return;
	
	tmp1=getenv(PKG_FTPIO_COMMAND);
	tmp2=getenv(PKG_FTPIO_ANSWER);
	
	/* (Only) the last one closes the link */
	if (tmp1 != NULL && tmp2 != NULL) {
		if (needclose)
			ftp_cmd("close\n", "\n(221 .*|Not connected.)\n");
		
		(void) close(ftpio.command);
		(void) close(ftpio.answer);
	}

#if defined(__svr4__) && defined(__sun__)
	(void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_COMMAND);
	putenv(env);
	(void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_ANSWER);
	putenv(env);
#else
	unsetenv(PKG_FTPIO_COMMAND); 
	unsetenv(PKG_FTPIO_ANSWER);
#endif
}


/*
 * (Start and re-)Connect the FTP coprocess to some host/dir.
 * If the requested host/dir is different than the one that the
 * coprocess is currently at, close first. 
 */
int
ftp_start(const char *base)
{
	const char *tmp1, *tmp2;
	char *p;
	int rc;
	char newHost[MAXHOSTNAMELEN];
	const char *newDir;
	const char *currentHost=getenv(PKG_FTPIO_CURRENTHOST);
	const char *currentDir=getenv(PKG_FTPIO_CURRENTDIR);
	int urllen;

	/* talk to termcap for bold on/off escape sequences */
	if (getenv("TERM") != NULL && tgetent(term, getenv("TERM")) > 0) {
		p = bold_on;  tgetstr("md", &p);
		p = bold_off; tgetstr("me", &p);
	} else {
		bold_on[0]  = '\0';
		bold_off[0] = '\0';
	}
	
	fileURLHost(base, newHost, sizeof(newHost));
	urllen = URLlength(base);
	if (urllen < 0 || !(newDir = strchr(base + URLlength(base), '/')))
		errx(EXIT_FAILURE, "ftp_start: bad URL '%s'", base);
	newDir++;
	if (currentHost
	    && currentDir
	    && ( strcmp(newHost, currentHost) != 0
		 || strcmp(newDir, currentDir) != 0)) { /* could handle new dir case better here, w/o reconnect */
		if (Verbose) {
			printf("ftp_start: new host or dir, stopping previous connect...\n");
			printf("currentHost='%s', newHost='%s'\n", currentHost, newHost);
			printf("currentDir='%s', newDir='%s'\n", currentDir, newDir);
		}
		
		ftp_stop();
		
		if (Verbose)
			printf("ftp stopped\n");
	}
	setenv(PKG_FTPIO_CURRENTHOST, newHost, 1); /* need to update this in the environment */
	setenv(PKG_FTPIO_CURRENTDIR, newDir, 1);   /* for subprocesses to have this available */
	
	tmp1=getenv(PKG_FTPIO_COMMAND);
	tmp2=getenv(PKG_FTPIO_ANSWER);
	if(tmp1==NULL || tmp2==NULL || *tmp1=='\0' || *tmp2=='\0') {
		/* no FTP coprocess running yet */
		
		if (Verbose)
			printf("Spawning FTP coprocess\n");
		
		rc = setupCoproc(base);
		if (rc == -1) {
			warnx("setupCoproc() failed");
			return -1;
		}
		
		needclose=1;
		signal(SIGPIPE, sigpipe_handler);
		signal(SIGCHLD, sigchld_handler);

		if ((expect(ftpio.answer, "\n(221|250|221|550).*\n", &rc) != 0)
		    || rc != 250) {
			warnx("expect1 failed, rc=%d", rc);
			return -1;
		}
		
		/* nbftp now issues a CWD for each part of the path
		 * and will return a code for each of them. No idea how to
		 * deal with that other than to issue a 'prompt off' to
		 * get something that we can wait for and that does NOT
		 * look like a CWD command's output */
		rc = ftp_cmd("prompt off\n", "\n(Interactive mode off|221).*\n");
		if ((rc == 221) || (rc == -1)) {
			/* something is wrong */
			ftp_started=1; /* not really, but for ftp_stop() */
			ftp_stop();
			warnx("prompt failed - wrong dir?");
			return -1;
		}
		
		ftp_started=1;
	} else {
		/* get FDs of our coprocess */
		
		ftpio.command = dup(atoi(tmp1));
		if (ftpio.command == -1 ) {
			warnx("command dup() failed, increase 'descriptors' limit");
			return -1;
		}
		ftpio.answer  = dup(atoi(tmp2));
		if (ftpio.answer == -1 ) {
			warnx("answer dup() failed, increase 'descriptors' limit");
			return -1;
		}
		
		if (Verbose)
			printf("Reusing FDs %s/%s for communication to FTP coprocess\n", tmp1, tmp2);
		
		fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
		fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
	}
	
	return 0;
}


/*
 * Expand the given wildcard URL "wildcardurl" if possible, and store the
 * expanded value into "expandedurl". return 0 if successful, -1 else.
 */
int
expandURL(char *expandedurl, const char *wildcardurl)
{
	char *pattern;
	char *bestmatch;
	char base[MaxPathSize];

	pattern=strrchr(wildcardurl, '/');
	if (pattern == NULL){
		warnx("expandURL: no '/' in URL %s?!", wildcardurl);
		return -1;
	}
	if (pattern-strchr(wildcardurl, '/') < 2) {
		/* only one or two slashes in total */
		warnx("expandURL: not enough '/' in URL %s", wildcardurl);
		return -1;
	}
	(void) snprintf(base, sizeof(base), "%.*s/",
			(int)(pattern-wildcardurl), wildcardurl);
	pattern++;

	if (strncmp(wildcardurl, "ftp://", 6) == 0)
		bestmatch=ftp_expand_URL(base, pattern);
	else if (strncmp(wildcardurl, "http://", 7) == 0)
		bestmatch=http_expand_URL(base, pattern);
	else {
		warnx("expandURL: unknown protocol in URL `%s'", wildcardurl);
		return -1;
	}

	/* no match found */
	if (bestmatch == NULL)
		return -1;

	snprintf(expandedurl, MaxPathSize, "%s%s", base, bestmatch);
	if (Verbose)
		printf("best match: '%s'\n", expandedurl);

	return 0;
}

/* for a given wildcard ftp:// URL, find the best matching pkg */
static char *
ftp_expand_URL(const char *base, char *pattern)
{
	char *s, buf[MaxPathSize];
	char tmpname[MaxPathSize];
	char best[MaxPathSize];
	char s_best[MaxPathSize];
	int rc, got_list, tfd, retry_tbz;

	retry_tbz = 0;
	best[0]='\0';
	s_best[0]='\0';

	rc = ftp_start(base);
	if (rc == -1) {
		warnx("ftp_start() failed");
		return NULL;
	}

	strlcpy(tmpname, "/var/tmp/pkg.XXXXXX", sizeof(tmpname));
	tfd=mkstemp(tmpname);
	if (tfd == -1) {
		warnx("Cannot generate temp file for ftp(1)'s nlist output");
		return NULL;
	}
	close(tfd); /* We don't need the file descriptor, but will use 
		       the file in a second */

	s=strpbrk(pattern, "<>[]?*{"); /* Could leave out "[]?*" here;
					* ftp(1) is not that stupid */
	if (!s) {
		/* This should only happen when getting here with (only) a package
		 * name specified to pkg_add, and PKG_PATH containing some URL.
		 */
		(void) snprintf(buf, sizeof(buf), "nlist %s %s\n", pattern, tmpname);
	} else {
		/* replace possible version(wildcard) given with "-*".
		 * we can't use the pkg wildcards here as dewey compare
		 * and alternates won't be handled by ftp(1); sort
		 * out later, using pkg_match() */
		if (retry_tbz) {
retry_with_tbz:
			(void) snprintf(buf,  sizeof(buf), "nlist %.*s*.tbz %s\n",
					(int)(s-pattern), pattern, tmpname);
			retry_tbz = 0;
		} else {
			(void) snprintf(buf,  sizeof(buf), "nlist %.*s*.tgz %s\n",
					(int)(s-pattern), pattern, tmpname);
			retry_tbz = 1;
		}
	}

	rc = ftp_cmd(buf, "\n(550|450|226).*\n"); /* catch errors */
	if (rc != 226)
		got_list = 0;
	else
		got_list = 1;

	/* Sync - don't remove */
	rc = ftp_cmd("cd .\n", "\n(550|250|257).*\n");
	if (rc != 250) {
		warnx("chdir failed!");
		unlink(tmpname);	/* remove clutter */
		return NULL;
	}
	
	if (got_list == 1 && access(tmpname, R_OK)==0) {
		FILE *f;
		char filename[MaxPathSize];

		f=fopen(tmpname, "r");
		if (f == NULL) {
			warn("fopen");
			unlink(tmpname);	/* remove clutter */
			return NULL;
		}
		/* The following loop is basically the same as the readdir() loop
		 * in findmatchingname() */
		while (fgets(filename, sizeof(filename), f)) {

			/*
			 * We need to strip off any .t[bg]z etc.
			 * suffix here
			 */

			char s_filename[MaxPathSize];
			char s_pattern[MaxPathSize];
	    
			filename[strlen(filename)-1] = '\0';

			strip_txz(s_filename, NULL, filename);
			strip_txz(s_pattern, NULL, pattern);

			if (pkg_order(s_pattern, s_filename,
				      s_best[0] != '\0' ? s_best : NULL) == 1) {
				strlcpy(s_best, s_filename, sizeof(s_best));
				strlcpy(best, filename, sizeof(best));
			}
		}
		(void) fclose(f);
	}

	if (retry_tbz)
		goto retry_with_tbz;

	if (best[0] == '\0' && Verbose)
		warnx("nothing appropriate found");

	unlink(tmpname);

	if (best[0] == '\0')
		return NULL;

	return strdup(best);
}

/* for a given wildcard http:// URL, find the best matching pkg */
static char *
http_expand_URL(const char *base, char *pattern)
{
	char    best[MaxPathSize];
	char    s_best[MaxPathSize];
	char    line[BUFSIZ];
	char    filename[MaxPathSize];
	FILE   *fp;
	int	pipefds[2];
	int     state;
	pid_t   pid;

	*best = '\0';
	*s_best = '\0';

	/* Set up a pipe for getting the file list */
	if (pipe(pipefds) == -1) {
		warnx("cannot create pipe");
		return NULL;
	}
	if ((pid = fork()) == -1) {
		warnx("cannot fork ftp process");
		return NULL;
	}
	if (pid == 0) {		/* The child */
		if (dup2(pipefds[1], STDOUT_FILENO) == -1) {
			warnx("dup2 failed before starting ftp");
			_exit(2);
		}
		close(pipefds[0]);
		close(pipefds[1]);
		/* get URL contents to stdout and thus to parent,
		 * silently */
		execlp("ftp", "ftp", "-V", "-o", "-", base, NULL);
		warnx("failed to execute ftp");
		_exit(2);
	}

	/* parent */
	close(pipefds[1]);

	if ((fp=fdopen(pipefds[0], "r")) == NULL)
		warn("can't fdopen pipe end");
	else {
		char s_pattern[MaxPathSize];
		int len, offset;

		/* strip of .t[bg]z for comparison */
		strip_txz(s_pattern, NULL, pattern);

		/* initialize http_extract_fn internal state */
		http_extract_fn(NULL, NULL, 0);

		/* read line from HTTP output and extract filenames */
		while (fgets(line, sizeof(line), fp) != NULL) {
			len = offset = 0;
			while ((len=http_extract_fn(line+offset, filename,
						      sizeof(filename))) > 0) {
				char s_filename[MaxPathSize];

				offset += len;
				strip_txz(s_filename, NULL, filename);

				if (pkg_order(s_pattern, s_filename,
					      *s_best != '\0' ? s_best : NULL) == 1) {
					strlcpy(best, filename, sizeof(best));
					strlcpy(s_best, s_filename, sizeof(best));
				}
			}
		}

	}

	fclose(fp);

	/* wait for child to exit */
	if (waitpid(pid, &state, 0) < 0) {
		/* error has been reported by child */
		return NULL;
	}

	if (best[0] == '\0') {
		if (Verbose)
			warnx("nothing appropriate found");
		return NULL;
	}

	return strdup(best);

}

enum http_states {
	ST_NONE,
	ST_LT, ST_LTA, ST_TAGA, ST_H, ST_R, ST_E, ST_F, ST_HREF,
	ST_TAG, ST_TAGAX
};

/* return any hrefs found */
static int
http_extract_fn(char *input, char *outbuf, size_t outbuflen)
{
	/* partial copied hrefs from previous calls are saved here */
	static char tempbuf[MaxPathSize];
	/* fill state of tempbuf */
	static int tempbuffill = 0;
	/* parsing state information */
	static enum http_states state;
	/* currently in double quotes (in parsing) */
	static int dqflag;
	char p;
	int offset, found;

	if (outbuf == NULL) {
		/* init */
		dqflag = tempbuffill = 0;
		state = ST_NONE;
		return 0;
	}

	offset = 0;
	found = 0;
	while ((p=input[offset++]) != '\0') {
		/* handle anything that's inside double quotes */
		if (dqflag) {
			/* incomplete href */
			if (state == ST_HREF) {
				/* check if space left in output
				 * buffer */
				if (tempbuffill >= sizeof(tempbuf)) {
					warnx("href starting with `%.*s'"
					      " too long", 60, tempbuf);
					/* ignore remainder */
					tempbuffill = 0;
					/* need space before "href"
					 * can start again (invalidly,
					 * of course, but we don't
					 * care) */
					state = ST_TAGAX;
				}

				/* href complete */
				if (p == '\"') {
					/* complete */
					dqflag = 0;
					tempbuf[tempbuffill++] = '\0';
					/* need space before "href"
					 * can start again (invalidly,
					 * of course, but we don't
					 * care) */
					state = ST_TAGAX;
					found = 1;
					break;
				} else {
					/* copy one more char */
					tempbuf[tempbuffill++] = p;
				}
			} else {
				/* leaving double quotes */
				if (p == '\"')
					dqflag = 0;
			}
			continue;
		}

		/*
		 * entering double quotes? (only relevant inside a tag)
		 */
		if (state != ST_NONE && p == '\"') {
			dqflag = 1;
			continue;
		}

		/* other cases */
		switch (state) {
		case ST_NONE:
			/* plain text, not in markup */
			if (p == '<')
				state = ST_LT;
			break;
		case ST_LT:
			/* in tag -- "<" already found */
			if (p == '>')
				state = ST_NONE;
			else if (p == 'a' || p == 'A')
				state = ST_LTA;
			else if (!isspace((unsigned char)p))
				state = ST_TAG;
			break;
		case ST_LTA:
			/* in tag -- "<a" already found */
			if (p == '>')
				state = ST_NONE;
			else if (isspace((unsigned char)p))
				state = ST_TAGA;
			else
				state = ST_TAG;
			break;
		case ST_TAG:
			/* in tag, but not "<a" -- disregard */
			if (p == '>')
				state = ST_NONE;
			break;
		case ST_TAGA:
			/* in a-tag -- "<a " already found */
			if (p == '>')
				state = ST_NONE;
			else if (p == 'h' || p == 'H')
				state = ST_H;
			else if (!isspace((unsigned char)p))
				state = ST_TAGAX;
			break;
		case ST_TAGAX:
			/* in unknown keyword in a-tag */
			if (p == '>')
				state = ST_NONE;
			else if (isspace((unsigned char)p))
				state = ST_TAGA;
			break;
		case ST_H:
			/* in a-tag -- "<a h" already found */
			if (p == '>')
				state = ST_NONE;
			else if (p == 'r' || p == 'R')
				state = ST_R;
			else if (isspace((unsigned char)p))
				state = ST_TAGA;
			else
				state = ST_TAGAX;
			break;
		case ST_R:
			/* in a-tag -- "<a hr" already found */
			if (p == '>')
				state = ST_NONE;
			else if (p == 'e' || p == 'E')
				state = ST_E;
			else if (isspace((unsigned char)p))
				state = ST_TAGA;
			else
				state = ST_TAGAX;
			break;
		case ST_E:
			/* in a-tag -- "<a hre" already found */
			if (p == '>')
				state = ST_NONE;
			else if (p == 'f' || p == 'F')
				state = ST_F;
			else if (isspace((unsigned char)p))
				state = ST_TAGA;
			else
				state = ST_TAGAX;
			break;
		case ST_F:
			/* in a-tag -- "<a href" already found */
			if (p == '>')
				state = ST_NONE;
			else if (p == '=')
				state = ST_HREF;
			else if (!isspace((unsigned char)p))
				state = ST_TAGAX;
			break;
		case ST_HREF:
			/* in a-tag -- "<a href=" already found */
			/* XXX: handle missing double quotes? */
			if (p == '>')
				state = ST_NONE;
			/* skip spaces before URL */
			else if (!isspace((unsigned char)p))
				state = ST_TAGA;
			break;
			/* no default case by purpose */
		}
	}

	if (p == '\0')
		return -1;

	if (found) {
		char *q;

		URL_decode(tempbuf);

		/* strip path (XXX) */
		if ((q=strrchr(tempbuf, '/')) == NULL)
			q = tempbuf;
			
		(void)strlcpy(outbuf, q, outbuflen);
		tempbuffill = 0;
	}
		
	return offset;
}


static int
hexvalue(char p)
{
	if (p >= '0' && p <= '9')
		return (p-'0');
	else if (p >= 'a' && p <= 'f')
		return (p-'a'+10);
	else if (p >= 'A' && p <= 'F')
		return (p-'A'+10);
	else
		return -1;
}

/* fetch and extract URL url into directory path */
static int
http_fetch(const char *url, const char *path)
{
	int     pipefds[2];
	int	stateftp, state;
	pid_t   pidftp, pid;

	/* Set up a pipe for passing the fetched contents. */
	if (pipe(pipefds) == -1) {
		warn("cannot create pipe");
		return -1;
	}
	/* fork ftp child */
	if ((pidftp = fork()) == -1) {
		warn("cannot fork process for ftp");
		return -1;
	}
	if (pidftp == 0) {
		/* child */
		if (dup2(pipefds[1], STDOUT_FILENO) == -1) {
			warn("dup2 failed before executing ftp");
			_exit(2);
		}
		close(pipefds[0]);
		close(pipefds[1]);
		execlp(FTP_CMD, FTP_CMD, "-o", "-", url, NULL);
		warnx("failed to execute ftp");
		_exit(2);
	}

	/* fork unpack child */
	if ((pid = fork()) == -1) {
		warn("cannot fork unpack process");
		return -1;
	}
	if (pid == 0) {
		/* child */
		if (dup2(pipefds[0], STDIN_FILENO) == -1) {
			warn("dup2 failed before unpack");
			_exit(2);
		}
		close(pipefds[0]);
		close(pipefds[1]);
		if ((path != NULL) && (chdir(path) < 0))
			_exit(127);

		if (unpack("-", NULL) != 0) {
			warnx("unpack failed");
			_exit(2);
		}

		_exit(0);
	}

	close(pipefds[0]);
	close(pipefds[1]);

	/* wait for unpack to exit */
	while (waitpid(pid, &state, 0) < 0) {
		if (errno != EINTR) {
			(void)waitpid(pidftp, &stateftp, 0);
			return -1;
		}
	}
	while (waitpid(pidftp, &stateftp, 0) < 0) {
		if (errno != EINTR) {
			return -1;
		}
	}

	if (!WIFEXITED(state) || !WIFEXITED(stateftp))
		return -1;

	if (WEXITSTATUS(state) != 0 || WEXITSTATUS(stateftp) != 0)
		return -1;

	return 0;
}

static void
URL_decode(char *URL)
{
	char *in, *out;

	in = out = URL;

	while (*in != '\0') {
		if (in[0] == '%' && in[1] != '\0' && in[2] != '\0') {
			/* URL-decode character */
			if (hexvalue(in[1]) != -1 && hexvalue(in[2]) != -1) {
				*out++ = hexvalue(in[1])*16+hexvalue(in[2]);
			}
			/* skip invalid encoded signs too */
			in += 3;
		}
		else
			*out++ = *in++;
	}

	*out = '\0';

	return;
}
/*
 * extract the given (expanded) URL "url" to the given directory "dir"
 * return -1 on error, 0 else;
 */
int
unpackURL(const char *url, const char *dir)
{
	char *pkg;
	int rc;
	char base[MaxPathSize];
	char pkg_path[MaxPathSize];

	{
		/* Verify if the URL is really ok */
		char expnd[MaxPathSize];

		rc=expandURL(expnd, url);
		if (rc == -1) {
			warnx("unpackURL: verification expandURL failed");
			return -1;
		}
		if (strcmp(expnd, url) != 0) {
			warnx("unpackURL: verification expandURL failed, '%s'!='%s'",
			      expnd, url);
			return -1;
		}
	}
	
	pkg=strrchr(url, '/');
	if (pkg == NULL){
		warnx("unpackURL: no '/' in URL %s?!", url);
		return -1;
	}
	(void) snprintf(base, sizeof(base), "%.*s/", (int)(pkg-url), url);
	(void) snprintf(pkg_path, sizeof(pkg_path), "%.*s",
                 (int)(pkg-url), url); /* no trailing '/' */
	pkg++;

	/* Leave a hint for any depending pkgs that may need it */
	if (getenv("PKG_PATH") == NULL) {
		setenv("PKG_PATH", pkg_path, 1);
#if 0
		path_create(pkg_path); /* XXX */
#endif
		if (Verbose)
			printf("setenv PKG_PATH='%s'\n", pkg_path);
	}

	if (strncmp(url, "http://", 7) == 0)
	    return http_fetch(url, dir);

	rc = ftp_start(base);
	if (rc == -1) {
		warnx("ftp_start() failed");
		return -1; /* error */
	}

	{
		char cmd[1024];
		const char *decompress_cmd = NULL;
		const char *suf;

		if (Verbose)
			printf("unpackURL '%s' to '%s'\n", url, dir);

		suf = suffix_of(pkg);
		if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2"))
			decompress_cmd = BZIP2_CMD;
		else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz"))
			decompress_cmd = GZIP_CMD;
		else if (!strcmp(suf, "tar"))
			; /* do nothing */
		else
			errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg);

		/* yes, this is gross, but needed for borken ftp(1) */
		(void) snprintf(cmd, sizeof(cmd), "get %s \"| ( cd %s; " TAR_CMD " %s %s -vvxp -f - | tee %s )\"\n",
		    pkg, dir,
		    decompress_cmd != NULL ? "--use-compress-program" : "",
		    decompress_cmd != NULL ? decompress_cmd : "",
		    Verbose ? "/dev/stderr" : "/dev/null");

		rc = ftp_cmd(cmd, "\n(226|550).*\n");
		if (rc != 226) {
			warnx("Cannot fetch file (%d!=226)!", rc);
			return -1;
		}
	}

	return 0;
}


#ifdef STANDALONE
static void
usage(void)
{
	errx(EXIT_FAILURE, "Usage: foo [-v] ftp://-pattern");
}


int
main(int argc, char *argv[])
{
	int rc, ch;
	char *argv0 = argv[0];

	while ((ch = getopt(argc, argv, "v")) != -1) {
		switch (ch) {
		case 'v':
			Verbose=1;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc<1)
		usage();

	while(argv[0] != NULL) {
		char newurl[MaxPathSize];
	    
		printf("Expand %s:\n", argv[0]);
		rc = expandURL(newurl, argv[0]);
		if (rc==-1)
			warnx("Cannot expand %s", argv[0]);
		else
			printf("Expanded URL: %s\n", newurl);

		/* test out connection caching */
		if (1) {
			char *s, buf[MaxPathSize];
		    
			if ((s=getenv(PKG_FTPIO_CNT)) && atoi(s)>0){
				(void) snprintf(buf, sizeof(buf),"%d", atoi(s)-1);
				setenv(PKG_FTPIO_CNT, buf, 1);
			    
				printf("%s>>> %s -v %s\n", s, argv0, argv[0]);
				fexec(argv0, "-v", argv[0], NULL);
			}
		}
	    
		printf("\n\n\n");
		argv++;
	}

	ftp_stop();

	return 0;
}

void
cleanup(int i)
{
}
#endif /* STANDALONE */

cvs diff -r1.43 -r1.44 pkgsrc/pkgtools/pkg_install/files/lib/lib.h (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/lib.h 2008/04/26 14:56:34 1.43
+++ pkgsrc/pkgtools/pkg_install/files/lib/lib.h 2008/04/26 17:40:01 1.44
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: lib.h,v 1.43 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: lib.h,v 1.44 2008/04/26 17:40:01 joerg Exp $ */
2 2
3/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */ 3/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
4 4
5/* 5/*
6 * FreeBSD install - a package for the installation and maintainance 6 * FreeBSD install - a package for the installation and maintainance
7 * of non-core utilities. 7 * of non-core utilities.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
@@ -76,38 +76,68 @@ @@ -76,38 +76,68 @@
76 76
77#ifndef FALSE 77#ifndef FALSE
78#define FALSE (0) 78#define FALSE (0)
79#endif 79#endif
80 80
81#ifndef OPSYS_NAME 81#ifndef OPSYS_NAME
82#define OPSYS_NAME "NetBSD" 82#define OPSYS_NAME "NetBSD"
83#endif 83#endif
84 84
85#ifndef DEF_UMASK 85#ifndef DEF_UMASK
86#define DEF_UMASK 022 86#define DEF_UMASK 022
87#endif 87#endif
88 88
89#define MKDIR_CMD "mkdir" 
90 
91/* Usually "rm", but often "echo" during debugging! */ 89/* Usually "rm", but often "echo" during debugging! */
92#define REMOVE_CMD "rm" 90#define REMOVE_CMD "rm"
93 91
94/* Usually "rm", but often "echo" during debugging! */ 92/* Usually "rm", but often "echo" during debugging! */
95#define RMDIR_CMD "rmdir" 93#define RMDIR_CMD "rmdir"
96 94
 95/* Define tar as a string, in case it's called gtar or something */
 96#ifndef TAR_CMD
 97#define TAR_CMD "tar"
 98#endif
 99
 100/* Define pax as a string, used to copy files from staging area */
 101#ifndef PAX_CMD
 102#define PAX_CMD "pax"
 103#endif
 104
 105/* Define gzip and bzip2, used to unpack binary packages */
 106#ifndef GZIP_CMD
 107#define GZIP_CMD "gzip"
 108#endif
 109
 110#ifndef BZIP2_CMD
 111#define BZIP2_CMD "bzip2"
 112#endif
 113
 114/* Define ftp as a string, in case the ftp client is called something else */
 115#ifndef FTP_CMD
 116#define FTP_CMD "ftp"
 117#endif
 118
 119#ifndef CHOWN_CMD
 120#define CHOWN_CMD "chown"
 121#endif
 122
97#ifndef CHMOD_CMD 123#ifndef CHMOD_CMD
98#define CHMOD_CMD "chmod" 124#define CHMOD_CMD "chmod"
99#endif 125#endif
100 126
 127#ifndef CHGRP_CMD
 128#define CHGRP_CMD "chgrp"
 129#endif
 130
101/* some operating systems don't have this */ 131/* some operating systems don't have this */
102#ifndef MAXPATHLEN 132#ifndef MAXPATHLEN
103#define MAXPATHLEN 1024 133#define MAXPATHLEN 1024
104#endif 134#endif
105 135
106enum { 136enum {
107 MaxPathSize = MAXPATHLEN 137 MaxPathSize = MAXPATHLEN
108}; 138};
109 139
110/* The names of our "special" files */ 140/* The names of our "special" files */
111#define CONTENTS_FNAME "+CONTENTS" 141#define CONTENTS_FNAME "+CONTENTS"
112#define COMMENT_FNAME "+COMMENT" 142#define COMMENT_FNAME "+COMMENT"
113#define DESC_FNAME "+DESC" 143#define DESC_FNAME "+DESC"
@@ -118,28 +148,33 @@ enum { @@ -118,28 +148,33 @@ enum {
118#define MTREE_FNAME "+MTREE_DIRS" 148#define MTREE_FNAME "+MTREE_DIRS"
119#define BUILD_VERSION_FNAME "+BUILD_VERSION" 149#define BUILD_VERSION_FNAME "+BUILD_VERSION"
120#define BUILD_INFO_FNAME "+BUILD_INFO" 150#define BUILD_INFO_FNAME "+BUILD_INFO"
121#define INSTALLED_INFO_FNAME "+INSTALLED_INFO" 151#define INSTALLED_INFO_FNAME "+INSTALLED_INFO"
122#define SIZE_PKG_FNAME "+SIZE_PKG" 152#define SIZE_PKG_FNAME "+SIZE_PKG"
123#define SIZE_ALL_FNAME "+SIZE_ALL" 153#define SIZE_ALL_FNAME "+SIZE_ALL"
124#define PRESERVE_FNAME "+PRESERVE" 154#define PRESERVE_FNAME "+PRESERVE"
125#define VIEWS_FNAME "+VIEWS" 155#define VIEWS_FNAME "+VIEWS"
126#define DEPOT_FNAME "+DEPOT" 156#define DEPOT_FNAME "+DEPOT"
127 157
128/* The names of special variables */ 158/* The names of special variables */
129#define AUTOMATIC_VARNAME "automatic" 159#define AUTOMATIC_VARNAME "automatic"
130 160
131/* Prefix for extended PLIST cmd */ 161/*
132#define CMD_CHAR '@'  162 * files which we expect to be in every package, passed to
 163 * tar --fast-read.
 164 */
 165#define ALL_FNAMES CONTENTS_FNAME" "COMMENT_FNAME" "DESC_FNAME" "MTREE_FNAME" "BUILD_VERSION_FNAME" "BUILD_INFO_FNAME" "SIZE_PKG_FNAME" "SIZE_ALL_FNAME
 166
 167#define CMD_CHAR '@' /* prefix for extended PLIST cmd */
133 168
134/* The name of the "prefix" environment variable given to scripts */ 169/* The name of the "prefix" environment variable given to scripts */
135#define PKG_PREFIX_VNAME "PKG_PREFIX" 170#define PKG_PREFIX_VNAME "PKG_PREFIX"
136 171
137/* 172/*
138 * The name of the "metadatadir" environment variable given to scripts. 173 * The name of the "metadatadir" environment variable given to scripts.
139 * This variable holds the location of the +-files for this package. 174 * This variable holds the location of the +-files for this package.
140 */ 175 */
141#define PKG_METADATA_DIR_VNAME "PKG_METADATA_DIR" 176#define PKG_METADATA_DIR_VNAME "PKG_METADATA_DIR"
142 177
143/* 178/*
144 * The name of the environment variable holding the location to the 179 * The name of the environment variable holding the location to the
145 * reference-counts database directory. 180 * reference-counts database directory.
@@ -228,108 +263,143 @@ typedef struct _lfile_head_t lfile_head_ @@ -228,108 +263,143 @@ typedef struct _lfile_head_t lfile_head_
228 lfp = malloc(sizeof(lfile_t)); \ 263 lfp = malloc(sizeof(lfile_t)); \
229 lfp->lf_name = str; \ 264 lfp->lf_name = str; \
230 TAILQ_INSERT_TAIL(lfhead,lfp,lf_link); \ 265 TAILQ_INSERT_TAIL(lfhead,lfp,lf_link); \
231 } while(0) 266 } while(0)
232 267
233/* List of packages */ 268/* List of packages */
234typedef struct _lpkg_t { 269typedef struct _lpkg_t {
235 TAILQ_ENTRY(_lpkg_t) lp_link; 270 TAILQ_ENTRY(_lpkg_t) lp_link;
236 char *lp_name; 271 char *lp_name;
237} lpkg_t; 272} lpkg_t;
238TAILQ_HEAD(_lpkg_head_t, _lpkg_t); 273TAILQ_HEAD(_lpkg_head_t, _lpkg_t);
239typedef struct _lpkg_head_t lpkg_head_t; 274typedef struct _lpkg_head_t lpkg_head_t;
240 275
 276/* This structure describes a pipe to a child process */
 277typedef struct {
 278 int fds[2]; /* pipe, 0=child stdin, 1=parent output */
 279 FILE *fp; /* output from parent process */
 280 pid_t pid; /* process id of child process */
 281 void (*cleanup)(void); /* called on non-zero child exit status */
 282} pipe_to_system_t;
 283
241struct pkg_vulnerabilities { 284struct pkg_vulnerabilities {
242 size_t entries; 285 size_t entries;
243 char **vulnerability; 286 char **vulnerability;
244 char **classification; 287 char **classification;
245 char **advisory; 288 char **advisory;
246}; 289};
247 290
248/* If URLlength()>0, then there is a ftp:// or http:// in the string, 291/* If URLlength()>0, then there is a ftp:// or http:// in the string,
249 * and this must be an URL. Hide this behind a more obvious name. */ 292 * and this must be an URL. Hide this behind a more obvious name. */
250#define IS_URL(str) (URLlength(str) > 0) 293#define IS_URL(str) (URLlength(str) > 0)
251 294
252#define IS_STDIN(str) ((str) != NULL && !strcmp((str), "-")) 295#define IS_STDIN(str) ((str) != NULL && !strcmp((str), "-"))
253#define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/') 296#define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/')
254 297
255/* Conflict handling (conflicts.c) */ 298/* Conflict handling (conflicts.c) */
256int some_installed_package_conflicts_with(const char *, const char *, char **, char **); 299int some_installed_package_conflicts_with(const char *, char **, char **);
257 300
258 301
259/* Prototypes */ 302/* Prototypes */
260/* Misc */ 303/* Misc */
261void cleanup(int); 304void cleanup(int);
 305char *make_playpen(char *, size_t, size_t);
 306char *where_playpen(void);
 307void leave_playpen(char *);
 308uint64_t min_free(const char *);
 309void save_dirs(char **, char **);
 310void restore_dirs(char *, char *);
262void show_version(void); 311void show_version(void);
263int fexec(const char *, ...); 312int fexec(const char *, ...);
264int fexec_skipempty(const char *, ...); 313int fexec_skipempty(const char *, ...);
265int fcexec(const char *, const char *, ...); 314int fcexec(const char *, const char *, ...);
266int pfcexec(const char *, const char *, const char **); 315int pfcexec(const char *, const char *, const char **);
 316pipe_to_system_t *pipe_to_system_begin(const char *, char *const *, void (*)(void));
 317int pipe_to_system_end(pipe_to_system_t *);
267 318
268/* variables file handling */ 319/* variables file handling */
269 320
270char *var_get(const char *, const char *); 321char *var_get(const char *, const char *);
271char *var_get_memory(const char *, const char *); 322char *var_get_memory(const char *, const char *);
272int var_set(const char *, const char *, const char *); 323int var_set(const char *, const char *, const char *);
273int var_copy_list(const char *, const char **); 324int var_copy_list(const char *, const char **);
274 325
275/* automatically installed as dependency */ 326/* automatically installed as dependency */
276 327
277Boolean is_automatic_installed(const char *); 328Boolean is_automatic_installed(const char *);
278int mark_as_automatic_installed(const char *, int); 329int mark_as_automatic_installed(const char *, int);
279 330
280/* String */ 331/* String */
281const char *basename_of(const char *); 332const char *basename_of(const char *);
282const char *dirname_of(const char *); 333const char *dirname_of(const char *);
283const char *suffix_of(const char *); 334const char *suffix_of(const char *);
284int pkg_match(const char *, const char *); 335int pkg_match(const char *, const char *);
285int pkg_order(const char *, const char *, const char *); 336int pkg_order(const char *, const char *, const char *);
286int ispkgpattern(const char *); 337int ispkgpattern(const char *);
 338void strip_txz(char *, char *, const char *);
287 339
288/* Iterator functions */ 340/* Iterator functions */
289int iterate_pkg_generic_src(int (*)(const char *, void *), void *, 341int iterate_pkg_generic_src(int (*)(const char *, void *), void *,
290 const char *(*)(void *),void *); 342 const char *(*)(void *),void *);
291int iterate_local_pkg_dir(const char *, int, int, int (*)(const char *, void *), 343int iterate_local_pkg_dir(const char *, int, int, int (*)(const char *, void *),
292 void *); 344 void *);
293int iterate_pkg_db(int (*)(const char *, void *), void *); 345int iterate_pkg_db(int (*)(const char *, void *), void *);
294 346
295int add_installed_pkgs_by_basename(const char *, lpkg_head_t *); 347int add_installed_pkgs_by_basename(const char *, lpkg_head_t *);
296int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *); 348int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *);
297char *find_best_matching_installed_pkg(const char *); 349char *find_best_matching_installed_pkg(const char *);
298char *find_best_matching_file(const char *, const char *, int, int); 350char *find_best_matching_file(const char *, const char *, int, int);
299int match_installed_pkgs(const char *, int (*)(const char *, void *), void *); 351int match_installed_pkgs(const char *, int (*)(const char *, void *), void *);
300int match_local_files(const char *, int, int, const char *, int (*cb)(const char *, void *), void *); 352int match_local_files(const char *, int, int, const char *, int (*cb)(const char *, void *), void *);
301 353
302/* File */ 354/* File */
303Boolean fexists(const char *); 355Boolean fexists(const char *);
304Boolean isdir(const char *); 356Boolean isdir(const char *);
305Boolean islinktodir(const char *); 357Boolean islinktodir(const char *);
306Boolean isemptydir(const char *); 358Boolean isemptydir(const char *);
307Boolean isemptyfile(const char *); 359Boolean isemptyfile(const char *);
308Boolean isfile(const char *); 360Boolean isfile(const char *);
309Boolean isbrokenlink(const char *); 361Boolean isbrokenlink(const char *);
310Boolean isempty(const char *); 362Boolean isempty(const char *);
311int URLlength(const char *); 363int URLlength(const char *);
 364char *fileGetURL(const char *);
 365const char *fileURLFilename(const char *, char *, int);
 366const char *fileURLHost(const char *, char *, int);
 367char *fileFindByPath(const char *);
 368char *fileGetContents(char *);
312Boolean make_preserve_name(char *, size_t, char *, char *); 369Boolean make_preserve_name(char *, size_t, char *, char *);
 370void write_file(char *, char *);
 371void copy_file(char *, char *, char *);
 372void move_file(char *, char *, char *);
 373void move_files(const char *, const char *, const char *);
313void remove_files(const char *, const char *); 374void remove_files(const char *, const char *);
314int delete_hierarchy(char *, Boolean, Boolean); 375int delete_hierarchy(char *, Boolean, Boolean);
315int format_cmd(char *, size_t, const char *, const char *, const char *); 376int unpack(const char *, const lfile_head_t *);
 377void format_cmd(char *, size_t, char *, char *, char *);
 378
 379/* ftpio.c: FTP handling */
 380int expandURL(char *, const char *);
 381int unpackURL(const char *, const char *);
 382int ftp_cmd(const char *, const char *);
 383int ftp_start(const char *);
 384void ftp_stop(void);
316 385
317/* pkg_io.c: Local and remote archive handling */ 386/* pkg_io.c: Local and remote archive handling */
318struct archive; 387struct archive;
319 388
320struct archive *open_archive(const char *, void **); 389struct archive *open_remote_archive(const char *, void **);
321void close_archive(void *); 390void close_remote_archive(void *);
322struct archive *find_archive(const char *, void **); 391struct archive *open_local_archive(const char *, void **);
 392void close_local_archive(void *);
323 393
324/* Packing list */ 394/* Packing list */
325plist_t *new_plist_entry(void); 395plist_t *new_plist_entry(void);
326plist_t *last_plist(package_t *); 396plist_t *last_plist(package_t *);
327plist_t *find_plist(package_t *, pl_ent_t); 397plist_t *find_plist(package_t *, pl_ent_t);
328char *find_plist_option(package_t *, char *); 398char *find_plist_option(package_t *, char *);
329void plist_delete(package_t *, Boolean, pl_ent_t, char *); 399void plist_delete(package_t *, Boolean, pl_ent_t, char *);
330void free_plist(package_t *); 400void free_plist(package_t *);
331void mark_plist(package_t *); 401void mark_plist(package_t *);
332void csum_plist_entry(char *, plist_t *); 402void csum_plist_entry(char *, plist_t *);
333void add_plist(package_t *, pl_ent_t, const char *); 403void add_plist(package_t *, pl_ent_t, const char *);
334void add_plist_top(package_t *, pl_ent_t, const char *); 404void add_plist_top(package_t *, pl_ent_t, const char *);
335void delete_plist(package_t *, Boolean, pl_ent_t, char *); 405void delete_plist(package_t *, Boolean, pl_ent_t, char *);

File Added: pkgsrc/pkgtools/pkg_install/files/lib/Attic/pen.c
/*	$NetBSD: pen.c,v 1.24 2008/04/26 17:40:01 joerg Exp $	*/

#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: pen.c,v 1.25 1997/10/08 07:48:12 charnier Exp";
#else
__RCSID("$NetBSD: pen.c,v 1.24 2008/04/26 17:40:01 joerg Exp $");
#endif
#endif

/*
 * FreeBSD install - a package for the installation and maintainance
 * of non-core utilities.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Jordan K. Hubbard
 * 18 July 1993
 *
 * Routines for managing the "play pen".
 *
 */

#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#if HAVE_SYS_SIGNAL_H
#include <sys/signal.h>
#endif

/* For keeping track of where we are */
static char Current[MaxPathSize];
static char Previous[MaxPathSize];
static int CurrentSet;		/* rm -fr Current only if it's really set! */
                                /* CurrentSet is set to 0 before strcpy()s
				 * to prevent rm'ing of a partial string
				 * when interrupted by ^C */

char   *
where_playpen(void)
{
	return Current;
}

/*
 * Find a good place to play.
 */
static char *
find_play_pen(char *pen, size_t pensize, size_t sz)
{
	const char **cp;
	struct stat sb;
	char *r;
	const char *tmpdir[] = {
		"PKG_TMPDIR",
		"TMPDIR",
		"/var/tmp",
		"/tmp",
		"/usr/tmp",
		NULL
	};

	if (pen == NULL) {
		cleanup(0);
		errx(2, "find_play_pen(): 'pen' variable is NULL\n"
		     "(this should not happen, please report!)");
		return NULL;
	}
	
	if (pen[0] && (r = strrchr(pen, '/')) != NULL) {
		*r = '\0';
		if (stat(pen, &sb) != FAIL && (min_free(pen) >= sz)) {
			*r = '/';
			return pen;
		}
	}

	for (cp = tmpdir; *cp; cp++) {
		const char *d = (**cp == '/') ? *cp : getenv(*cp);

		if (d == NULL || stat(d, &sb) == FAIL || min_free(d) < sz)
			continue;

		(void)snprintf(pen, pensize, "%s/instmp.XXXXXX", d);
		return pen;
	}

	cleanup(0);
	errx(2, "Can't find enough temporary space to extract the files.\n"
	    "Please set your PKG_TMPDIR environment variable to a location "
	    "with at least %zu bytes free", sz);
	return NULL;
}

/*
 * Make a temporary directory to play in and chdir() to it, returning
 * pathname of previous working directory.
 */
char   *
make_playpen(char *pen, size_t pensize, size_t sz)
{
	if (!find_play_pen(pen, pensize, sz))
		return NULL;

	if (!mkdtemp(pen)) {
		cleanup(0);
		errx(2, "can't mkdtemp '%s'", pen);
	}

	/*
	 * On at least NetBSD, the temporary directory may have a group
	 * that isn't in the group list of the current user. In that
	 * case, it is impossible to extract setgid binaries from the
	 * package, since chmod(2) doesn't allow to set the S_ISGID bit
	 * for a group that isn't yours.
	 */
	(void)chown(pen, -1, getegid());

	if (Verbose) {
		if (sz)
			fprintf(stderr,
		"Requested space: %lu bytes, free space: %lld bytes in %s\n",
			    (u_long) sz, (long long) min_free(pen), pen);
	}
	if (min_free(pen) < sz) {
		rmdir(pen);
		cleanup(0);
		errx(2, "not enough free space to create '%s'.\n"
		    "Please set your PKG_TMPDIR environment variable to a location\n"
		    "with more space and\ntry the command again", pen);
	}
	if (Current[0])
		strlcpy(Previous, Current, sizeof(Previous));
	else if (!getcwd(Previous, MaxPathSize)) {
		cleanup(0);
		err(EXIT_FAILURE, "fatal error during execution: getcwd");
	}
	if (chdir(pen) == FAIL) {
		cleanup(0);
		errx(2, "can't chdir to '%s'", pen);
	}
	CurrentSet = 0; strlcpy(Current, pen, sizeof(Current)); CurrentSet = 1;
	
	return Previous;
}

/*
 * Convenience routine for getting out of playpen
 */
void
leave_playpen(char *save)
{
	void    (*oldsig) (int);

	/* Make us interruptable while we're cleaning up - just in case... */
	oldsig = signal(SIGINT, SIG_DFL);
	if (Previous[0] && chdir(Previous) == FAIL) {
		cleanup(0);
		errx(2, "can't chdir back to '%s'", Previous);
	} else if (CurrentSet && Current[0] && strcmp(Current, Previous)) {
		if (strcmp(Current, "/") == 0) {
			fprintf(stderr, "PANIC: About to rm -fr / (not doing so, aborting)\n");
			abort();
		}
		if (fexec("rm", "-fr", Current, NULL))
			warnx("couldn't remove temporary dir '%s'", Current);
		strlcpy(Current, Previous, sizeof(Current));
	}
	if (save)
		strlcpy(Previous, save, sizeof(Previous));
	else
		Previous[0] = '\0';
	signal(SIGINT, oldsig);
}

/*
 * Return free disk space (in bytes) on given file system.
 * Returns size in a uint64_t since off_t isn't 64 bits on all
 * operating systems.
 */
uint64_t
min_free(const char *tmpdir)
{
	struct statvfs buf;

	if (statvfs(tmpdir, &buf) != 0) {
		warn("statvfs");
		return 0;
	}
	return (uint64_t)buf.f_bavail * buf.f_bsize;
}

File Added: pkgsrc/pkgtools/pkg_install/files/lib/Attic/pexec.c
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif

#include "lib.h"

/*
 * If the supplied callback is not NULL, then call it.
 */
static void call_callback(void (*callback)(void))
{
	if (callback != NULL) {
		callback();
	}
}

/*
 * create pipe, fork and exec file with arguments in argv
 * child takes stdin from pipe, set up fp for parent to
 * output to pipe, and return this information.
 */
pipe_to_system_t *pipe_to_system_begin(const char *file, char *const argv[],
	void (*cleanup_callback)(void))
{
	pipe_to_system_t *retval;

	retval = malloc(sizeof(pipe_to_system_t));
	if (retval == NULL) {
		call_callback(cleanup_callback);
		errx(2, "can't get pipe space");
	}

	retval->cleanup = cleanup_callback;

	if (pipe(retval->fds) == -1) {
		call_callback(retval->cleanup);
		errx(2, "cannot create pipe");
	}

	retval->pid = fork();
	if (retval->pid == -1) {
		call_callback(retval->cleanup);
		errx(2, "cannot fork process for %s", file);
	}

	if (retval->pid == 0) {		/* The child */
		if (retval->fds[0] != 0) {
			dup2(retval->fds[0], 0);
			close(retval->fds[0]);
		}
		close(retval->fds[1]);
		execvp(file, argv);
		warn("failed to execute %s command", file);
		_exit(2);
	}

	/* Meanwhile, back in the parent process ... */
	close(retval->fds[0]);
	retval->fp = fdopen(retval->fds[1], "w");
	if (retval->fp == NULL) {
		call_callback(retval->cleanup);
		errx(2, "fdopen failed");
	}
	return retval;
}

/*
 * close pipe and wait for child to exit.  on non-zero exit status,
 * call cleanup callback.  return exit status.
 */
int pipe_to_system_end(pipe_to_system_t *to_pipe)
{
	int status;
	int wait_ret;

	fclose(to_pipe->fp);
	do {
		wait_ret = waitpid(to_pipe->pid, &status, 0);
	} while (wait_ret == -1 && errno == EINTR);

	if (wait_ret < 0) {
		call_callback(to_pipe->cleanup);
		errx(2, "waitpid returned failure");
	}
	if (!WIFEXITED(status)) {
		call_callback(to_pipe->cleanup);
		errx(2, "waitpid: process terminated abnormally");
	}
	free(to_pipe);
	return WEXITSTATUS(status);
}

cvs diff -r1.2 -r1.3 pkgsrc/pkgtools/pkg_install/files/lib/pkg_io.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/pkg_io.c 2008/04/26 14:56:34 1.2
+++ pkgsrc/pkgtools/pkg_install/files/lib/pkg_io.c 2008/04/26 17:40:01 1.3
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: pkg_io.c,v 1.2 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $ */
2/*- 2/*-
3 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. 3 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 9 *
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in 13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the 14 * the documentation and/or other materials provided with the
@@ -26,243 +26,114 @@ @@ -26,243 +26,114 @@
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE. 28 * SUCH DAMAGE.
29 */ 29 */
30 30
31#if HAVE_CONFIG_H 31#if HAVE_CONFIG_H
32#include "config.h" 32#include "config.h"
33#endif 33#endif
34#include <nbcompat.h> 34#include <nbcompat.h>
35#if HAVE_SYS_CDEFS_H 35#if HAVE_SYS_CDEFS_H
36#include <sys/cdefs.h> 36#include <sys/cdefs.h>
37#endif 37#endif
38 38
39__RCSID("$NetBSD: pkg_io.c,v 1.2 2008/04/26 14:56:34 joerg Exp $"); 39__RCSID("$NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $");
40 40
41#include <archive.h> 41#include <archive.h>
42#include <archive_entry.h> 42#include <archive_entry.h>
43#if HAVE_ERR_H 43#if HAVE_ERR_H
44#include <err.h> 44#include <err.h>
45#endif 45#endif
46#if HAVE_ERRNO_H 46#if HAVE_ERRNO_H
47#include <errno.h> 47#include <errno.h>
48#endif 48#endif
49#include <fetch.h> 49#include <fetch.h>
50#include <stdlib.h> 50#include <stdlib.h>
51 51
52#include "lib.h" 52#include "lib.h"
53 53
54struct fetch_archive { 54struct fetch_archive {
55 struct url *url; 55 const char *url;
56 fetchIO *fetch; 56 fetchIO *fetch;
57 char buffer[32768]; 57 char buffer[32768];
58}; 58};
59 59
60static int 60static int
61fetch_archive_open(struct archive *a, void *client_data) 61fetch_archive_open(struct archive *a, void *client_data)
62{ 62{
63 struct fetch_archive *f = client_data; 63 struct fetch_archive *f = client_data;
64 64
65 f->fetch = fetchGet(f->url, ""); 65 f->fetch = fetchGetURL(f->url, "");
66 if (f->fetch == NULL) 66 if (f->fetch == NULL)
67 return ENOENT; 67 return ENOENT;
68 return 0; 68 return 0;
69} 69}
70 70
71static ssize_t 71static ssize_t
72fetch_archive_read(struct archive *a, void *client_data, 72fetch_archive_read(struct archive *a, void *client_data,
73 const void **buffer) 73 const void **buffer)
74{ 74{
75 struct fetch_archive *f = client_data; 75 struct fetch_archive *f = client_data;
76  76
77 *buffer = f->buffer; 77 *buffer = f->buffer;
78 return fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));  78 return fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
79} 79}
80 80
81static int 81static int
82fetch_archive_close(struct archive *a, void *client_data) 82fetch_archive_close(struct archive *a, void *client_data)
83{ 83{
84 struct fetch_archive *f = client_data; 84 struct fetch_archive *f = client_data;
85 85
86 if (f->fetch != NULL) 86 if (f->fetch != NULL)
87 fetchIO_close(f->fetch); 87 fetchIO_close(f->fetch);
88 return 0; 88 return 0;
89} 89}
90 90
91static struct archive * 91struct archive *
92open_archive_by_url(struct url *url, void **cookie) 92open_remote_archive(const char *url, void **cookie)
93{ 93{
94 struct fetch_archive *f; 94 struct fetch_archive *f;
95 struct archive *a; 95 struct archive *archive;
96 96
97 f = malloc(sizeof(*f)); 97 f = malloc(sizeof(*f));
98 if (f == NULL) 98 if (f == NULL)
99 err(2, "cannot allocate memory for remote archive"); 99 err(2, "cannot allocate memory for remote archive");
100 f->url = url; 100 f->url = url;
101 101
102 a = archive_read_new(); 102 archive = archive_read_new();
103 archive_read_support_compression_all(a); 103 archive_read_support_compression_all(archive);
104 archive_read_support_format_all(a); 104 archive_read_support_format_all(archive);
105 if (archive_read_open(a, f, fetch_archive_open, fetch_archive_read, 105 if (archive_read_open(archive, f, fetch_archive_open, fetch_archive_read,
106 fetch_archive_close)) { 106 fetch_archive_close))
107 archive_read_close(a); 107 errx(2, "cannot open archive: %s", archive_error_string(archive));
108 free(f); 
109 return NULL; 
110 } 
111 108
112 *cookie = f; 109 *cookie = f;
113 return a; 
114} 
115 
116struct archive * 
117open_archive(const char *url, void **cookie) 
118{ 
119 struct url *u; 
120 struct archive *a; 
121 
122 if (!IS_URL(url)) { 
123 a = archive_read_new(); 
124 archive_read_support_compression_all(a); 
125 archive_read_support_format_all(a); 
126 if (archive_read_open_filename(a, url, 1024)) { 
127 archive_read_close(a); 
128 return NULL; 
129 } 
130 *cookie = NULL; 
131 return a; 
132 } 
133 
134 if ((u = fetchParseURL(url)) == NULL) 
135 return NULL; 
136 
137 a = open_archive_by_url(u, cookie); 
138 110
139 fetchFreeURL(u); 111 return archive;
140 return a; 
141} 112}
142 113
143void 114void
144close_archive(void *cookie) 115close_remote_archive(void *cookie)
145{ 116{
146 free(cookie); 117 free(cookie);
147} 118}
148 119
149static int 120struct archive *
150strip_suffix(char *filename) 121open_local_archive(const char *path, void **cookie)
151{ 122{
152 size_t len; 123 struct archive *archive;
153 124
154 len = strlen(filename); 125 archive = archive_read_new();
155 if (len <= 4) 126 archive_read_support_compression_all(archive);
156 return 0; 127 archive_read_support_format_all(archive);
157 if (strcmp(filename + len - 4, ".tgz") == 0 || 128 if (archive_read_open_filename(archive, path, 1024))
158 strcmp(filename + len - 4, ".tbz") == 0) { 129 errx(2, "cannot open archive: %s",
159 filename[len - 4] = '\0'; 130 archive_error_string(archive));
160 return 1; 131 *cookie = NULL;
161 } else 
162 return 0; 
163} 
164 132
165static int 133 return archive;
166find_best_package(struct url *url, const char *pattern, struct url **best_url) 
167{ 
168 char *cur_match, *best_match = NULL; 
169 struct url_list ue; 
170 size_t i; 
171 
172 if (*best_url) { 
173 if ((best_match = fetchUnquoteFilename(*best_url)) == NULL) 
174 return -1; 
175 } else 
176 best_match = NULL;  
177 
178 if (best_match && strip_suffix(best_match) == 0) { 
179 free(best_match); 
180 return -1; 
181 } 
182 
183 fetchInitURLList(&ue); 
184 if (fetchList(&ue, url, NULL, "")) { 
185 fetchFreeURLList(&ue); 
186 return -1; 
187 } 
188 for (i = 0; i < ue.length; ++i) { 
189 cur_match = fetchUnquoteFilename(ue.urls + i); 
190 
191 if (cur_match == NULL) { 
192 free(best_match); 
193 fetchFreeURLList(&ue); 
194 return -1; 
195 } 
196 if (strip_suffix(cur_match) == 0) { 
197 free(cur_match); 
198 continue;  
199 } 
200 if (pkg_order(pattern, cur_match, best_match) == 1) { 
201 if (*best_url) 
202 fetchFreeURL(*best_url); 
203 *best_url = fetchCopyURL(ue.urls + i); 
204 free(best_match); 
205 best_match = cur_match; 
206 cur_match = NULL; 
207 if (*best_url == NULL) { 
208 free(best_match); 
209 return -1; 
210 } 
211 } 
212 free(cur_match); 
213 } 
214 free(best_match); 
215 fetchFreeURLList(&ue); 
216 return 0; 
217} 134}
218 135
219struct archive * 136void
220find_archive(const char *fname, void **cookie) 137close_local_archive(void *cookie)
221{ 138{
222 struct archive *a; 
223 struct path *path; 
224 const char *cur_path; 
225 struct url *url, *best_match; 
226 char tmp[MaxPathSize]; 
227 
228 best_match = NULL; 
229 
230 a = open_archive(fname, cookie); 
231 if (a != NULL) 
232 return a; 
233 
234 if (strchr(fname, '/') != NULL) { 
235 const char *last_slash; 
236 
237 last_slash = strrchr(fname, '/'); 
238 snprintf(tmp, sizeof(tmp), "%s%.*s", 
239 IS_URL(fname) ? "" : "file://", 
240 (int)(last_slash - fname + 1), fname); 
241 url = fetchParseURL(tmp); 
242 if (url == NULL) 
243 return NULL; 
244 fname = last_slash + 1; /* XXX fetchUnquoteFilename */ 
245 find_best_package(url, fname, &best_match); 
246 fetchFreeURL(url); 
247 } else { 
248 TAILQ_FOREACH(path, &PkgPath, pl_entry) { 
249 cur_path = path->pl_path; 
250 if (!IS_URL(cur_path)) { 
251 snprintf(tmp, sizeof(tmp), "file://%s", cur_path); 
252 cur_path = tmp; 
253 } 
254 url = fetchParseURL(cur_path); 
255 if (url == NULL) 
256 continue; 
257 find_best_package(url, fname, &best_match); 
258 /* XXX Check return value and complain */ 
259 fetchFreeURL(url); 
260 } 
261 } 
262 
263 if (best_match == NULL) 
264 return NULL; 
265 a = open_archive_by_url(best_match, cookie); 
266 fetchFreeURL(best_match); 
267 return a; 
268} 139}

cvs diff -r1.18 -r1.19 pkgsrc/pkgtools/pkg_install/files/lib/plist.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/plist.c 2008/04/26 14:56:34 1.18
+++ pkgsrc/pkgtools/pkg_install/files/lib/plist.c 2008/04/26 17:40:01 1.19
@@ -1,27 +1,27 @@ @@ -1,27 +1,27 @@
1/* $NetBSD: plist.c,v 1.18 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: plist.c,v 1.19 2008/04/26 17:40:01 joerg Exp $ */
2 2
3#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
4#include "config.h" 4#include "config.h"
5#endif 5#endif
6#include <nbcompat.h> 6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#endif 9#endif
10#ifndef lint 10#ifndef lint
11#if 0 11#if 0
12static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp"; 12static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp";
13#else 13#else
14__RCSID("$NetBSD: plist.c,v 1.18 2008/04/26 14:56:34 joerg Exp $"); 14__RCSID("$NetBSD: plist.c,v 1.19 2008/04/26 17:40:01 joerg Exp $");
15#endif 15#endif
16#endif 16#endif
17 17
18/* 18/*
19 * FreeBSD install - a package for the installation and maintainance 19 * FreeBSD install - a package for the installation and maintainance
20 * of non-core utilities. 20 * of non-core utilities.
21 * 21 *
22 * Redistribution and use in source and binary forms, with or without 22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions 23 * modification, are permitted provided that the following conditions
24 * are met: 24 * are met:
25 * 1. Redistributions of source code must retain the above copyright 25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer. 26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright 27 * 2. Redistributions in binary form must reproduce the above copyright
@@ -529,27 +529,26 @@ delete_package(Boolean ign_err, Boolean  @@ -529,27 +529,26 @@ delete_package(Boolean ign_err, Boolean
529 p = p->next; 529 p = p->next;
530 break; 530 break;
531 531
532 case PLIST_CWD: 532 case PLIST_CWD:
533 Where = p->name; 533 Where = p->name;
534 if (Verbose) 534 if (Verbose)
535 printf("Change working directory to %s\n", Where); 535 printf("Change working directory to %s\n", Where);
536 break; 536 break;
537 537
538 case PLIST_UNEXEC: 538 case PLIST_UNEXEC:
539 if (NoDeleteFiles) 539 if (NoDeleteFiles)
540 break; 540 break;
541 format_cmd(tmp, sizeof(tmp), p->name, Where, last_file); 541 format_cmd(tmp, sizeof(tmp), p->name, Where, last_file);
542 /* XXX cleanup(0); */ 
543 printf("Executing `%s'\n", tmp); 542 printf("Executing `%s'\n", tmp);
544 if (!Fake && system(tmp)) { 543 if (!Fake && system(tmp)) {
545 warnx("unexec command for `%s' failed", tmp); 544 warnx("unexec command for `%s' failed", tmp);
546 fail = FAIL; 545 fail = FAIL;
547 } 546 }
548 break; 547 break;
549 548
550 case PLIST_FILE: 549 case PLIST_FILE:
551 last_file = p->name; 550 last_file = p->name;
552 (void) snprintf(tmp, sizeof(tmp), "%s/%s", Where, p->name); 551 (void) snprintf(tmp, sizeof(tmp), "%s/%s", Where, p->name);
553 if (isdir(tmp)) { 552 if (isdir(tmp)) {
554 warnx("attempting to delete directory `%s' as a file\n" 553 warnx("attempting to delete directory `%s' as a file\n"
555 "this packing list is incorrect - ignoring delete request", tmp); 554 "this packing list is incorrect - ignoring delete request", tmp);

cvs diff -r1.23 -r1.24 pkgsrc/pkgtools/pkg_install/files/lib/str.c (expand / switch to unified diff)

--- pkgsrc/pkgtools/pkg_install/files/lib/str.c 2008/04/26 14:56:34 1.23
+++ pkgsrc/pkgtools/pkg_install/files/lib/str.c 2008/04/26 17:40:01 1.24
@@ -1,27 +1,27 @@ @@ -1,27 +1,27 @@
1/* $NetBSD: str.c,v 1.23 2008/04/26 14:56:34 joerg Exp $ */ 1/* $NetBSD: str.c,v 1.24 2008/04/26 17:40:01 joerg Exp $ */
2 2
3#if HAVE_CONFIG_H 3#if HAVE_CONFIG_H
4#include "config.h" 4#include "config.h"
5#endif 5#endif
6#include <nbcompat.h> 6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H 7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h> 8#include <sys/cdefs.h>
9#endif 9#endif
10#ifndef lint 10#ifndef lint
11#if 0 11#if 0
12static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp"; 12static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
13#else 13#else
14__RCSID("$NetBSD: str.c,v 1.23 2008/04/26 14:56:34 joerg Exp $"); 14__RCSID("$NetBSD: str.c,v 1.24 2008/04/26 17:40:01 joerg Exp $");
15#endif 15#endif
16#endif 16#endif
17 17
18/* 18/*
19 * FreeBSD install - a package for the installation and maintainance 19 * FreeBSD install - a package for the installation and maintainance
20 * of non-core utilities. 20 * of non-core utilities.
21 * 21 *
22 * Redistribution and use in source and binary forms, with or without 22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions 23 * modification, are permitted provided that the following conditions
24 * are met: 24 * are met:
25 * 1. Redistributions of source code must retain the above copyright 25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer. 26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright 27 * 2. Redistributions in binary form must reproduce the above copyright
@@ -96,13 +96,54 @@ dirname_of(const char *path) @@ -96,13 +96,54 @@ dirname_of(const char *path)
96 buf[cc] = 0; 96 buf[cc] = 0;
97 return buf; 97 return buf;
98} 98}
99 99
100/* 100/*
101 * Does the pkgname contain any of the special chars ("{[]?*<>")?  101 * Does the pkgname contain any of the special chars ("{[]?*<>")?
102 * If so, return 1, else 0 102 * If so, return 1, else 0
103 */ 103 */
104int 104int
105ispkgpattern(const char *pkg) 105ispkgpattern(const char *pkg)
106{ 106{
107 return strpbrk(pkg, "<>[]?*{") != NULL; 107 return strpbrk(pkg, "<>[]?*{") != NULL;
108} 108}
 109
 110/*
 111 * Strip off any .tgz, .tbz or .t[bg]z suffix from fname,
 112 * and copy into buffer "buf", the suffix is stored in "sfx"
 113 * if "sfx" is not NULL. If no suffix is found, "sfx" is set
 114 * to an empty string.
 115 */
 116void
 117strip_txz(char *buf, char *sfx, const char *fname)
 118{
 119 static const char *const suffixes[] = {
 120 ".tgz", ".tbz", ".t[bg]z", 0};
 121 const char *const *suffixp;
 122 size_t len;
 123
 124 len = strlen(fname);
 125 assert(len < PKG_PATTERN_MAX);
 126
 127 if (sfx)
 128 sfx[0] = '\0';
 129
 130 for (suffixp = suffixes; *suffixp; suffixp++) {
 131 size_t suffixlen = strlen(*suffixp);
 132
 133 if (memcmp(&fname[len - suffixlen], *suffixp, suffixlen))
 134 continue;
 135
 136 /* matched! */
 137 memcpy(buf, fname, len - suffixlen);
 138 buf[len - suffixlen] = 0;
 139 if (sfx) {
 140 if (suffixlen >= PKG_SUFFIX_MAX)
 141 errx(EXIT_FAILURE, "too long suffix '%s'", fname);
 142 memcpy(sfx, *suffixp, suffixlen+1);
 143 return;
 144 }
 145 }
 146
 147 /* not found */
 148 memcpy(buf, fname, len+1);
 149}