summaryrefslogtreecommitdiff
path: root/pkgtools/pkg_install
diff options
context:
space:
mode:
authorjoerg <joerg@pkgsrc.org>2008-04-26 14:56:33 +0000
committerjoerg <joerg@pkgsrc.org>2008-04-26 14:56:33 +0000
commitba8b7d38610a93992f56700fb6e51bd0bf6c32a7 (patch)
tree3c32c07dd243ab0b71b371435e4f5ab5dc222c46 /pkgtools/pkg_install
parent51d4e31fe51bc34e46cfe59331690ccbb7e7a99c (diff)
downloadpkgsrc-ba8b7d38610a93992f56700fb6e51bd0bf6c32a7.tar.gz
Add a clean pkg_add implementation on top of libarchive and libfetch.
Known regressions: - "pkg_add -" (aka reading from stdin) is currently not supported - "pkg_add -s" is not supported either - no progress reports for the downloads - binary packages with hardlinks created by pkg_create before pkg_install-20080422 will not extract correctly (libarchive issue) - no adhoc check for potential conflicts between dependencies and already installed packages Features: - Twice as fast for the typical case of /var/tmp and /usr/pkg on different filesystems - Standalone - implicit conflict detection before actual installation.
Diffstat (limited to 'pkgtools/pkg_install')
-rw-r--r--pkgtools/pkg_install/files/add/Makefile.in8
-rw-r--r--pkgtools/pkg_install/files/add/add.h9
-rw-r--r--pkgtools/pkg_install/files/add/extract.c340
-rw-r--r--pkgtools/pkg_install/files/add/futil.c151
-rw-r--r--pkgtools/pkg_install/files/add/main.c18
-rw-r--r--pkgtools/pkg_install/files/add/perform.c1897
-rw-r--r--pkgtools/pkg_install/files/add/pkg_add.138
-rw-r--r--pkgtools/pkg_install/files/create/perform.c36
-rw-r--r--pkgtools/pkg_install/files/info/Makefile.in4
-rw-r--r--pkgtools/pkg_install/files/info/perform.c29
-rw-r--r--pkgtools/pkg_install/files/lib/Makefile.in8
-rw-r--r--pkgtools/pkg_install/files/lib/conflicts.c9
-rw-r--r--pkgtools/pkg_install/files/lib/file.c429
-rw-r--r--pkgtools/pkg_install/files/lib/ftpio.c1259
-rw-r--r--pkgtools/pkg_install/files/lib/lib.h90
-rw-r--r--pkgtools/pkg_install/files/lib/pen.c206
-rw-r--r--pkgtools/pkg_install/files/lib/pexec.c110
-rw-r--r--pkgtools/pkg_install/files/lib/pkg_io.c185
-rw-r--r--pkgtools/pkg_install/files/lib/plist.c5
-rw-r--r--pkgtools/pkg_install/files/lib/str.c45
20 files changed, 1289 insertions, 3587 deletions
diff --git a/pkgtools/pkg_install/files/add/Makefile.in b/pkgtools/pkg_install/files/add/Makefile.in
index 07cff421baa..3cf26e92a48 100644
--- a/pkgtools/pkg_install/files/add/Makefile.in
+++ b/pkgtools/pkg_install/files/add/Makefile.in
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.in,v 1.16 2008/03/10 12:14:32 wiz Exp $
+# $NetBSD: Makefile.in,v 1.17 2008/04/26 14:56:33 joerg Exp $
srcdir= @srcdir@
@@ -13,9 +13,9 @@ cat1dir= $(mandir)/cat1
CC= @CC@
CCLD= $(CC)
-LIBS= -linstall @LIBS@
+LIBS= -linstall -lfetch -larchive -lbz2 -lz @LIBS@
CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib
-DEFS= @DEFS@ -DOPSYS_NAME=\"$(OPSYS)\" -DMACHINE_ARCH=\"$(MACHINE_ARCH)\" -DBINDIR=\"$(sbindir)\" -DTAR_CMD=\"@tar@\" -DPAX_CMD=\"@pax@\"
+DEFS= @DEFS@ -DOPSYS_NAME=\"$(OPSYS)\" -DMACHINE_ARCH=\"$(MACHINE_ARCH)\" -DBINDIR=\"$(sbindir)\"
CFLAGS= @CFLAGS@
LDFLAGS= @LDFLAGS@ -L../lib
@@ -23,7 +23,7 @@ INSTALL= @INSTALL@
PROG= pkg_add
-OBJS= main.o perform.o futil.o extract.o verify.o
+OBJS= main.o perform.o verify.o
all: $(PROG)
diff --git a/pkgtools/pkg_install/files/add/add.h b/pkgtools/pkg_install/files/add/add.h
index ca6ce6f3195..3f9002b5604 100644
--- a/pkgtools/pkg_install/files/add/add.h
+++ b/pkgtools/pkg_install/files/add/add.h
@@ -1,4 +1,4 @@
-/* $NetBSD: add.h,v 1.10 2007/09/29 13:24:32 rillig Exp $ */
+/* $NetBSD: add.h,v 1.11 2008/04/26 14:56:33 joerg Exp $ */
/* from FreeBSD Id: add.h,v 1.8 1997/02/22 16:09:15 peter Exp */
@@ -35,15 +35,8 @@ extern Boolean NoRecord;
extern Boolean Force;
extern Boolean Automatic;
extern int Replace;
-extern char *Mode;
-extern char *Owner;
-extern char *Group;
-extern char *Directory;
-extern char *PkgName;
-extern char FirstPen[];
int make_hierarchy(char *);
-int extract_plist(char *, package_t *);
void apply_perms(char *, char **, int);
int pkg_perform(lpkg_head_t *);
diff --git a/pkgtools/pkg_install/files/add/extract.c b/pkgtools/pkg_install/files/add/extract.c
deleted file mode 100644
index 9bfb3b678f6..00000000000
--- a/pkgtools/pkg_install/files/add/extract.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/* $NetBSD: extract.c,v 1.16 2007/09/11 13:46:10 rillig 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.16 2007/09/11 13:46:10 rillig 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;
-}
diff --git a/pkgtools/pkg_install/files/add/futil.c b/pkgtools/pkg_install/files/add/futil.c
deleted file mode 100644
index c314842b789..00000000000
--- a/pkgtools/pkg_install/files/add/futil.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $NetBSD: futil.c,v 1.9 2005/12/06 01:08:09 ben 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.9 2005/12/06 01:08:09 ben 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);
-}
diff --git a/pkgtools/pkg_install/files/add/main.c b/pkgtools/pkg_install/files/add/main.c
index 92335db7ddc..1e68005cff9 100644
--- a/pkgtools/pkg_install/files/add/main.c
+++ b/pkgtools/pkg_install/files/add/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.14 2008/03/01 19:06:10 rillig Exp $ */
+/* $NetBSD: main.c,v 1.15 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static char *rcsid = "from FreeBSD Id: main.c,v 1.16 1997/10/08 07:45:43 charnier Exp";
#else
-__RCSID("$NetBSD: main.c,v 1.14 2008/03/01 19:06:10 rillig Exp $");
+__RCSID("$NetBSD: main.c,v 1.15 2008/04/26 14:56:34 joerg Exp $");
#endif
#endif
@@ -60,12 +60,6 @@ Boolean NoInstall = FALSE;
Boolean NoRecord = FALSE;
Boolean Automatic = FALSE;
-char *Mode = NULL;
-char *Owner = NULL;
-char *Group = NULL;
-char *PkgName = NULL;
-char *Directory = NULL;
-char FirstPen[MaxPathSize];
int Replace = 0;
static void
@@ -73,7 +67,7 @@ usage(void)
{
(void) fprintf(stderr, "%s\n%s\n%s\n",
"usage: pkg_add [-AfhILnRuVv] [-K pkg_dbdir] [-m machine] [-p prefix]",
- " [-s verification-type] [-t template] [-W viewbase] [-w view]",
+ " [-s verification-type] [-W viewbase] [-w view]",
" [[ftp|http]://[user[:password]@]host[:port]][/path/]pkg-name ...");
exit(1);
}
@@ -126,13 +120,11 @@ main(int argc, char **argv)
Prefix = optarg;
break;
+#if 0
case 's':
set_verification(optarg);
break;
-
- case 't':
- strlcpy(FirstPen, optarg, sizeof(FirstPen));
- break;
+#endif
case 'u':
Replace++;
diff --git a/pkgtools/pkg_install/files/add/perform.c b/pkgtools/pkg_install/files/add/perform.c
index 66d34420fdc..fa72d03576e 100644
--- a/pkgtools/pkg_install/files/add/perform.c
+++ b/pkgtools/pkg_install/files/add/perform.c
@@ -1,5 +1,4 @@
-/* $NetBSD: perform.c,v 1.70 2008/02/08 00:58:17 joerg Exp $ */
-
+/* $NetBSD: perform.c,v 1.71 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
@@ -7,1047 +6,1223 @@
#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 = "from FreeBSD Id: perform.c,v 1.44 1997/10/13 15:03:46 jkh Exp";
-#else
-__RCSID("$NetBSD: perform.c,v 1.70 2008/02/08 00:58:17 joerg Exp $");
-#endif
-#endif
-
-/*
- * FreeBSD install - a package for the installation and maintainance
- * of non-core utilities.
+__RCSID("$NetBSD: perform.c,v 1.71 2008/04/26 14:56:34 joerg Exp $");
+
+/*-
+ * Copyright (c) 2003 Grant Beattie <grant@NetBSD.org>
+ * Copyright (c) 2005 Dieter Baron <dillo@NetBSD.org>
+ * Copyright (c) 2007 Roland Illig <rillig@NetBSD.org>
+ * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>
+ * All rights reserved.
*
* 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 main body of the add module.
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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_ASSERT_H
-#include <assert.h>
-#endif
-#if HAVE_ERR_H
+#include <sys/utsname.h>
+#include <archive.h>
+#include <archive_entry.h>
#include <err.h>
-#endif
-#if HAVE_ERRNO_H
#include <errno.h>
-#endif
-#include "defs.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
#include "lib.h"
#include "add.h"
-#include "verify.h"
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-#if HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_SYS_UTSNAME_H
-#include <sys/utsname.h>
-#endif
+struct pkg_meta {
+ char *meta_contents;
+ char *meta_comment;
+ char *meta_desc;
+ char *meta_mtree;
+ char *meta_build_version;
+ char *meta_build_info;
+ char *meta_size_pkg;
+ char *meta_size_all;
+ char *meta_required_by;
+ char *meta_display;
+ char *meta_install;
+ char *meta_deinstall;
+ char *meta_preserve;
+ char *meta_views;
+ char *meta_installed_info;
+};
-static char LogDir[MaxPathSize];
-static int zapLogDir; /* Should we delete LogDir? */
+struct pkg_task {
+ const char *pkgname;
-static package_t Plist;
-static char *Home;
+ const char *prefix;
+ const char *install_prefix;
-static lfile_head_t files;
+ char *logdir;
+ char *other_version;
-/* used in build information */
-enum {
- Good,
- Missing,
- Warning,
- Fatal
+ package_t plist;
+
+ struct pkg_meta meta_data;
+
+ struct archive *archive;
+ struct archive_entry *entry;
+
+ char *buildinfo[BI_ENUM_COUNT];
+
+ size_t dep_length, dep_allocated;
+ char **dependencies;
};
-static void
-normalise_platform(struct utsname *host_name)
-{
-#ifdef NUMERIC_VERSION_ONLY
- size_t span;
+static const struct pkg_meta_desc {
+ size_t entry_offset;
+ const char *entry_filename;
+ int required_file;
+ mode_t perm;
+} pkg_meta_descriptors[] = {
+ { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 1, 0644 },
+ { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 1, 0444},
+ { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 1, 0444},
+ { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 0, 0555 },
+ { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 0, 0555 },
+ { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_views), VIEWS_FNAME, 0, 0444 },
+ { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME, 0, 0644 },
+ { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME, 0, 0644 },
+ { 0, NULL, 0 },
+};
- span = strspn(host_name->release, "0123456789.");
- host_name->release[span] = '\0';
-#endif
+static int pkg_do(const char *, int);
+
+static int
+mkdir_p(const char *path)
+{
+ return fexec(MKDIR_CMD, "-p", path, (void *)NULL);
}
-/* Read package build information */
+/*
+ * Read meta data from archive.
+ * Bail out if a required entry is missing or entries are in the wrong order.
+ */
static int
-read_buildinfo(char **buildinfo)
+read_meta_data(struct pkg_task *pkg)
{
- char *key;
- char *line;
- size_t len;
- FILE *fp;
+ const struct pkg_meta_desc *descr, *last_descr;
+ const char *fname;
+ char **target;
+ int64_t size;
+ int r, found_required;
+
+ found_required = 0;
+
+ last_descr = 0;
+ while ((r = archive_read_next_header(pkg->archive, &pkg->entry)) ==
+ ARCHIVE_OK) {
+ fname = archive_entry_pathname(pkg->entry);
+
+ for (descr = pkg_meta_descriptors; descr->entry_filename;
+ ++descr) {
+ if (strcmp(descr->entry_filename, fname) == 0)
+ break;
+ }
+ if (descr->entry_filename == NULL)
+ break;
- if ((fp = fopen(BUILD_INFO_FNAME, "r")) == NULL) {
- warnx("unable to open %s file.", BUILD_INFO_FNAME);
- return 0;
- }
+ if (descr->required_file)
+ ++found_required;
- while ((line = fgetln(fp, &len)) != NULL) {
- if (line[len - 1] == '\n')
- line[len - 1] = '\0';
+ target = (char **)((char *)&pkg->meta_data +
+ descr->entry_offset);
+ if (*target) {
+ warnx("duplicate entry, package corrupt");
+ return -1;
+ }
+ if (descr < last_descr) {
+ warnx("misordered package");
+ return -1;
+ }
+ last_descr = descr;
- if ((key = strsep(&line, "=")) == NULL)
- continue;
+ size = archive_entry_size(pkg->entry);
+ if (size > SSIZE_MAX - 1) {
+ warnx("package meta data too large to process");
+ return -1;
+ }
+ if ((*target = malloc(size + 1)) == NULL)
+ err(2, "cannot allocate meta data");
+ if (archive_read_data(pkg->archive, *target, size) != size) {
+ warn("cannot read package meta data");
+ return -1;
+ }
+ (*target)[size] = '\0';
+ }
- /*
- * pkgsrc used to create the BUILDINFO file using
- * "key= value", so skip the space if it's there.
- */
- if (line == NULL)
- continue;
- if (line[0] == ' ')
- line += sizeof(char);
+ if (r != ARCHIVE_OK)
+ pkg->entry = NULL;
- /*
- * we only care about opsys, arch, version, and
- * dependency recommendations
- */
- if (line[0] != '\0') {
- if (strcmp(key, "OPSYS") == 0)
- buildinfo[BI_OPSYS] = strdup(line);
- else if (strcmp(key, "OS_VERSION") == 0)
- buildinfo[BI_OS_VERSION] = strdup(line);
- else if (strcmp(key, "MACHINE_ARCH") == 0)
- buildinfo[BI_MACHINE_ARCH] = strdup(line);
- else if (strcmp(key, "IGNORE_RECOMMENDED") == 0)
- buildinfo[BI_IGNORE_RECOMMENDED] = strdup(line);
- else if (strcmp(key, "USE_ABI_DEPENDS") == 0)
- buildinfo[BI_USE_ABI_DEPENDS] = strdup(line);
- }
+ for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
+ if (descr->required_file)
+ --found_required;
}
- (void) fclose(fp);
- if (buildinfo[BI_OPSYS] == NULL ||
- buildinfo[BI_OS_VERSION] == NULL ||
- buildinfo[BI_MACHINE_ARCH] == NULL) {
- warnx("couldn't extract build information from package.");
- return 0;
+
+ return !found_required ? 0 : -1;
+}
+
+/*
+ * Free meta data.
+ */
+static void
+free_meta_data(struct pkg_task *pkg)
+{
+ const struct pkg_meta_desc *descr;
+ char **target;
+
+ for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
+ target = (char **)((char *)&pkg->meta_data +
+ descr->entry_offset);
+ free(*target);
+ *target = NULL;
}
- return 1;
}
+/*
+ * Parse PLIST and populate pkg.
+ */
static int
-sanity_check(const char *pkg)
+pkg_parse_plist(struct pkg_task *pkg)
{
- int errc = 0;
-
- if (!fexists(CONTENTS_FNAME)) {
- warnx("package %s has no CONTENTS file!", pkg);
- errc = 1;
- } else if (!fexists(COMMENT_FNAME)) {
- warnx("package %s has no COMMENT file!", pkg);
- errc = 1;
- } else if (!fexists(DESC_FNAME)) {
- warnx("package %s has no DESC file!", pkg);
- errc = 1;
+ plist_t *p;
+
+ parse_plist(&pkg->plist, pkg->meta_data.meta_contents);
+ if ((p = find_plist(&pkg->plist, PLIST_NAME)) == NULL) {
+ warnx("Invalid PLIST: missing @name");
+ return -1;
+ }
+ pkg->pkgname = p->name;
+ if ((p = find_plist(&pkg->plist, PLIST_CWD)) == NULL) {
+ warnx("Invalid PLIST: missing @cwd");
+ return -1;
}
- return errc;
+ /* XXX change first @cwd in PLIST? */
+ pkg->prefix = p->name;
+ pkg->install_prefix = Prefix != NULL ? Prefix : pkg->prefix;
+
+ return 0;
+}
+
+/*
+ * Helper function to extract value from a string of the
+ * form key=value ending at eol.
+ */
+static char *
+dup_value(const char *line, const char *eol)
+{
+ const char *key;
+ char *val;
+
+ key = strchr(line, '=');
+ val = malloc(eol - key);
+ if (val == NULL)
+ err(2, "malloc failed");
+ memcpy(val, key + 1, eol - key - 1);
+ val[eol - key - 1] = '\0';
+ return val;
}
-/* install a pre-requisite package. Returns 1 if it installed it */
static int
-installprereq(const char *name, int *errc, int doupdate)
+check_already_installed(struct pkg_task *pkg)
{
- int ret;
- ret = 0;
+ char *filename;
+ int fd;
- if (Verbose)
- printf("Loading it from %s.\n", name);
- path_setenv("PKG_PATH");
-
- if (fexec_skipempty(BINDIR "/pkg_add", "-K", _pkgdb_getPKGDB_DIR(),
- "-s", get_verification(),
- doupdate > 1 ? "-uu" : (doupdate ? "-u" : ""),
- Fake ? "-n" : "",
- NoView ? "-L" : "",
- View ? "-w" : "", View ? View : "",
- Viewbase ? "-W" : "", Viewbase ? Viewbase : "",
- Force ? "-f" : "",
- Prefix ? "-p" : "", Prefix ? Prefix : "",
- Verbose ? "-v" : "",
- OverrideMachine ? "-m" : "",
- OverrideMachine ? OverrideMachine : "",
- NoInstall ? "-I" : "",
- "-A", name, NULL)) {
- warnx("autoload of dependency `%s' failed%s",
- name, Force ? " (proceeding anyway)" : "!");
- if (!Force)
- ++(*errc);
+ if (Force)
+ return -1;
+
+ filename = pkgdb_pkg_file(pkg->pkgname, CONTENTS_FNAME);
+ fd = open(filename, O_RDONLY);
+ free(filename);
+ if (fd == -1)
+ return -1;
+
+ /* We can only arrive here for explicitly requested packages. */
+ if (!Automatic && is_automatic_installed(pkg->pkgname)) {
+ if (Fake ||
+ mark_as_automatic_installed(pkg->pkgname, 0) == 0)
+ warnx("package `%s' was already installed as "
+ "dependency, now marked as installed "
+ "manually", pkg->pkgname);
} else {
- ret = 1;
+ warnx("package `%s' already recorded as installed",
+ pkg->pkgname);
}
+ return 0;
- return ret;
}
static int
-pkg_do_installed(int *replacing, char replace_via[MaxPathSize], char replace_to[MaxPathSize],
- Boolean is_depoted_pkg, const char *dbdir)
+check_other_installed(struct pkg_task *pkg)
{
- char replace_from[MaxPathSize];
- char *s;
- char buf[MaxPathSize];
- char *best_installed;
-
- const size_t replace_via_size = MaxPathSize;
- const size_t replace_to_size = MaxPathSize;
+ FILE *f, *f_pkg;
+ size_t len;
+ char *pkgbase, *iter, *filename;
+ package_t plist;
+ plist_t *p;
+ int status;
- if ((s = strrchr(PkgName, '-')) == NULL) {
- warnx("Package name %s does not contain a version, bailing out", PkgName);
+ if ((pkgbase = strdup(pkg->pkgname)) == NULL) {
+ warnx("strdup failed");
return -1;
}
-
- /*
- * See if the pkg is already installed. If so, we might want to
- * upgrade/replace it. Otherwise, just return and let pkg_do work.
- */
- (void) snprintf(buf, sizeof(buf), "%.*s[0-9]*",
- (int)(s - PkgName) + 1, PkgName);
- best_installed = find_best_matching_installed_pkg(buf);
- if (best_installed == NULL)
+ if ((iter = strrchr(pkgbase, '-')) == NULL) {
+ free(pkgbase);
+ warnx("Invalid package name %s", pkg->pkgname);
+ return -1;
+ }
+ *iter = '\0';
+ pkg->other_version = find_best_matching_installed_pkg(pkgbase);
+ free(pkgbase);
+ if (pkg->other_version == NULL)
return 0;
- if (!Replace || Fake) {
- if (is_depoted_pkg) {
- free(best_installed);
- return 0;
- } else {
- warnx("other version '%s' already installed", best_installed);
- free(best_installed);
- return 1; /* close enough for government work */
- }
+ if (!Replace) {
+ /* XXX This is redundant to the implicit conflict check. */
+ warnx("A different version of %s is already installed: %s",
+ pkg->pkgname, pkg->other_version);
+ return -1;
}
- /* XXX Should list the steps in Fake mode */
- snprintf(replace_from, sizeof(replace_from), "%s/%s/" REQUIRED_BY_FNAME,
- dbdir, best_installed);
- snprintf(replace_via, replace_via_size, "%s/.%s." REQUIRED_BY_FNAME,
- dbdir, best_installed);
- snprintf(replace_to, replace_to_size, "%s/%s/" REQUIRED_BY_FNAME,
- dbdir, PkgName);
-
- if (Verbose)
- printf("Upgrading %s to %s.\n", best_installed, PkgName);
+ filename = pkgdb_pkg_file(pkg->other_version, REQUIRED_BY_FNAME);
+ errno = 0;
+ f = fopen(filename, "r");
+ free(filename);
+ if (f == NULL) {
+ if (errno == ENOENT) {
+ /* No packages depend on this, so everything is well. */
+ return 0;
+ }
+ warnx("Can't open +REQUIRED_BY of %s", pkg->other_version);
+ return -1;
+ }
- if (fexists(replace_from)) { /* Are there any dependencies? */
- /*
- * Upgrade step 1/4: Check if the new version is ok with all pkgs
- * (from +REQUIRED_BY) that require this pkg
- */
- FILE *rb; /* +REQUIRED_BY file */
- char pkg2chk[MaxPathSize];
-
- rb = fopen(replace_from, "r");
- if (! rb) {
- warnx("Cannot open '%s' for reading%s", replace_from,
- Force ? " (proceeding anyways)" : "");
- if (Force)
- goto ignore_replace_depends_check;
- else
- return -1;
+ status = 0;
+
+ while ((iter = fgetln(f, &len)) != NULL) {
+ if (iter[len - 1] == '\n')
+ iter[len - 1] = '\0';
+ filename = pkgdb_pkg_file(iter, CONTENTS_FNAME);
+ if ((f_pkg = fopen(filename, "r")) == NULL) {
+ warnx("Can't open +CONTENTS of depending package %s",
+ iter);
+ fclose(f);
+ return -1;
}
- while (fgets(pkg2chk, sizeof(pkg2chk), rb)) {
- package_t depPlist;
- FILE *depf;
- plist_t *depp;
- char depC[MaxPathSize];
-
- depPlist.head = depPlist.tail = NULL;
-
- s = strrchr(pkg2chk, '\n');
- if (s)
- *s = '\0'; /* strip trailing '\n' */
-
- /*
- * step into pkg2chk, read it's +CONTENTS file and see if
- * all @pkgdep lines agree with PkgName (using pkg_match())
+ plist.head = plist.tail = NULL;
+ read_plist(&plist, f_pkg);
+ fclose(f_pkg);
+ for (p = plist.head; p != NULL; p = p->next) {
+ if (p->type == PLIST_IGNORE) {
+ p = p->next;
+ continue;
+ } else if (p->type != PLIST_PKGDEP)
+ continue;
+ /*
+ * XXX This is stricter than necessary.
+ * XXX One pattern might be fulfilled by
+ * XXX a different package and still need this
+ * XXX one for a different pattern.
*/
- snprintf(depC, sizeof(depC), "%s/%s/%s", dbdir, pkg2chk, CONTENTS_FNAME);
- depf = fopen(depC , "r");
- if (depf == NULL) {
- warnx("Cannot check depends in '%s'%s", depC,
- Force ? " (proceeding anyways)" : "!" );
- if (Force)
- goto ignore_replace_depends_check;
- else
- return -1;
- }
- read_plist(&depPlist, depf);
- fclose(depf);
-
- for (depp = depPlist.head; depp; depp = depp->next) {
- char base_new[MaxPathSize];
- char base_exist[MaxPathSize];
- char *s2;
-
- if (depp->type != PLIST_PKGDEP)
- continue;
-
- /*
- * Prepare basename (no versions) of both pkgs,
- * to see if we want to compare against that
- * one at all.
- */
- strlcpy(base_new, PkgName, sizeof(base_new));
- s2 = strpbrk(base_new, "<>[]?*{"); /* } */
- if (s2)
- *s2 = '\0';
- else {
- s2 = strrchr(base_new, '-');
- if (s2)
- *s2 = '\0';
- }
- strlcpy(base_exist, depp->name, sizeof(base_exist));
- s2 = strpbrk(base_exist, "<>[]?*{"); /* } */
- if (s2)
- *s2 = '\0';
- else {
- s2 = strrchr(base_exist, '-');
- if (s2)
- *s2 = '\0';
- }
- if (strcmp(base_new, base_exist) == 0) {
- /* Same pkg, so do the interesting compare */
- if (pkg_match(depp->name, PkgName)) {
- if (Verbose)
- printf("@pkgdep check: %s is ok for %s (in %s pkg)\n",
- PkgName, depp->name, pkg2chk);
- } else {
- printf("Package %s requires %s, \n\tCannot replace with %s%s\n",
- pkg2chk, depp->name, PkgName,
- Force? " (proceeding anyways)" : "!");
- if (! Force)
- return -1;
- }
- }
- }
+ if (pkg_match(p->name, pkg->other_version) == 0)
+ continue;
+ if (pkg_match(p->name, pkg->pkgname) == 1)
+ continue; /* Both match, ok. */
+ warnx("Dependency of %s fulfilled by %s, but not by %s",
+ iter, pkg->other_version, pkg->pkgname);
+ if (!Force)
+ status = -1;
+ break;
}
- fclose(rb);
+ free_plist(&plist);
+ }
-ignore_replace_depends_check:
- /*
- * Upgrade step 2/4: Do the actual update by moving aside
- * the +REQUIRED_BY file, deinstalling the old pkg, adding
- * the new one and moving the +REQUIRED_BY file back
- * into place (finished in step 3/4)
- */
- if (Verbose)
- printf("mv %s %s\n", replace_from, replace_via);
- if (rename(replace_from, replace_via) != 0)
- err(EXIT_FAILURE, "renaming \"%s\" to \"%s\" failed", replace_from, replace_via);
+ fclose(f);
- *replacing = 1;
- }
+ return status;
+}
- if (Verbose) {
- printf("%s/pkg_delete -K %s '%s'\n",
- BINDIR, dbdir, best_installed);
+/*
+ * Read package build information from meta data.
+ */
+static int
+read_buildinfo(struct pkg_task *pkg)
+{
+ const char *data, *eol, *next_line;
+
+ data = pkg->meta_data.meta_build_info;
+
+ for (; *data != '\0'; data = next_line) {
+ if ((eol = strchr(data, '\n')) == NULL) {
+ eol = data + strlen(data);
+ next_line = eol;
+ } else
+ next_line = eol + 1;
+
+ if (strncmp(data, "OPSYS=", 6) == 0)
+ pkg->buildinfo[BI_OPSYS] = dup_value(data, eol);
+ else if (strncmp(data, "OS_VERSION=", 11) == 0)
+ pkg->buildinfo[BI_OS_VERSION] = dup_value(data, eol);
+ else if (strncmp(data, "MACHINE_ARCH=", 13) == 0)
+ pkg->buildinfo[BI_MACHINE_ARCH] = dup_value(data, eol);
+ else if (strncmp(data, "IGNORE_RECOMMENDED=", 19) == 0)
+ pkg->buildinfo[BI_IGNORE_RECOMMENDED] = dup_value(data,
+ eol);
+ else if (strncmp(data, "USE_ABI_DEPENDS=", 16) == 0)
+ pkg->buildinfo[BI_USE_ABI_DEPENDS] = dup_value(data,
+ eol);
+ }
+ if (pkg->buildinfo[BI_OPSYS] == NULL ||
+ pkg->buildinfo[BI_OS_VERSION] == NULL ||
+ pkg->buildinfo[BI_MACHINE_ARCH] == NULL) {
+ warnx("Not all required build information are present.");
+ return -1;
}
- fexec(BINDIR "/pkg_delete", "-K", dbdir, best_installed, NULL);
- free(best_installed);
+ if ((pkg->buildinfo[BI_USE_ABI_DEPENDS] != NULL &&
+ strcasecmp(pkg->buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) ||
+ (pkg->buildinfo[BI_IGNORE_RECOMMENDED] != NULL &&
+ strcasecmp(pkg->buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) {
+ warnx("%s was built to ignore ABI dependencies", pkg->pkgname);
+ }
return 0;
}
/*
- * Install a single package
- * Returns 0 if everything is ok, >0 else
+ * Free buildinfo.
*/
-static int
-pkg_do(const char *pkg, lpkg_head_t *pkgs)
+static void
+free_buildinfo(struct pkg_task *pkg)
{
- char playpen[MaxPathSize];
- char replace_via[MaxPathSize];
- char replace_to[MaxPathSize];
- char *buildinfo[BI_ENUM_COUNT];
- int replacing = 0;
- char dbdir[MaxPathSize];
- const char *tmppkg;
- FILE *cfile;
- int errc, err_prescan;
- plist_t *p;
- struct stat sb;
- struct utsname host_uname;
- uint64_t needed;
- Boolean is_depoted_pkg = FALSE;
- lfile_t *lfp;
- int result;
-
- errc = 0;
- zapLogDir = 0;
- LogDir[0] = '\0';
- strlcpy(playpen, FirstPen, sizeof(playpen));
- memset(buildinfo, '\0', sizeof(buildinfo));
-
- umask(DEF_UMASK);
-
- tmppkg = fileFindByPath(pkg);
- if (tmppkg == NULL) {
- warnx("no pkg found for '%s', sorry.", pkg);
- return 1;
+ size_t i;
+
+ for (i = 0; i < BI_ENUM_COUNT; ++i) {
+ free(pkg->buildinfo[i]);
+ pkg->buildinfo[i] = NULL;
}
+}
- pkg = tmppkg;
+/*
+ * Write meta data files to pkgdb after creating the directory.
+ */
+static int
+write_meta_data(struct pkg_task *pkg)
+{
+ const struct pkg_meta_desc *descr;
+ char *filename, **target;
+ size_t len;
+ ssize_t ret;
+ int fd;
- if (IS_URL(pkg)) {
- Home = fileGetURL(pkg);
- if (Home == NULL) {
- warnx("unable to fetch `%s' by URL", pkg);
- }
+ if (Fake)
+ return 0;
+
+ if (mkdir_p(pkg->logdir)) {
+ warn("Can't create pkgdb entry: %s", pkg->logdir);
+ return -1;
+ }
- /* make sure the pkg is verified */
- if (!verify(pkg)) {
- warnx("Package %s will not be extracted", pkg);
- goto bomb;
+ for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
+ target = (char **)((char *)&pkg->meta_data +
+ descr->entry_offset);
+ if (*target == NULL)
+ continue;
+ if (asprintf(&filename, "%s/%s", pkg->logdir,
+ descr->entry_filename) == -1) {
+ warn("asprintf failed");
+ return -1;
}
- } else { /* local */
- if (!IS_STDIN(pkg)) {
- /* not stdin */
- if (!ispkgpattern(pkg)) {
- if (stat(pkg, &sb) == FAIL) {
- warnx("can't stat package file '%s'", pkg);
- goto bomb;
- }
- /* make sure the pkg is verified */
- if (!verify(pkg)) {
- warnx("Package %s will not be extracted", pkg);
- goto bomb;
- }
+ (void)unlink(filename);
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, descr->perm);
+ if (fd == -1) {
+ warn("Can't open meta data file: %s", filename);
+ return -1;
+ }
+ len = strlen(*target);
+ do {
+ ret = write(fd, *target, len);
+ if (ret == -1) {
+ warn("Can't write meta data file: %s",
+ filename);
+ free(filename);
+ return -1;
}
- LFILE_ADD(&files, lfp, CONTENTS_FNAME);
- } else {
- /* some values for stdin */
- sb.st_size = 100000; /* Make up a plausible average size */
+ len -= ret;
+ } while (ret > 0);
+ if (close(fd) == -1) {
+ warn("Can't close meta data file: %s", filename);
+ free(filename);
+ return -1;
}
- Home = make_playpen(playpen, sizeof(playpen), sb.st_size * 4);
- if (!Home)
- warnx("unable to make playpen for %ld bytes",
- (long) (sb.st_size * 4));
- result = unpack(pkg, &files);
- while ((lfp = TAILQ_FIRST(&files)) != NULL) {
- TAILQ_REMOVE(&files, lfp, lf_link);
- free(lfp);
+ free(filename);
+ }
+
+ return 0;
+}
+
+/*
+ * Helper function for extract_files.
+ */
+static int
+copy_data_to_disk(struct archive *reader, struct archive *writer,
+ const char *filename)
+{
+ int r;
+ const void *buff;
+ size_t size;
+ off_t offset;
+
+ for (;;) {
+ r = archive_read_data_block(reader, &buff, &size, &offset);
+ if (r == ARCHIVE_EOF)
+ return 0;
+ if (r != ARCHIVE_OK) {
+ warnx("Read error for %s: %s", filename,
+ archive_error_string(reader));
+ return -1;
}
- if (result) {
- warnx("unable to extract table of contents file from `%s' - not a package?",
- pkg);
- goto bomb;
+ r = archive_write_data_block(writer, buff, size, offset);
+ if (r != ARCHIVE_OK) {
+ warnx("Write error for %s: %s", filename,
+ archive_error_string(writer));
+ return -1;
}
}
+}
- cfile = fopen(CONTENTS_FNAME, "r");
- if (!cfile) {
- warnx("unable to open table of contents file `%s' - not a package?",
- CONTENTS_FNAME);
- goto bomb;
- }
- read_plist(&Plist, cfile);
- fclose(cfile);
+/*
+ * Extract package.
+ * Any misordered, missing or unlisted file in the package is an error.
+ */
- if (!IS_URL(pkg)) {
- /*
- * Apply a crude heuristic to see how much space the package will
- * take up once it's unpacked. I've noticed that most packages
- * compress an average of 75%, so multiply by 4 for good measure.
- */
+static const int extract_flags = /* ARCHIVE_EXTRACT_OWNER | */
+ ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK |
+ ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR;
- needed = 4 * (uint64_t) sb.st_size;
- if (min_free(playpen) < needed) {
- warnx("projected size of %" MY_PRIu64 " bytes exceeds available free space\n"
- "in %s. Please set your PKG_TMPDIR variable to point\n"
- "to a location with more free space and try again.",
- needed, playpen);
- goto bomb;
- }
+static int
+extract_files(struct pkg_task *pkg)
+{
+ char cmd[MaxPathSize];
+ const char *owner, *group, *permissions;
+ struct archive *writer;
+ int r;
+ plist_t *p;
+ const char *last_file;
+ char *fullpath;
- /* Finally unpack the whole mess */
- if (unpack(pkg, NULL)) {
- warnx("unable to extract `%s'!", pkg);
- goto bomb;
- }
+ if (Fake)
+ return 0;
+
+ if (mkdir_p(pkg->install_prefix)) {
+ warn("Can't create prefix: %s", pkg->install_prefix);
+ return -1;
}
- /* Check for sanity */
- if (sanity_check(pkg))
- goto bomb;
+ if (chdir(pkg->install_prefix) == -1) {
+ warn("Can't change into prefix: %s", pkg->install_prefix);
+ return -1;
+ }
- /* Read the OS, version and architecture from BUILD_INFO file */
- if (!read_buildinfo(buildinfo)) {
- warn("can't read build information from %s", BUILD_INFO_FNAME);
- if (!Force) {
- warnx("aborting.");
- goto bomb;
- }
+ if (!NoRecord && !pkgdb_open(ReadWrite)) {
+ warn("Can't open pkgdb for writing");
+ return -1;
}
- if (uname(&host_uname) < 0) {
- warnx("uname() failed.");
- if (!Force) {
- warnx("aborting.");
- goto bomb;
- }
- } else {
- int status = Good;
+ writer = archive_write_disk_new();
+ archive_write_disk_set_options(writer, extract_flags);
+ archive_write_disk_set_standard_lookup(writer);
+
+ owner = NULL;
+ group = NULL;
+ permissions = NULL;
+ last_file = NULL;
+
+ r = -1;
+
+ for (p = pkg->plist.head; p != NULL; p = p->next) {
+ switch (p->type) {
+ case PLIST_FILE:
+ last_file = p->name;
+ if (pkg->entry == NULL) {
+ warnx("PLIST entry not in package (%s)",
+ archive_entry_pathname(pkg->entry));
+ goto out;
+ }
+ if (strcmp(p->name, archive_entry_pathname(pkg->entry))) {
+ warnx("PLIST entry and package don't match (%s vs %s)",
+ p->name, archive_entry_pathname(pkg->entry));
+ goto out;
+ }
+ if (asprintf(&fullpath, "%s/%s", pkg->install_prefix, p->name) == -1) {
+ warnx("asprintf failed");
+ goto out;
+ }
+ pkgdb_store(fullpath, pkg->pkgname);
+ free(fullpath);
+ if (Verbose)
+ printf("%s", p->name);
+ break;
- normalise_platform(&host_uname);
+ case PLIST_CMD:
+ if (format_cmd(cmd, sizeof(cmd), p->name, pkg->install_prefix, last_file))
+ return -1;
+ printf("Executing '%s'\n", cmd);
+ if (!Fake && system(cmd))
+ warnx("command '%s' failed", cmd); /* XXX bail out? */
+ continue;
- /* check that we have read some values from buildinfo */
- if (buildinfo[BI_OPSYS] == NULL) {
- warnx("Missing operating system value from build information");
- status = Missing;
- }
- if (buildinfo[BI_MACHINE_ARCH] == NULL) {
- warnx("Missing machine architecture value from build information");
- status = Missing;
- }
- if (buildinfo[BI_OS_VERSION] == NULL) {
- warnx("Missing operating system version value from build information");
- status = Missing;
+ case PLIST_CHMOD:
+ permissions = p->name;
+ continue;
+
+ case PLIST_CHOWN:
+ owner = p->name;
+ continue;
+
+ case PLIST_CHGRP:
+ group = p->name;
+ continue;
+
+ case PLIST_IGNORE:
+ p = p->next;
+ continue;
+
+ default:
+ continue;
}
- if (status == Good) {
- const char *effective_arch;
-
- if (OverrideMachine != NULL)
- effective_arch = OverrideMachine;
- else
- effective_arch = MACHINE_ARCH;
-
- /* If either the OS or arch are different, bomb */
- if (strcmp(OPSYS_NAME, buildinfo[BI_OPSYS]) != 0)
- status = Fatal;
- if (strcmp(effective_arch, buildinfo[BI_MACHINE_ARCH]) != 0)
- status = Fatal;
-
- /* If OS and arch are the same, warn if version differs */
- if (status == Good &&
- strcmp(host_uname.release, buildinfo[BI_OS_VERSION]) != 0)
- status = Warning;
-
- if (status != Good) {
- warnx("Warning: package `%s' was built for a different version of the OS:", pkg);
- warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)",
- buildinfo[BI_OPSYS],
- buildinfo[BI_MACHINE_ARCH],
- buildinfo[BI_OS_VERSION],
- OPSYS_NAME,
- effective_arch,
- host_uname.release);
- }
+ r = archive_write_header(writer, pkg->entry);
+ if (r != ARCHIVE_OK) {
+ warnx("Failed to write %s: %s",
+ archive_entry_pathname(pkg->entry),
+ archive_error_string(writer));
+ goto out;
}
- if (!Force && status == Fatal) {
- warnx("aborting.");
- goto bomb;
+ if (owner != NULL)
+ archive_entry_set_uname(pkg->entry, owner);
+ if (group != NULL)
+ archive_entry_set_uname(pkg->entry, group);
+ if (permissions != NULL) {
+ mode_t mode;
+
+ mode = archive_entry_mode(pkg->entry);
+ mode = getmode(setmode(permissions), mode);
+ archive_entry_set_mode(pkg->entry, mode);
}
- }
- /* Check if USE_ABI_DEPENDS or IGNORE_RECOMMENDED was set
- * when this package was built. IGNORE_RECOMMENDED is historical. */
+ r = copy_data_to_disk(pkg->archive, writer,
+ archive_entry_pathname(pkg->entry));
+ if (r)
+ goto out;
+ if (Verbose)
+ printf("\n");
- if ((buildinfo[BI_USE_ABI_DEPENDS] != NULL &&
- strcasecmp(buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) ||
- (buildinfo[BI_IGNORE_RECOMMENDED] != NULL &&
- strcasecmp(buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) {
- warnx("%s was built", pkg);
- warnx("\tto ignore recommended ABI dependencies, this may cause problems!\n");
+ r = archive_read_next_header(pkg->archive, &pkg->entry);
+ if (r == ARCHIVE_EOF) {
+ pkg->entry = NULL;
+ continue;
+ }
+ if (r != ARCHIVE_OK) {
+ warnx("Failed to read from archive: %s",
+ archive_error_string(pkg->archive));
+ goto out;
+ }
}
- /*
- * If we have a prefix, delete the first one we see and add this
- * one in place of it.
- */
- if (Prefix) {
- delete_plist(&Plist, FALSE, PLIST_CWD, NULL);
- add_plist_top(&Plist, PLIST_CWD, Prefix);
+ if (pkg->entry != NULL) {
+ warnx("Package contains entries not in PLIST: %s",
+ archive_entry_pathname(pkg->entry));
+ goto out;
}
- /* Protect against old packages with bogus @name fields */
- p = find_plist(&Plist, PLIST_NAME);
- if (p->name == NULL) {
- warnx("PLIST contains no @name field");
- goto bomb;
+ r = 0;
+
+out:
+ if (!NoRecord)
+ pkgdb_close();
+ archive_write_close(writer);
+ archive_write_finish(writer);
+
+ return r;
+}
+
+/*
+ * Register dependencies after sucessfully installing the package.
+ */
+static void
+pkg_register_depends(struct pkg_task *pkg)
+{
+ int fd;
+ size_t text_len, i;
+ char *required_by, *text;
+
+ if (Fake)
+ return;
+
+ if (pkg->other_version != NULL)
+ return; /* XXX It's using the old dependencies. */
+
+ if (asprintf(&text, "%s\n", pkg->pkgname) == -1)
+ err(2, "asprintf failed");
+ text_len = strlen(text);
+
+ for (i = 0; i < pkg->dep_length; ++i) {
+ required_by = pkgdb_pkg_file(pkg->dependencies[i], REQUIRED_BY_FNAME);
+
+ fd = open(required_by, O_WRONLY | O_APPEND | O_CREAT, 644);
+ if (fd == -1)
+ warn("can't open dependency file '%s',"
+ "registration is incomplete!", required_by);
+ else if (write(fd, text, text_len) != text_len)
+ warn("can't write to dependency file `%s'", required_by);
+ else if (close(fd) == -1)
+ warn("cannot close file %s", required_by);
+
+ free(required_by);
}
- PkgName = p->name;
-
- if (fexists(VIEWS_FNAME))
- is_depoted_pkg = TRUE;
-
- /*
- * Depoted packages' dbdir is the same as DEPOTBASE. Non-depoted
- * packages' dbdir comes from the command-line or the environment.
- */
- if (is_depoted_pkg) {
- p = find_plist(&Plist, PLIST_CWD);
- if (p == NULL) {
- warn("no @cwd in +CONTENTS file?! aborting.");
- goto bomb;
+
+ free(text);
+}
+
+/*
+ * Reduce the result from uname(3) to a canonical form.
+ */
+static void
+normalise_platform(struct utsname *host_name)
+{
+#ifdef NUMERIC_VERSION_ONLY
+ size_t span;
+
+ span = strspn(host_name->release, "0123456789.");
+ host_name->release[span] = '\0';
+#endif
+}
+
+/*
+ * Check build platform of the package against local host.
+ */
+static int
+check_platform(struct pkg_task *pkg)
+{
+ struct utsname host_uname;
+ const char *effective_arch;
+ int fatal;
+
+ if (uname(&host_uname) < 0) {
+ if (Force) {
+ warnx("uname() failed, continuing.");
+ return 0;
+ } else {
+ warnx("uname() failed, aborting.");
+ return -1;
}
- (void) strlcpy(dbdir, dirname_of(p->name), sizeof(dbdir));
- (void) strlcpy(LogDir, p->name, sizeof(LogDir));
- } else {
- (void) strlcpy(dbdir, _pkgdb_getPKGDB_DIR(), sizeof(dbdir));
- (void) snprintf(LogDir, sizeof(LogDir), "%s/%s", dbdir, PkgName);
}
- /* Set environment variables expected by the +INSTALL script. */
- setenv(PKG_PREFIX_VNAME, (p = find_plist(&Plist, PLIST_CWD)) ? p->name : ".", 1);
- setenv(PKG_METADATA_DIR_VNAME, LogDir, 1);
+ normalise_platform(&host_uname);
+
+ if (OverrideMachine != NULL)
+ effective_arch = OverrideMachine;
+ else
+ effective_arch = MACHINE_ARCH;
+
+ /* If either the OS or arch are different, bomb */
+ if (strcmp(OPSYS_NAME, pkg->buildinfo[BI_OPSYS]) ||
+ strcmp(effective_arch, pkg->buildinfo[BI_MACHINE_ARCH]) != 0)
+ fatal = 1;
+ else
+ fatal = 0;
+
+ if (fatal ||
+ strcmp(host_uname.release, pkg->buildinfo[BI_OS_VERSION]) != 0) {
+ warnx("Warning: package `%s' was built for a platform:",
+ pkg->pkgname);
+ warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)",
+ pkg->buildinfo[BI_OPSYS],
+ pkg->buildinfo[BI_MACHINE_ARCH],
+ pkg->buildinfo[BI_OS_VERSION],
+ OPSYS_NAME,
+ effective_arch,
+ host_uname.release);
+ if (!Force && fatal)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Run the install script.
+ */
+static int
+run_install_script(struct pkg_task *pkg, const char *argument)
+{
+ int ret;
+ char *filename;
+
+ if (pkg->meta_data.meta_install == NULL || NoInstall)
+ return 0;
+
+ setenv(PKG_PREFIX_VNAME, pkg->install_prefix, 1); /* XXX or prefix? */
+ setenv(PKG_METADATA_DIR_VNAME, pkg->logdir, 1);
setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1);
-
- /* make sure dbdir actually exists! */
- if (!(isdir(dbdir) || islinktodir(dbdir))) {
- if (fexec("mkdir", "-p", dbdir, NULL)) {
- errx(EXIT_FAILURE,
- "Database-dir %s cannot be generated, aborting.",
- dbdir);
- }
+
+ filename = pkgdb_pkg_file(pkg->pkgname, INSTALL_FNAME);
+ if (Verbose)
+ printf("Running install with PRE-INSTALL for %s.\n", pkg->pkgname);
+ if (Fake) {
+ free(filename);
+ return 0;
}
- /* See if this package (exact version) is already registered */
- if (isdir(LogDir) && !Force) {
- if (!Automatic && is_automatic_installed(PkgName)) {
- if (mark_as_automatic_installed(PkgName, 0) == 0)
- warnx("package `%s' was already installed as "
- "dependency, now marked as installed "
- "manually", PkgName);
- } else {
- warnx("package `%s' already recorded as installed",
- PkgName);
- }
- goto success; /* close enough for government work */
+ ret = 0;
+
+ if (chdir(pkg->logdir) == -1) {
+ warn("Can't change to %s", pkg->logdir);
+ ret = -1;
}
- /* See if some other version of us is already installed */
- switch (pkg_do_installed(&replacing, replace_via, replace_to, is_depoted_pkg, dbdir)) {
- case 0:
- break;
- case 1:
- errc = 1;
- goto success;
- case -1:
- goto bomb;
+ errno = 0;
+ if (ret == 0 && fexec(filename, pkg->pkgname, argument, (void *)NULL)) {
+ if (errno != 0)
+ warn("exec of install script failed");
+ else
+ warnx("install script returned error status");
+ ret = -1;
}
- /* See if there are conflicting packages installed */
- for (p = Plist.head; p; p = p->next) {
- char *best_installed;
+ free(filename);
+ return ret;
+}
- if (p->type != PLIST_PKGCFL)
+static int
+check_explicit_conflict(struct pkg_task *pkg)
+{
+ char *installed, *installed_pattern;
+ plist_t *p;
+ int status;
+
+ status = 0;
+
+ for (p = pkg->plist.head; p != NULL; p = p->next) {
+ if (p->type == PLIST_IGNORE) {
+ p = p->next;
continue;
- if (Verbose)
- printf("Package `%s' conflicts with `%s'.\n", PkgName, p->name);
- best_installed = find_best_matching_installed_pkg(p->name);
- if (best_installed) {
+ } else if (p->type != PLIST_PKGCFL)
+ continue;
+ installed = find_best_matching_installed_pkg(p->name);
+ if (installed) {
warnx("Package `%s' conflicts with `%s', and `%s' is installed.",
- PkgName, p->name, best_installed);
- free(best_installed);
- ++errc;
+ pkg->pkgname, p->name, installed);
+ free(installed);
+ status = -1;
}
}
- /* See if any of the installed packages conflicts with this one. */
- {
- char *inst_pkgname, *inst_pattern;
+ if (some_installed_package_conflicts_with(pkg->pkgname,
+ pkg->other_version, &installed, &installed_pattern)) {
+ warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.",
+ installed, installed_pattern, pkg->pkgname);
+ free(installed);
+ free(installed_pattern);
+ status = -1;
+ }
- if (some_installed_package_conflicts_with(PkgName, &inst_pkgname, &inst_pattern)) {
- warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.",
- inst_pkgname, inst_pattern, PkgName);
- free(inst_pkgname);
- free(inst_pattern);
- errc++;
- }
+ return status;
+}
+
+static int
+check_implicit_conflict(struct pkg_task *pkg)
+{
+ plist_t *p;
+ char *fullpath, *existing;
+ int status;
+
+ if (!pkgdb_open(ReadOnly)) {
+#if notyet /* XXX empty pkgdb without database? */
+ warn("Can't open pkgdb for reading");
+ return -1;
+#else
+ return 0;
+#endif
}
- /* Quick pre-check if any conflicting dependencies are installed
- * (e.g. version X is installed, but version Y is required)
- */
- err_prescan=0;
- for (p = Plist.head; p; p = p->next) {
- char *best_installed;
-
- if (p->type != PLIST_PKGDEP)
+ status = 0;
+
+ for (p = pkg->plist.head; p != NULL; p = p->next) {
+ if (p->type == PLIST_IGNORE) {
+ p = p->next;
continue;
- if (Verbose)
- printf("Depends pre-scan: `%s' required.\n", p->name);
- best_installed = find_best_matching_installed_pkg(p->name);
- if (best_installed == NULL) {
- /*
- * required pkg not found. look if it's available with a more liberal
- * pattern. If so, this will lead to problems later (check on "some
- * other version of us is already installed" will fail, see above),
- * and we better stop right now.
- */
- char *s;
- int skip = -1;
-
- /* doing this right required to parse the full version(s),
- * do a 99% solution here for now */
- if (strchr(p->name, '{'))
- continue; /* would remove trailing '}' else */
-
- if ((s = strpbrk(p->name, "<>")) != NULL) {
- skip = 0;
- } else if (((s = strstr(p->name, "-[0-9]*")) != NULL) &&
- (*(s + sizeof("-[0-9]*") - 1) == '\0')) {
- /* -[0-9]* already present so no need to */
- /* add it a second time */
- skip = -1;
- } else if ((s = strrchr(p->name, '-')) != NULL) {
- skip = 1;
- }
-
- if (skip >= 0) {
- char buf[MaxPathSize];
-
- (void) snprintf(buf, sizeof(buf),
- skip ? "%.*s[0-9]*" : "%.*s-[0-9]*",
- (int)(s - p->name) + skip, p->name);
- best_installed = find_best_matching_installed_pkg(buf);
- if (best_installed) {
- int done = 0;
-
- if (Replace > 1)
- {
- int errc0 = 0;
- char tmp[MaxPathSize];
-
- warnx("Attempting to update `%s' using binary package\n", p->name);
- /* Yes, append .tgz after the version so the */
- /* pattern can match a filename. */
- snprintf(tmp, sizeof(tmp), "%s.tgz", p->name);
- done = installprereq(tmp, &errc0, 2);
- }
- else if (Replace)
- {
- warnx("To perform necessary upgrades on required packages specify -u twice.\n");
- }
-
- if (!done)
- {
- warnx("pkg `%s' required, but `%s' found installed.",
- p->name, best_installed);
- if (Force) {
- warnx("Proceeding anyway.");
- } else {
- err_prescan++;
- }
- }
- free(best_installed);
- }
- }
- } else {
- free(best_installed);
+ } else if (p->type != PLIST_FILE)
+ continue;
+
+ if (asprintf(&fullpath, "%s/%s", pkg->install_prefix, p->name) == -1) {
+ warnx("asprintf failed");
+ status = -1;
+ break;
+ }
+ existing = pkgdb_retrieve(fullpath);
+ free(fullpath);
+ if (existing == NULL)
+ continue;
+ if (pkg->other_version != NULL &&
+ strcmp(pkg->other_version, existing) == 0)
+ continue;
+
+ warnx("Conflicting PLIST with %s: %s", existing, p->name);
+ if (!Force) {
+ status = -1;
+ if (!Verbose)
+ break;
}
}
- if (err_prescan > 0) {
- warnx("Please resolve this conflict!");
- errc += err_prescan;
- goto success; /* close enough */
- }
-
-
- /* Now check the packing list for dependencies */
- for (p = Plist.head; p; p = p->next) {
- char *best_installed;
-
- if (p->type != PLIST_PKGDEP)
+
+ pkgdb_close();
+ return status;
+}
+
+static int
+check_dependencies(struct pkg_task *pkg)
+{
+ plist_t *p;
+ char *best_installed;
+ int status;
+ size_t i;
+
+ status = 0;
+
+ for (p = pkg->plist.head; p != NULL; p = p->next) {
+ if (p->type == PLIST_IGNORE) {
+ p = p->next;
+ continue;
+ } else if (p->type != PLIST_PKGDEP)
continue;
- if (Verbose)
- printf("Package `%s' depends on `%s'.\n", PkgName, p->name);
best_installed = find_best_matching_installed_pkg(p->name);
if (best_installed == NULL) {
- /* required pkg not found - need to pull in */
-
- if (Fake) {
- /* fake install (???) */
- if (Verbose)
- printf("Package dependency %s for %s not installed%s\n", p->name, pkg,
- Force ? " (proceeding anyway)" : "!");
- } else {
- int done = 0;
- int errc0 = 0;
-
- done = installprereq(p->name, &errc0, (Replace > 1) ? 2 : 0);
- if (!done && !Force) {
- errc += errc0;
+ /* XXX check cyclic dependencies? */
+ if (Fake || NoRecord) {
+ if (!Force) {
+ warnx("Missing dependency %s\n",
+ p->name);
+ status = -1;
+ break;
}
+ warnx("Missing dependency %s, continuing",
+ p->name);
+ continue;
}
- } else {
- if (Verbose)
- printf(" - %s already installed.\n", best_installed);
+ if (pkg_do(p->name, 1)) {
+ warnx("Can't install dependency %s", p->name);
+ status = -1;
+ break;
+ }
+ best_installed = find_best_matching_installed_pkg(p->name);
+ if (best_installed == NULL && Force) {
+ warnx("Missing dependency %s ignored", p->name);
+ continue;
+ } else if (best_installed == NULL) {
+ warnx("Just installed dependency %s disappeared", p->name);
+ status = -1;
+ break;
+ }
+ }
+ for (i = 0; i < pkg->dep_length; ++i) {
+ if (strcmp(best_installed, pkg->dependencies[i]) == 0)
+ break;
+ }
+ if (i < pkg->dep_length) {
+ /* Already used as dependency, so skip it. */
free(best_installed);
+ continue;
+ }
+ if (pkg->dep_length + 1 >= pkg->dep_allocated) {
+ char **tmp;
+ pkg->dep_allocated = 2 * pkg->dep_allocated + 1;
+ tmp = realloc(pkg->dependencies,
+ pkg->dep_allocated * sizeof(*tmp));
+ if (tmp == NULL) {
+ warnx("realloc failed");
+ free(pkg->dependencies);
+ pkg->dependencies = NULL;
+ pkg->dep_length = pkg->dep_allocated = 0;
+ free(best_installed);
+ return -1;
+ }
+ pkg->dependencies = tmp;
}
+ pkg->dependencies[pkg->dep_length++] = best_installed;
}
- if (errc != 0)
- goto bomb;
+ return status;
+}
- /* If we're really installing, and have an installation file, run it */
- if (!NoInstall && fexists(INSTALL_FNAME)) {
- (void) fexec(CHMOD_CMD, "+x", INSTALL_FNAME, NULL); /* make sure */
- if (Verbose)
- printf("Running install with PRE-INSTALL for %s.\n", PkgName);
- errno = 0;
- if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "PRE-INSTALL", NULL)) {
- if (errno != 0)
- warn("exec of install script failed");
- else
- warnx("install script returned error status");
- errc = 1;
- goto success; /* nothing to uninstall yet */
- }
+/*
+ * If this package uses pkg_views, register it in the default view.
+ */
+static void
+pkg_register_views(struct pkg_task *pkg)
+{
+ if (Fake || NoView || pkg->meta_data.meta_views == NULL)
+ return;
+
+ if (Verbose) {
+ printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n",
+ BINDIR, _pkgdb_getPKGDB_DIR(),
+ View ? "-w " : "", View ? View : "",
+ Viewbase ? "-W " : "", Viewbase ? Viewbase : "",
+ Verbose ? "-v " : "", pkg->pkgname);
}
- /*
- * Now finally extract the entire show if we're not going direct.
- * We need to reset the package dbdir so that extract_plist()
- * updates the correct pkgdb.byfile.db database.
- */
+ fexec_skipempty(BINDIR "/pkg_view", "-d", _pkgdb_getPKGDB_DIR(),
+ View ? "-w " : "", View ? View : "",
+ Viewbase ? "-W " : "", Viewbase ? Viewbase : "",
+ Verbose ? "-v " : "", "add", pkg->pkgname,
+ (void *)NULL);
+}
+
+static int
+start_replacing(struct pkg_task *pkg)
+{
+ char *old_required_by, *new_required_by;
+
+ old_required_by = pkgdb_pkg_file(pkg->other_version,
+ REQUIRED_BY_FNAME);
+ new_required_by = pkgdb_pkg_file(pkg->pkgname,
+ REQUIRED_BY_FNAME);
+
if (!Fake) {
- _pkgdb_setPKGDB_DIR(dbdir);
- if (!extract_plist(".", &Plist)) {
- errc = 1;
- goto fail;
+ if (rename(old_required_by, new_required_by) == -1 &&
+ errno != ENOENT) {
+ warn("Can't move +REQUIRED_BY from %s to %s",
+ old_required_by, new_required_by);
+ return -1;
}
}
- if (!Fake && fexists(MTREE_FNAME)) {
- warnx("Mtree file ignored for package %s", PkgName);
- }
-
- /* Run the installation script one last time? */
- if (!NoInstall && fexists(INSTALL_FNAME)) {
- if (Verbose)
- printf("Running install with POST-INSTALL for %s.\n", PkgName);
- if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "POST-INSTALL", NULL)) {
- warnx("install script returned error status");
- errc = 1;
- goto fail;
- }
+ if (Verbose || Fake) {
+ printf("%s/pkg_delete -K %s -p %s '%s'\n",
+ BINDIR, _pkgdb_getPKGDB_DIR(), pkg->install_prefix,
+ pkg->other_version);
}
+ if (!Fake)
+ fexec(BINDIR "/pkg_delete", "-K", _pkgdb_getPKGDB_DIR(),
+ "-p", pkg->install_prefix,
+ pkg->other_version, NULL);
- /* Time to record the deed? */
- if (!NoRecord && !Fake) {
- char contents[MaxPathSize];
+ /* XXX Check return value and do what? */
+ return 0;
+}
- if (!PkgName) {
- warnx("no package name! can't record package, sorry");
- errc = 1;
- goto success; /* well, partial anyway */
- }
- (void) snprintf(LogDir, sizeof(LogDir), "%s/%s", dbdir, PkgName);
- zapLogDir = 1; /* LogDir contains something valid now */
- if (Verbose)
- printf("Attempting to record package into %s.\n", LogDir);
- if (make_hierarchy(LogDir)) {
- warnx("can't record package into '%s', you're on your own!",
- LogDir);
- memset(LogDir, 0, sizeof(LogDir));
- errc = 1;
- goto success; /* close enough for government work */
- }
- /* Make sure pkg_info can read the entry */
- (void) fexec(CHMOD_CMD, "a+rx", LogDir, NULL);
-
- /* Move all of the +-files into place */
- move_files(".", "+*", LogDir);
-
- /* Generate the +CONTENTS file in-place from the Plist */
- (void) snprintf(contents, sizeof(contents), "%s/%s", LogDir, CONTENTS_FNAME);
- cfile = fopen(contents, "w");
- if (!cfile) {
- warnx("can't open new contents file '%s'! can't register pkg",
- contents);
- goto success; /* can't log, but still keep pkg */
- }
- write_plist(&Plist, cfile, NULL);
- fclose(cfile);
-
- /* register dependencies */
- /* we could save some cycles here if we remembered what we
- * installed above (in case we got a wildcard dependency) */
- /* XXX remembering in p->name would NOT be good! */
- for (p = Plist.head; p; p = p->next) {
- if (p->type != PLIST_PKGDEP)
- continue;
- if (Verbose)
- printf("Attempting to record dependency on package `%s'\n", p->name);
- (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir,
- basename_of(p->name));
- if (ispkgpattern(p->name)) {
- char *s;
+/*
+ * Install a single package.
+ */
+static int
+pkg_do(const char *pkgpath, int mark_automatic)
+{
+ int status;
+ void *archive_cookie;
+ struct pkg_task *pkg;
- s = find_best_matching_installed_pkg(p->name);
+ if ((pkg = calloc(1, sizeof(*pkg))) == NULL)
+ err(2, "malloc failed");
- if (s == NULL)
- errx(EXIT_FAILURE, "Where did our dependency go?!");
+ status = -1;
- (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir, s);
- free(s);
- }
- strlcat(contents, "/", sizeof(contents));
- strlcat(contents, REQUIRED_BY_FNAME, sizeof(contents));
-
- cfile = fopen(contents, "a");
- if (!cfile)
- warnx("can't open dependency file '%s'!\n"
- "dependency registration is incomplete", contents);
- else {
- fprintf(cfile, "%s\n", PkgName);
- if (fclose(cfile) == EOF)
- warnx("cannot properly close file %s", contents);
- }
- }
- if (Automatic)
- mark_as_automatic_installed(PkgName, 1);
- if (Verbose)
- printf("Package %s registered in %s\n", PkgName, LogDir);
+ if ((pkg->archive = find_archive(pkgpath, &archive_cookie)) == NULL) {
+ warnx("no pkg found for '%s', sorry.", pkgpath);
+ goto clean_memory;
}
+ if (read_meta_data(pkg))
+ goto clean_memory;
- if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) {
- FILE *fp;
- char buf[BUFSIZ];
-
- (void) snprintf(buf, sizeof(buf), "%s/%s", LogDir, p->name);
- fp = fopen(buf, "r");
- if (fp) {
- putc('\n', stdout);
- while (fgets(buf, sizeof(buf), fp))
- fputs(buf, stdout);
- putc('\n', stdout);
- (void) fclose(fp);
- } else
- warnx("cannot open %s as display file", buf);
+ /* Parse PLIST early, so that messages can use real package name. */
+ if (pkg_parse_plist(pkg))
+ goto clean_memory;
+
+ if (pkg->meta_data.meta_mtree != NULL)
+ warnx("mtree specification in pkg `%s' ignored", pkg->pkgname);
+
+ if (pkg->meta_data.meta_views != NULL) {
+ if ((pkg->logdir = strdup(pkg->install_prefix)) == NULL)
+ err(EXIT_FAILURE, "strdup failed");
+ _pkgdb_setPKGDB_DIR(dirname_of(pkg->logdir));
+ } else {
+ if (asprintf(&pkg->logdir, "%s/%s", _pkgdb_getPKGDB_DIR(),
+ pkg->pkgname) == -1)
+ err(EXIT_FAILURE, "asprintf failed");
}
- /* Add the package to a default view. */
- if (!Fake && !NoView && is_depoted_pkg) {
- if (Verbose) {
- printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n",
- BINDIR, dbdir,
- View ? "-w " : "", View ? View : "",
- Viewbase ? "-W " : "", Viewbase ? Viewbase : "",
- Verbose ? "-v " : "", PkgName);
+ if (NoRecord && !Fake) {
+ const char *tmpdir;
+
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = "/tmp";
+
+ free(pkg->logdir);
+ if (asprintf(&pkg->logdir, "%s/pkg_install.XXXXXX", tmpdir) == -1)
+ err(EXIT_FAILURE, "asprintf failed");
+ /* XXX pkg_add -u... */
+ if (mkdtemp(pkg->logdir) == NULL) {
+ warn("mkdtemp failed");
+ goto clean_memory;
}
+ }
- fexec_skipempty(BINDIR "/pkg_view", "-d", dbdir,
- View ? "-w " : "", View ? View : "",
- Viewbase ? "-W " : "", Viewbase ? Viewbase : "",
- Verbose ? "-v " : "", "add", PkgName, NULL);
+ if (check_already_installed(pkg) == 0) {
+ status = 0;
+ goto clean_memory;
}
- goto success;
+ if (read_buildinfo(pkg))
+ goto clean_memory;
-bomb:
- errc = 1;
- goto success;
+ if (check_platform(pkg))
+ goto clean_memory;
-fail:
- /* Nuke the whole (installed) show, XXX but don't clean directories */
- if (!Fake)
- delete_package(FALSE, FALSE, &Plist, FALSE);
+ if (check_other_installed(pkg))
+ goto clean_memory;
+
+ if (check_explicit_conflict(pkg))
+ goto clean_memory;
-success:
- /* delete the packing list contents */
- free_plist(&Plist);
- leave_playpen(Home);
+ if (check_implicit_conflict(pkg))
+ goto clean_memory;
- if (replacing) {
+ if (pkg->other_version != NULL) {
/*
- * Upgrade step 3/4: move back +REQUIRED_BY file
- * (see also step 2/4)
+ * Replacing an existing package.
+ * Write meta-data, get rid of the old version,
+ * install/update dependencies and finally extract.
*/
- if (rename(replace_via, replace_to) != 0)
- err(EXIT_FAILURE, "renaming \"%s\" to \"%s\" failed", replace_via, replace_to);
-
+ if (write_meta_data(pkg))
+ goto nuke_pkgdb;
+
+ if (start_replacing(pkg))
+ goto nuke_pkgdb;
+
+ if (check_dependencies(pkg))
+ goto nuke_pkgdb;
+ } else {
/*
- * Upgrade step 4/4: Fix pkgs that depend on us to
- * depend on the new version instead of the old
- * one by fixing @pkgdep lines in +CONTENTS files.
- */
- /* TODO */
+ * Normal installation.
+ * Install/update dependencies first and
+ * write the current package to disk afterwards.
+ */
+ if (check_dependencies(pkg))
+ goto clean_memory;
+
+ if (write_meta_data(pkg))
+ goto nuke_pkgdb;
}
- return errc;
-}
+ if (run_install_script(pkg, "PRE-INSTALL"))
+ goto nuke_pkgdb;
-void
-cleanup(int signo)
-{
- static int alreadyCleaning;
- void (*oldint) (int);
- void (*oldhup) (int);
- int saved_errno;
-
- saved_errno = errno;
- oldint = signal(SIGINT, SIG_IGN);
- oldhup = signal(SIGHUP, SIG_IGN);
-
- if (!alreadyCleaning) {
- alreadyCleaning = 1;
- if (signo)
- printf("Signal %d received, cleaning up.\n", signo);
- if (!Fake && zapLogDir && LogDir[0])
- (void) fexec(REMOVE_CMD, "-fr", LogDir, NULL);
- leave_playpen(Home);
- if (signo)
- exit(1);
+ if (extract_files(pkg))
+ goto nuke_pkg;
+
+ if (run_install_script(pkg, "POST-INSTALL"))
+ goto nuke_pkgdb;
+
+ /* XXX keep +INSTALL_INFO for updates? */
+ /* XXX keep +PRESERVE for updates? */
+ if (mark_automatic)
+ mark_as_automatic_installed(pkg->pkgname, 1);
+
+ pkg_register_depends(pkg);
+
+ if (Verbose)
+ printf("Package %s registered in %s\n", pkg->pkgname, pkg->logdir);
+
+ if (pkg->meta_data.meta_display != NULL)
+ fputs(pkg->meta_data.meta_display, stdout);
+
+ pkg_register_views(pkg);
+
+ status = 0;
+ goto clean_memory;
+
+nuke_pkg:
+ if (!Fake) {
+ if (pkg->other_version) {
+ warnx("Updating of %s to %s failed.",
+ pkg->other_version, pkg->pkgname);
+ warnx("Remember to run pkg_admin rebuild-tree after fixing this.");
+ }
+ delete_package(FALSE, FALSE, &pkg->plist, FALSE);
+ }
+
+nuke_pkgdb:
+ if (!Fake) {
+ (void) fexec(REMOVE_CMD, "-fr", pkg->logdir, (void *)NULL);
+ free(pkg->logdir);
+ pkg->logdir = NULL;
+ }
+
+clean_memory:
+ if (pkg->logdir != NULL && NoRecord && !Fake)
+ (void) fexec(REMOVE_CMD, "-fr", pkg->logdir, (void *)NULL);
+ free(pkg->logdir);
+ free_buildinfo(pkg);
+ free_plist(&pkg->plist);
+ free_meta_data(pkg);
+ if (pkg->archive) {
+ archive_read_close(pkg->archive);
+ close_archive(archive_cookie);
}
- signal(SIGINT, oldint);
- signal(SIGHUP, oldhup);
- errno = saved_errno;
+ free(pkg->other_version);
+ free(pkg);
+ return status;
}
int
pkg_perform(lpkg_head_t *pkgs)
{
- int err_cnt = 0;
+ int errors = 0;
lpkg_t *lpp;
- signal(SIGINT, cleanup);
- signal(SIGHUP, cleanup);
-
- TAILQ_INIT(&files);
-
while ((lpp = TAILQ_FIRST(pkgs)) != NULL) {
path_prepend_from_pkgname(lpp->lp_name);
- err_cnt += pkg_do(lpp->lp_name, pkgs);
+ if (pkg_do(lpp->lp_name, Automatic))
+ ++errors;
path_prepend_clear();
TAILQ_REMOVE(pkgs, lpp, lp_link);
free_lpkg(lpp);
}
-
- ftp_stop();
-
- return err_cnt;
+
+ return errors;
}
diff --git a/pkgtools/pkg_install/files/add/pkg_add.1 b/pkgtools/pkg_install/files/add/pkg_add.1
index 295d3fa0416..69df18cfb43 100644
--- a/pkgtools/pkg_install/files/add/pkg_add.1
+++ b/pkgtools/pkg_install/files/add/pkg_add.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: pkg_add.1,v 1.28 2007/10/13 19:38:27 rillig Exp $
+.\" $NetBSD: pkg_add.1,v 1.29 2008/04/26 14:56:34 joerg Exp $
.\"
.\" FreeBSD install - a package for the installation and maintenance
.\" of non-core utilities.
@@ -30,7 +30,6 @@
.Op Fl m Ar machine
.Op Fl p Ar prefix
.Op Fl s Ar verification-type
-.Op Fl t Ar template
.Op Fl W Ar viewbase
.Op Fl w Ar view
.Ar \fR[[ftp|http]://[\fIuser\fR[:\fIpassword]\fR@]\fIhost\fR[:\fIport\fR]][/\fIpath/\fR]pkg-name ...
@@ -160,6 +159,8 @@ into
.Ar pkgdb .
.It Fl R
Do not record the installation of a package.
+This implies
+.Fl I .
This means that you cannot deinstall it later, so only use this option if
you know what you are doing!
.It Fl s Ar verification-type
@@ -183,30 +184,6 @@ the verification feature when using
to add a binary package via a URL - the package, and the related
detached signature file, must be local
for the verification to work.
-.It Fl t Ar template
-Use
-.Ar template
-as the input to
-.Xr mktemp 3
-when creating a
-.Dq staging area .
-By default, this is the string
-.Pa /var/tmp/instmp.XXXXXX ,
-but it may be necessary to override it in the situation where
-space in your
-.Pa /var/tmp
-directory is limited.
-Be sure to leave some number of
-.Sq X
-characters for
-.Xr mktemp 3
-to fill in with a unique ID.
-.Pp
-You can get a performance boost by setting the staging area
-.Ar template
-to reside on the same disk partition as target directories for package
-file installation; often this is
-.Pa /usr .
.It Fl u
If the package that's being installed is already installed, either
in the same or a different version, an update is performed.
@@ -275,11 +252,10 @@ passive mode
ftp.
.Sh TECHNICAL DETAILS
.Nm
-extracts each package's
-.Dq packing list
-into a special staging directory in /var/tmp (or $PKG_TMPDIR if set)
-and then runs through the following sequence to fully extract the contents
-of the package:
+extracts each package's meta data (including the
+.Dq packing list )
+to memory and then runs through the following sequence to fully extract
+the contents of the package:
.Bl -enum -offset indent
.It
A check is made to determine if the package or another version of it
diff --git a/pkgtools/pkg_install/files/create/perform.c b/pkgtools/pkg_install/files/create/perform.c
index 51c84c04f27..7c8d1b29e5f 100644
--- a/pkgtools/pkg_install/files/create/perform.c
+++ b/pkgtools/pkg_install/files/create/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.19 2008/04/18 17:16:44 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.20 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.38 1997/10/13 15:03:51 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.19 2008/04/18 17:16:44 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.20 2008/04/26 14:56:34 joerg Exp $");
#endif
#endif
@@ -91,6 +91,38 @@ register_depends(package_t *plist, char *deps, int build_only)
}
/*
+ * Expect "fname" to point at a file, and read it into
+ * the buffer returned.
+ */
+static char *
+fileGetContents(char *fname)
+{
+ char *contents;
+ struct stat sb;
+ int fd;
+
+ if (stat(fname, &sb) == FAIL) {
+ cleanup(0);
+ errx(2, "can't stat '%s'", fname);
+ }
+
+ contents = (char *) malloc((size_t) (sb.st_size) + 1);
+ fd = open(fname, O_RDONLY, 0);
+ if (fd == FAIL) {
+ cleanup(0);
+ errx(2, "unable to open '%s' for reading", fname);
+ }
+ if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) {
+ cleanup(0);
+ errx(2, "short read on '%s' - did not get %lld bytes",
+ fname, (long long) sb.st_size);
+ }
+ close(fd);
+ contents[(size_t) sb.st_size] = '\0';
+ return contents;
+}
+
+/*
* Get a string parameter as a file spec or as a "contents follow -" spec
*/
static void
diff --git a/pkgtools/pkg_install/files/info/Makefile.in b/pkgtools/pkg_install/files/info/Makefile.in
index 5e1bbc856e5..fed22801e5a 100644
--- a/pkgtools/pkg_install/files/info/Makefile.in
+++ b/pkgtools/pkg_install/files/info/Makefile.in
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.in,v 1.14 2008/04/04 15:21:32 joerg Exp $
+# $NetBSD: Makefile.in,v 1.15 2008/04/26 14:56:34 joerg Exp $
srcdir= @srcdir@
@@ -16,7 +16,7 @@ BOOTSTRAP= @bootstrap@
CC= @CC@
CCLD= $(CC)
.if empty(BOOTSTRAP)
-LIBS= -linstall -larchive -lbz2 -lfetch -lz @LIBS@
+LIBS= -linstall -larchive -lfetch -lbz2 -lz @LIBS@
CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib
.else
LIBS= -linstall @LIBS@
diff --git a/pkgtools/pkg_install/files/info/perform.c b/pkgtools/pkg_install/files/info/perform.c
index 528ec13c7a9..2acde1f1337 100644
--- a/pkgtools/pkg_install/files/info/perform.c
+++ b/pkgtools/pkg_install/files/info/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.46 2008/04/04 15:21:32 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.47 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -17,7 +17,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.46 2008/04/04 15:21:32 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.47 2008/04/26 14:56:34 joerg Exp $");
#endif
#endif
@@ -126,7 +126,7 @@ static const struct pkg_meta_desc {
int entry_mask;
int required_file;
} pkg_meta_descriptors[] = {
- { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME ,
+ { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME,
LOAD_CONTENTS, 1},
{ offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME,
LOAD_COMMENT, 1 },
@@ -302,30 +302,19 @@ pkg_do(const char *pkg)
int code = 0;
const char *binpkgfile = NULL;
- if (IS_URL(pkg)) {
-#ifdef BOOTSTRAP
- errx(2, "Remote access not supported during bootstrap");
-#else
- struct archive *archive;
- void *remote_archive_cookie;
-
- archive = open_remote_archive(pkg, &remote_archive_cookie);
-
- meta = read_meta_data_from_archive(archive);
- close_remote_archive(remote_archive_cookie);
-#endif
- } else if (fexists(pkg) && isfile(pkg)) {
+ if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) {
#ifdef BOOTSTRAP
errx(2, "Binary packages not supported during bootstrap");
#else
struct archive *archive;
- void *remote_archive_cookie;
+ void *archive_cookie;
- archive = open_local_archive(pkg, &remote_archive_cookie);
+ archive = open_archive(pkg, &archive_cookie);
meta = read_meta_data_from_archive(archive);
- close_local_archive(remote_archive_cookie);
- binpkgfile = pkg;
+ close_archive(archive_cookie);
+ if (!IS_URL(pkg))
+ binpkgfile = pkg;
#endif
} else {
/*
diff --git a/pkgtools/pkg_install/files/lib/Makefile.in b/pkgtools/pkg_install/files/lib/Makefile.in
index 95b846a5b83..8a10272a905 100644
--- a/pkgtools/pkg_install/files/lib/Makefile.in
+++ b/pkgtools/pkg_install/files/lib/Makefile.in
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.in,v 1.21 2008/04/06 17:47:27 joerg Exp $
+# $NetBSD: Makefile.in,v 1.22 2008/04/26 14:56:34 joerg Exp $
srcdir= @srcdir@
@@ -20,7 +20,7 @@ RANLIB= @RANLIB@
AR= @AR@
CC= @CC@
CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir)
-DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" -DTAR_CMD=\"$(tar)\" -DFTP_CMD=\"$(ftp)\"
+DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\"
CFLAGS= @CFLAGS@
INSTALL= @INSTALL@
@@ -28,8 +28,8 @@ INSTALL= @INSTALL@
LIB= libinstall.a
OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \
- ftpio.o global.o iterate.o lpkg.o opattern.o \
- path.o pen.o pexec.o pkgdb.o plist.o \
+ global.o iterate.o lpkg.o opattern.o \
+ path.o pkgdb.o plist.o \
str.o var.o version.o vulnerabilities-file.o
.if !empty(BOOTSTRAP)
diff --git a/pkgtools/pkg_install/files/lib/conflicts.c b/pkgtools/pkg_install/files/lib/conflicts.c
index 35dd204ccf7..01468ce0ff6 100644
--- a/pkgtools/pkg_install/files/lib/conflicts.c
+++ b/pkgtools/pkg_install/files/lib/conflicts.c
@@ -30,6 +30,7 @@
*/
struct package_conflict {
const char *pkgname;
+ const char *skip_pkgname;
char **conflicting_pkgname;
char **conflicting_pattern;
};
@@ -70,6 +71,10 @@ check_package_conflict(const char *pkgname, void *v)
FILE *f;
int rv;
+ if (conflict->skip_pkgname != NULL &&
+ strcmp(conflict->skip_pkgname, pkgname) == 0)
+ return 0;
+
rv = 0;
pkg.head = NULL;
pkg.tail = NULL;
@@ -102,12 +107,14 @@ check_package_conflict(const char *pkgname, void *v)
* variables are set to NULL.
*/
int
-some_installed_package_conflicts_with(const char *pkgname, char **inst_pkgname, char **inst_pattern)
+some_installed_package_conflicts_with(const char *pkgname,
+ const char *skip_pkgname, char **inst_pkgname, char **inst_pattern)
{
struct package_conflict cfl;
int rv;
cfl.pkgname = pkgname;
+ cfl.skip_pkgname = skip_pkgname;
*inst_pkgname = NULL;
*inst_pattern = NULL;
cfl.conflicting_pkgname = inst_pkgname;
diff --git a/pkgtools/pkg_install/files/lib/file.c b/pkgtools/pkg_install/files/lib/file.c
index b683c205e6a..17322df70e3 100644
--- a/pkgtools/pkg_install/files/lib/file.c
+++ b/pkgtools/pkg_install/files/lib/file.c
@@ -1,4 +1,4 @@
-/* $NetBSD: file.c,v 1.23 2007/08/29 15:42:39 jlam Exp $ */
+/* $NetBSD: file.c,v 1.24 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -17,7 +17,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp";
#else
-__RCSID("$NetBSD: file.c,v 1.23 2007/08/29 15:42:39 jlam Exp $");
+__RCSID("$NetBSD: file.c,v 1.24 2008/04/26 14:56:34 joerg Exp $");
#endif
#endif
@@ -218,263 +218,6 @@ URLlength(const char *fname)
}
/*
- * Returns the host part of a URL
- */
-const char *
-fileURLHost(const char *fname, char *where, int max)
-{
- const char *ret;
- int i;
-
- assert(where != NULL);
- assert(max > 0);
-
- if ((i = URLlength(fname)) < 0) { /* invalid URL? */
- errx(EXIT_FAILURE, "fileURLhost called with a bad URL: `%s'", fname);
- }
- fname += i;
- /* Do we have a place to stick our work? */
- ret = where;
- while (*fname && *fname != '/' && --max)
- *where++ = *fname++;
- *where = '\0';
-
- return ret;
-}
-
-/*
- * Returns the filename part of a URL
- */
-const char *
-fileURLFilename(const char *fname, char *where, int max)
-{
- const char *ret;
- int i;
-
- assert(where != NULL);
- assert(max > 0);
-
- if ((i = URLlength(fname)) < 0) { /* invalid URL? */
- errx(EXIT_FAILURE, "fileURLFilename called with a bad URL: `%s'", fname);
- }
- fname += i;
- /* Do we have a place to stick our work? */
- ret = where;
- while (*fname && *fname != '/')
- ++fname;
- if (*fname == '/') {
- while (*fname && --max)
- *where++ = *fname++;
- }
- *where = '\0';
-
- return ret;
-}
-
-/*
- * Try and fetch a file by URL, returning the directory name for where
- * it's unpacked, if successful. To be handed to leave_playpen() later.
- */
-char *
-fileGetURL(const char *spec)
-{
- char host[MAXHOSTNAMELEN], file[MaxPathSize];
- const char *cp;
- char *rp;
- char pen[MaxPathSize];
- int rc;
-
- rp = NULL;
- if (!IS_URL(spec)) {
- errx(EXIT_FAILURE, "fileGetURL was called with non-URL arg '%s'", spec);
- }
-
- /* Some sanity checks on the URL */
- cp = fileURLHost(spec, host, MAXHOSTNAMELEN);
- if (!*cp) {
- warnx("URL `%s' has bad host part!", spec);
- return NULL;
- }
- cp = fileURLFilename(spec, file, MaxPathSize);
- if (!*cp) {
- warnx("URL `%s' has bad filename part!", spec);
- return NULL;
- }
-
- if (Verbose)
- printf("Trying to fetch %s.\n", spec);
-
- pen[0] = '\0';
- rp = make_playpen(pen, sizeof(pen), 0);
- if (rp == NULL) {
- printf("Error: Unable to construct a new playpen for FTP!\n");
- return NULL;
- }
-
- rp = strdup(pen);
- rc = unpackURL(spec, pen);
- if (rc < 0) {
- leave_playpen(rp); /* Don't leave dir hang around! */
-
- printf("Error on unpackURL('%s', '%s')\n", spec, pen);
- return NULL;
- }
- return rp;
-}
-
-static char *
-resolvepattern1(const char *name)
-{
- static char tmp[MaxPathSize];
- char *cp;
-
- if (IS_URL(name)) {
- /* some package depends on a wildcard pkg */
- int rc;
-
- rc = expandURL(tmp, name);
- if (rc < 0) {
- return NULL;
- }
- if (Verbose)
- printf("'%s' expanded to '%s'\n", name, tmp);
- return tmp; /* return expanded URL w/ corrent pkg */
- }
- else if (ispkgpattern(name)) {
- cp = find_best_matching_file(dirname_of(name), basename_of(name), 1, 0);
- if (cp) {
- snprintf(tmp, sizeof(tmp), "%s/%s", dirname_of(name), cp);
- free(cp);
- return tmp;
- }
- } else {
- if (isfile(name)) {
- strlcpy(tmp, name, sizeof(tmp));
- return tmp;
- }
- }
-
- return NULL;
-}
-
-static char *
-resolvepattern(const char *name)
-{
- char tmp[MaxPathSize];
- char *cp;
- const char *suf;
-
- cp = resolvepattern1(name);
- if (cp != NULL)
- return cp;
-
- if (ispkgpattern(name))
- return NULL;
-
- suf = suffix_of(name);
- if (!strcmp(suf, "tbz") || !strcmp(suf, "tgz"))
- return NULL;
-
- /* add suffix and try */
- snprintf(tmp, sizeof(tmp), "%s.tbz", name);
- cp = resolvepattern1(tmp);
- if (cp != NULL)
- return cp;
- snprintf(tmp, sizeof(tmp), "%s.tgz", name);
- cp = resolvepattern1(tmp);
- if (cp != NULL)
- return cp;
-
- /* add version number wildcard and try */
- snprintf(tmp, sizeof(tmp), "%s-[0-9]*", name);
- return resolvepattern1(tmp);
-}
-
-/*
- * Look for filename/pattern "fname" in
- * Returns a full path/URL where the pkg can be found
- */
-char *
-fileFindByPath(const char *fname)
-{
- char tmp[MaxPathSize];
- struct path *path;
-
- /*
- * 1. if fname is an absolute pathname or a URL,
- * just use it.
- */
- if (IS_FULLPATH(fname) || IS_URL(fname))
- return resolvepattern(fname);
-
- /*
- * 2. otherwise, use PKG_PATH.
- */
- TAILQ_FOREACH(path, &PkgPath, pl_entry) {
- char *cp;
- const char *cp2 = path->pl_path;
-
- if (Verbose)
- printf("trying PKG_PATH %s\n", cp2);
-
- if (IS_FULLPATH(cp2) || IS_URL(cp2)) {
- snprintf(tmp, sizeof(tmp), "%s/%s", cp2, fname);
- }
- else {
- char cwdtmp[MaxPathSize];
- if (getcwd(cwdtmp, sizeof(cwdtmp)) == NULL)
- errx(EXIT_FAILURE, "getcwd");
- snprintf(tmp, sizeof(tmp), "%s/%s/%s", cwdtmp, cp2, fname);
- }
- cp = resolvepattern(tmp);
- if (cp)
- return cp;
- }
-
-#if 0
- /*
- * 3. finally, search current directory.
- */
- snprintf(tmp, sizeof(tmp), "./%s", fname);
- return resolvepattern(tmp);
-#else
- return NULL;
-#endif
-}
-
-/*
- * Expect "fname" to point at a file, and read it into
- * the buffer returned.
- */
-char *
-fileGetContents(char *fname)
-{
- char *contents;
- struct stat sb;
- int fd;
-
- if (stat(fname, &sb) == FAIL) {
- cleanup(0);
- errx(2, "can't stat '%s'", fname);
- }
-
- contents = (char *) malloc((size_t) (sb.st_size) + 1);
- fd = open(fname, O_RDONLY, 0);
- if (fd == FAIL) {
- cleanup(0);
- errx(2, "unable to open '%s' for reading", fname);
- }
- if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) {
- cleanup(0);
- errx(2, "short read on '%s' - did not get %lld bytes",
- fname, (long long) sb.st_size);
- }
- close(fd);
- contents[(size_t) sb.st_size] = '\0';
- return contents;
-}
-
-/*
* Takes a filename and package name, returning (in "try") the canonical
* "preserve" name for it.
*/
@@ -509,97 +252,6 @@ make_preserve_name(char *try, size_t max, char *name, char *file)
return TRUE;
}
-/*
- * Write the contents of "str" to a file
- */
-void
-write_file(char *name, char *str)
-{
- size_t len;
- FILE *fp;
-
- if ((fp = fopen(name, "w")) == (FILE *) NULL) {
- cleanup(0);
- errx(2, "cannot fopen '%s' for writing", name);
- }
- len = strlen(str);
- if (fwrite(str, 1, len, fp) != len) {
- cleanup(0);
- errx(2, "short fwrite on '%s', tried to write %ld bytes",
- name, (long) len);
- }
- if (fclose(fp)) {
- cleanup(0);
- errx(2, "failure to fclose '%s'", name);
- }
-}
-
-void
-copy_file(char *dir, char *fname, char *to)
-{
- char fpath[MaxPathSize];
-
- (void) snprintf(fpath, sizeof(fpath), "%s%s%s",
- (fname[0] != '/') ? dir : "",
- (fname[0] != '/') ? "/" : "",
- fname);
- if (fexec("cp", "-r", fpath, to, NULL)) {
- cleanup(0);
- errx(2, "could not perform 'cp -r %s %s'", fpath, to);
- }
-}
-
-void
-move_file(char *dir, char *fname, char *to)
-{
- char fpath[MaxPathSize];
-
- (void) snprintf(fpath, sizeof(fpath), "%s%s%s",
- (fname[0] != '/') ? dir : "",
- (fname[0] != '/') ? "/" : "",
- fname);
- if (fexec("mv", fpath, to, NULL)) {
- cleanup(0);
- errx(2, "could not perform 'mv %s %s'", fpath, to);
- }
-}
-
-void
-move_files(const char *dir, const char *pattern, const char *to)
-{
- char fpath[MaxPathSize];
- glob_t globbed;
- size_t i;
-
- (void) snprintf(fpath, sizeof(fpath), "%s/%s", dir, pattern);
- if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) {
- switch(i) {
- case GLOB_NOMATCH:
- warn("no files matching ``%s'' found", fpath);
- break;
- case GLOB_ABORTED:
- warn("globbing aborted");
- break;
- case GLOB_NOSPACE:
- warn("out-of-memory during globbing");
- break;
- default:
- warn("unknown error during globbing");
- break;
- }
- return;
- }
-
- /* Moving globbed files -- we just use mv(1) to do the job */
- for (i=0; i<globbed.gl_pathc; i++)
- if (fexec("mv", globbed.gl_pathv[i], to, NULL)) {
- cleanup(0);
- errx(2, "could not perform 'mv %s %s'", globbed.gl_pathv[i], to);
- }
-
- return;
-}
-
void
remove_files(const char *path, const char *pattern)
{
@@ -635,74 +287,6 @@ remove_files(const char *path, const char *pattern)
}
/*
- * Unpack a tar file
- */
-int
-unpack(const char *pkg, const lfile_head_t *filesp)
-{
- const char *decompress_cmd = NULL;
- const char *suf;
- int count = 0;
- lfile_t *lfp;
- char **up_argv;
- int up_argc = 7;
- int i = 0;
- int result;
-
- if (filesp != NULL)
- TAILQ_FOREACH(lfp, filesp, lf_link)
- count++;
- up_argc += count;
- up_argv = malloc((count + up_argc + 1) * sizeof(char *));
- if (!IS_STDIN(pkg)) {
- 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);
- } else
- decompress_cmd = GZIP_CMD;
-
- up_argv[i] = (char *)strrchr(TAR_CMD, '/');
- if (up_argv[i] == NULL)
- up_argv[i] = TAR_CMD;
- else
- up_argv[i]++; /* skip / character */
- if (count > 0)
- up_argv[++i] = "--fast-read";
- if (decompress_cmd != NULL) {
- up_argv[++i] = "--use-compress-program";
- up_argv[++i] = (char *)decompress_cmd;
- }
- up_argv[++i] = "-xpf";
- up_argv[++i] = (char *)pkg;
- if (count > 0)
- TAILQ_FOREACH(lfp, filesp, lf_link)
- up_argv[++i] = lfp->lf_name;
- up_argv[++i] = NULL;
-
- if (Verbose) {
- printf("running: %s", TAR_CMD);
- for (i = 1; up_argv[i] != NULL; i++)
- printf(" %s", up_argv[i]);
- printf("\n");
- }
-
- result = pfcexec(NULL, TAR_CMD, (const char **)up_argv);
- free(up_argv);
- if (result != 0) {
- warnx("extract of %s failed", pkg);
- return 1;
- }
-
- return 0;
-}
-
-/*
* Using fmt, replace all instances of:
*
* %F With the parameter "name"
@@ -712,8 +296,8 @@ unpack(const char *pkg, const lfile_head_t *filesp)
*
* Check that no overflows can occur.
*/
-void
-format_cmd(char *buf, size_t size, char *fmt, char *dir, char *name)
+int
+format_cmd(char *buf, size_t size, const char *fmt, const char *dir, const char *name)
{
char scratch[MaxPathSize * 2];
char *bufp;
@@ -722,8 +306,8 @@ format_cmd(char *buf, size_t size, char *fmt, char *dir, char *name)
for (bufp = buf; (int) (bufp - buf) < size && *fmt;) {
if (*fmt == '%') {
if (*++fmt != 'D' && name == NULL) {
- cleanup(0);
- errx(2, "no last file available for '%s' command", buf);
+ warnx("no last file available for '%s' command", buf);
+ return -1;
}
switch (*fmt) {
case 'F':
@@ -768,4 +352,5 @@ format_cmd(char *buf, size_t size, char *fmt, char *dir, char *name)
}
}
*bufp = '\0';
+ return 0;
}
diff --git a/pkgtools/pkg_install/files/lib/ftpio.c b/pkgtools/pkg_install/files/lib/ftpio.c
deleted file mode 100644
index f23612ee391..00000000000
--- a/pkgtools/pkg_install/files/lib/ftpio.c
+++ /dev/null
@@ -1,1259 +0,0 @@
-/* $NetBSD: ftpio.c,v 1.26 2008/01/29 15:39:31 hubertf 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.26 2008/01/29 15:39:31 hubertf 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 */
diff --git a/pkgtools/pkg_install/files/lib/lib.h b/pkgtools/pkg_install/files/lib/lib.h
index bb52d0c2d59..e9ed05d68d7 100644
--- a/pkgtools/pkg_install/files/lib/lib.h
+++ b/pkgtools/pkg_install/files/lib/lib.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lib.h,v 1.42 2008/04/18 17:16:44 joerg Exp $ */
+/* $NetBSD: lib.h,v 1.43 2008/04/26 14:56:34 joerg Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
@@ -86,48 +86,18 @@
#define DEF_UMASK 022
#endif
+#define MKDIR_CMD "mkdir"
+
/* Usually "rm", but often "echo" during debugging! */
#define REMOVE_CMD "rm"
/* Usually "rm", but often "echo" during debugging! */
#define RMDIR_CMD "rmdir"
-/* Define tar as a string, in case it's called gtar or something */
-#ifndef TAR_CMD
-#define TAR_CMD "tar"
-#endif
-
-/* Define pax as a string, used to copy files from staging area */
-#ifndef PAX_CMD
-#define PAX_CMD "pax"
-#endif
-
-/* Define gzip and bzip2, used to unpack binary packages */
-#ifndef GZIP_CMD
-#define GZIP_CMD "gzip"
-#endif
-
-#ifndef BZIP2_CMD
-#define BZIP2_CMD "bzip2"
-#endif
-
-/* Define ftp as a string, in case the ftp client is called something else */
-#ifndef FTP_CMD
-#define FTP_CMD "ftp"
-#endif
-
-#ifndef CHOWN_CMD
-#define CHOWN_CMD "chown"
-#endif
-
#ifndef CHMOD_CMD
#define CHMOD_CMD "chmod"
#endif
-#ifndef CHGRP_CMD
-#define CHGRP_CMD "chgrp"
-#endif
-
/* some operating systems don't have this */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
@@ -158,13 +128,8 @@ enum {
/* The names of special variables */
#define AUTOMATIC_VARNAME "automatic"
-/*
- * files which we expect to be in every package, passed to
- * tar --fast-read.
- */
-#define ALL_FNAMES CONTENTS_FNAME" "COMMENT_FNAME" "DESC_FNAME" "MTREE_FNAME" "BUILD_VERSION_FNAME" "BUILD_INFO_FNAME" "SIZE_PKG_FNAME" "SIZE_ALL_FNAME
-
-#define CMD_CHAR '@' /* prefix for extended PLIST cmd */
+/* Prefix for extended PLIST cmd */
+#define CMD_CHAR '@'
/* The name of the "prefix" environment variable given to scripts */
#define PKG_PREFIX_VNAME "PKG_PREFIX"
@@ -273,14 +238,6 @@ typedef struct _lpkg_t {
TAILQ_HEAD(_lpkg_head_t, _lpkg_t);
typedef struct _lpkg_head_t lpkg_head_t;
-/* This structure describes a pipe to a child process */
-typedef struct {
- int fds[2]; /* pipe, 0=child stdin, 1=parent output */
- FILE *fp; /* output from parent process */
- pid_t pid; /* process id of child process */
- void (*cleanup)(void); /* called on non-zero child exit status */
-} pipe_to_system_t;
-
struct pkg_vulnerabilities {
size_t entries;
char **vulnerability;
@@ -296,25 +253,17 @@ struct pkg_vulnerabilities {
#define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/')
/* Conflict handling (conflicts.c) */
-int some_installed_package_conflicts_with(const char *, char **, char **);
+int some_installed_package_conflicts_with(const char *, const char *, char **, char **);
/* Prototypes */
/* Misc */
void cleanup(int);
-char *make_playpen(char *, size_t, size_t);
-char *where_playpen(void);
-void leave_playpen(char *);
-uint64_t min_free(const char *);
-void save_dirs(char **, char **);
-void restore_dirs(char *, char *);
void show_version(void);
int fexec(const char *, ...);
int fexec_skipempty(const char *, ...);
int fcexec(const char *, const char *, ...);
int pfcexec(const char *, const char *, const char **);
-pipe_to_system_t *pipe_to_system_begin(const char *, char *const *, void (*)(void));
-int pipe_to_system_end(pipe_to_system_t *);
/* variables file handling */
@@ -335,7 +284,6 @@ const char *suffix_of(const char *);
int pkg_match(const char *, const char *);
int pkg_order(const char *, const char *, const char *);
int ispkgpattern(const char *);
-void strip_txz(char *, char *, const char *);
/* Iterator functions */
int iterate_pkg_generic_src(int (*)(const char *, void *), void *,
@@ -361,35 +309,17 @@ Boolean isfile(const char *);
Boolean isbrokenlink(const char *);
Boolean isempty(const char *);
int URLlength(const char *);
-char *fileGetURL(const char *);
-const char *fileURLFilename(const char *, char *, int);
-const char *fileURLHost(const char *, char *, int);
-char *fileFindByPath(const char *);
-char *fileGetContents(char *);
Boolean make_preserve_name(char *, size_t, char *, char *);
-void write_file(char *, char *);
-void copy_file(char *, char *, char *);
-void move_file(char *, char *, char *);
-void move_files(const char *, const char *, const char *);
void remove_files(const char *, const char *);
int delete_hierarchy(char *, Boolean, Boolean);
-int unpack(const char *, const lfile_head_t *);
-void format_cmd(char *, size_t, char *, char *, char *);
-
-/* ftpio.c: FTP handling */
-int expandURL(char *, const char *);
-int unpackURL(const char *, const char *);
-int ftp_cmd(const char *, const char *);
-int ftp_start(const char *);
-void ftp_stop(void);
+int format_cmd(char *, size_t, const char *, const char *, const char *);
/* pkg_io.c: Local and remote archive handling */
struct archive;
-struct archive *open_remote_archive(const char *, void **);
-void close_remote_archive(void *);
-struct archive *open_local_archive(const char *, void **);
-void close_local_archive(void *);
+struct archive *open_archive(const char *, void **);
+void close_archive(void *);
+struct archive *find_archive(const char *, void **);
/* Packing list */
plist_t *new_plist_entry(void);
diff --git a/pkgtools/pkg_install/files/lib/pen.c b/pkgtools/pkg_install/files/lib/pen.c
deleted file mode 100644
index dd73a0de2e5..00000000000
--- a/pkgtools/pkg_install/files/lib/pen.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* $NetBSD: pen.c,v 1.22 2008/02/04 14:28:27 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.22 2008/02/04 14:28:27 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;
-}
diff --git a/pkgtools/pkg_install/files/lib/pexec.c b/pkgtools/pkg_install/files/lib/pexec.c
deleted file mode 100644
index 1358aedb910..00000000000
--- a/pkgtools/pkg_install/files/lib/pexec.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#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);
-}
diff --git a/pkgtools/pkg_install/files/lib/pkg_io.c b/pkgtools/pkg_install/files/lib/pkg_io.c
index 643262e0221..0a87bfc5a64 100644
--- a/pkgtools/pkg_install/files/lib/pkg_io.c
+++ b/pkgtools/pkg_install/files/lib/pkg_io.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pkg_io.c,v 1.1 2008/04/04 15:21:32 joerg Exp $ */
+/* $NetBSD: pkg_io.c,v 1.2 2008/04/26 14:56:34 joerg Exp $ */
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
@@ -36,7 +36,7 @@
#include <sys/cdefs.h>
#endif
-__RCSID("$NetBSD: pkg_io.c,v 1.1 2008/04/04 15:21:32 joerg Exp $");
+__RCSID("$NetBSD: pkg_io.c,v 1.2 2008/04/26 14:56:34 joerg Exp $");
#include <archive.h>
#include <archive_entry.h>
@@ -52,7 +52,7 @@ __RCSID("$NetBSD: pkg_io.c,v 1.1 2008/04/04 15:21:32 joerg Exp $");
#include "lib.h"
struct fetch_archive {
- const char *url;
+ struct url *url;
fetchIO *fetch;
char buffer[32768];
};
@@ -62,7 +62,7 @@ fetch_archive_open(struct archive *a, void *client_data)
{
struct fetch_archive *f = client_data;
- f->fetch = fetchGetURL(f->url, "");
+ f->fetch = fetchGet(f->url, "");
if (f->fetch == NULL)
return ENOENT;
return 0;
@@ -88,52 +88,181 @@ fetch_archive_close(struct archive *a, void *client_data)
return 0;
}
-struct archive *
-open_remote_archive(const char *url, void **cookie)
+static struct archive *
+open_archive_by_url(struct url *url, void **cookie)
{
struct fetch_archive *f;
- struct archive *archive;
+ struct archive *a;
f = malloc(sizeof(*f));
if (f == NULL)
err(2, "cannot allocate memory for remote archive");
f->url = url;
- archive = archive_read_new();
- archive_read_support_compression_all(archive);
- archive_read_support_format_all(archive);
- if (archive_read_open(archive, f, fetch_archive_open, fetch_archive_read,
- fetch_archive_close))
- errx(2, "cannot open archive: %s", archive_error_string(archive));
+ a = archive_read_new();
+ archive_read_support_compression_all(a);
+ archive_read_support_format_all(a);
+ if (archive_read_open(a, f, fetch_archive_open, fetch_archive_read,
+ fetch_archive_close)) {
+ archive_read_close(a);
+ free(f);
+ return NULL;
+ }
*cookie = f;
+ return a;
+}
+
+struct archive *
+open_archive(const char *url, void **cookie)
+{
+ struct url *u;
+ struct archive *a;
+
+ if (!IS_URL(url)) {
+ a = archive_read_new();
+ archive_read_support_compression_all(a);
+ archive_read_support_format_all(a);
+ if (archive_read_open_filename(a, url, 1024)) {
+ archive_read_close(a);
+ return NULL;
+ }
+ *cookie = NULL;
+ return a;
+ }
+
+ if ((u = fetchParseURL(url)) == NULL)
+ return NULL;
- return archive;
+ a = open_archive_by_url(u, cookie);
+
+ fetchFreeURL(u);
+ return a;
}
void
-close_remote_archive(void *cookie)
+close_archive(void *cookie)
{
free(cookie);
}
-struct archive *
-open_local_archive(const char *path, void **cookie)
+static int
+strip_suffix(char *filename)
{
- struct archive *archive;
+ size_t len;
- archive = archive_read_new();
- archive_read_support_compression_all(archive);
- archive_read_support_format_all(archive);
- if (archive_read_open_filename(archive, path, 1024))
- errx(2, "cannot open archive: %s",
- archive_error_string(archive));
- *cookie = NULL;
+ len = strlen(filename);
+ if (len <= 4)
+ return 0;
+ if (strcmp(filename + len - 4, ".tgz") == 0 ||
+ strcmp(filename + len - 4, ".tbz") == 0) {
+ filename[len - 4] = '\0';
+ return 1;
+ } else
+ return 0;
+}
- return archive;
+static int
+find_best_package(struct url *url, const char *pattern, struct url **best_url)
+{
+ char *cur_match, *best_match = NULL;
+ struct url_list ue;
+ size_t i;
+
+ if (*best_url) {
+ if ((best_match = fetchUnquoteFilename(*best_url)) == NULL)
+ return -1;
+ } else
+ best_match = NULL;
+
+ if (best_match && strip_suffix(best_match) == 0) {
+ free(best_match);
+ return -1;
+ }
+
+ fetchInitURLList(&ue);
+ if (fetchList(&ue, url, NULL, "")) {
+ fetchFreeURLList(&ue);
+ return -1;
+ }
+ for (i = 0; i < ue.length; ++i) {
+ cur_match = fetchUnquoteFilename(ue.urls + i);
+
+ if (cur_match == NULL) {
+ free(best_match);
+ fetchFreeURLList(&ue);
+ return -1;
+ }
+ if (strip_suffix(cur_match) == 0) {
+ free(cur_match);
+ continue;
+ }
+ if (pkg_order(pattern, cur_match, best_match) == 1) {
+ if (*best_url)
+ fetchFreeURL(*best_url);
+ *best_url = fetchCopyURL(ue.urls + i);
+ free(best_match);
+ best_match = cur_match;
+ cur_match = NULL;
+ if (*best_url == NULL) {
+ free(best_match);
+ return -1;
+ }
+ }
+ free(cur_match);
+ }
+ free(best_match);
+ fetchFreeURLList(&ue);
+ return 0;
}
-void
-close_local_archive(void *cookie)
+struct archive *
+find_archive(const char *fname, void **cookie)
{
+ struct archive *a;
+ struct path *path;
+ const char *cur_path;
+ struct url *url, *best_match;
+ char tmp[MaxPathSize];
+
+ best_match = NULL;
+
+ a = open_archive(fname, cookie);
+ if (a != NULL)
+ return a;
+
+ if (strchr(fname, '/') != NULL) {
+ const char *last_slash;
+
+ last_slash = strrchr(fname, '/');
+ snprintf(tmp, sizeof(tmp), "%s%.*s",
+ IS_URL(fname) ? "" : "file://",
+ (int)(last_slash - fname + 1), fname);
+ url = fetchParseURL(tmp);
+ if (url == NULL)
+ return NULL;
+ fname = last_slash + 1; /* XXX fetchUnquoteFilename */
+ find_best_package(url, fname, &best_match);
+ fetchFreeURL(url);
+ } else {
+ TAILQ_FOREACH(path, &PkgPath, pl_entry) {
+ cur_path = path->pl_path;
+ if (!IS_URL(cur_path)) {
+ snprintf(tmp, sizeof(tmp), "file://%s", cur_path);
+ cur_path = tmp;
+ }
+ url = fetchParseURL(cur_path);
+ if (url == NULL)
+ continue;
+ find_best_package(url, fname, &best_match);
+ /* XXX Check return value and complain */
+ fetchFreeURL(url);
+ }
+ }
+
+ if (best_match == NULL)
+ return NULL;
+ a = open_archive_by_url(best_match, cookie);
+ fetchFreeURL(best_match);
+ return a;
}
diff --git a/pkgtools/pkg_install/files/lib/plist.c b/pkgtools/pkg_install/files/lib/plist.c
index 0c0f0064fd1..8539272be75 100644
--- a/pkgtools/pkg_install/files/lib/plist.c
+++ b/pkgtools/pkg_install/files/lib/plist.c
@@ -1,4 +1,4 @@
-/* $NetBSD: plist.c,v 1.17 2008/02/02 16:21:45 joerg Exp $ */
+/* $NetBSD: plist.c,v 1.18 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp";
#else
-__RCSID("$NetBSD: plist.c,v 1.17 2008/02/02 16:21:45 joerg Exp $");
+__RCSID("$NetBSD: plist.c,v 1.18 2008/04/26 14:56:34 joerg Exp $");
#endif
#endif
@@ -539,6 +539,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele
if (NoDeleteFiles)
break;
format_cmd(tmp, sizeof(tmp), p->name, Where, last_file);
+ /* XXX cleanup(0); */
printf("Executing `%s'\n", tmp);
if (!Fake && system(tmp)) {
warnx("unexec command for `%s' failed", tmp);
diff --git a/pkgtools/pkg_install/files/lib/str.c b/pkgtools/pkg_install/files/lib/str.c
index d8229cea050..be5a156319a 100644
--- a/pkgtools/pkg_install/files/lib/str.c
+++ b/pkgtools/pkg_install/files/lib/str.c
@@ -1,4 +1,4 @@
-/* $NetBSD: str.c,v 1.22 2008/04/18 17:16:44 joerg Exp $ */
+/* $NetBSD: str.c,v 1.23 2008/04/26 14:56:34 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
#else
-__RCSID("$NetBSD: str.c,v 1.22 2008/04/18 17:16:44 joerg Exp $");
+__RCSID("$NetBSD: str.c,v 1.23 2008/04/26 14:56:34 joerg Exp $");
#endif
#endif
@@ -106,44 +106,3 @@ ispkgpattern(const char *pkg)
{
return strpbrk(pkg, "<>[]?*{") != NULL;
}
-
-/*
- * Strip off any .tgz, .tbz or .t[bg]z suffix from fname,
- * and copy into buffer "buf", the suffix is stored in "sfx"
- * if "sfx" is not NULL. If no suffix is found, "sfx" is set
- * to an empty string.
- */
-void
-strip_txz(char *buf, char *sfx, const char *fname)
-{
- static const char *const suffixes[] = {
- ".tgz", ".tbz", ".t[bg]z", 0};
- const char *const *suffixp;
- size_t len;
-
- len = strlen(fname);
- assert(len < PKG_PATTERN_MAX);
-
- if (sfx)
- sfx[0] = '\0';
-
- for (suffixp = suffixes; *suffixp; suffixp++) {
- size_t suffixlen = strlen(*suffixp);
-
- if (memcmp(&fname[len - suffixlen], *suffixp, suffixlen))
- continue;
-
- /* matched! */
- memcpy(buf, fname, len - suffixlen);
- buf[len - suffixlen] = 0;
- if (sfx) {
- if (suffixlen >= PKG_SUFFIX_MAX)
- errx(EXIT_FAILURE, "too long suffix '%s'", fname);
- memcpy(sfx, *suffixp, suffixlen+1);
- return;
- }
- }
-
- /* not found */
- memcpy(buf, fname, len+1);
-}