Revert last change, it was not intended to go into HEAD.diff -r1.17 -r1.18 pkgsrc/pkgtools/pkg_install/files/add/Makefile.in
(joerg)
@@ -1,39 +1,39 @@ | @@ -1,39 +1,39 @@ | |||
1 | # $NetBSD: Makefile.in,v 1.17 2008/04/26 14:56:33 joerg Exp $ | 1 | # $NetBSD: Makefile.in,v 1.18 2008/04/26 17:40:01 joerg Exp $ | |
2 | 2 | |||
3 | srcdir= @srcdir@ | 3 | srcdir= @srcdir@ | |
4 | 4 | |||
5 | prefix= @prefix@ | 5 | prefix= @prefix@ | |
6 | exec_prefix= @exec_prefix@ | 6 | exec_prefix= @exec_prefix@ | |
7 | sbindir= @sbindir@ | 7 | sbindir= @sbindir@ | |
8 | mandir= @mandir@ | 8 | mandir= @mandir@ | |
9 | datarootdir= @datarootdir@ | 9 | datarootdir= @datarootdir@ | |
10 | 10 | |||
11 | man1dir= $(mandir)/man1 | 11 | man1dir= $(mandir)/man1 | |
12 | cat1dir= $(mandir)/cat1 | 12 | cat1dir= $(mandir)/cat1 | |
13 | 13 | |||
14 | CC= @CC@ | 14 | CC= @CC@ | |
15 | CCLD= $(CC) | 15 | CCLD= $(CC) | |
16 | LIBS= -linstall -lfetch -larchive -lbz2 -lz @LIBS@ | 16 | LIBS= -linstall @LIBS@ | |
17 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib | 17 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib | |
18 | DEFS= @DEFS@ -DOPSYS_NAME=\"$(OPSYS)\" -DMACHINE_ARCH=\"$(MACHINE_ARCH)\" -DBINDIR=\"$(sbindir)\" | 18 | DEFS= @DEFS@ -DOPSYS_NAME=\"$(OPSYS)\" -DMACHINE_ARCH=\"$(MACHINE_ARCH)\" -DBINDIR=\"$(sbindir)\" -DTAR_CMD=\"@tar@\" -DPAX_CMD=\"@pax@\" | |
19 | CFLAGS= @CFLAGS@ | 19 | CFLAGS= @CFLAGS@ | |
20 | LDFLAGS= @LDFLAGS@ -L../lib | 20 | LDFLAGS= @LDFLAGS@ -L../lib | |
21 | 21 | |||
22 | INSTALL= @INSTALL@ | 22 | INSTALL= @INSTALL@ | |
23 | 23 | |||
24 | PROG= pkg_add | 24 | PROG= pkg_add | |
25 | 25 | |||
26 | OBJS= main.o perform.o verify.o | 26 | OBJS= main.o perform.o futil.o extract.o verify.o | |
27 | 27 | |||
28 | all: $(PROG) | 28 | all: $(PROG) | |
29 | 29 | |||
30 | .c.o: | 30 | .c.o: | |
31 | $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< | 31 | $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< | |
32 | 32 | |||
33 | $(PROG): $(OBJS) | 33 | $(PROG): $(OBJS) | |
34 | $(CCLD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) | 34 | $(CCLD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) | |
35 | 35 | |||
36 | clean: | 36 | clean: | |
37 | rm -f $(OBJS) $(PROG) | 37 | rm -f $(OBJS) $(PROG) | |
38 | 38 | |||
39 | install: | 39 | install: |
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: add.h,v 1.11 2008/04/26 14:56:33 joerg Exp $ */ | 1 | /* $NetBSD: add.h,v 1.12 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | /* from FreeBSD Id: add.h,v 1.8 1997/02/22 16:09:15 peter Exp */ | 3 | /* from FreeBSD Id: add.h,v 1.8 1997/02/22 16:09:15 peter Exp */ | |
4 | 4 | |||
5 | /* | 5 | /* | |
6 | * FreeBSD install - a package for the installation and maintainance | 6 | * FreeBSD install - a package for the installation and maintainance | |
7 | * of non-core utilities. | 7 | * of non-core utilities. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -25,20 +25,27 @@ | @@ -25,20 +25,27 @@ | |||
25 | #ifndef _INST_ADD_H_INCLUDE | 25 | #ifndef _INST_ADD_H_INCLUDE | |
26 | #define _INST_ADD_H_INCLUDE | 26 | #define _INST_ADD_H_INCLUDE | |
27 | 27 | |||
28 | extern char *OverrideMachine; | 28 | extern char *OverrideMachine; | |
29 | extern char *Prefix; | 29 | extern char *Prefix; | |
30 | extern char *View; | 30 | extern char *View; | |
31 | extern char *Viewbase; | 31 | extern char *Viewbase; | |
32 | extern Boolean NoView; | 32 | extern Boolean NoView; | |
33 | extern Boolean NoInstall; | 33 | extern Boolean NoInstall; | |
34 | extern Boolean NoRecord; | 34 | extern Boolean NoRecord; | |
35 | extern Boolean Force; | 35 | extern Boolean Force; | |
36 | extern Boolean Automatic; | 36 | extern Boolean Automatic; | |
37 | extern int Replace; | 37 | extern int Replace; | |
38 | extern char *Mode; | |||
39 | extern char *Owner; | |||
40 | extern char *Group; | |||
41 | extern char *Directory; | |||
42 | extern char *PkgName; | |||
43 | extern char FirstPen[]; | |||
38 | 44 | |||
39 | int make_hierarchy(char *); | 45 | int make_hierarchy(char *); | |
46 | int extract_plist(char *, package_t *); | |||
40 | void apply_perms(char *, char **, int); | 47 | void apply_perms(char *, char **, int); | |
41 | 48 | |||
42 | int pkg_perform(lpkg_head_t *); | 49 | int pkg_perform(lpkg_head_t *); | |
43 | 50 | |||
44 | #endif /* _INST_ADD_H_INCLUDE */ | 51 | #endif /* _INST_ADD_H_INCLUDE */ |
/* $NetBSD: extract.c,v 1.18 2008/04/26 17:40:01 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#ifndef lint
#if 0
static const char *rcsid = "FreeBSD - Id: extract.c,v 1.17 1997/10/08 07:45:35 charnier Exp";
#else
__RCSID("$NetBSD: extract.c,v 1.18 2008/04/26 17:40:01 joerg Exp $");
#endif
#endif
/*
* FreeBSD install - a package for the installation and maintainance
* of non-core utilities.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Jordan K. Hubbard
* 18 July 1993
*
* This is the package extraction code for the add module.
*
*/
#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#include "add.h"
lfile_head_t files;
lfile_head_t perms;
/*
* Copy files from staging area to todir.
* This is only used when the files cannot be directory rename()ed.
*/
static void
pushout(char *todir)
{
pipe_to_system_t *pipe_to;
char *file_args[4];
char **perm_argv;
int perm_argc = 1;
lfile_t *lfp;
int count;
/* set up arguments to run "pax -r -w -p e" */
file_args[0] = (char *)strrchr(PAX_CMD, '/');
if (file_args[0] == NULL)
file_args[0] = PAX_CMD;
else
file_args[0]++;
file_args[1] = "-rwpe";
file_args[2] = todir;
file_args[3] = NULL;
/* count entries for files */
count = 0;
TAILQ_FOREACH(lfp, &files, lf_link)
count++;
if (count > 0) {
/* open pipe, feed it files, close pipe */
pipe_to = pipe_to_system_begin(PAX_CMD, file_args, NULL);
while ((lfp = TAILQ_FIRST(&files)) != NULL) {
fprintf(pipe_to->fp, "%s\n", lfp->lf_name);
TAILQ_REMOVE(&files, lfp, lf_link);
free(lfp);
}
pipe_to_system_end(pipe_to);
}
/* count entries for permissions */
count = 0;
TAILQ_FOREACH(lfp, &perms, lf_link)
count++;
if (count > 0) {
perm_argv = malloc((count + 1) * sizeof(char *));
perm_argc = 0;
TAILQ_FOREACH(lfp, &perms, lf_link)
perm_argv[perm_argc++] = lfp->lf_name;
perm_argv[perm_argc] = NULL;
apply_perms(todir, perm_argv, perm_argc);
/* empty the perm list */
while ((lfp = TAILQ_FIRST(&perms)) != NULL) {
TAILQ_REMOVE(&perms, lfp, lf_link);
free(lfp);
}
free(perm_argv);
}
}
static void
rollback(char *name, char *home, plist_t *start, plist_t *stop)
{
plist_t *q;
char try[MaxPathSize], bup[MaxPathSize], *dir;
dir = home;
for (q = start; q != stop; q = q->next) {
if (q->type == PLIST_FILE) {
(void) snprintf(try, sizeof(try), "%s/%s", dir, q->name);
if (make_preserve_name(bup, sizeof(bup), name, try) && fexists(bup)) {
#if HAVE_CHFLAGS
(void) chflags(try, 0);
#endif
(void) unlink(try);
if (rename(bup, try))
warnx("rollback: unable to rename %s back to %s", bup, try);
}
} else if (q->type == PLIST_CWD) {
if (strcmp(q->name, "."))
dir = q->name;
else
dir = home;
}
}
}
/*
* Return 0 on error, 1 for success.
*/
int
extract_plist(char *home, package_t *pkg)
{
plist_t *p = pkg->head;
char *last_file;
char *last_chdir;
Boolean preserve;
lfile_t *lfp;
TAILQ_INIT(&files);
TAILQ_INIT(&perms);
last_chdir = 0;
preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
/* Reset the world */
Owner = NULL;
Group = NULL;
Mode = NULL;
last_file = NULL;
Directory = home;
if (!NoRecord) {
/* Open Package Database for writing */
if (!pkgdb_open(ReadWrite)) {
cleanup(0);
err(EXIT_FAILURE, "can't open pkgdb");
}
}
/* Do it */
while (p) {
char cmd[MaxPathSize];
switch (p->type) {
case PLIST_NAME:
PkgName = p->name;
if (Verbose)
printf("extract: Package name is %s\n", p->name);
break;
case PLIST_FILE:
last_file = p->name;
if (Verbose)
printf("extract: %s/%s\n", Directory, p->name);
if (!Fake) {
char try[MaxPathSize];
if (strrchr(p->name, '\'')) {
cleanup(0);
errx(2, "Bogus filename \"%s\"", p->name);
}
/* first try to rename it into place */
(void) snprintf(try, sizeof(try), "%s/%s", Directory, p->name);
if (fexists(try)) {
#if HAVE_CHFLAGS
(void) chflags(try, 0); /* XXX hack - if truly immutable, rename fails */
#endif
if (preserve && PkgName) {
char pf[MaxPathSize];
if (make_preserve_name(pf, sizeof(pf), PkgName, try)) {
if (rename(try, pf)) {
warnx(
"unable to back up %s to %s, aborting pkg_add",
try, pf);
rollback(PkgName, home, pkg->head, p);
return 0;
}
}
}
}
if (rename(p->name, try) == 0) {
if (!NoRecord) {
/* note in pkgdb */
char *s, t[MaxPathSize];
int rc;
(void) snprintf(t, sizeof(t), "%s/%s", Directory, p->name);
s = pkgdb_retrieve(t);
#ifdef PKGDB_DEBUG
printf("pkgdb_retrieve(\"%s\")=\"%s\"\n", t, s); /* pkgdb-debug - HF */
#endif
if (s)
warnx("Overwriting %s - pkg %s bogus/conflicting?", t, s);
else {
rc = pkgdb_store(t, PkgName);
#ifdef PKGDB_DEBUG
printf("pkgdb_store(\"%s\", \"%s\") = %d\n", t, PkgName, rc); /* pkgdb-debug - HF */
#endif
}
}
/* try to add to list of perms to be changed and run in bulk. */
if (p->name[0] == '/')
pushout(Directory);
LFILE_ADD(&perms, lfp, p->name);
} else {
/* rename failed, try copying with a big tar command */
if (last_chdir != Directory) {
if (last_chdir != NULL)
pushout(last_chdir);
last_chdir = Directory;
} else if (p->name[0] == '/') {
pushout(Directory);
}
if (!NoRecord) {
/* note in pkgdb */
/* XXX would be better to store in PUSHOUT, but
* that would probably affect too much code I prefer
* not to touch - HF */
char *s, t[MaxPathSize];
int rc;
LFILE_ADD(&files, lfp, p->name);
LFILE_ADD(&perms, lfp, p->name);
if (p->name[0] == '/')
errx(EXIT_FAILURE, "File names must not be absolute (%s).", p->name);
else {
(void) snprintf(t, sizeof(t), "%s/%s", Directory, p->name);
}
s = pkgdb_retrieve(t);
#ifdef PKGDB_DEBUG
printf("pkgdb_retrieve(\"%s\")=\"%s\"\n", t, s); /* pkgdb-debug - HF */
#endif
if (s)
warnx("Overwriting %s - pkg %s bogus/conflicting?", t, s);
else {
rc = pkgdb_store(t, PkgName);
#ifdef PKGDB_DEBUG
printf("pkgdb_store(\"%s\", \"%s\") = %d\n", t, PkgName, rc); /* pkgdb-debug - HF */
#endif
}
}
}
}
break;
case PLIST_CWD:
if (Verbose)
printf("extract: CWD to %s\n", p->name);
pushout(Directory);
if (strcmp(p->name, ".")) {
if (!Fake && make_hierarchy(p->name) == FAIL) {
cleanup(0);
errx(2, "unable to make directory '%s'", p->name);
}
Directory = p->name;
} else
Directory = home;
break;
case PLIST_CMD:
format_cmd(cmd, sizeof(cmd), p->name, Directory, last_file);
pushout(Directory);
printf("Executing '%s'\n", cmd);
if (!Fake && system(cmd))
warnx("command '%s' failed", cmd);
break;
case PLIST_CHMOD:
pushout(Directory);
Mode = p->name;
break;
case PLIST_CHOWN:
pushout(Directory);
Owner = p->name;
break;
case PLIST_CHGRP:
pushout(Directory);
Group = p->name;
break;
case PLIST_COMMENT:
break;
case PLIST_IGNORE:
p = p->next;
break;
default:
break;
}
p = p->next;
}
pushout(Directory);
if (!NoRecord)
pkgdb_close();
return 1;
}
/* $NetBSD: futil.c,v 1.11 2008/04/26 17:40:01 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: futil.c,v 1.7 1997/10/08 07:45:39 charnier Exp";
#else
__RCSID("$NetBSD: futil.c,v 1.11 2008/04/26 17:40:01 joerg Exp $");
#endif
#endif
/*
* FreeBSD install - a package for the installation and maintainance
* of non-core utilities.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Jordan K. Hubbard
* 18 July 1993
*
* Miscellaneous file access utilities.
*
*/
#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#include "add.h"
/*
* Assuming dir is a desired directory name, make it and all intervening
* directories necessary.
*/
int
make_hierarchy(char *dir)
{
char *cp1, *cp2;
char *argv[2];
argv[0] = dir;
argv[1] = NULL;
if (dir[0] == '/')
cp1 = cp2 = dir + 1;
else
cp1 = cp2 = dir;
while (cp2) {
if ((cp2 = strchr(cp1, '/')) != NULL)
*cp2 = '\0';
if (fexists(dir)) {
if (!(isdir(dir) || islinktodir(dir)))
return FAIL;
} else {
if (fexec("mkdir", dir, NULL))
return FAIL;
apply_perms(NULL, argv, 1);
}
/* Put it back */
if (cp2) {
*cp2 = '/';
cp1 = cp2 + 1;
}
}
return SUCCESS;
}
/*
* Using permission defaults, apply them as necessary
*/
void
apply_perms(char *dir, char **args, int nargs)
{
char *cd_to;
char owner_group[128];
const char **argv;
int i;
argv = malloc((nargs + 4) * sizeof(char *));
/*
* elements 0..2 are set later depending on Mode.
* args is a NULL terminated list of file names.
* by appending them to argv, argv becomes NULL terminated also.
*/
for (i = 0; i <= nargs; i++)
argv[i + 3] = args[i];
if (!dir || args[0][0] == '/') /* absolute path? */
cd_to = "/";
else
cd_to = dir;
if (Mode) {
argv[0] = CHMOD_CMD;
argv[1] = "-R";
argv[2] = Mode;
if (pfcexec(cd_to, argv[0], argv))
warnx("couldn't change modes of '%s' ... to '%s'",
args[0], Mode);
}
if (Owner != NULL && Group != NULL) {
if (snprintf(owner_group, sizeof(owner_group),
"%s:%s", Owner, Group) > sizeof(owner_group)) {
warnx("'%s:%s' is too long (%lu max)",
Owner, Group, (unsigned long) sizeof(owner_group));
free(argv);
return;
}
argv[0] = CHOWN_CMD;
argv[1] = "-R";
argv[2] = owner_group;
if (pfcexec(cd_to, argv[0], argv))
warnx("couldn't change owner/group of '%s' ... to '%s:%s'",
args[0], Owner, Group);
free(argv);
return;
}
if (Owner != NULL) {
argv[0] = CHOWN_CMD;
argv[1] = "-R";
argv[2] = Owner;
if (pfcexec(cd_to, argv[0], argv))
warnx("couldn't change owner of '%s' ... to '%s'",
args[0], Owner);
free(argv);
return;
}
if (Group != NULL) {
argv[0] = CHGRP_CMD;
argv[1] = "-R";
argv[2] = Group;
if (pfcexec(cd_to, argv[0], argv))
warnx("couldn't change group of '%s' ... to '%s'",
args[0], Group);
}
free(argv);
}
@@ -1,27 +1,27 @@ | @@ -1,27 +1,27 @@ | |||
1 | /* $NetBSD: main.c,v 1.15 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: main.c,v 1.16 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | #ifndef lint | 10 | #ifndef lint | |
11 | #if 0 | 11 | #if 0 | |
12 | static char *rcsid = "from FreeBSD Id: main.c,v 1.16 1997/10/08 07:45:43 charnier Exp"; | 12 | static char *rcsid = "from FreeBSD Id: main.c,v 1.16 1997/10/08 07:45:43 charnier Exp"; | |
13 | #else | 13 | #else | |
14 | __RCSID("$NetBSD: main.c,v 1.15 2008/04/26 14:56:34 joerg Exp $"); | 14 | __RCSID("$NetBSD: main.c,v 1.16 2008/04/26 17:40:01 joerg Exp $"); | |
15 | #endif | 15 | #endif | |
16 | #endif | 16 | #endif | |
17 | 17 | |||
18 | /* | 18 | /* | |
19 | * | 19 | * | |
20 | * FreeBSD install - a package for the installation and maintainance | 20 | * FreeBSD install - a package for the installation and maintainance | |
21 | * of non-core utilities. | 21 | * of non-core utilities. | |
22 | * | 22 | * | |
23 | * Redistribution and use in source and binary forms, with or without | 23 | * Redistribution and use in source and binary forms, with or without | |
24 | * modification, are permitted provided that the following conditions | 24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | 25 | * are met: | |
26 | * 1. Redistributions of source code must retain the above copyright | 26 | * 1. Redistributions of source code must retain the above copyright | |
27 | * notice, this list of conditions and the following disclaimer. | 27 | * notice, this list of conditions and the following disclaimer. | |
@@ -50,34 +50,40 @@ __RCSID("$NetBSD: main.c,v 1.15 2008/04/ | @@ -50,34 +50,40 @@ __RCSID("$NetBSD: main.c,v 1.15 2008/04/ | |||
50 | #include "verify.h" | 50 | #include "verify.h" | |
51 | 51 | |||
52 | static char Options[] = "AIK:LRVW:fhm:np:s:t:uvw:"; | 52 | static char Options[] = "AIK:LRVW:fhm:np:s:t:uvw:"; | |
53 | 53 | |||
54 | char *OverrideMachine = NULL; | 54 | char *OverrideMachine = NULL; | |
55 | char *Prefix = NULL; | 55 | char *Prefix = NULL; | |
56 | char *View = NULL; | 56 | char *View = NULL; | |
57 | char *Viewbase = NULL; | 57 | char *Viewbase = NULL; | |
58 | Boolean NoView = FALSE; | 58 | Boolean NoView = FALSE; | |
59 | Boolean NoInstall = FALSE; | 59 | Boolean NoInstall = FALSE; | |
60 | Boolean NoRecord = FALSE; | 60 | Boolean NoRecord = FALSE; | |
61 | Boolean Automatic = FALSE; | 61 | Boolean Automatic = FALSE; | |
62 | 62 | |||
63 | char *Mode = NULL; | |||
64 | char *Owner = NULL; | |||
65 | char *Group = NULL; | |||
66 | char *PkgName = NULL; | |||
67 | char *Directory = NULL; | |||
68 | char FirstPen[MaxPathSize]; | |||
63 | int Replace = 0; | 69 | int Replace = 0; | |
64 | 70 | |||
65 | static void | 71 | static void | |
66 | usage(void) | 72 | usage(void) | |
67 | { | 73 | { | |
68 | (void) fprintf(stderr, "%s\n%s\n%s\n", | 74 | (void) fprintf(stderr, "%s\n%s\n%s\n", | |
69 | "usage: pkg_add [-AfhILnRuVv] [-K pkg_dbdir] [-m machine] [-p prefix]", | 75 | "usage: pkg_add [-AfhILnRuVv] [-K pkg_dbdir] [-m machine] [-p prefix]", | |
70 | " [-s verification-type] [-W viewbase] [-w view]", | 76 | " [-s verification-type] [-t template] [-W viewbase] [-w view]", | |
71 | " [[ftp|http]://[user[:password]@]host[:port]][/path/]pkg-name ..."); | 77 | " [[ftp|http]://[user[:password]@]host[:port]][/path/]pkg-name ..."); | |
72 | exit(1); | 78 | exit(1); | |
73 | } | 79 | } | |
74 | 80 | |||
75 | int | 81 | int | |
76 | main(int argc, char **argv) | 82 | main(int argc, char **argv) | |
77 | { | 83 | { | |
78 | int ch, error=0; | 84 | int ch, error=0; | |
79 | lpkg_head_t pkgs; | 85 | lpkg_head_t pkgs; | |
80 | struct rlimit rlim; | 86 | struct rlimit rlim; | |
81 | int rc; | 87 | int rc; | |
82 | 88 | |||
83 | setprogname(argv[0]); | 89 | setprogname(argv[0]); | |
@@ -110,31 +116,33 @@ main(int argc, char **argv) | @@ -110,31 +116,33 @@ main(int argc, char **argv) | |||
110 | case 'm': | 116 | case 'm': | |
111 | OverrideMachine = optarg; | 117 | OverrideMachine = optarg; | |
112 | break; | 118 | break; | |
113 | 119 | |||
114 | case 'n': | 120 | case 'n': | |
115 | Fake = TRUE; | 121 | Fake = TRUE; | |
116 | Verbose = TRUE; | 122 | Verbose = TRUE; | |
117 | break; | 123 | break; | |
118 | 124 | |||
119 | case 'p': | 125 | case 'p': | |
120 | Prefix = optarg; | 126 | Prefix = optarg; | |
121 | break; | 127 | break; | |
122 | 128 | |||
123 | #if 0 | |||
124 | case 's': | 129 | case 's': | |
125 | set_verification(optarg); | 130 | set_verification(optarg); | |
126 | break; | 131 | break; | |
127 | #endif | 132 | ||
133 | case 't': | |||
134 | strlcpy(FirstPen, optarg, sizeof(FirstPen)); | |||
135 | break; | |||
128 | 136 | |||
129 | case 'u': | 137 | case 'u': | |
130 | Replace++; | 138 | Replace++; | |
131 | break; | 139 | break; | |
132 | 140 | |||
133 | case 'V': | 141 | case 'V': | |
134 | show_version(); | 142 | show_version(); | |
135 | /* NOTREACHED */ | 143 | /* NOTREACHED */ | |
136 | 144 | |||
137 | case 'v': | 145 | case 'v': | |
138 | Verbose = TRUE; | 146 | Verbose = TRUE; | |
139 | break; | 147 | break; | |
140 | 148 |
@@ -1,1228 +1,1053 @@ | @@ -1,1228 +1,1053 @@ | |||
1 | /* $NetBSD: perform.c,v 1.71 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: perform.c,v 1.72 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | ||||
2 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
3 | #include "config.h" | 4 | #include "config.h" | |
4 | #endif | 5 | #endif | |
5 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
6 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
7 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
8 | #endif | 9 | #endif | |
9 | __RCSID("$NetBSD: perform.c,v 1.71 2008/04/26 14:56:34 joerg Exp $"); | 10 | #if HAVE_SYS_QUEUE_H | |
11 | #include <sys/queue.h> | |||
12 | #endif | |||
13 | #ifndef lint | |||
14 | #if 0 | |||
15 | static const char *rcsid = "from FreeBSD Id: perform.c,v 1.44 1997/10/13 15:03:46 jkh Exp"; | |||
16 | #else | |||
17 | __RCSID("$NetBSD: perform.c,v 1.72 2008/04/26 17:40:01 joerg Exp $"); | |||
18 | #endif | |||
19 | #endif | |||
10 | 20 | |||
11 | /*- | 21 | /* | |
12 | * Copyright (c) 2003 Grant Beattie <grant@NetBSD.org> | 22 | * FreeBSD install - a package for the installation and maintainance | |
13 | * Copyright (c) 2005 Dieter Baron <dillo@NetBSD.org> | 23 | * of non-core utilities. | |
14 | * Copyright (c) 2007 Roland Illig <rillig@NetBSD.org> | |||
15 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org> | |||
16 | * All rights reserved. | |||
17 | * | 24 | * | |
18 | * Redistribution and use in source and binary forms, with or without | 25 | * Redistribution and use in source and binary forms, with or without | |
19 | * modification, are permitted provided that the following conditions | 26 | * modification, are permitted provided that the following conditions | |
20 | * are met: | 27 | * are met: | |
21 | * | |||
22 | * 1. Redistributions of source code must retain the above copyright | 28 | * 1. Redistributions of source code must retain the above copyright | |
23 | * notice, this list of conditions and the following disclaimer. | 29 | * notice, this list of conditions and the following disclaimer. | |
24 | * 2. Redistributions in binary form must reproduce the above copyright | 30 | * 2. Redistributions in binary form must reproduce the above copyright | |
25 | * notice, this list of conditions and the following disclaimer in | 31 | * notice, this list of conditions and the following disclaimer in the | |
26 | * the documentation and/or other materials provided with the | 32 | * documentation and/or other materials provided with the distribution. | |
27 | * distribution. | 33 | * | |
34 | * Jordan K. Hubbard | |||
35 | * 18 July 1993 | |||
36 | * | |||
37 | * This is the main body of the add module. | |||
28 | * | 38 | * | |
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
30 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||
32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||
33 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
34 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||
35 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
36 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |||
37 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
38 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
39 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
40 | * SUCH DAMAGE. | |||
41 | */ | 39 | */ | |
42 | 40 | |||
43 | #include <sys/utsname.h> | 41 | #if HAVE_ASSERT_H | |
44 | #include <archive.h> | 42 | #include <assert.h> | |
45 | #include <archive_entry.h> | 43 | #endif | |
44 | #if HAVE_ERR_H | |||
46 | #include <err.h> | 45 | #include <err.h> | |
46 | #endif | |||
47 | #if HAVE_ERRNO_H | |||
47 | #include <errno.h> | 48 | #include <errno.h> | |
48 | #include <stdlib.h> | 49 | #endif | |
49 | #include <string.h> | 50 | #include "defs.h" | |
50 | #include <unistd.h> | |||
51 | ||||
52 | #include "lib.h" | 51 | #include "lib.h" | |
53 | #include "add.h" | 52 | #include "add.h" | |
53 | #include "verify.h" | |||
54 | 54 | |||
55 | struct pkg_meta { | 55 | #if HAVE_INTTYPES_H | |
56 | char *meta_contents; | 56 | #include <inttypes.h> | |
57 | char *meta_comment; | 57 | #endif | |
58 | char *meta_desc; | 58 | #if HAVE_SIGNAL_H | |
59 | char *meta_mtree; | 59 | #include <signal.h> | |
60 | char *meta_build_version; | 60 | #endif | |
61 | char *meta_build_info; | 61 | #if HAVE_STRING_H | |
62 | char *meta_size_pkg; | 62 | #include <string.h> | |
63 | char *meta_size_all; | 63 | #endif | |
64 | char *meta_required_by; | 64 | #if HAVE_STDLIB_H | |
65 | char *meta_display; | 65 | #include <stdlib.h> | |
66 | char *meta_install; | 66 | #endif | |
67 | char *meta_deinstall; | 67 | #if HAVE_SYS_UTSNAME_H | |
68 | char *meta_preserve; | 68 | #include <sys/utsname.h> | |
69 | char *meta_views; | 69 | #endif | |
70 | char *meta_installed_info; | |||
71 | }; | |||
72 | ||||
73 | struct pkg_task { | |||
74 | const char *pkgname; | |||
75 | ||||
76 | const char *prefix; | |||
77 | const char *install_prefix; | |||
78 | ||||
79 | char *logdir; | |||
80 | char *other_version; | |||
81 | ||||
82 | package_t plist; | |||
83 | ||||
84 | struct pkg_meta meta_data; | |||
85 | 70 | |||
86 | struct archive *archive; | 71 | static char LogDir[MaxPathSize]; | |
87 | struct archive_entry *entry; | 72 | static int zapLogDir; /* Should we delete LogDir? */ | |
88 | 73 | |||
89 | char *buildinfo[BI_ENUM_COUNT]; | 74 | static package_t Plist; | |
75 | static char *Home; | |||
90 | 76 | |||
91 | size_t dep_length, dep_allocated; | 77 | static lfile_head_t files; | |
92 | char **dependencies; | |||
93 | }; | |||
94 | 78 | |||
95 | static const struct pkg_meta_desc { | 79 | /* used in build information */ | |
96 | size_t entry_offset; | 80 | enum { | |
97 | const char *entry_filename; | 81 | Good, | |
98 | int required_file; | 82 | Missing, | |
99 | mode_t perm; | 83 | Warning, | |
100 | } pkg_meta_descriptors[] = { | 84 | Fatal | |
101 | { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 1, 0644 }, | |||
102 | { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 1, 0444}, | |||
103 | { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 1, 0444}, | |||
104 | { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 0, 0555 }, | |||
105 | { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 0, 0555 }, | |||
106 | { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 0, 0444 }, | |||
107 | { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 0, 0444 }, | |||
108 | { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME, 0, 0444 }, | |||
109 | { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME, 0, 0444 }, | |||
110 | { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME, 0, 0444 }, | |||
111 | { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME, 0, 0444 }, | |||
112 | { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME, 0, 0444 }, | |||
113 | { offsetof(struct pkg_meta, meta_views), VIEWS_FNAME, 0, 0444 }, | |||
114 | { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME, 0, 0644 }, | |||
115 | { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME, 0, 0644 }, | |||
116 | { 0, NULL, 0 }, | |||
117 | }; | 85 | }; | |
118 | 86 | |||
119 | static int pkg_do(const char *, int); | 87 | static void | |
120 | 88 | normalise_platform(struct utsname *host_name) | ||
121 | static int | |||
122 | mkdir_p(const char *path) | |||
123 | { | 89 | { | |
124 | return fexec(MKDIR_CMD, "-p", path, (void *)NULL); | 90 | #ifdef NUMERIC_VERSION_ONLY | |
91 | size_t span; | |||
92 | ||||
93 | span = strspn(host_name->release, "0123456789."); | |||
94 | host_name->release[span] = '\0'; | |||
95 | #endif | |||
125 | } | 96 | } | |
126 | 97 | |||
127 | /* | 98 | /* Read package build information */ | |
128 | * Read meta data from archive. | |||
129 | * Bail out if a required entry is missing or entries are in the wrong order. | |||
130 | */ | |||
131 | static int | 99 | static int | |
132 | read_meta_data(struct pkg_task *pkg) | 100 | read_buildinfo(char **buildinfo) | |
133 | { | 101 | { | |
134 | const struct pkg_meta_desc *descr, *last_descr; | 102 | char *key; | |
135 | const char *fname; | 103 | char *line; | |
136 | char **target; | 104 | size_t len; | |
137 | int64_t size; | 105 | FILE *fp; | |
138 | int r, found_required; | |||
139 | ||||
140 | found_required = 0; | |||
141 | 106 | |||
142 | last_descr = 0; | 107 | if ((fp = fopen(BUILD_INFO_FNAME, "r")) == NULL) { | |
143 | while ((r = archive_read_next_header(pkg->archive, &pkg->entry)) == | 108 | warnx("unable to open %s file.", BUILD_INFO_FNAME); | |
144 | ARCHIVE_OK) { | 109 | return 0; | |
145 | fname = archive_entry_pathname(pkg->entry); | |||
146 | ||||
147 | for (descr = pkg_meta_descriptors; descr->entry_filename; | |||
148 | ++descr) { | |||
149 | if (strcmp(descr->entry_filename, fname) == 0) | |||
150 | break; | |||
151 | } | |||
152 | if (descr->entry_filename == NULL) | |||
153 | break; | |||
154 | ||||
155 | if (descr->required_file) | |||
156 | ++found_required; | |||
157 | ||||
158 | target = (char **)((char *)&pkg->meta_data + | |||
159 | descr->entry_offset); | |||
160 | if (*target) { | |||
161 | warnx("duplicate entry, package corrupt"); | |||
162 | return -1; | |||
163 | } | |||
164 | if (descr < last_descr) { | |||
165 | warnx("misordered package"); | |||
166 | return -1; | |||
167 | } | |||
168 | last_descr = descr; | |||
169 | ||||
170 | size = archive_entry_size(pkg->entry); | |||
171 | if (size > SSIZE_MAX - 1) { | |||
172 | warnx("package meta data too large to process"); | |||
173 | return -1; | |||
174 | } | |||
175 | if ((*target = malloc(size + 1)) == NULL) | |||
176 | err(2, "cannot allocate meta data"); | |||
177 | if (archive_read_data(pkg->archive, *target, size) != size) { | |||
178 | warn("cannot read package meta data"); | |||
179 | return -1; | |||
180 | } | |||
181 | (*target)[size] = '\0'; | |||
182 | } | 110 | } | |
183 | 111 | |||
184 | if (r != ARCHIVE_OK) | 112 | while ((line = fgetln(fp, &len)) != NULL) { | |
185 | pkg->entry = NULL; | 113 | if (line[len - 1] == '\n') | |
114 | line[len - 1] = '\0'; | |||
186 | 115 | |||
187 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | 116 | if ((key = strsep(&line, "=")) == NULL) | |
188 | if (descr->required_file) | 117 | continue; | |
189 | --found_required; | |||
190 | } | |||
191 | ||||
192 | return !found_required ? 0 : -1; | |||
193 | } | |||
194 | 118 | |||
195 | /* | 119 | /* | |
196 | * Free meta data. | 120 | * pkgsrc used to create the BUILDINFO file using | |
197 | */ | 121 | * "key= value", so skip the space if it's there. | |
198 | static void | 122 | */ | |
199 | free_meta_data(struct pkg_task *pkg) | 123 | if (line == NULL) | |
200 | { | 124 | continue; | |
201 | const struct pkg_meta_desc *descr; | 125 | if (line[0] == ' ') | |
202 | char **target; | 126 | line += sizeof(char); | |
203 | 127 | |||
204 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | 128 | /* | |
205 | target = (char **)((char *)&pkg->meta_data + | 129 | * we only care about opsys, arch, version, and | |
206 | descr->entry_offset); | 130 | * dependency recommendations | |
207 | free(*target); | 131 | */ | |
208 | *target = NULL; | 132 | if (line[0] != '\0') { | |
133 | if (strcmp(key, "OPSYS") == 0) | |||
134 | buildinfo[BI_OPSYS] = strdup(line); | |||
135 | else if (strcmp(key, "OS_VERSION") == 0) | |||
136 | buildinfo[BI_OS_VERSION] = strdup(line); | |||
137 | else if (strcmp(key, "MACHINE_ARCH") == 0) | |||
138 | buildinfo[BI_MACHINE_ARCH] = strdup(line); | |||
139 | else if (strcmp(key, "IGNORE_RECOMMENDED") == 0) | |||
140 | buildinfo[BI_IGNORE_RECOMMENDED] = strdup(line); | |||
141 | else if (strcmp(key, "USE_ABI_DEPENDS") == 0) | |||
142 | buildinfo[BI_USE_ABI_DEPENDS] = strdup(line); | |||
143 | } | |||
144 | } | |||
145 | (void) fclose(fp); | |||
146 | if (buildinfo[BI_OPSYS] == NULL || | |||
147 | buildinfo[BI_OS_VERSION] == NULL || | |||
148 | buildinfo[BI_MACHINE_ARCH] == NULL) { | |||
149 | warnx("couldn't extract build information from package."); | |||
150 | return 0; | |||
209 | } | 151 | } | |
152 | return 1; | |||
210 | } | 153 | } | |
211 | 154 | |||
212 | /* | |||
213 | * Parse PLIST and populate pkg. | |||
214 | */ | |||
215 | static int | 155 | static int | |
216 | pkg_parse_plist(struct pkg_task *pkg) | 156 | sanity_check(const char *pkg) | |
217 | { | 157 | { | |
218 | plist_t *p; | 158 | int errc = 0; | |
219 | 159 | |||
220 | parse_plist(&pkg->plist, pkg->meta_data.meta_contents); | 160 | if (!fexists(CONTENTS_FNAME)) { | |
221 | if ((p = find_plist(&pkg->plist, PLIST_NAME)) == NULL) { | 161 | warnx("package %s has no CONTENTS file!", pkg); | |
222 | warnx("Invalid PLIST: missing @name"); | 162 | errc = 1; | |
223 | return -1; | 163 | } else if (!fexists(COMMENT_FNAME)) { | |
164 | warnx("package %s has no COMMENT file!", pkg); | |||
165 | errc = 1; | |||
166 | } else if (!fexists(DESC_FNAME)) { | |||
167 | warnx("package %s has no DESC file!", pkg); | |||
168 | errc = 1; | |||
224 | } | 169 | } | |
225 | pkg->pkgname = p->name; | 170 | return errc; | |
226 | if ((p = find_plist(&pkg->plist, PLIST_CWD)) == NULL) { | |||
227 | warnx("Invalid PLIST: missing @cwd"); | |||
228 | return -1; | |||
229 | } | |||
230 | /* XXX change first @cwd in PLIST? */ | |||
231 | pkg->prefix = p->name; | |||
232 | pkg->install_prefix = Prefix != NULL ? Prefix : pkg->prefix; | |||
233 | ||||
234 | return 0; | |||
235 | } | |||
236 | ||||
237 | /* | |||
238 | * Helper function to extract value from a string of the | |||
239 | * form key=value ending at eol. | |||
240 | */ | |||
241 | static char * | |||
242 | dup_value(const char *line, const char *eol) | |||
243 | { | |||
244 | const char *key; | |||
245 | char *val; | |||
246 | ||||
247 | key = strchr(line, '='); | |||
248 | val = malloc(eol - key); | |||
249 | if (val == NULL) | |||
250 | err(2, "malloc failed"); | |||
251 | memcpy(val, key + 1, eol - key - 1); | |||
252 | val[eol - key - 1] = '\0'; | |||
253 | return val; | |||
254 | } | 171 | } | |
255 | 172 | |||
173 | /* install a pre-requisite package. Returns 1 if it installed it */ | |||
256 | static int | 174 | static int | |
257 | check_already_installed(struct pkg_task *pkg) | 175 | installprereq(const char *name, int *errc, int doupdate) | |
258 | { | 176 | { | |
259 | char *filename; | 177 | int ret; | |
260 | int fd; | 178 | ret = 0; | |
261 | ||||
262 | if (Force) | |||
263 | return -1; | |||
264 | 179 | |||
265 | filename = pkgdb_pkg_file(pkg->pkgname, CONTENTS_FNAME); | 180 | if (Verbose) | |
266 | fd = open(filename, O_RDONLY); | 181 | printf("Loading it from %s.\n", name); | |
267 | free(filename); | 182 | path_setenv("PKG_PATH"); | |
268 | if (fd == -1) | |||
269 | return -1; | |||
270 | 183 | |||
271 | /* We can only arrive here for explicitly requested packages. */ | 184 | if (fexec_skipempty(BINDIR "/pkg_add", "-K", _pkgdb_getPKGDB_DIR(), | |
272 | if (!Automatic && is_automatic_installed(pkg->pkgname)) { | 185 | "-s", get_verification(), | |
273 | if (Fake || | 186 | doupdate > 1 ? "-uu" : (doupdate ? "-u" : ""), | |
274 | mark_as_automatic_installed(pkg->pkgname, 0) == 0) | 187 | Fake ? "-n" : "", | |
275 | warnx("package `%s' was already installed as " | 188 | NoView ? "-L" : "", | |
276 | "dependency, now marked as installed " | 189 | View ? "-w" : "", View ? View : "", | |
277 | "manually", pkg->pkgname); | 190 | Viewbase ? "-W" : "", Viewbase ? Viewbase : "", | |
191 | Force ? "-f" : "", | |||
192 | Prefix ? "-p" : "", Prefix ? Prefix : "", | |||
193 | Verbose ? "-v" : "", | |||
194 | OverrideMachine ? "-m" : "", | |||
195 | OverrideMachine ? OverrideMachine : "", | |||
196 | NoInstall ? "-I" : "", | |||
197 | "-A", name, NULL)) { | |||
198 | warnx("autoload of dependency `%s' failed%s", | |||
199 | name, Force ? " (proceeding anyway)" : "!"); | |||
200 | if (!Force) | |||
201 | ++(*errc); | |||
278 | } else { | 202 | } else { | |
279 | warnx("package `%s' already recorded as installed", | 203 | ret = 1; | |
280 | pkg->pkgname); | |||
281 | } | 204 | } | |
282 | return 0; | |||
283 | 205 | |||
206 | return ret; | |||
284 | } | 207 | } | |
285 | 208 | |||
286 | static int | 209 | static int | |
287 | check_other_installed(struct pkg_task *pkg) | 210 | pkg_do_installed(int *replacing, char replace_via[MaxPathSize], char replace_to[MaxPathSize], | |
211 | Boolean is_depoted_pkg, const char *dbdir) | |||
288 | { | 212 | { | |
289 | FILE *f, *f_pkg; | 213 | char replace_from[MaxPathSize]; | |
290 | size_t len; | 214 | char *s; | |
291 | char *pkgbase, *iter, *filename; | 215 | char buf[MaxPathSize]; | |
292 | package_t plist; | 216 | char *best_installed; | |
293 | plist_t *p; | |||
294 | int status; | |||
295 | ||||
296 | if ((pkgbase = strdup(pkg->pkgname)) == NULL) { | |||
297 | warnx("strdup failed"); | |||
298 | return -1; | |||
299 | } | |||
300 | if ((iter = strrchr(pkgbase, '-')) == NULL) { | |||
301 | free(pkgbase); | |||
302 | warnx("Invalid package name %s", pkg->pkgname); | |||
303 | return -1; | |||
304 | } | |||
305 | *iter = '\0'; | |||
306 | pkg->other_version = find_best_matching_installed_pkg(pkgbase); | |||
307 | free(pkgbase); | |||
308 | if (pkg->other_version == NULL) | |||
309 | return 0; | |||
310 | 217 | |||
311 | if (!Replace) { | 218 | const size_t replace_via_size = MaxPathSize; | |
312 | /* XXX This is redundant to the implicit conflict check. */ | 219 | const size_t replace_to_size = MaxPathSize; | |
313 | warnx("A different version of %s is already installed: %s", | |||
314 | pkg->pkgname, pkg->other_version); | |||
315 | return -1; | |||
316 | } | |||
317 | 220 | |||
318 | filename = pkgdb_pkg_file(pkg->other_version, REQUIRED_BY_FNAME); | 221 | if ((s = strrchr(PkgName, '-')) == NULL) { | |
319 | errno = 0; | 222 | warnx("Package name %s does not contain a version, bailing out", PkgName); | |
320 | f = fopen(filename, "r"); | |||
321 | free(filename); | |||
322 | if (f == NULL) { | |||
323 | if (errno == ENOENT) { | |||
324 | /* No packages depend on this, so everything is well. */ | |||
325 | return 0; | |||
326 | } | |||
327 | warnx("Can't open +REQUIRED_BY of %s", pkg->other_version); | |||
328 | return -1; | 223 | return -1; | |
329 | } | 224 | } | |
225 | ||||
226 | /* | |||
227 | * See if the pkg is already installed. If so, we might want to | |||
228 | * upgrade/replace it. Otherwise, just return and let pkg_do work. | |||
229 | */ | |||
230 | (void) snprintf(buf, sizeof(buf), "%.*s[0-9]*", | |||
231 | (int)(s - PkgName) + 1, PkgName); | |||
232 | best_installed = find_best_matching_installed_pkg(buf); | |||
233 | if (best_installed == NULL) | |||
234 | return 0; | |||
330 | 235 | |||
331 | status = 0; | 236 | if (!Replace || Fake) { | |
332 | 237 | if (is_depoted_pkg) { | ||
333 | while ((iter = fgetln(f, &len)) != NULL) { | 238 | free(best_installed); | |
334 | if (iter[len - 1] == '\n') | 239 | return 0; | |
335 | iter[len - 1] = '\0'; | 240 | } else { | |
336 | filename = pkgdb_pkg_file(iter, CONTENTS_FNAME); | 241 | warnx("other version '%s' already installed", best_installed); | |
337 | if ((f_pkg = fopen(filename, "r")) == NULL) { | 242 | free(best_installed); | |
338 | warnx("Can't open +CONTENTS of depending package %s", | 243 | return 1; /* close enough for government work */ | |
339 | iter); | |||
340 | fclose(f); | |||
341 | return -1; | |||
342 | } | |||
343 | plist.head = plist.tail = NULL; | |||
344 | read_plist(&plist, f_pkg); | |||
345 | fclose(f_pkg); | |||
346 | for (p = plist.head; p != NULL; p = p->next) { | |||
347 | if (p->type == PLIST_IGNORE) { | |||
348 | p = p->next; | |||
349 | continue; | |||
350 | } else if (p->type != PLIST_PKGDEP) | |||
351 | continue; | |||
352 | /* | |||
353 | * XXX This is stricter than necessary. | |||
354 | * XXX One pattern might be fulfilled by | |||
355 | * XXX a different package and still need this | |||
356 | * XXX one for a different pattern. | |||
357 | */ | |||
358 | if (pkg_match(p->name, pkg->other_version) == 0) | |||
359 | continue; | |||
360 | if (pkg_match(p->name, pkg->pkgname) == 1) | |||
361 | continue; /* Both match, ok. */ | |||
362 | warnx("Dependency of %s fulfilled by %s, but not by %s", | |||
363 | iter, pkg->other_version, pkg->pkgname); | |||
364 | if (!Force) | |||
365 | status = -1; | |||
366 | break; | |||
367 | } | 244 | } | |
368 | free_plist(&plist); | |||
369 | } | 245 | } | |
370 | 246 | |||
371 | fclose(f); | 247 | /* XXX Should list the steps in Fake mode */ | |
248 | snprintf(replace_from, sizeof(replace_from), "%s/%s/" REQUIRED_BY_FNAME, | |||
249 | dbdir, best_installed); | |||
250 | snprintf(replace_via, replace_via_size, "%s/.%s." REQUIRED_BY_FNAME, | |||
251 | dbdir, best_installed); | |||
252 | snprintf(replace_to, replace_to_size, "%s/%s/" REQUIRED_BY_FNAME, | |||
253 | dbdir, PkgName); | |||
372 | 254 | |||
373 | return status; | 255 | if (Verbose) | |
374 | } | 256 | printf("Upgrading %s to %s.\n", best_installed, PkgName); | |
375 | 257 | |||
376 | /* | 258 | if (fexists(replace_from)) { /* Are there any dependencies? */ | |
377 | * Read package build information from meta data. | 259 | /* | |
378 | */ | 260 | * Upgrade step 1/4: Check if the new version is ok with all pkgs | |
379 | static int | 261 | * (from +REQUIRED_BY) that require this pkg | |
380 | read_buildinfo(struct pkg_task *pkg) | 262 | */ | |
381 | { | 263 | FILE *rb; /* +REQUIRED_BY file */ | |
382 | const char *data, *eol, *next_line; | 264 | char pkg2chk[MaxPathSize]; | |
383 | 265 | |||
384 | data = pkg->meta_data.meta_build_info; | 266 | rb = fopen(replace_from, "r"); | |
267 | if (! rb) { | |||
268 | warnx("Cannot open '%s' for reading%s", replace_from, | |||
269 | Force ? " (proceeding anyways)" : ""); | |||
270 | if (Force) | |||
271 | goto ignore_replace_depends_check; | |||
272 | else | |||
273 | return -1; | |||
274 | } | |||
275 | while (fgets(pkg2chk, sizeof(pkg2chk), rb)) { | |||
276 | package_t depPlist; | |||
277 | FILE *depf; | |||
278 | plist_t *depp; | |||
279 | char depC[MaxPathSize]; | |||
280 | ||||
281 | depPlist.head = depPlist.tail = NULL; | |||
282 | ||||
283 | s = strrchr(pkg2chk, '\n'); | |||
284 | if (s) | |||
285 | *s = '\0'; /* strip trailing '\n' */ | |||
286 | ||||
287 | /* | |||
288 | * step into pkg2chk, read it's +CONTENTS file and see if | |||
289 | * all @pkgdep lines agree with PkgName (using pkg_match()) | |||
290 | */ | |||
291 | snprintf(depC, sizeof(depC), "%s/%s/%s", dbdir, pkg2chk, CONTENTS_FNAME); | |||
292 | depf = fopen(depC , "r"); | |||
293 | if (depf == NULL) { | |||
294 | warnx("Cannot check depends in '%s'%s", depC, | |||
295 | Force ? " (proceeding anyways)" : "!" ); | |||
296 | if (Force) | |||
297 | goto ignore_replace_depends_check; | |||
298 | else | |||
299 | return -1; | |||
300 | } | |||
301 | read_plist(&depPlist, depf); | |||
302 | fclose(depf); | |||
303 | ||||
304 | for (depp = depPlist.head; depp; depp = depp->next) { | |||
305 | char base_new[MaxPathSize]; | |||
306 | char base_exist[MaxPathSize]; | |||
307 | char *s2; | |||
308 | ||||
309 | if (depp->type != PLIST_PKGDEP) | |||
310 | continue; | |||
311 | ||||
312 | /* | |||
313 | * Prepare basename (no versions) of both pkgs, | |||
314 | * to see if we want to compare against that | |||
315 | * one at all. | |||
316 | */ | |||
317 | strlcpy(base_new, PkgName, sizeof(base_new)); | |||
318 | s2 = strpbrk(base_new, "<>[]?*{"); /* } */ | |||
319 | if (s2) | |||
320 | *s2 = '\0'; | |||
321 | else { | |||
322 | s2 = strrchr(base_new, '-'); | |||
323 | if (s2) | |||
324 | *s2 = '\0'; | |||
325 | } | |||
326 | strlcpy(base_exist, depp->name, sizeof(base_exist)); | |||
327 | s2 = strpbrk(base_exist, "<>[]?*{"); /* } */ | |||
328 | if (s2) | |||
329 | *s2 = '\0'; | |||
330 | else { | |||
331 | s2 = strrchr(base_exist, '-'); | |||
332 | if (s2) | |||
333 | *s2 = '\0'; | |||
334 | } | |||
335 | if (strcmp(base_new, base_exist) == 0) { | |||
336 | /* Same pkg, so do the interesting compare */ | |||
337 | if (pkg_match(depp->name, PkgName)) { | |||
338 | if (Verbose) | |||
339 | printf("@pkgdep check: %s is ok for %s (in %s pkg)\n", | |||
340 | PkgName, depp->name, pkg2chk); | |||
341 | } else { | |||
342 | printf("Package %s requires %s, \n\tCannot replace with %s%s\n", | |||
343 | pkg2chk, depp->name, PkgName, | |||
344 | Force? " (proceeding anyways)" : "!"); | |||
345 | if (! Force) | |||
346 | return -1; | |||
347 | } | |||
348 | } | |||
349 | } | |||
350 | } | |||
351 | fclose(rb); | |||
385 | 352 | |||
386 | for (; *data != '\0'; data = next_line) { | 353 | ignore_replace_depends_check: | |
387 | if ((eol = strchr(data, '\n')) == NULL) { | 354 | /* | |
388 | eol = data + strlen(data); | 355 | * Upgrade step 2/4: Do the actual update by moving aside | |
389 | next_line = eol; | 356 | * the +REQUIRED_BY file, deinstalling the old pkg, adding | |
390 | } else | 357 | * the new one and moving the +REQUIRED_BY file back | |
391 | next_line = eol + 1; | 358 | * into place (finished in step 3/4) | |
359 | */ | |||
360 | if (Verbose) | |||
361 | printf("mv %s %s\n", replace_from, replace_via); | |||
362 | if (rename(replace_from, replace_via) != 0) | |||
363 | err(EXIT_FAILURE, "renaming \"%s\" to \"%s\" failed", replace_from, replace_via); | |||
392 | 364 | |||
393 | if (strncmp(data, "OPSYS=", 6) == 0) | 365 | *replacing = 1; | |
394 | pkg->buildinfo[BI_OPSYS] = dup_value(data, eol); | |||
395 | else if (strncmp(data, "OS_VERSION=", 11) == 0) | |||
396 | pkg->buildinfo[BI_OS_VERSION] = dup_value(data, eol); | |||
397 | else if (strncmp(data, "MACHINE_ARCH=", 13) == 0) | |||
398 | pkg->buildinfo[BI_MACHINE_ARCH] = dup_value(data, eol); | |||
399 | else if (strncmp(data, "IGNORE_RECOMMENDED=", 19) == 0) | |||
400 | pkg->buildinfo[BI_IGNORE_RECOMMENDED] = dup_value(data, | |||
401 | eol); | |||
402 | else if (strncmp(data, "USE_ABI_DEPENDS=", 16) == 0) | |||
403 | pkg->buildinfo[BI_USE_ABI_DEPENDS] = dup_value(data, | |||
404 | eol); | |||
405 | } | |||
406 | if (pkg->buildinfo[BI_OPSYS] == NULL || | |||
407 | pkg->buildinfo[BI_OS_VERSION] == NULL || | |||
408 | pkg->buildinfo[BI_MACHINE_ARCH] == NULL) { | |||
409 | warnx("Not all required build information are present."); | |||
410 | return -1; | |||
411 | } | 366 | } | |
412 | 367 | |||
413 | if ((pkg->buildinfo[BI_USE_ABI_DEPENDS] != NULL && | 368 | if (Verbose) { | |
414 | strcasecmp(pkg->buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) || | 369 | printf("%s/pkg_delete -K %s '%s'\n", | |
415 | (pkg->buildinfo[BI_IGNORE_RECOMMENDED] != NULL && | 370 | BINDIR, dbdir, best_installed); | |
416 | strcasecmp(pkg->buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) { | |||
417 | warnx("%s was built to ignore ABI dependencies", pkg->pkgname); | |||
418 | } | 371 | } | |
372 | fexec(BINDIR "/pkg_delete", "-K", dbdir, best_installed, NULL); | |||
419 | 373 | |||
420 | return 0; | 374 | free(best_installed); | |
421 | } | |||
422 | 375 | |||
423 | /* | 376 | return 0; | |
424 | * Free buildinfo. | |||
425 | */ | |||
426 | static void | |||
427 | free_buildinfo(struct pkg_task *pkg) | |||
428 | { | |||
429 | size_t i; | |||
430 | ||||
431 | for (i = 0; i < BI_ENUM_COUNT; ++i) { | |||
432 | free(pkg->buildinfo[i]); | |||
433 | pkg->buildinfo[i] = NULL; | |||
434 | } | |||
435 | } | 377 | } | |
436 | 378 | |||
437 | /* | 379 | /* | |
438 | * Write meta data files to pkgdb after creating the directory. | 380 | * Install a single package | |
381 | * Returns 0 if everything is ok, >0 else | |||
439 | */ | 382 | */ | |
440 | static int | 383 | static int | |
441 | write_meta_data(struct pkg_task *pkg) | 384 | pkg_do(const char *pkg, lpkg_head_t *pkgs) | |
442 | { | 385 | { | |
443 | const struct pkg_meta_desc *descr; | 386 | char playpen[MaxPathSize]; | |
444 | char *filename, **target; | 387 | char replace_via[MaxPathSize]; | |
445 | size_t len; | 388 | char replace_to[MaxPathSize]; | |
446 | ssize_t ret; | 389 | char *buildinfo[BI_ENUM_COUNT]; | |
447 | int fd; | 390 | int replacing = 0; | |
448 | 391 | char dbdir[MaxPathSize]; | ||
449 | if (Fake) | 392 | const char *tmppkg; | |
450 | return 0; | 393 | FILE *cfile; | |
451 | 394 | int errc, err_prescan; | ||
452 | if (mkdir_p(pkg->logdir)) { | 395 | plist_t *p; | |
453 | warn("Can't create pkgdb entry: %s", pkg->logdir); | 396 | struct stat sb; | |
454 | return -1; | 397 | struct utsname host_uname; | |
455 | } | 398 | uint64_t needed; | |
456 | 399 | Boolean is_depoted_pkg = FALSE; | ||
457 | for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { | 400 | lfile_t *lfp; | |
458 | target = (char **)((char *)&pkg->meta_data + | 401 | int result; | |
459 | descr->entry_offset); | 402 | ||
460 | if (*target == NULL) | 403 | errc = 0; | |
461 | continue; | 404 | zapLogDir = 0; | |
462 | if (asprintf(&filename, "%s/%s", pkg->logdir, | 405 | LogDir[0] = '\0'; | |
463 | descr->entry_filename) == -1) { | 406 | strlcpy(playpen, FirstPen, sizeof(playpen)); | |
464 | warn("asprintf failed"); | 407 | memset(buildinfo, '\0', sizeof(buildinfo)); | |
465 | return -1; | 408 | ||
466 | } | 409 | umask(DEF_UMASK); | |
467 | (void)unlink(filename); | 410 | ||
468 | fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, descr->perm); | 411 | tmppkg = fileFindByPath(pkg); | |
469 | if (fd == -1) { | 412 | if (tmppkg == NULL) { | |
470 | warn("Can't open meta data file: %s", filename); | 413 | warnx("no pkg found for '%s', sorry.", pkg); | |
471 | return -1; | 414 | return 1; | |
472 | } | 415 | } | |
473 | len = strlen(*target); | 416 | ||
474 | do { | 417 | pkg = tmppkg; | |
475 | ret = write(fd, *target, len); | 418 | ||
476 | if (ret == -1) { | 419 | if (IS_URL(pkg)) { | |
477 | warn("Can't write meta data file: %s", | 420 | Home = fileGetURL(pkg); | |
478 | filename); | 421 | if (Home == NULL) { | |
479 | free(filename); | 422 | warnx("unable to fetch `%s' by URL", pkg); | |
480 | return -1; | 423 | } | |
424 | ||||
425 | /* make sure the pkg is verified */ | |||
426 | if (!verify(pkg)) { | |||
427 | warnx("Package %s will not be extracted", pkg); | |||
428 | goto bomb; | |||
429 | } | |||
430 | } else { /* local */ | |||
431 | if (!IS_STDIN(pkg)) { | |||
432 | /* not stdin */ | |||
433 | if (!ispkgpattern(pkg)) { | |||
434 | if (stat(pkg, &sb) == FAIL) { | |||
435 | warnx("can't stat package file '%s'", pkg); | |||
436 | goto bomb; | |||
437 | } | |||
438 | /* make sure the pkg is verified */ | |||
439 | if (!verify(pkg)) { | |||
440 | warnx("Package %s will not be extracted", pkg); | |||
441 | goto bomb; | |||
442 | } | |||
481 | } | 443 | } | |
482 | len -= ret; | 444 | LFILE_ADD(&files, lfp, CONTENTS_FNAME); | |
483 | } while (ret > 0); | 445 | } else { | |
484 | if (close(fd) == -1) { | 446 | /* some values for stdin */ | |
485 | warn("Can't close meta data file: %s", filename); | 447 | sb.st_size = 100000; /* Make up a plausible average size */ | |
486 | free(filename); | |||
487 | return -1; | |||
488 | } | 448 | } | |
489 | free(filename); | 449 | Home = make_playpen(playpen, sizeof(playpen), sb.st_size * 4); | |
490 | } | 450 | if (!Home) | |
491 | 451 | warnx("unable to make playpen for %ld bytes", | ||
492 | return 0; | 452 | (long) (sb.st_size * 4)); | |
493 | } | 453 | result = unpack(pkg, &files); | |
494 | 454 | while ((lfp = TAILQ_FIRST(&files)) != NULL) { | ||
495 | /* | 455 | TAILQ_REMOVE(&files, lfp, lf_link); | |
496 | * Helper function for extract_files. | 456 | free(lfp); | |
497 | */ | 457 | } | |
498 | static int | 458 | if (result) { | |
499 | copy_data_to_disk(struct archive *reader, struct archive *writer, | 459 | warnx("unable to extract table of contents file from `%s' - not a package?", | |
500 | const char *filename) | 460 | pkg); | |
501 | { | 461 | goto bomb; | |
502 | int r; | |||
503 | const void *buff; | |||
504 | size_t size; | |||
505 | off_t offset; | |||
506 | ||||
507 | for (;;) { | |||
508 | r = archive_read_data_block(reader, &buff, &size, &offset); | |||
509 | if (r == ARCHIVE_EOF) | |||
510 | return 0; | |||
511 | if (r != ARCHIVE_OK) { | |||
512 | warnx("Read error for %s: %s", filename, | |||
513 | archive_error_string(reader)); | |||
514 | return -1; | |||
515 | } | |||
516 | r = archive_write_data_block(writer, buff, size, offset); | |||
517 | if (r != ARCHIVE_OK) { | |||
518 | warnx("Write error for %s: %s", filename, | |||
519 | archive_error_string(writer)); | |||
520 | return -1; | |||
521 | } | 462 | } | |
522 | } | 463 | } | |
523 | } | |||
524 | ||||
525 | /* | |||
526 | * Extract package. | |||
527 | * Any misordered, missing or unlisted file in the package is an error. | |||
528 | */ | |||
529 | ||||
530 | static const int extract_flags = /* ARCHIVE_EXTRACT_OWNER | */ | |||
531 | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | | |||
532 | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR; | |||
533 | ||||
534 | static int | |||
535 | extract_files(struct pkg_task *pkg) | |||
536 | { | |||
537 | char cmd[MaxPathSize]; | |||
538 | const char *owner, *group, *permissions; | |||
539 | struct archive *writer; | |||
540 | int r; | |||
541 | plist_t *p; | |||
542 | const char *last_file; | |||
543 | char *fullpath; | |||
544 | 464 | |||
545 | if (Fake) | 465 | cfile = fopen(CONTENTS_FNAME, "r"); | |
546 | return 0; | 466 | if (!cfile) { | |
547 | 467 | warnx("unable to open table of contents file `%s' - not a package?", | ||
548 | if (mkdir_p(pkg->install_prefix)) { | 468 | CONTENTS_FNAME); | |
549 | warn("Can't create prefix: %s", pkg->install_prefix); | 469 | goto bomb; | |
550 | return -1; | |||
551 | } | |||
552 | ||||
553 | if (chdir(pkg->install_prefix) == -1) { | |||
554 | warn("Can't change into prefix: %s", pkg->install_prefix); | |||
555 | return -1; | |||
556 | } | 470 | } | |
471 | read_plist(&Plist, cfile); | |||
472 | fclose(cfile); | |||
557 | 473 | |||
558 | if (!NoRecord && !pkgdb_open(ReadWrite)) { | 474 | if (!IS_URL(pkg)) { | |
559 | warn("Can't open pkgdb for writing"); | 475 | /* | |
560 | return -1; | 476 | * Apply a crude heuristic to see how much space the package will | |
561 | } | 477 | * take up once it's unpacked. I've noticed that most packages | |
562 | 478 | * compress an average of 75%, so multiply by 4 for good measure. | ||
563 | writer = archive_write_disk_new(); | 479 | */ | |
564 | archive_write_disk_set_options(writer, extract_flags); | |||
565 | archive_write_disk_set_standard_lookup(writer); | |||
566 | ||||
567 | owner = NULL; | |||
568 | group = NULL; | |||
569 | permissions = NULL; | |||
570 | last_file = NULL; | |||
571 | ||||
572 | r = -1; | |||
573 | ||||
574 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |||
575 | switch (p->type) { | |||
576 | case PLIST_FILE: | |||
577 | last_file = p->name; | |||
578 | if (pkg->entry == NULL) { | |||
579 | warnx("PLIST entry not in package (%s)", | |||
580 | archive_entry_pathname(pkg->entry)); | |||
581 | goto out; | |||
582 | } | |||
583 | if (strcmp(p->name, archive_entry_pathname(pkg->entry))) { | |||
584 | warnx("PLIST entry and package don't match (%s vs %s)", | |||
585 | p->name, archive_entry_pathname(pkg->entry)); | |||
586 | goto out; | |||
587 | } | |||
588 | if (asprintf(&fullpath, "%s/%s", pkg->install_prefix, p->name) == -1) { | |||
589 | warnx("asprintf failed"); | |||
590 | goto out; | |||
591 | } | |||
592 | pkgdb_store(fullpath, pkg->pkgname); | |||
593 | free(fullpath); | |||
594 | if (Verbose) | |||
595 | printf("%s", p->name); | |||
596 | break; | |||
597 | ||||
598 | case PLIST_CMD: | |||
599 | if (format_cmd(cmd, sizeof(cmd), p->name, pkg->install_prefix, last_file)) | |||
600 | return -1; | |||
601 | printf("Executing '%s'\n", cmd); | |||
602 | if (!Fake && system(cmd)) | |||
603 | warnx("command '%s' failed", cmd); /* XXX bail out? */ | |||
604 | continue; | |||
605 | ||||
606 | case PLIST_CHMOD: | |||
607 | permissions = p->name; | |||
608 | continue; | |||
609 | ||||
610 | case PLIST_CHOWN: | |||
611 | owner = p->name; | |||
612 | continue; | |||
613 | ||||
614 | case PLIST_CHGRP: | |||
615 | group = p->name; | |||
616 | continue; | |||
617 | ||||
618 | case PLIST_IGNORE: | |||
619 | p = p->next; | |||
620 | continue; | |||
621 | 480 | |||
622 | default: | 481 | needed = 4 * (uint64_t) sb.st_size; | |
623 | continue; | 482 | if (min_free(playpen) < needed) { | |
483 | warnx("projected size of %" MY_PRIu64 " bytes exceeds available free space\n" | |||
484 | "in %s. Please set your PKG_TMPDIR variable to point\n" | |||
485 | "to a location with more free space and try again.", | |||
486 | needed, playpen); | |||
487 | goto bomb; | |||
624 | } | 488 | } | |
625 | 489 | |||
626 | r = archive_write_header(writer, pkg->entry); | 490 | /* Finally unpack the whole mess */ | |
627 | if (r != ARCHIVE_OK) { | 491 | if (unpack(pkg, NULL)) { | |
628 | warnx("Failed to write %s: %s", | 492 | warnx("unable to extract `%s'!", pkg); | |
629 | archive_entry_pathname(pkg->entry), | 493 | goto bomb; | |
630 | archive_error_string(writer)); | |||
631 | goto out; | |||
632 | } | |||
633 | ||||
634 | if (owner != NULL) | |||
635 | archive_entry_set_uname(pkg->entry, owner); | |||
636 | if (group != NULL) | |||
637 | archive_entry_set_uname(pkg->entry, group); | |||
638 | if (permissions != NULL) { | |||
639 | mode_t mode; | |||
640 | ||||
641 | mode = archive_entry_mode(pkg->entry); | |||
642 | mode = getmode(setmode(permissions), mode); | |||
643 | archive_entry_set_mode(pkg->entry, mode); | |||
644 | } | |||
645 | ||||
646 | r = copy_data_to_disk(pkg->archive, writer, | |||
647 | archive_entry_pathname(pkg->entry)); | |||
648 | if (r) | |||
649 | goto out; | |||
650 | if (Verbose) | |||
651 | printf("\n"); | |||
652 | ||||
653 | r = archive_read_next_header(pkg->archive, &pkg->entry); | |||
654 | if (r == ARCHIVE_EOF) { | |||
655 | pkg->entry = NULL; | |||
656 | continue; | |||
657 | } | |||
658 | if (r != ARCHIVE_OK) { | |||
659 | warnx("Failed to read from archive: %s", | |||
660 | archive_error_string(pkg->archive)); | |||
661 | goto out; | |||
662 | } | 494 | } | |
663 | } | 495 | } | |
664 | 496 | |||
665 | if (pkg->entry != NULL) { | 497 | /* Check for sanity */ | |
666 | warnx("Package contains entries not in PLIST: %s", | 498 | if (sanity_check(pkg)) | |
667 | archive_entry_pathname(pkg->entry)); | 499 | goto bomb; | |
668 | goto out; | |||
669 | } | |||
670 | ||||
671 | r = 0; | |||
672 | ||||
673 | out: | |||
674 | if (!NoRecord) | |||
675 | pkgdb_close(); | |||
676 | archive_write_close(writer); | |||
677 | archive_write_finish(writer); | |||
678 | 500 | |||
679 | return r; | 501 | /* Read the OS, version and architecture from BUILD_INFO file */ | |
680 | } | 502 | if (!read_buildinfo(buildinfo)) { | |
681 | 503 | warn("can't read build information from %s", BUILD_INFO_FNAME); | ||
682 | /* | 504 | if (!Force) { | |
683 | * Register dependencies after sucessfully installing the package. | 505 | warnx("aborting."); | |
684 | */ | 506 | goto bomb; | |
685 | static void | 507 | } | |
686 | pkg_register_depends(struct pkg_task *pkg) | |||
687 | { | |||
688 | int fd; | |||
689 | size_t text_len, i; | |||
690 | char *required_by, *text; | |||
691 | ||||
692 | if (Fake) | |||
693 | return; | |||
694 | ||||
695 | if (pkg->other_version != NULL) | |||
696 | return; /* XXX It's using the old dependencies. */ | |||
697 | ||||
698 | if (asprintf(&text, "%s\n", pkg->pkgname) == -1) | |||
699 | err(2, "asprintf failed"); | |||
700 | text_len = strlen(text); | |||
701 | ||||
702 | for (i = 0; i < pkg->dep_length; ++i) { | |||
703 | required_by = pkgdb_pkg_file(pkg->dependencies[i], REQUIRED_BY_FNAME); | |||
704 | ||||
705 | fd = open(required_by, O_WRONLY | O_APPEND | O_CREAT, 644); | |||
706 | if (fd == -1) | |||
707 | warn("can't open dependency file '%s'," | |||
708 | "registration is incomplete!", required_by); | |||
709 | else if (write(fd, text, text_len) != text_len) | |||
710 | warn("can't write to dependency file `%s'", required_by); | |||
711 | else if (close(fd) == -1) | |||
712 | warn("cannot close file %s", required_by); | |||
713 | ||||
714 | free(required_by); | |||
715 | } | 508 | } | |
716 | 509 | |||
717 | free(text); | 510 | if (uname(&host_uname) < 0) { | |
718 | } | 511 | warnx("uname() failed."); | |
719 | 512 | if (!Force) { | ||
720 | /* | 513 | warnx("aborting."); | |
721 | * Reduce the result from uname(3) to a canonical form. | 514 | goto bomb; | |
722 | */ | 515 | } | |
723 | static void | 516 | } else { | |
724 | normalise_platform(struct utsname *host_name) | 517 | int status = Good; | |
725 | { | |||
726 | #ifdef NUMERIC_VERSION_ONLY | |||
727 | size_t span; | |||
728 | 518 | |||
729 | span = strspn(host_name->release, "0123456789."); | 519 | normalise_platform(&host_uname); | |
730 | host_name->release[span] = '\0'; | |||
731 | #endif | |||
732 | } | |||
733 | 520 | |||
734 | /* | 521 | /* check that we have read some values from buildinfo */ | |
735 | * Check build platform of the package against local host. | 522 | if (buildinfo[BI_OPSYS] == NULL) { | |
736 | */ | 523 | warnx("Missing operating system value from build information"); | |
737 | static int | 524 | status = Missing; | |
738 | check_platform(struct pkg_task *pkg) | 525 | } | |
739 | { | 526 | if (buildinfo[BI_MACHINE_ARCH] == NULL) { | |
740 | struct utsname host_uname; | 527 | warnx("Missing machine architecture value from build information"); | |
741 | const char *effective_arch; | 528 | status = Missing; | |
742 | int fatal; | 529 | } | |
530 | if (buildinfo[BI_OS_VERSION] == NULL) { | |||
531 | warnx("Missing operating system version value from build information"); | |||
532 | status = Missing; | |||
533 | } | |||
534 | ||||
535 | if (status == Good) { | |||
536 | const char *effective_arch; | |||
537 | ||||
538 | if (OverrideMachine != NULL) | |||
539 | effective_arch = OverrideMachine; | |||
540 | else | |||
541 | effective_arch = MACHINE_ARCH; | |||
542 | ||||
543 | /* If either the OS or arch are different, bomb */ | |||
544 | if (strcmp(OPSYS_NAME, buildinfo[BI_OPSYS]) != 0) | |||
545 | status = Fatal; | |||
546 | if (strcmp(effective_arch, buildinfo[BI_MACHINE_ARCH]) != 0) | |||
547 | status = Fatal; | |||
548 | ||||
549 | /* If OS and arch are the same, warn if version differs */ | |||
550 | if (status == Good && | |||
551 | strcmp(host_uname.release, buildinfo[BI_OS_VERSION]) != 0) | |||
552 | status = Warning; | |||
553 | ||||
554 | if (status != Good) { | |||
555 | warnx("Warning: package `%s' was built for a different version of the OS:", pkg); | |||
556 | warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)", | |||
557 | buildinfo[BI_OPSYS], | |||
558 | buildinfo[BI_MACHINE_ARCH], | |||
559 | buildinfo[BI_OS_VERSION], | |||
560 | OPSYS_NAME, | |||
561 | effective_arch, | |||
562 | host_uname.release); | |||
563 | } | |||
564 | } | |||
743 | 565 | |||
744 | if (uname(&host_uname) < 0) { | 566 | if (!Force && status == Fatal) { | |
745 | if (Force) { | 567 | warnx("aborting."); | |
746 | warnx("uname() failed, continuing."); | 568 | goto bomb; | |
747 | return 0; | |||
748 | } else { | |||
749 | warnx("uname() failed, aborting."); | |||
750 | return -1; | |||
751 | } | 569 | } | |
752 | } | 570 | } | |
753 | 571 | |||
754 | normalise_platform(&host_uname); | 572 | /* Check if USE_ABI_DEPENDS or IGNORE_RECOMMENDED was set | |
755 | 573 | * when this package was built. IGNORE_RECOMMENDED is historical. */ | ||
756 | if (OverrideMachine != NULL) | 574 | ||
757 | effective_arch = OverrideMachine; | 575 | if ((buildinfo[BI_USE_ABI_DEPENDS] != NULL && | |
758 | else | 576 | strcasecmp(buildinfo[BI_USE_ABI_DEPENDS], "YES") != 0) || | |
759 | effective_arch = MACHINE_ARCH; | 577 | (buildinfo[BI_IGNORE_RECOMMENDED] != NULL && | |
760 | 578 | strcasecmp(buildinfo[BI_IGNORE_RECOMMENDED], "NO") != 0)) { | ||
761 | /* If either the OS or arch are different, bomb */ | 579 | warnx("%s was built", pkg); | |
762 | if (strcmp(OPSYS_NAME, pkg->buildinfo[BI_OPSYS]) || | 580 | warnx("\tto ignore recommended ABI dependencies, this may cause problems!\n"); | |
763 | strcmp(effective_arch, pkg->buildinfo[BI_MACHINE_ARCH]) != 0) | 581 | } | |
764 | fatal = 1; | 582 | ||
765 | else | 583 | /* | |
766 | fatal = 0; | 584 | * If we have a prefix, delete the first one we see and add this | |
767 | 585 | * one in place of it. | ||
768 | if (fatal || | 586 | */ | |
769 | strcmp(host_uname.release, pkg->buildinfo[BI_OS_VERSION]) != 0) { | 587 | if (Prefix) { | |
770 | warnx("Warning: package `%s' was built for a platform:", | 588 | delete_plist(&Plist, FALSE, PLIST_CWD, NULL); | |
771 | pkg->pkgname); | 589 | add_plist_top(&Plist, PLIST_CWD, Prefix); | |
772 | warnx("%s/%s %s (pkg) vs. %s/%s %s (this host)", | 590 | } | |
773 | pkg->buildinfo[BI_OPSYS], | 591 | ||
774 | pkg->buildinfo[BI_MACHINE_ARCH], | 592 | /* Protect against old packages with bogus @name fields */ | |
775 | pkg->buildinfo[BI_OS_VERSION], | 593 | p = find_plist(&Plist, PLIST_NAME); | |
776 | OPSYS_NAME, | 594 | if (p->name == NULL) { | |
777 | effective_arch, | 595 | warnx("PLIST contains no @name field"); | |
778 | host_uname.release); | 596 | goto bomb; | |
779 | if (!Force && fatal) | 597 | } | |
780 | return -1; | 598 | PkgName = p->name; | |
599 | ||||
600 | if (fexists(VIEWS_FNAME)) | |||
601 | is_depoted_pkg = TRUE; | |||
602 | ||||
603 | /* | |||
604 | * Depoted packages' dbdir is the same as DEPOTBASE. Non-depoted | |||
605 | * packages' dbdir comes from the command-line or the environment. | |||
606 | */ | |||
607 | if (is_depoted_pkg) { | |||
608 | p = find_plist(&Plist, PLIST_CWD); | |||
609 | if (p == NULL) { | |||
610 | warn("no @cwd in +CONTENTS file?! aborting."); | |||
611 | goto bomb; | |||
612 | } | |||
613 | (void) strlcpy(dbdir, dirname_of(p->name), sizeof(dbdir)); | |||
614 | (void) strlcpy(LogDir, p->name, sizeof(LogDir)); | |||
615 | } else { | |||
616 | (void) strlcpy(dbdir, _pkgdb_getPKGDB_DIR(), sizeof(dbdir)); | |||
617 | (void) snprintf(LogDir, sizeof(LogDir), "%s/%s", dbdir, PkgName); | |||
781 | } | 618 | } | |
782 | return 0; | |||
783 | } | |||
784 | 619 | |||
785 | /* | 620 | /* Set environment variables expected by the +INSTALL script. */ | |
786 | * Run the install script. | 621 | setenv(PKG_PREFIX_VNAME, (p = find_plist(&Plist, PLIST_CWD)) ? p->name : ".", 1); | |
787 | */ | 622 | setenv(PKG_METADATA_DIR_VNAME, LogDir, 1); | |
788 | static int | |||
789 | run_install_script(struct pkg_task *pkg, const char *argument) | |||
790 | { | |||
791 | int ret; | |||
792 | char *filename; | |||
793 | ||||
794 | if (pkg->meta_data.meta_install == NULL || NoInstall) | |||
795 | return 0; | |||
796 | ||||
797 | setenv(PKG_PREFIX_VNAME, pkg->install_prefix, 1); /* XXX or prefix? */ | |||
798 | setenv(PKG_METADATA_DIR_VNAME, pkg->logdir, 1); | |||
799 | setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1); | 623 | setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1); | |
800 | 624 | |||
801 | filename = pkgdb_pkg_file(pkg->pkgname, INSTALL_FNAME); | 625 | /* make sure dbdir actually exists! */ | |
802 | if (Verbose) | 626 | if (!(isdir(dbdir) || islinktodir(dbdir))) { | |
803 | printf("Running install with PRE-INSTALL for %s.\n", pkg->pkgname); | 627 | if (fexec("mkdir", "-p", dbdir, NULL)) { | |
804 | if (Fake) { | 628 | errx(EXIT_FAILURE, | |
805 | free(filename); | 629 | "Database-dir %s cannot be generated, aborting.", | |
806 | return 0; | 630 | dbdir); | |
631 | } | |||
807 | } | 632 | } | |
808 | 633 | |||
809 | ret = 0; | 634 | /* See if this package (exact version) is already registered */ | |
810 | 635 | if (isdir(LogDir) && !Force) { | ||
811 | if (chdir(pkg->logdir) == -1) { | 636 | if (!Automatic && is_automatic_installed(PkgName)) { | |
812 | warn("Can't change to %s", pkg->logdir); | 637 | if (mark_as_automatic_installed(PkgName, 0) == 0) | |
813 | ret = -1; | 638 | warnx("package `%s' was already installed as " | |
639 | "dependency, now marked as installed " | |||
640 | "manually", PkgName); | |||
641 | } else { | |||
642 | warnx("package `%s' already recorded as installed", | |||
643 | PkgName); | |||
644 | } | |||
645 | goto success; /* close enough for government work */ | |||
814 | } | 646 | } | |
815 | 647 | |||
816 | errno = 0; | 648 | /* See if some other version of us is already installed */ | |
817 | if (ret == 0 && fexec(filename, pkg->pkgname, argument, (void *)NULL)) { | 649 | switch (pkg_do_installed(&replacing, replace_via, replace_to, is_depoted_pkg, dbdir)) { | |
818 | if (errno != 0) | 650 | case 0: | |
819 | warn("exec of install script failed"); | 651 | break; | |
820 | else | 652 | case 1: | |
821 | warnx("install script returned error status"); | 653 | errc = 1; | |
822 | ret = -1; | 654 | goto success; | |
655 | case -1: | |||
656 | goto bomb; | |||
823 | } | 657 | } | |
824 | 658 | |||
825 | free(filename); | 659 | /* See if there are conflicting packages installed */ | |
826 | return ret; | 660 | for (p = Plist.head; p; p = p->next) { | |
827 | } | 661 | char *best_installed; | |
828 | 662 | |||
829 | static int | 663 | if (p->type != PLIST_PKGCFL) | |
830 | check_explicit_conflict(struct pkg_task *pkg) | |||
831 | { | |||
832 | char *installed, *installed_pattern; | |||
833 | plist_t *p; | |||
834 | int status; | |||
835 | ||||
836 | status = 0; | |||
837 | ||||
838 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |||
839 | if (p->type == PLIST_IGNORE) { | |||
840 | p = p->next; | |||
841 | continue; | |||
842 | } else if (p->type != PLIST_PKGCFL) | |||
843 | continue; | 664 | continue; | |
844 | installed = find_best_matching_installed_pkg(p->name); | 665 | if (Verbose) | |
845 | if (installed) { | 666 | printf("Package `%s' conflicts with `%s'.\n", PkgName, p->name); | |
667 | best_installed = find_best_matching_installed_pkg(p->name); | |||
668 | if (best_installed) { | |||
846 | warnx("Package `%s' conflicts with `%s', and `%s' is installed.", | 669 | warnx("Package `%s' conflicts with `%s', and `%s' is installed.", | |
847 | pkg->pkgname, p->name, installed); | 670 | PkgName, p->name, best_installed); | |
848 | free(installed); | 671 | free(best_installed); | |
849 | status = -1; | 672 | ++errc; | |
850 | } | 673 | } | |
851 | } | 674 | } | |
852 | 675 | |||
853 | if (some_installed_package_conflicts_with(pkg->pkgname, | 676 | /* See if any of the installed packages conflicts with this one. */ | |
854 | pkg->other_version, &installed, &installed_pattern)) { | 677 | { | |
855 | warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.", | 678 | char *inst_pkgname, *inst_pattern; | |
856 | installed, installed_pattern, pkg->pkgname); | |||
857 | free(installed); | |||
858 | free(installed_pattern); | |||
859 | status = -1; | |||
860 | } | |||
861 | ||||
862 | return status; | |||
863 | } | |||
864 | ||||
865 | static int | |||
866 | check_implicit_conflict(struct pkg_task *pkg) | |||
867 | { | |||
868 | plist_t *p; | |||
869 | char *fullpath, *existing; | |||
870 | int status; | |||
871 | 679 | |||
872 | if (!pkgdb_open(ReadOnly)) { | 680 | if (some_installed_package_conflicts_with(PkgName, &inst_pkgname, &inst_pattern)) { | |
873 | #if notyet /* XXX empty pkgdb without database? */ | 681 | warnx("Installed package `%s' conflicts with `%s' when trying to install `%s'.", | |
874 | warn("Can't open pkgdb for reading"); | 682 | inst_pkgname, inst_pattern, PkgName); | |
875 | return -1; | 683 | free(inst_pkgname); | |
876 | #else | 684 | free(inst_pattern); | |
877 | return 0; | 685 | errc++; | |
878 | #endif | 686 | } | |
879 | } | 687 | } | |
880 | 688 | |||
881 | status = 0; | 689 | /* Quick pre-check if any conflicting dependencies are installed | |
882 | 690 | * (e.g. version X is installed, but version Y is required) | ||
883 | for (p = pkg->plist.head; p != NULL; p = p->next) { | 691 | */ | |
884 | if (p->type == PLIST_IGNORE) { | 692 | err_prescan=0; | |
885 | p = p->next; | 693 | for (p = Plist.head; p; p = p->next) { | |
886 | continue; | 694 | char *best_installed; | |
887 | } else if (p->type != PLIST_FILE) | 695 | ||
888 | continue; | 696 | if (p->type != PLIST_PKGDEP) | |
889 | ||||
890 | if (asprintf(&fullpath, "%s/%s", pkg->install_prefix, p->name) == -1) { | |||
891 | warnx("asprintf failed"); | |||
892 | status = -1; | |||
893 | break; | |||
894 | } | |||
895 | existing = pkgdb_retrieve(fullpath); | |||
896 | free(fullpath); | |||
897 | if (existing == NULL) | |||
898 | continue; | |||
899 | if (pkg->other_version != NULL && | |||
900 | strcmp(pkg->other_version, existing) == 0) | |||
901 | continue; | 697 | continue; | |
698 | if (Verbose) | |||
699 | printf("Depends pre-scan: `%s' required.\n", p->name); | |||
700 | best_installed = find_best_matching_installed_pkg(p->name); | |||
701 | if (best_installed == NULL) { | |||
702 | /* | |||
703 | * required pkg not found. look if it's available with a more liberal | |||
704 | * pattern. If so, this will lead to problems later (check on "some | |||
705 | * other version of us is already installed" will fail, see above), | |||
706 | * and we better stop right now. | |||
707 | */ | |||
708 | char *s; | |||
709 | int skip = -1; | |||
902 | 710 | |||
903 | warnx("Conflicting PLIST with %s: %s", existing, p->name); | 711 | /* doing this right required to parse the full version(s), | |
904 | if (!Force) { | 712 | * do a 99% solution here for now */ | |
905 | status = -1; | 713 | if (strchr(p->name, '{')) | |
906 | if (!Verbose) | 714 | continue; /* would remove trailing '}' else */ | |
907 | break; | 715 | ||
716 | if ((s = strpbrk(p->name, "<>")) != NULL) { | |||
717 | skip = 0; | |||
718 | } else if (((s = strstr(p->name, "-[0-9]*")) != NULL) && | |||
719 | (*(s + sizeof("-[0-9]*") - 1) == '\0')) { | |||
720 | /* -[0-9]* already present so no need to */ | |||
721 | /* add it a second time */ | |||
722 | skip = -1; | |||
723 | } else if ((s = strrchr(p->name, '-')) != NULL) { | |||
724 | skip = 1; | |||
725 | } | |||
726 | ||||
727 | if (skip >= 0) { | |||
728 | char buf[MaxPathSize]; | |||
729 | ||||
730 | (void) snprintf(buf, sizeof(buf), | |||
731 | skip ? "%.*s[0-9]*" : "%.*s-[0-9]*", | |||
732 | (int)(s - p->name) + skip, p->name); | |||
733 | best_installed = find_best_matching_installed_pkg(buf); | |||
734 | if (best_installed) { | |||
735 | int done = 0; | |||
736 | ||||
737 | if (Replace > 1) | |||
738 | { | |||
739 | int errc0 = 0; | |||
740 | char tmp[MaxPathSize]; | |||
741 | ||||
742 | warnx("Attempting to update `%s' using binary package\n", p->name); | |||
743 | /* Yes, append .tgz after the version so the */ | |||
744 | /* pattern can match a filename. */ | |||
745 | snprintf(tmp, sizeof(tmp), "%s.tgz", p->name); | |||
746 | done = installprereq(tmp, &errc0, 2); | |||
747 | } | |||
748 | else if (Replace) | |||
749 | { | |||
750 | warnx("To perform necessary upgrades on required packages specify -u twice.\n"); | |||
751 | } | |||
752 | ||||
753 | if (!done) | |||
754 | { | |||
755 | warnx("pkg `%s' required, but `%s' found installed.", | |||
756 | p->name, best_installed); | |||
757 | if (Force) { | |||
758 | warnx("Proceeding anyway."); | |||
759 | } else { | |||
760 | err_prescan++; | |||
761 | } | |||
762 | } | |||
763 | free(best_installed); | |||
764 | } | |||
765 | } | |||
766 | } else { | |||
767 | free(best_installed); | |||
908 | } | 768 | } | |
909 | } | 769 | } | |
770 | if (err_prescan > 0) { | |||
771 | warnx("Please resolve this conflict!"); | |||
772 | errc += err_prescan; | |||
773 | goto success; /* close enough */ | |||
774 | } | |||
775 | ||||
776 | ||||
777 | /* Now check the packing list for dependencies */ | |||
778 | for (p = Plist.head; p; p = p->next) { | |||
779 | char *best_installed; | |||
910 | 780 | |||
911 | pkgdb_close(); | 781 | if (p->type != PLIST_PKGDEP) | |
912 | return status; | |||
913 | } | |||
914 | ||||
915 | static int | |||
916 | check_dependencies(struct pkg_task *pkg) | |||
917 | { | |||
918 | plist_t *p; | |||
919 | char *best_installed; | |||
920 | int status; | |||
921 | size_t i; | |||
922 | ||||
923 | status = 0; | |||
924 | ||||
925 | for (p = pkg->plist.head; p != NULL; p = p->next) { | |||
926 | if (p->type == PLIST_IGNORE) { | |||
927 | p = p->next; | |||
928 | continue; | |||
929 | } else if (p->type != PLIST_PKGDEP) | |||
930 | continue; | 782 | continue; | |
783 | if (Verbose) | |||
784 | printf("Package `%s' depends on `%s'.\n", PkgName, p->name); | |||
931 | 785 | |||
932 | best_installed = find_best_matching_installed_pkg(p->name); | 786 | best_installed = find_best_matching_installed_pkg(p->name); | |
933 | 787 | |||
934 | if (best_installed == NULL) { | 788 | if (best_installed == NULL) { | |
935 | /* XXX check cyclic dependencies? */ | 789 | /* required pkg not found - need to pull in */ | |
936 | if (Fake || NoRecord) { | 790 | ||
937 | if (!Force) { | 791 | if (Fake) { | |
938 | warnx("Missing dependency %s\n", | 792 | /* fake install (???) */ | |
939 | p->name); | 793 | if (Verbose) | |
940 | status = -1; | 794 | printf("Package dependency %s for %s not installed%s\n", p->name, pkg, | |
941 | break; | 795 | Force ? " (proceeding anyway)" : "!"); | |
796 | } else { | |||
797 | int done = 0; | |||
798 | int errc0 = 0; | |||
799 | ||||
800 | done = installprereq(p->name, &errc0, (Replace > 1) ? 2 : 0); | |||
801 | if (!done && !Force) { | |||
802 | errc += errc0; | |||
942 | } | 803 | } | |
943 | warnx("Missing dependency %s, continuing", | |||
944 | p->name); | |||
945 | continue; | |||
946 | } | |||
947 | if (pkg_do(p->name, 1)) { | |||
948 | warnx("Can't install dependency %s", p->name); | |||
949 | status = -1; | |||
950 | break; | |||
951 | } | 804 | } | |
952 | best_installed = find_best_matching_installed_pkg(p->name); | 805 | } else { | |
953 | if (best_installed == NULL && Force) { | 806 | if (Verbose) | |
954 | warnx("Missing dependency %s ignored", p->name); | 807 | printf(" - %s already installed.\n", best_installed); | |
955 | continue; | |||
956 | } else if (best_installed == NULL) { | |||
957 | warnx("Just installed dependency %s disappeared", p->name); | |||
958 | status = -1; | |||
959 | break; | |||
960 | } | |||
961 | } | |||
962 | for (i = 0; i < pkg->dep_length; ++i) { | |||
963 | if (strcmp(best_installed, pkg->dependencies[i]) == 0) | |||
964 | break; | |||
965 | } | |||
966 | if (i < pkg->dep_length) { | |||
967 | /* Already used as dependency, so skip it. */ | |||
968 | free(best_installed); | 808 | free(best_installed); | |
969 | continue; | |||
970 | } | 809 | } | |
971 | if (pkg->dep_length + 1 >= pkg->dep_allocated) { | |||
972 | char **tmp; | |||
973 | pkg->dep_allocated = 2 * pkg->dep_allocated + 1; | |||
974 | tmp = realloc(pkg->dependencies, | |||
975 | pkg->dep_allocated * sizeof(*tmp)); | |||
976 | if (tmp == NULL) { | |||
977 | warnx("realloc failed"); | |||
978 | free(pkg->dependencies); | |||
979 | pkg->dependencies = NULL; | |||
980 | pkg->dep_length = pkg->dep_allocated = 0; | |||
981 | free(best_installed); | |||
982 | return -1; | |||
983 | } | |||
984 | pkg->dependencies = tmp; | |||
985 | } | |||
986 | pkg->dependencies[pkg->dep_length++] = best_installed; | |||
987 | } | 810 | } | |
988 | 811 | |||
989 | return status; | 812 | if (errc != 0) | |
990 | } | 813 | goto bomb; | |
991 | 814 | |||
992 | /* | 815 | /* If we're really installing, and have an installation file, run it */ | |
993 | * If this package uses pkg_views, register it in the default view. | 816 | if (!NoInstall && fexists(INSTALL_FNAME)) { | |
994 | */ | 817 | (void) fexec(CHMOD_CMD, "+x", INSTALL_FNAME, NULL); /* make sure */ | |
995 | static void | 818 | if (Verbose) | |
996 | pkg_register_views(struct pkg_task *pkg) | 819 | printf("Running install with PRE-INSTALL for %s.\n", PkgName); | |
997 | { | 820 | errno = 0; | |
998 | if (Fake || NoView || pkg->meta_data.meta_views == NULL) | 821 | if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "PRE-INSTALL", NULL)) { | |
999 | return; | 822 | if (errno != 0) | |
1000 | 823 | warn("exec of install script failed"); | ||
1001 | if (Verbose) { | 824 | else | |
1002 | printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n", | 825 | warnx("install script returned error status"); | |
1003 | BINDIR, _pkgdb_getPKGDB_DIR(), | 826 | errc = 1; | |
1004 | View ? "-w " : "", View ? View : "", | 827 | goto success; /* nothing to uninstall yet */ | |
1005 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | 828 | } | |
1006 | Verbose ? "-v " : "", pkg->pkgname); | |||
1007 | } | 829 | } | |
1008 | 830 | |||
1009 | fexec_skipempty(BINDIR "/pkg_view", "-d", _pkgdb_getPKGDB_DIR(), | 831 | /* | |
1010 | View ? "-w " : "", View ? View : "", | 832 | * Now finally extract the entire show if we're not going direct. | |
1011 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | 833 | * We need to reset the package dbdir so that extract_plist() | |
1012 | Verbose ? "-v " : "", "add", pkg->pkgname, | 834 | * updates the correct pkgdb.byfile.db database. | |
1013 | (void *)NULL); | 835 | */ | |
1014 | } | |||
1015 | ||||
1016 | static int | |||
1017 | start_replacing(struct pkg_task *pkg) | |||
1018 | { | |||
1019 | char *old_required_by, *new_required_by; | |||
1020 | ||||
1021 | old_required_by = pkgdb_pkg_file(pkg->other_version, | |||
1022 | REQUIRED_BY_FNAME); | |||
1023 | new_required_by = pkgdb_pkg_file(pkg->pkgname, | |||
1024 | REQUIRED_BY_FNAME); | |||
1025 | ||||
1026 | if (!Fake) { | 836 | if (!Fake) { | |
1027 | if (rename(old_required_by, new_required_by) == -1 && | 837 | _pkgdb_setPKGDB_DIR(dbdir); | |
1028 | errno != ENOENT) { | 838 | if (!extract_plist(".", &Plist)) { | |
1029 | warn("Can't move +REQUIRED_BY from %s to %s", | 839 | errc = 1; | |
1030 | old_required_by, new_required_by); | 840 | goto fail; | |
1031 | return -1; | |||
1032 | } | 841 | } | |
1033 | } | 842 | } | |
1034 | 843 | |||
1035 | if (Verbose || Fake) { | 844 | if (!Fake && fexists(MTREE_FNAME)) { | |
1036 | printf("%s/pkg_delete -K %s -p %s '%s'\n", | 845 | warnx("Mtree file ignored for package %s", PkgName); | |
1037 | BINDIR, _pkgdb_getPKGDB_DIR(), pkg->install_prefix, | |||
1038 | pkg->other_version); | |||
1039 | } | 846 | } | |
1040 | if (!Fake) | |||
1041 | fexec(BINDIR "/pkg_delete", "-K", _pkgdb_getPKGDB_DIR(), | |||
1042 | "-p", pkg->install_prefix, | |||
1043 | pkg->other_version, NULL); | |||
1044 | ||||
1045 | /* XXX Check return value and do what? */ | |||
1046 | return 0; | |||
1047 | } | |||
1048 | 847 | |||
1049 | /* | 848 | /* Run the installation script one last time? */ | |
1050 | * Install a single package. | 849 | if (!NoInstall && fexists(INSTALL_FNAME)) { | |
1051 | */ | 850 | if (Verbose) | |
1052 | static int | 851 | printf("Running install with POST-INSTALL for %s.\n", PkgName); | |
1053 | pkg_do(const char *pkgpath, int mark_automatic) | 852 | if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "POST-INSTALL", NULL)) { | |
1054 | { | 853 | warnx("install script returned error status"); | |
1055 | int status; | 854 | errc = 1; | |
1056 | void *archive_cookie; | 855 | goto fail; | |
1057 | struct pkg_task *pkg; | 856 | } | |
1058 | ||||
1059 | if ((pkg = calloc(1, sizeof(*pkg))) == NULL) | |||
1060 | err(2, "malloc failed"); | |||
1061 | ||||
1062 | status = -1; | |||
1063 | ||||
1064 | if ((pkg->archive = find_archive(pkgpath, &archive_cookie)) == NULL) { | |||
1065 | warnx("no pkg found for '%s', sorry.", pkgpath); | |||
1066 | goto clean_memory; | |||
1067 | } | 857 | } | |
1068 | if (read_meta_data(pkg)) | |||
1069 | goto clean_memory; | |||
1070 | 858 | |||
1071 | /* Parse PLIST early, so that messages can use real package name. */ | 859 | /* Time to record the deed? */ | |
1072 | if (pkg_parse_plist(pkg)) | 860 | if (!NoRecord && !Fake) { | |
1073 | goto clean_memory; | 861 | char contents[MaxPathSize]; | |
1074 | 862 | |||
1075 | if (pkg->meta_data.meta_mtree != NULL) | 863 | if (!PkgName) { | |
1076 | warnx("mtree specification in pkg `%s' ignored", pkg->pkgname); | 864 | warnx("no package name! can't record package, sorry"); | |
865 | errc = 1; | |||
866 | goto success; /* well, partial anyway */ | |||
867 | } | |||
868 | (void) snprintf(LogDir, sizeof(LogDir), "%s/%s", dbdir, PkgName); | |||
869 | zapLogDir = 1; /* LogDir contains something valid now */ | |||
870 | if (Verbose) | |||
871 | printf("Attempting to record package into %s.\n", LogDir); | |||
872 | if (make_hierarchy(LogDir)) { | |||
873 | warnx("can't record package into '%s', you're on your own!", | |||
874 | LogDir); | |||
875 | memset(LogDir, 0, sizeof(LogDir)); | |||
876 | errc = 1; | |||
877 | goto success; /* close enough for government work */ | |||
878 | } | |||
879 | /* Make sure pkg_info can read the entry */ | |||
880 | (void) fexec(CHMOD_CMD, "a+rx", LogDir, NULL); | |||
881 | ||||
882 | /* Move all of the +-files into place */ | |||
883 | move_files(".", "+*", LogDir); | |||
884 | ||||
885 | /* Generate the +CONTENTS file in-place from the Plist */ | |||
886 | (void) snprintf(contents, sizeof(contents), "%s/%s", LogDir, CONTENTS_FNAME); | |||
887 | cfile = fopen(contents, "w"); | |||
888 | if (!cfile) { | |||
889 | warnx("can't open new contents file '%s'! can't register pkg", | |||
890 | contents); | |||
891 | goto success; /* can't log, but still keep pkg */ | |||
892 | } | |||
893 | write_plist(&Plist, cfile, NULL); | |||
894 | fclose(cfile); | |||
895 | ||||
896 | /* register dependencies */ | |||
897 | /* we could save some cycles here if we remembered what we | |||
898 | * installed above (in case we got a wildcard dependency) */ | |||
899 | /* XXX remembering in p->name would NOT be good! */ | |||
900 | for (p = Plist.head; p; p = p->next) { | |||
901 | if (p->type != PLIST_PKGDEP) | |||
902 | continue; | |||
903 | if (Verbose) | |||
904 | printf("Attempting to record dependency on package `%s'\n", p->name); | |||
905 | (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir, | |||
906 | basename_of(p->name)); | |||
907 | if (ispkgpattern(p->name)) { | |||
908 | char *s; | |||
1077 | 909 | |||
1078 | if (pkg->meta_data.meta_views != NULL) { | 910 | s = find_best_matching_installed_pkg(p->name); | |
1079 | if ((pkg->logdir = strdup(pkg->install_prefix)) == NULL) | |||
1080 | err(EXIT_FAILURE, "strdup failed"); | |||
1081 | _pkgdb_setPKGDB_DIR(dirname_of(pkg->logdir)); | |||
1082 | } else { | |||
1083 | if (asprintf(&pkg->logdir, "%s/%s", _pkgdb_getPKGDB_DIR(), | |||
1084 | pkg->pkgname) == -1) | |||
1085 | err(EXIT_FAILURE, "asprintf failed"); | |||
1086 | } | |||
1087 | 911 | |||
1088 | if (NoRecord && !Fake) { | 912 | if (s == NULL) | |
1089 | const char *tmpdir; | 913 | errx(EXIT_FAILURE, "Where did our dependency go?!"); | |
1090 | 914 | |||
1091 | tmpdir = getenv("TMPDIR"); | 915 | (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir, s); | |
1092 | if (tmpdir == NULL) | 916 | free(s); | |
1093 | tmpdir = "/tmp"; | 917 | } | |
918 | strlcat(contents, "/", sizeof(contents)); | |||
919 | strlcat(contents, REQUIRED_BY_FNAME, sizeof(contents)); | |||
1094 | 920 | |||
1095 | free(pkg->logdir); | 921 | cfile = fopen(contents, "a"); | |
1096 | if (asprintf(&pkg->logdir, "%s/pkg_install.XXXXXX", tmpdir) == -1) | 922 | if (!cfile) | |
1097 | err(EXIT_FAILURE, "asprintf failed"); | 923 | warnx("can't open dependency file '%s'!\n" | |
1098 | /* XXX pkg_add -u... */ | 924 | "dependency registration is incomplete", contents); | |
1099 | if (mkdtemp(pkg->logdir) == NULL) { | 925 | else { | |
1100 | warn("mkdtemp failed"); | 926 | fprintf(cfile, "%s\n", PkgName); | |
1101 | goto clean_memory; | 927 | if (fclose(cfile) == EOF) | |
928 | warnx("cannot properly close file %s", contents); | |||
929 | } | |||
1102 | } | 930 | } | |
931 | if (Automatic) | |||
932 | mark_as_automatic_installed(PkgName, 1); | |||
933 | if (Verbose) | |||
934 | printf("Package %s registered in %s\n", PkgName, LogDir); | |||
1103 | } | 935 | } | |
1104 | 936 | |||
1105 | if (check_already_installed(pkg) == 0) { | 937 | if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) { | |
1106 | status = 0; | 938 | FILE *fp; | |
1107 | goto clean_memory; | 939 | char buf[BUFSIZ]; | |
940 | ||||
941 | (void) snprintf(buf, sizeof(buf), "%s/%s", LogDir, p->name); | |||
942 | fp = fopen(buf, "r"); | |||
943 | if (fp) { | |||
944 | putc('\n', stdout); | |||
945 | while (fgets(buf, sizeof(buf), fp)) | |||
946 | fputs(buf, stdout); | |||
947 | putc('\n', stdout); | |||
948 | (void) fclose(fp); | |||
949 | } else | |||
950 | warnx("cannot open %s as display file", buf); | |||
1108 | } | 951 | } | |
1109 | 952 | |||
1110 | if (read_buildinfo(pkg)) | 953 | /* Add the package to a default view. */ | |
1111 | goto clean_memory; | 954 | if (!Fake && !NoView && is_depoted_pkg) { | |
955 | if (Verbose) { | |||
956 | printf("%s/pkg_view -d %s %s%s %s%s %sadd %s\n", | |||
957 | BINDIR, dbdir, | |||
958 | View ? "-w " : "", View ? View : "", | |||
959 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | |||
960 | Verbose ? "-v " : "", PkgName); | |||
961 | } | |||
1112 | 962 | |||
1113 | if (check_platform(pkg)) | 963 | fexec_skipempty(BINDIR "/pkg_view", "-d", dbdir, | |
1114 | goto clean_memory; | 964 | View ? "-w " : "", View ? View : "", | |
965 | Viewbase ? "-W " : "", Viewbase ? Viewbase : "", | |||
966 | Verbose ? "-v " : "", "add", PkgName, NULL); | |||
967 | } | |||
968 | ||||
969 | goto success; | |||
1115 | 970 | |||
1116 | if (check_other_installed(pkg)) | 971 | bomb: | |
1117 | goto clean_memory; | 972 | errc = 1; | |
973 | goto success; | |||
1118 | 974 | |||
1119 | if (check_explicit_conflict(pkg)) | 975 | fail: | |
1120 | goto clean_memory; | 976 | /* Nuke the whole (installed) show, XXX but don't clean directories */ | |
977 | if (!Fake) | |||
978 | delete_package(FALSE, FALSE, &Plist, FALSE); | |||
1121 | 979 | |||
1122 | if (check_implicit_conflict(pkg)) | 980 | success: | |
1123 | goto clean_memory; | 981 | /* delete the packing list contents */ | |
982 | free_plist(&Plist); | |||
983 | leave_playpen(Home); | |||
1124 | 984 | |||
1125 | if (pkg->other_version != NULL) { | 985 | if (replacing) { | |
1126 | /* | 986 | /* | |
1127 | * Replacing an existing package. | 987 | * Upgrade step 3/4: move back +REQUIRED_BY file | |
1128 | * Write meta-data, get rid of the old version, | 988 | * (see also step 2/4) | |
1129 | * install/update dependencies and finally extract. | |||
1130 | */ | 989 | */ | |
1131 | if (write_meta_data(pkg)) | 990 | if (rename(replace_via, replace_to) != 0) | |
1132 | goto nuke_pkgdb; | 991 | err(EXIT_FAILURE, "renaming \"%s\" to \"%s\" failed", replace_via, replace_to); | |
1133 | 992 | |||
1134 | if (start_replacing(pkg)) | |||
1135 | goto nuke_pkgdb; | |||
1136 | ||||
1137 | if (check_dependencies(pkg)) | |||
1138 | goto nuke_pkgdb; | |||
1139 | } else { | |||
1140 | /* | 993 | /* | |
1141 | * Normal installation. | 994 | * Upgrade step 4/4: Fix pkgs that depend on us to | |
1142 | * Install/update dependencies first and | 995 | * depend on the new version instead of the old | |
1143 | * write the current package to disk afterwards. | 996 | * one by fixing @pkgdep lines in +CONTENTS files. | |
1144 | */ | 997 | */ | |
1145 | if (check_dependencies(pkg)) | 998 | /* TODO */ | |
1146 | goto clean_memory; | |||
1147 | ||||
1148 | if (write_meta_data(pkg)) | |||
1149 | goto nuke_pkgdb; | |||
1150 | } | 999 | } | |
1151 | 1000 | |||
1152 | if (run_install_script(pkg, "PRE-INSTALL")) | 1001 | return errc; | |
1153 | goto nuke_pkgdb; | 1002 | } | |
1154 | ||||
1155 | if (extract_files(pkg)) | |||
1156 | goto nuke_pkg; | |||
1157 | ||||
1158 | if (run_install_script(pkg, "POST-INSTALL")) | |||
1159 | goto nuke_pkgdb; | |||
1160 | ||||
1161 | /* XXX keep +INSTALL_INFO for updates? */ | |||
1162 | /* XXX keep +PRESERVE for updates? */ | |||
1163 | if (mark_automatic) | |||
1164 | mark_as_automatic_installed(pkg->pkgname, 1); | |||
1165 | ||||
1166 | pkg_register_depends(pkg); | |||
1167 | ||||
1168 | if (Verbose) | |||
1169 | printf("Package %s registered in %s\n", pkg->pkgname, pkg->logdir); | |||
1170 | ||||
1171 | if (pkg->meta_data.meta_display != NULL) | |||
1172 | fputs(pkg->meta_data.meta_display, stdout); | |||
1173 | 1003 | |||
1174 | pkg_register_views(pkg); | 1004 | void | |
1005 | cleanup(int signo) | |||
1006 | { | |||
1007 | static int alreadyCleaning; | |||
1008 | void (*oldint) (int); | |||
1009 | void (*oldhup) (int); | |||
1010 | int saved_errno; | |||
1175 | 1011 | |||
1176 | status = 0; | 1012 | saved_errno = errno; | |
1177 | goto clean_memory; | 1013 | oldint = signal(SIGINT, SIG_IGN); | |
1014 | oldhup = signal(SIGHUP, SIG_IGN); | |||
1178 | 1015 | |||
1179 | nuke_pkg: | 1016 | if (!alreadyCleaning) { | |
1180 | if (!Fake) { | 1017 | alreadyCleaning = 1; | |
1181 | if (pkg->other_version) { | 1018 | if (signo) | |
1182 | warnx("Updating of %s to %s failed.", | 1019 | printf("Signal %d received, cleaning up.\n", signo); | |
1183 | pkg->other_version, pkg->pkgname); | 1020 | if (!Fake && zapLogDir && LogDir[0]) | |
1184 | warnx("Remember to run pkg_admin rebuild-tree after fixing this."); | 1021 | (void) fexec(REMOVE_CMD, "-fr", LogDir, NULL); | |
1185 | } | 1022 | leave_playpen(Home); | |
1186 | delete_package(FALSE, FALSE, &pkg->plist, FALSE); | 1023 | if (signo) | |
1024 | exit(1); | |||
1187 | } | 1025 | } | |
1188 | 1026 | signal(SIGINT, oldint); | ||
1189 | nuke_pkgdb: | 1027 | signal(SIGHUP, oldhup); | |
1190 | if (!Fake) { | 1028 | errno = saved_errno; | |
1191 | (void) fexec(REMOVE_CMD, "-fr", pkg->logdir, (void *)NULL); | |||
1192 | free(pkg->logdir); | |||
1193 | pkg->logdir = NULL; | |||
1194 | } | |||
1195 | ||||
1196 | clean_memory: | |||
1197 | if (pkg->logdir != NULL && NoRecord && !Fake) | |||
1198 | (void) fexec(REMOVE_CMD, "-fr", pkg->logdir, (void *)NULL); | |||
1199 | free(pkg->logdir); | |||
1200 | free_buildinfo(pkg); | |||
1201 | free_plist(&pkg->plist); | |||
1202 | free_meta_data(pkg); | |||
1203 | if (pkg->archive) { | |||
1204 | archive_read_close(pkg->archive); | |||
1205 | close_archive(archive_cookie); | |||
1206 | } | |||
1207 | free(pkg->other_version); | |||
1208 | free(pkg); | |||
1209 | return status; | |||
1210 | } | 1029 | } | |
1211 | 1030 | |||
1212 | int | 1031 | int | |
1213 | pkg_perform(lpkg_head_t *pkgs) | 1032 | pkg_perform(lpkg_head_t *pkgs) | |
1214 | { | 1033 | { | |
1215 | int errors = 0; | 1034 | int err_cnt = 0; | |
1216 | lpkg_t *lpp; | 1035 | lpkg_t *lpp; | |
1217 | 1036 | |||
1037 | signal(SIGINT, cleanup); | |||
1038 | signal(SIGHUP, cleanup); | |||
1039 | ||||
1040 | TAILQ_INIT(&files); | |||
1041 | ||||
1218 | while ((lpp = TAILQ_FIRST(pkgs)) != NULL) { | 1042 | while ((lpp = TAILQ_FIRST(pkgs)) != NULL) { | |
1219 | path_prepend_from_pkgname(lpp->lp_name); | 1043 | path_prepend_from_pkgname(lpp->lp_name); | |
1220 | if (pkg_do(lpp->lp_name, Automatic)) | 1044 | err_cnt += pkg_do(lpp->lp_name, pkgs); | |
1221 | ++errors; | |||
1222 | path_prepend_clear(); | 1045 | path_prepend_clear(); | |
1223 | TAILQ_REMOVE(pkgs, lpp, lp_link); | 1046 | TAILQ_REMOVE(pkgs, lpp, lp_link); | |
1224 | free_lpkg(lpp); | 1047 | free_lpkg(lpp); | |
1225 | } | 1048 | } | |
1226 | 1049 | |||
1227 | return errors; | 1050 | ftp_stop(); | |
1051 | ||||
1052 | return err_cnt; | |||
1228 | } | 1053 | } |
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | .\" $NetBSD: pkg_add.1,v 1.29 2008/04/26 14:56:34 joerg Exp $ | 1 | .\" $NetBSD: pkg_add.1,v 1.30 2008/04/26 17:40:01 joerg Exp $ | |
2 | .\" | 2 | .\" | |
3 | .\" FreeBSD install - a package for the installation and maintenance | 3 | .\" FreeBSD install - a package for the installation and maintenance | |
4 | .\" of non-core utilities. | 4 | .\" of non-core utilities. | |
5 | .\" | 5 | .\" | |
6 | .\" Redistribution and use in source and binary forms, with or without | 6 | .\" Redistribution and use in source and binary forms, with or without | |
7 | .\" modification, are permitted provided that the following conditions | 7 | .\" modification, are permitted provided that the following conditions | |
8 | .\" are met: | 8 | .\" are met: | |
9 | .\" 1. Redistributions of source code must retain the above copyright | 9 | .\" 1. Redistributions of source code must retain the above copyright | |
10 | .\" notice, this list of conditions and the following disclaimer. | 10 | .\" notice, this list of conditions and the following disclaimer. | |
11 | .\" 2. Redistributions in binary form must reproduce the above copyright | 11 | .\" 2. Redistributions in binary form must reproduce the above copyright | |
12 | .\" notice, this list of conditions and the following disclaimer in the | 12 | .\" notice, this list of conditions and the following disclaimer in the | |
13 | .\" documentation and/or other materials provided with the distribution. | 13 | .\" documentation and/or other materials provided with the distribution. | |
14 | .\" | 14 | .\" | |
@@ -20,26 +20,27 @@ | @@ -20,26 +20,27 @@ | |||
20 | .Dd August 23, 2007 | 20 | .Dd August 23, 2007 | |
21 | .Dt PKG_ADD 1 | 21 | .Dt PKG_ADD 1 | |
22 | .Os | 22 | .Os | |
23 | .Sh NAME | 23 | .Sh NAME | |
24 | .Nm pkg_add | 24 | .Nm pkg_add | |
25 | .Nd a utility for installing and upgrading software package distributions | 25 | .Nd a utility for installing and upgrading software package distributions | |
26 | .Sh SYNOPSIS | 26 | .Sh SYNOPSIS | |
27 | .Nm | 27 | .Nm | |
28 | .Op Fl AfILnRuVv | 28 | .Op Fl AfILnRuVv | |
29 | .Op Fl K Ar pkg_dbdir | 29 | .Op Fl K Ar pkg_dbdir | |
30 | .Op Fl m Ar machine | 30 | .Op Fl m Ar machine | |
31 | .Op Fl p Ar prefix | 31 | .Op Fl p Ar prefix | |
32 | .Op Fl s Ar verification-type | 32 | .Op Fl s Ar verification-type | |
33 | .Op Fl t Ar template | |||
33 | .Op Fl W Ar viewbase | 34 | .Op Fl W Ar viewbase | |
34 | .Op Fl w Ar view | 35 | .Op Fl w Ar view | |
35 | .Ar \fR[[ftp|http]://[\fIuser\fR[:\fIpassword]\fR@]\fIhost\fR[:\fIport\fR]][/\fIpath/\fR]pkg-name ... | 36 | .Ar \fR[[ftp|http]://[\fIuser\fR[:\fIpassword]\fR@]\fIhost\fR[:\fIport\fR]][/\fIpath/\fR]pkg-name ... | |
36 | .Sh DESCRIPTION | 37 | .Sh DESCRIPTION | |
37 | The | 38 | The | |
38 | .Nm | 39 | .Nm | |
39 | command is used to extract and upgrade packages that have been | 40 | command is used to extract and upgrade packages that have been | |
40 | previously created with the | 41 | previously created with the | |
41 | .Xr pkg_create 1 | 42 | .Xr pkg_create 1 | |
42 | command. | 43 | command. | |
43 | Packages are prepared collections of pre-built binaries, documentation, | 44 | Packages are prepared collections of pre-built binaries, documentation, | |
44 | configurations, installation instructions and/or other files. | 45 | configurations, installation instructions and/or other files. | |
45 | .Nm | 46 | .Nm | |
@@ -149,51 +150,73 @@ as the directory in which to extract fil | @@ -149,51 +150,73 @@ as the directory in which to extract fil | |||
149 | If a package has set its default directory, it will be overridden | 150 | If a package has set its default directory, it will be overridden | |
150 | by this flag. | 151 | by this flag. | |
151 | Note that only the first | 152 | Note that only the first | |
152 | .Cm @cwd | 153 | .Cm @cwd | |
153 | directive will be replaced, since | 154 | directive will be replaced, since | |
154 | .Nm | 155 | .Nm | |
155 | has no way of knowing which directory settings are relative and | 156 | has no way of knowing which directory settings are relative and | |
156 | which are absolute. | 157 | which are absolute. | |
157 | Only one directory transition is supported and the second one is expected to go | 158 | Only one directory transition is supported and the second one is expected to go | |
158 | into | 159 | into | |
159 | .Ar pkgdb . | 160 | .Ar pkgdb . | |
160 | .It Fl R | 161 | .It Fl R | |
161 | Do not record the installation of a package. | 162 | Do not record the installation of a package. | |
162 | This implies | |||
163 | .Fl I . | |||
164 | This means that you cannot deinstall it later, so only use this option if | 163 | This means that you cannot deinstall it later, so only use this option if | |
165 | you know what you are doing! | 164 | you know what you are doing! | |
166 | .It Fl s Ar verification-type | 165 | .It Fl s Ar verification-type | |
167 | Use a callout to an external program to verify the binary package | 166 | Use a callout to an external program to verify the binary package | |
168 | being installed against an existing detached signature file. | 167 | being installed against an existing detached signature file. | |
169 | The signature file must reside in the same directory | 168 | The signature file must reside in the same directory | |
170 | as the binary package. | 169 | as the binary package. | |
171 | At the present time, the following verification types | 170 | At the present time, the following verification types | |
172 | are defined: none, gpg and pgp5. | 171 | are defined: none, gpg and pgp5. | |
173 | The signature will be verified at install time, and the results | 172 | The signature will be verified at install time, and the results | |
174 | will be displayed. | 173 | will be displayed. | |
175 | If the signature type is anything other than none, the user will be asked if | 174 | If the signature type is anything other than none, the user will be asked if | |
176 | .Nm | 175 | .Nm | |
177 | should proceed to install the binary package. | 176 | should proceed to install the binary package. | |
178 | The user must then take the decision whether to proceed or not, depending | 177 | The user must then take the decision whether to proceed or not, depending | |
179 | upon the amount of trust that is placed in the signatory of the binary | 178 | upon the amount of trust that is placed in the signatory of the binary | |
180 | package. | 179 | package. | |
181 | Please note that, at the current time, it is not possible to use | 180 | Please note that, at the current time, it is not possible to use | |
182 | the verification feature when using | 181 | the verification feature when using | |
183 | .Nm | 182 | .Nm | |
184 | to add a binary package via a URL - the package, and the related | 183 | to add a binary package via a URL - the package, and the related | |
185 | detached signature file, must be local | 184 | detached signature file, must be local | |
186 | for the verification to work. | 185 | for the verification to work. | |
186 | .It Fl t Ar template | |||
187 | Use | |||
188 | .Ar template | |||
189 | as the input to | |||
190 | .Xr mktemp 3 | |||
191 | when creating a | |||
192 | .Dq staging area . | |||
193 | By default, this is the string | |||
194 | .Pa /var/tmp/instmp.XXXXXX , | |||
195 | but it may be necessary to override it in the situation where | |||
196 | space in your | |||
197 | .Pa /var/tmp | |||
198 | directory is limited. | |||
199 | Be sure to leave some number of | |||
200 | .Sq X | |||
201 | characters for | |||
202 | .Xr mktemp 3 | |||
203 | to fill in with a unique ID. | |||
204 | .Pp | |||
205 | You can get a performance boost by setting the staging area | |||
206 | .Ar template | |||
207 | to reside on the same disk partition as target directories for package | |||
208 | file installation; often this is | |||
209 | .Pa /usr . | |||
187 | .It Fl u | 210 | .It Fl u | |
188 | If the package that's being installed is already installed, either | 211 | If the package that's being installed is already installed, either | |
189 | in the same or a different version, an update is performed. | 212 | in the same or a different version, an update is performed. | |
190 | If this is specified twice, then any dependant packages that are | 213 | If this is specified twice, then any dependant packages that are | |
191 | too old will also be updated to fulfill the dependency. | 214 | too old will also be updated to fulfill the dependency. | |
192 | See below for a more detailed description of the process. | 215 | See below for a more detailed description of the process. | |
193 | .It Fl V | 216 | .It Fl V | |
194 | Print version number and exit. | 217 | Print version number and exit. | |
195 | .It Fl v | 218 | .It Fl v | |
196 | Turn on verbose output. | 219 | Turn on verbose output. | |
197 | .It Fl W Ar viewbase | 220 | .It Fl W Ar viewbase | |
198 | Set | 221 | Set | |
199 | .Ar viewbase | 222 | .Ar viewbase | |
@@ -242,30 +265,31 @@ FTP_PASSIVE_MODE | @@ -242,30 +265,31 @@ FTP_PASSIVE_MODE | |||
242 | .Ef | 265 | .Ef | |
243 | to some value in your environment. | 266 | to some value in your environment. | |
244 | Otherwise, the more standard ACTIVE mode may be used. | 267 | Otherwise, the more standard ACTIVE mode may be used. | |
245 | If | 268 | If | |
246 | .Nm | 269 | .Nm | |
247 | consistently fails to fetch a package from a site known to work, | 270 | consistently fails to fetch a package from a site known to work, | |
248 | it may be because you have a firewall that demands the usage of | 271 | it may be because you have a firewall that demands the usage of | |
249 | .Bf -emphasis | 272 | .Bf -emphasis | |
250 | passive mode | 273 | passive mode | |
251 | .Ef | 274 | .Ef | |
252 | ftp. | 275 | ftp. | |
253 | .Sh TECHNICAL DETAILS | 276 | .Sh TECHNICAL DETAILS | |
254 | .Nm | 277 | .Nm | |
255 | extracts each package's meta data (including the | 278 | extracts each package's | |
256 | .Dq packing list ) | 279 | .Dq packing list | |
257 | to memory and then runs through the following sequence to fully extract | 280 | into a special staging directory in /var/tmp (or $PKG_TMPDIR if set) | |
258 | the contents of the package: | 281 | and then runs through the following sequence to fully extract the contents | |
282 | of the package: | |||
259 | .Bl -enum -offset indent | 283 | .Bl -enum -offset indent | |
260 | .It | 284 | .It | |
261 | A check is made to determine if the package or another version of it | 285 | A check is made to determine if the package or another version of it | |
262 | is already recorded as installed. | 286 | is already recorded as installed. | |
263 | If it is, | 287 | If it is, | |
264 | installation is terminated if the | 288 | installation is terminated if the | |
265 | .Fl u | 289 | .Fl u | |
266 | option is not given. | 290 | option is not given. | |
267 | .Pp | 291 | .Pp | |
268 | If the | 292 | If the | |
269 | .Fl u | 293 | .Fl u | |
270 | option is given, it's assumed the package should be replaced by the | 294 | option is given, it's assumed the package should be replaced by the | |
271 | new version instead. | 295 | new version instead. |
@@ -1,27 +1,27 @@ | @@ -1,27 +1,27 @@ | |||
1 | /* $NetBSD: perform.c,v 1.20 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: perform.c,v 1.21 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | #ifndef lint | 10 | #ifndef lint | |
11 | #if 0 | 11 | #if 0 | |
12 | static const char *rcsid = "from FreeBSD Id: perform.c,v 1.38 1997/10/13 15:03:51 jkh Exp"; | 12 | static const char *rcsid = "from FreeBSD Id: perform.c,v 1.38 1997/10/13 15:03:51 jkh Exp"; | |
13 | #else | 13 | #else | |
14 | __RCSID("$NetBSD: perform.c,v 1.20 2008/04/26 14:56:34 joerg Exp $"); | 14 | __RCSID("$NetBSD: perform.c,v 1.21 2008/04/26 17:40:01 joerg Exp $"); | |
15 | #endif | 15 | #endif | |
16 | #endif | 16 | #endif | |
17 | 17 | |||
18 | /* | 18 | /* | |
19 | * FreeBSD install - a package for the installation and maintainance | 19 | * FreeBSD install - a package for the installation and maintainance | |
20 | * of non-core utilities. | 20 | * of non-core utilities. | |
21 | * | 21 | * | |
22 | * Redistribution and use in source and binary forms, with or without | 22 | * Redistribution and use in source and binary forms, with or without | |
23 | * modification, are permitted provided that the following conditions | 23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | 24 | * are met: | |
25 | * 1. Redistributions of source code must retain the above copyright | 25 | * 1. Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | 26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must reproduce the above copyright | 27 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -81,58 +81,26 @@ register_depends(package_t *plist, char | @@ -81,58 +81,26 @@ register_depends(package_t *plist, char | |||
81 | free(best_installed); | 81 | free(best_installed); | |
82 | if (!build_only) { | 82 | if (!build_only) { | |
83 | add_plist(plist, PLIST_PKGDEP, cp); | 83 | add_plist(plist, PLIST_PKGDEP, cp); | |
84 | if (Verbose && !PlistOnly) | 84 | if (Verbose && !PlistOnly) | |
85 | printf(" %s", cp); | 85 | printf(" %s", cp); | |
86 | } | 86 | } | |
87 | } | 87 | } | |
88 | } | 88 | } | |
89 | if (Verbose && !PlistOnly) | 89 | if (Verbose && !PlistOnly) | |
90 | printf(".\n"); | 90 | printf(".\n"); | |
91 | } | 91 | } | |
92 | 92 | |||
93 | /* | 93 | /* | |
94 | * Expect "fname" to point at a file, and read it into | |||
95 | * the buffer returned. | |||
96 | */ | |||
97 | static char * | |||
98 | fileGetContents(char *fname) | |||
99 | { | |||
100 | char *contents; | |||
101 | struct stat sb; | |||
102 | int fd; | |||
103 | ||||
104 | if (stat(fname, &sb) == FAIL) { | |||
105 | cleanup(0); | |||
106 | errx(2, "can't stat '%s'", fname); | |||
107 | } | |||
108 | ||||
109 | contents = (char *) malloc((size_t) (sb.st_size) + 1); | |||
110 | fd = open(fname, O_RDONLY, 0); | |||
111 | if (fd == FAIL) { | |||
112 | cleanup(0); | |||
113 | errx(2, "unable to open '%s' for reading", fname); | |||
114 | } | |||
115 | if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) { | |||
116 | cleanup(0); | |||
117 | errx(2, "short read on '%s' - did not get %lld bytes", | |||
118 | fname, (long long) sb.st_size); | |||
119 | } | |||
120 | close(fd); | |||
121 | contents[(size_t) sb.st_size] = '\0'; | |||
122 | return contents; | |||
123 | } | |||
124 | ||||
125 | /* | |||
126 | * Get a string parameter as a file spec or as a "contents follow -" spec | 94 | * Get a string parameter as a file spec or as a "contents follow -" spec | |
127 | */ | 95 | */ | |
128 | static void | 96 | static void | |
129 | get_dash_string(char **s) | 97 | get_dash_string(char **s) | |
130 | { | 98 | { | |
131 | if (**s == '-') | 99 | if (**s == '-') | |
132 | *s = strdup(*s + 1); | 100 | *s = strdup(*s + 1); | |
133 | else | 101 | else | |
134 | *s = fileGetContents(*s); | 102 | *s = fileGetContents(*s); | |
135 | } | 103 | } | |
136 | 104 | |||
137 | int | 105 | int | |
138 | pkg_perform(const char *pkg) | 106 | pkg_perform(const char *pkg) |
@@ -1,32 +1,32 @@ | @@ -1,32 +1,32 @@ | |||
1 | # $NetBSD: Makefile.in,v 1.15 2008/04/26 14:56:34 joerg Exp $ | 1 | # $NetBSD: Makefile.in,v 1.16 2008/04/26 17:40:01 joerg Exp $ | |
2 | 2 | |||
3 | srcdir= @srcdir@ | 3 | srcdir= @srcdir@ | |
4 | 4 | |||
5 | prefix= @prefix@ | 5 | prefix= @prefix@ | |
6 | exec_prefix= @exec_prefix@ | 6 | exec_prefix= @exec_prefix@ | |
7 | sbindir= @sbindir@ | 7 | sbindir= @sbindir@ | |
8 | mandir= @mandir@ | 8 | mandir= @mandir@ | |
9 | datarootdir= @datarootdir@ | 9 | datarootdir= @datarootdir@ | |
10 | 10 | |||
11 | man1dir= $(mandir)/man1 | 11 | man1dir= $(mandir)/man1 | |
12 | cat1dir= $(mandir)/cat1 | 12 | cat1dir= $(mandir)/cat1 | |
13 | 13 | |||
14 | BOOTSTRAP= @bootstrap@ | 14 | BOOTSTRAP= @bootstrap@ | |
15 | 15 | |||
16 | CC= @CC@ | 16 | CC= @CC@ | |
17 | CCLD= $(CC) | 17 | CCLD= $(CC) | |
18 | .if empty(BOOTSTRAP) | 18 | .if empty(BOOTSTRAP) | |
19 | LIBS= -linstall -larchive -lfetch -lbz2 -lz @LIBS@ | 19 | LIBS= -linstall -larchive -lbz2 -lfetch -lz @LIBS@ | |
20 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib | 20 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib | |
21 | .else | 21 | .else | |
22 | LIBS= -linstall @LIBS@ | 22 | LIBS= -linstall @LIBS@ | |
23 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib -DBOOTSTRAP | 23 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -I../lib -DBOOTSTRAP | |
24 | .endif | 24 | .endif | |
25 | DEFS= @DEFS@ | 25 | DEFS= @DEFS@ | |
26 | CFLAGS= @CFLAGS@ | 26 | CFLAGS= @CFLAGS@ | |
27 | LDFLAGS= @LDFLAGS@ -L../lib | 27 | LDFLAGS= @LDFLAGS@ -L../lib | |
28 | 28 | |||
29 | INSTALL= @INSTALL@ | 29 | INSTALL= @INSTALL@ | |
30 | 30 | |||
31 | PROG= pkg_info | 31 | PROG= pkg_info | |
32 | 32 |
@@ -1,33 +1,33 @@ | @@ -1,33 +1,33 @@ | |||
1 | /* $NetBSD: perform.c,v 1.47 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: perform.c,v 1.48 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | #if HAVE_SYS_QUEUE_H | 10 | #if HAVE_SYS_QUEUE_H | |
11 | #include <sys/queue.h> | 11 | #include <sys/queue.h> | |
12 | #endif | 12 | #endif | |
13 | #if HAVE_SYS_WAIT_H | 13 | #if HAVE_SYS_WAIT_H | |
14 | #include <sys/wait.h> | 14 | #include <sys/wait.h> | |
15 | #endif | 15 | #endif | |
16 | #ifndef lint | 16 | #ifndef lint | |
17 | #if 0 | 17 | #if 0 | |
18 | static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp"; | 18 | static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp"; | |
19 | #else | 19 | #else | |
20 | __RCSID("$NetBSD: perform.c,v 1.47 2008/04/26 14:56:34 joerg Exp $"); | 20 | __RCSID("$NetBSD: perform.c,v 1.48 2008/04/26 17:40:01 joerg Exp $"); | |
21 | #endif | 21 | #endif | |
22 | #endif | 22 | #endif | |
23 | 23 | |||
24 | /*- | 24 | /*- | |
25 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | 25 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | |
26 | * All rights reserved. | 26 | * All rights reserved. | |
27 | * | 27 | * | |
28 | * Redistribution and use in source and binary forms, with or without | 28 | * Redistribution and use in source and binary forms, with or without | |
29 | * modification, are permitted provided that the following conditions | 29 | * modification, are permitted provided that the following conditions | |
30 | * are met: | 30 | * are met: | |
31 | * | 31 | * | |
32 | * 1. Redistributions of source code must retain the above copyright | 32 | * 1. Redistributions of source code must retain the above copyright | |
33 | * notice, this list of conditions and the following disclaimer. | 33 | * notice, this list of conditions and the following disclaimer. | |
@@ -116,27 +116,27 @@ __RCSID("$NetBSD: perform.c,v 1.47 2008/ | @@ -116,27 +116,27 @@ __RCSID("$NetBSD: perform.c,v 1.47 2008/ | |||
116 | #define LOAD_SIZE_PKG (1 << 9) | 116 | #define LOAD_SIZE_PKG (1 << 9) | |
117 | #define LOAD_SIZE_ALL (1 << 10) | 117 | #define LOAD_SIZE_ALL (1 << 10) | |
118 | #define LOAD_PRESERVE (1 << 11) | 118 | #define LOAD_PRESERVE (1 << 11) | |
119 | #define LOAD_VIEWS (1 << 12) | 119 | #define LOAD_VIEWS (1 << 12) | |
120 | #define LOAD_REQUIRED_BY (1 << 13) | 120 | #define LOAD_REQUIRED_BY (1 << 13) | |
121 | #define LOAD_INSTALLED_INFO (1 << 14) | 121 | #define LOAD_INSTALLED_INFO (1 << 14) | |
122 | 122 | |||
123 | static const struct pkg_meta_desc { | 123 | static const struct pkg_meta_desc { | |
124 | size_t entry_offset; | 124 | size_t entry_offset; | |
125 | const char *entry_filename; | 125 | const char *entry_filename; | |
126 | int entry_mask; | 126 | int entry_mask; | |
127 | int required_file; | 127 | int required_file; | |
128 | } pkg_meta_descriptors[] = { | 128 | } pkg_meta_descriptors[] = { | |
129 | { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, | 129 | { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME , | |
130 | LOAD_CONTENTS, 1}, | 130 | LOAD_CONTENTS, 1}, | |
131 | { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, | 131 | { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, | |
132 | LOAD_COMMENT, 1 }, | 132 | LOAD_COMMENT, 1 }, | |
133 | { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, | 133 | { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, | |
134 | LOAD_DESC, 1 }, | 134 | LOAD_DESC, 1 }, | |
135 | { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, | 135 | { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, | |
136 | LOAD_INSTALL, 0 }, | 136 | LOAD_INSTALL, 0 }, | |
137 | { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, | 137 | { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, | |
138 | LOAD_DEINSTALL, 0 }, | 138 | LOAD_DEINSTALL, 0 }, | |
139 | { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, | 139 | { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, | |
140 | LOAD_DISPLAY, 0 }, | 140 | LOAD_DISPLAY, 0 }, | |
141 | { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, | 141 | { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, | |
142 | LOAD_MTREE, 0 }, | 142 | LOAD_MTREE, 0 }, | |
@@ -292,39 +292,50 @@ read_meta_data_from_pkgdb(const char *pk | @@ -292,39 +292,50 @@ read_meta_data_from_pkgdb(const char *pk | |||
292 | return meta; | 292 | return meta; | |
293 | } | 293 | } | |
294 | 294 | |||
295 | static lfile_head_t files; | 295 | static lfile_head_t files; | |
296 | 296 | |||
297 | static int | 297 | static int | |
298 | pkg_do(const char *pkg) | 298 | pkg_do(const char *pkg) | |
299 | { | 299 | { | |
300 | struct pkg_meta *meta; | 300 | struct pkg_meta *meta; | |
301 | char log_dir[MaxPathSize]; | 301 | char log_dir[MaxPathSize]; | |
302 | int code = 0; | 302 | int code = 0; | |
303 | const char *binpkgfile = NULL; | 303 | const char *binpkgfile = NULL; | |
304 | 304 | |||
305 | if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) { | 305 | if (IS_URL(pkg)) { | |
306 | #ifdef BOOTSTRAP | |||
307 | errx(2, "Remote access not supported during bootstrap"); | |||
308 | #else | |||
309 | struct archive *archive; | |||
310 | void *remote_archive_cookie; | |||
311 | ||||
312 | archive = open_remote_archive(pkg, &remote_archive_cookie); | |||
313 | ||||
314 | meta = read_meta_data_from_archive(archive); | |||
315 | close_remote_archive(remote_archive_cookie); | |||
316 | #endif | |||
317 | } else if (fexists(pkg) && isfile(pkg)) { | |||
306 | #ifdef BOOTSTRAP | 318 | #ifdef BOOTSTRAP | |
307 | errx(2, "Binary packages not supported during bootstrap"); | 319 | errx(2, "Binary packages not supported during bootstrap"); | |
308 | #else | 320 | #else | |
309 | struct archive *archive; | 321 | struct archive *archive; | |
310 | void *archive_cookie; | 322 | void *remote_archive_cookie; | |
311 | 323 | |||
312 | archive = open_archive(pkg, &archive_cookie); | 324 | archive = open_local_archive(pkg, &remote_archive_cookie); | |
313 | 325 | |||
314 | meta = read_meta_data_from_archive(archive); | 326 | meta = read_meta_data_from_archive(archive); | |
315 | close_archive(archive_cookie); | 327 | close_local_archive(remote_archive_cookie); | |
316 | if (!IS_URL(pkg)) | 328 | binpkgfile = pkg; | |
317 | binpkgfile = pkg; | |||
318 | #endif | 329 | #endif | |
319 | } else { | 330 | } else { | |
320 | /* | 331 | /* | |
321 | * It's not an uninstalled package, try and find it among the | 332 | * It's not an uninstalled package, try and find it among the | |
322 | * installed | 333 | * installed | |
323 | */ | 334 | */ | |
324 | (void) snprintf(log_dir, sizeof(log_dir), "%s/%s", | 335 | (void) snprintf(log_dir, sizeof(log_dir), "%s/%s", | |
325 | _pkgdb_getPKGDB_DIR(), pkg); | 336 | _pkgdb_getPKGDB_DIR(), pkg); | |
326 | if (!fexists(log_dir) || !(isdir(log_dir) || islinktodir(log_dir))) { | 337 | if (!fexists(log_dir) || !(isdir(log_dir) || islinktodir(log_dir))) { | |
327 | switch (add_installed_pkgs_by_basename(pkg, &pkgs)) { | 338 | switch (add_installed_pkgs_by_basename(pkg, &pkgs)) { | |
328 | case 1: | 339 | case 1: | |
329 | return 0; | 340 | return 0; | |
330 | case 0: | 341 | case 0: |
@@ -1,45 +1,45 @@ | @@ -1,45 +1,45 @@ | |||
1 | # $NetBSD: Makefile.in,v 1.22 2008/04/26 14:56:34 joerg Exp $ | 1 | # $NetBSD: Makefile.in,v 1.23 2008/04/26 17:40:01 joerg Exp $ | |
2 | 2 | |||
3 | srcdir= @srcdir@ | 3 | srcdir= @srcdir@ | |
4 | 4 | |||
5 | pkgdbdir= @pkgdbdir@ | 5 | pkgdbdir= @pkgdbdir@ | |
6 | mandir= @mandir@ | 6 | mandir= @mandir@ | |
7 | datarootdir= @datarootdir@ | 7 | datarootdir= @datarootdir@ | |
8 | 8 | |||
9 | cat5dir= $(mandir)/cat5 | 9 | cat5dir= $(mandir)/cat5 | |
10 | cat7dir= $(mandir)/cat7 | 10 | cat7dir= $(mandir)/cat7 | |
11 | man5dir= $(mandir)/man5 | 11 | man5dir= $(mandir)/man5 | |
12 | man7dir= $(mandir)/man7 | 12 | man7dir= $(mandir)/man7 | |
13 | 13 | |||
14 | tar= @tar@ | 14 | tar= @tar@ | |
15 | ftp= @ftp@ | 15 | ftp= @ftp@ | |
16 | 16 | |||
17 | BOOTSTRAP= @bootstrap@ | 17 | BOOTSTRAP= @bootstrap@ | |
18 | 18 | |||
19 | RANLIB= @RANLIB@ | 19 | RANLIB= @RANLIB@ | |
20 | AR= @AR@ | 20 | AR= @AR@ | |
21 | CC= @CC@ | 21 | CC= @CC@ | |
22 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) | 22 | CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) | |
23 | DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" | 23 | DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" -DTAR_CMD=\"$(tar)\" -DFTP_CMD=\"$(ftp)\" | |
24 | CFLAGS= @CFLAGS@ | 24 | CFLAGS= @CFLAGS@ | |
25 | 25 | |||
26 | INSTALL= @INSTALL@ | 26 | INSTALL= @INSTALL@ | |
27 | 27 | |||
28 | LIB= libinstall.a | 28 | LIB= libinstall.a | |
29 | 29 | |||
30 | OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \ | 30 | OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \ | |
31 | global.o iterate.o lpkg.o opattern.o \ | 31 | ftpio.o global.o iterate.o lpkg.o opattern.o \ | |
32 | path.o pkgdb.o plist.o \ | 32 | path.o pen.o pexec.o pkgdb.o plist.o \ | |
33 | str.o var.o version.o vulnerabilities-file.o | 33 | str.o var.o version.o vulnerabilities-file.o | |
34 | 34 | |||
35 | .if !empty(BOOTSTRAP) | 35 | .if !empty(BOOTSTRAP) | |
36 | CPPFLAGS+= -DBOOTSTRAP | 36 | CPPFLAGS+= -DBOOTSTRAP | |
37 | .else | 37 | .else | |
38 | OBJS+= pkg_io.o | 38 | OBJS+= pkg_io.o | |
39 | .endif | 39 | .endif | |
40 | 40 | |||
41 | all: $(LIB) | 41 | all: $(LIB) | |
42 | 42 | |||
43 | .c.o: | 43 | .c.o: | |
44 | $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< | 44 | $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< | |
45 | 45 |
@@ -20,27 +20,26 @@ | @@ -20,27 +20,26 @@ | |||
20 | #include "dewey.h" | 20 | #include "dewey.h" | |
21 | #include "lib.h" | 21 | #include "lib.h" | |
22 | 22 | |||
23 | /** | 23 | /** | |
24 | * Data structure to keep the intermediate result of the conflict | 24 | * Data structure to keep the intermediate result of the conflict | |
25 | * search. ''pkgname'' is the package in question. The first | 25 | * search. ''pkgname'' is the package in question. The first | |
26 | * installed package that conflicts is filled into | 26 | * installed package that conflicts is filled into | |
27 | * ''conflicting_pkgname''. The pattern that leads to the conflict is | 27 | * ''conflicting_pkgname''. The pattern that leads to the conflict is | |
28 | * also filled in to help the user in deciding what to do with the | 28 | * also filled in to help the user in deciding what to do with the | |
29 | * conflict. | 29 | * conflict. | |
30 | */ | 30 | */ | |
31 | struct package_conflict { | 31 | struct package_conflict { | |
32 | const char *pkgname; | 32 | const char *pkgname; | |
33 | const char *skip_pkgname; | |||
34 | char **conflicting_pkgname; | 33 | char **conflicting_pkgname; | |
35 | char **conflicting_pattern; | 34 | char **conflicting_pattern; | |
36 | }; | 35 | }; | |
37 | 36 | |||
38 | static void * | 37 | static void * | |
39 | nonnull(void *p) | 38 | nonnull(void *p) | |
40 | { | 39 | { | |
41 | 40 | |||
42 | if (p == NULL) { | 41 | if (p == NULL) { | |
43 | err(EXIT_FAILURE, "NullPointerException"); | 42 | err(EXIT_FAILURE, "NullPointerException"); | |
44 | /* NOTREACHED */ | 43 | /* NOTREACHED */ | |
45 | } | 44 | } | |
46 | return p; | 45 | return p; | |
@@ -61,30 +60,26 @@ fopen_contents(const char *pkgname, cons | @@ -61,30 +60,26 @@ fopen_contents(const char *pkgname, cons | |||
61 | return f; | 60 | return f; | |
62 | } | 61 | } | |
63 | 62 | |||
64 | 63 | |||
65 | static int | 64 | static int | |
66 | check_package_conflict(const char *pkgname, void *v) | 65 | check_package_conflict(const char *pkgname, void *v) | |
67 | { | 66 | { | |
68 | struct package_conflict *conflict = v; | 67 | struct package_conflict *conflict = v; | |
69 | package_t pkg; | 68 | package_t pkg; | |
70 | plist_t *p; | 69 | plist_t *p; | |
71 | FILE *f; | 70 | FILE *f; | |
72 | int rv; | 71 | int rv; | |
73 | 72 | |||
74 | if (conflict->skip_pkgname != NULL && | |||
75 | strcmp(conflict->skip_pkgname, pkgname) == 0) | |||
76 | return 0; | |||
77 | ||||
78 | rv = 0; | 73 | rv = 0; | |
79 | pkg.head = NULL; | 74 | pkg.head = NULL; | |
80 | pkg.tail = NULL; | 75 | pkg.tail = NULL; | |
81 | 76 | |||
82 | f = fopen_contents(pkgname, "r"); | 77 | f = fopen_contents(pkgname, "r"); | |
83 | read_plist(&pkg, f); | 78 | read_plist(&pkg, f); | |
84 | (void)fclose(f); | 79 | (void)fclose(f); | |
85 | 80 | |||
86 | for (p = pkg.head; p; p = p->next) { | 81 | for (p = pkg.head; p; p = p->next) { | |
87 | if (p->type != PLIST_PKGCFL) | 82 | if (p->type != PLIST_PKGCFL) | |
88 | continue; | 83 | continue; | |
89 | 84 | |||
90 | if (pkg_match(p->name, conflict->pkgname) == 1) { | 85 | if (pkg_match(p->name, conflict->pkgname) == 1) { | |
@@ -97,34 +92,32 @@ check_package_conflict(const char *pkgna | @@ -97,34 +92,32 @@ check_package_conflict(const char *pkgna | |||
97 | 92 | |||
98 | free_plist(&pkg); | 93 | free_plist(&pkg); | |
99 | return rv; | 94 | return rv; | |
100 | } | 95 | } | |
101 | 96 | |||
102 | /** | 97 | /** | |
103 | * Checks if some installed package has a pkgcfl entry that matches | 98 | * Checks if some installed package has a pkgcfl entry that matches | |
104 | * PkgName. If such an entry is found, the package name is returned in | 99 | * PkgName. If such an entry is found, the package name is returned in | |
105 | * inst_pkgname, the matching pattern in inst_pattern, and the function | 100 | * inst_pkgname, the matching pattern in inst_pattern, and the function | |
106 | * returns a non-zero value. Otherwise, zero is returned and the result | 101 | * returns a non-zero value. Otherwise, zero is returned and the result | |
107 | * variables are set to NULL. | 102 | * variables are set to NULL. | |
108 | */ | 103 | */ | |
109 | int | 104 | int | |
110 | some_installed_package_conflicts_with(const char *pkgname, | 105 | some_installed_package_conflicts_with(const char *pkgname, char **inst_pkgname, char **inst_pattern) | |
111 | const char *skip_pkgname, char **inst_pkgname, char **inst_pattern) | |||
112 | { | 106 | { | |
113 | struct package_conflict cfl; | 107 | struct package_conflict cfl; | |
114 | int rv; | 108 | int rv; | |
115 | 109 | |||
116 | cfl.pkgname = pkgname; | 110 | cfl.pkgname = pkgname; | |
117 | cfl.skip_pkgname = skip_pkgname; | |||
118 | *inst_pkgname = NULL; | 111 | *inst_pkgname = NULL; | |
119 | *inst_pattern = NULL; | 112 | *inst_pattern = NULL; | |
120 | cfl.conflicting_pkgname = inst_pkgname; | 113 | cfl.conflicting_pkgname = inst_pkgname; | |
121 | cfl.conflicting_pattern = inst_pattern; | 114 | cfl.conflicting_pattern = inst_pattern; | |
122 | rv = iterate_pkg_db(check_package_conflict, &cfl); | 115 | rv = iterate_pkg_db(check_package_conflict, &cfl); | |
123 | if (rv == -1) { | 116 | if (rv == -1) { | |
124 | errx(EXIT_FAILURE, "Couldn't read list of installed packages."); | 117 | errx(EXIT_FAILURE, "Couldn't read list of installed packages."); | |
125 | /* NOTREACHED */ | 118 | /* NOTREACHED */ | |
126 | } | 119 | } | |
127 | return *inst_pkgname != NULL; | 120 | return *inst_pkgname != NULL; | |
128 | } | 121 | } | |
129 | 122 | |||
130 | #if 0 | 123 | #if 0 |
@@ -1,33 +1,33 @@ | @@ -1,33 +1,33 @@ | |||
1 | /* $NetBSD: file.c,v 1.24 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: file.c,v 1.25 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | #if HAVE_SYS_PARAM_H | 10 | #if HAVE_SYS_PARAM_H | |
11 | #include <sys/param.h> | 11 | #include <sys/param.h> | |
12 | #endif | 12 | #endif | |
13 | #if HAVE_SYS_QUEUE_H | 13 | #if HAVE_SYS_QUEUE_H | |
14 | #include <sys/queue.h> | 14 | #include <sys/queue.h> | |
15 | #endif | 15 | #endif | |
16 | #ifndef lint | 16 | #ifndef lint | |
17 | #if 0 | 17 | #if 0 | |
18 | static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp"; | 18 | static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp"; | |
19 | #else | 19 | #else | |
20 | __RCSID("$NetBSD: file.c,v 1.24 2008/04/26 14:56:34 joerg Exp $"); | 20 | __RCSID("$NetBSD: file.c,v 1.25 2008/04/26 17:40:01 joerg Exp $"); | |
21 | #endif | 21 | #endif | |
22 | #endif | 22 | #endif | |
23 | 23 | |||
24 | /* | 24 | /* | |
25 | * FreeBSD install - a package for the installation and maintainance | 25 | * FreeBSD install - a package for the installation and maintainance | |
26 | * of non-core utilities. | 26 | * of non-core utilities. | |
27 | * | 27 | * | |
28 | * Redistribution and use in source and binary forms, with or without | 28 | * Redistribution and use in source and binary forms, with or without | |
29 | * modification, are permitted provided that the following conditions | 29 | * modification, are permitted provided that the following conditions | |
30 | * are met: | 30 | * are met: | |
31 | * 1. Redistributions of source code must retain the above copyright | 31 | * 1. Redistributions of source code must retain the above copyright | |
32 | * notice, this list of conditions and the following disclaimer. | 32 | * notice, this list of conditions and the following disclaimer. | |
33 | * 2. Redistributions in binary form must reproduce the above copyright | 33 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -208,26 +208,283 @@ URLlength(const char *fname) | @@ -208,26 +208,283 @@ URLlength(const char *fname) | |||
208 | for (i = 0; isspace((unsigned char) *fname); i++) { | 208 | for (i = 0; isspace((unsigned char) *fname); i++) { | |
209 | fname++; | 209 | fname++; | |
210 | } | 210 | } | |
211 | for (up = urls; up->u_s; up++) { | 211 | for (up = urls; up->u_s; up++) { | |
212 | if (strncmp(fname, up->u_s, up->u_len) == 0) { | 212 | if (strncmp(fname, up->u_s, up->u_len) == 0) { | |
213 | return i + up->u_len; /* ... + sizeof(up->u_s); - HF */ | 213 | return i + up->u_len; /* ... + sizeof(up->u_s); - HF */ | |
214 | } | 214 | } | |
215 | } | 215 | } | |
216 | } | 216 | } | |
217 | return -1; | 217 | return -1; | |
218 | } | 218 | } | |
219 | 219 | |||
220 | /* | 220 | /* | |
221 | * Returns the host part of a URL | |||
222 | */ | |||
223 | const char * | |||
224 | fileURLHost(const char *fname, char *where, int max) | |||
225 | { | |||
226 | const char *ret; | |||
227 | int i; | |||
228 | ||||
229 | assert(where != NULL); | |||
230 | assert(max > 0); | |||
231 | ||||
232 | if ((i = URLlength(fname)) < 0) { /* invalid URL? */ | |||
233 | errx(EXIT_FAILURE, "fileURLhost called with a bad URL: `%s'", fname); | |||
234 | } | |||
235 | fname += i; | |||
236 | /* Do we have a place to stick our work? */ | |||
237 | ret = where; | |||
238 | while (*fname && *fname != '/' && --max) | |||
239 | *where++ = *fname++; | |||
240 | *where = '\0'; | |||
241 | ||||
242 | return ret; | |||
243 | } | |||
244 | ||||
245 | /* | |||
246 | * Returns the filename part of a URL | |||
247 | */ | |||
248 | const char * | |||
249 | fileURLFilename(const char *fname, char *where, int max) | |||
250 | { | |||
251 | const char *ret; | |||
252 | int i; | |||
253 | ||||
254 | assert(where != NULL); | |||
255 | assert(max > 0); | |||
256 | ||||
257 | if ((i = URLlength(fname)) < 0) { /* invalid URL? */ | |||
258 | errx(EXIT_FAILURE, "fileURLFilename called with a bad URL: `%s'", fname); | |||
259 | } | |||
260 | fname += i; | |||
261 | /* Do we have a place to stick our work? */ | |||
262 | ret = where; | |||
263 | while (*fname && *fname != '/') | |||
264 | ++fname; | |||
265 | if (*fname == '/') { | |||
266 | while (*fname && --max) | |||
267 | *where++ = *fname++; | |||
268 | } | |||
269 | *where = '\0'; | |||
270 | ||||
271 | return ret; | |||
272 | } | |||
273 | ||||
274 | /* | |||
275 | * Try and fetch a file by URL, returning the directory name for where | |||
276 | * it's unpacked, if successful. To be handed to leave_playpen() later. | |||
277 | */ | |||
278 | char * | |||
279 | fileGetURL(const char *spec) | |||
280 | { | |||
281 | char host[MAXHOSTNAMELEN], file[MaxPathSize]; | |||
282 | const char *cp; | |||
283 | char *rp; | |||
284 | char pen[MaxPathSize]; | |||
285 | int rc; | |||
286 | ||||
287 | rp = NULL; | |||
288 | if (!IS_URL(spec)) { | |||
289 | errx(EXIT_FAILURE, "fileGetURL was called with non-URL arg '%s'", spec); | |||
290 | } | |||
291 | ||||
292 | /* Some sanity checks on the URL */ | |||
293 | cp = fileURLHost(spec, host, MAXHOSTNAMELEN); | |||
294 | if (!*cp) { | |||
295 | warnx("URL `%s' has bad host part!", spec); | |||
296 | return NULL; | |||
297 | } | |||
298 | cp = fileURLFilename(spec, file, MaxPathSize); | |||
299 | if (!*cp) { | |||
300 | warnx("URL `%s' has bad filename part!", spec); | |||
301 | return NULL; | |||
302 | } | |||
303 | ||||
304 | if (Verbose) | |||
305 | printf("Trying to fetch %s.\n", spec); | |||
306 | ||||
307 | pen[0] = '\0'; | |||
308 | rp = make_playpen(pen, sizeof(pen), 0); | |||
309 | if (rp == NULL) { | |||
310 | printf("Error: Unable to construct a new playpen for FTP!\n"); | |||
311 | return NULL; | |||
312 | } | |||
313 | ||||
314 | rp = strdup(pen); | |||
315 | rc = unpackURL(spec, pen); | |||
316 | if (rc < 0) { | |||
317 | leave_playpen(rp); /* Don't leave dir hang around! */ | |||
318 | ||||
319 | printf("Error on unpackURL('%s', '%s')\n", spec, pen); | |||
320 | return NULL; | |||
321 | } | |||
322 | return rp; | |||
323 | } | |||
324 | ||||
325 | static char * | |||
326 | resolvepattern1(const char *name) | |||
327 | { | |||
328 | static char tmp[MaxPathSize]; | |||
329 | char *cp; | |||
330 | ||||
331 | if (IS_URL(name)) { | |||
332 | /* some package depends on a wildcard pkg */ | |||
333 | int rc; | |||
334 | ||||
335 | rc = expandURL(tmp, name); | |||
336 | if (rc < 0) { | |||
337 | return NULL; | |||
338 | } | |||
339 | if (Verbose) | |||
340 | printf("'%s' expanded to '%s'\n", name, tmp); | |||
341 | return tmp; /* return expanded URL w/ corrent pkg */ | |||
342 | } | |||
343 | else if (ispkgpattern(name)) { | |||
344 | cp = find_best_matching_file(dirname_of(name), basename_of(name), 1, 0); | |||
345 | if (cp) { | |||
346 | snprintf(tmp, sizeof(tmp), "%s/%s", dirname_of(name), cp); | |||
347 | free(cp); | |||
348 | return tmp; | |||
349 | } | |||
350 | } else { | |||
351 | if (isfile(name)) { | |||
352 | strlcpy(tmp, name, sizeof(tmp)); | |||
353 | return tmp; | |||
354 | } | |||
355 | } | |||
356 | ||||
357 | return NULL; | |||
358 | } | |||
359 | ||||
360 | static char * | |||
361 | resolvepattern(const char *name) | |||
362 | { | |||
363 | char tmp[MaxPathSize]; | |||
364 | char *cp; | |||
365 | const char *suf; | |||
366 | ||||
367 | cp = resolvepattern1(name); | |||
368 | if (cp != NULL) | |||
369 | return cp; | |||
370 | ||||
371 | if (ispkgpattern(name)) | |||
372 | return NULL; | |||
373 | ||||
374 | suf = suffix_of(name); | |||
375 | if (!strcmp(suf, "tbz") || !strcmp(suf, "tgz")) | |||
376 | return NULL; | |||
377 | ||||
378 | /* add suffix and try */ | |||
379 | snprintf(tmp, sizeof(tmp), "%s.tbz", name); | |||
380 | cp = resolvepattern1(tmp); | |||
381 | if (cp != NULL) | |||
382 | return cp; | |||
383 | snprintf(tmp, sizeof(tmp), "%s.tgz", name); | |||
384 | cp = resolvepattern1(tmp); | |||
385 | if (cp != NULL) | |||
386 | return cp; | |||
387 | ||||
388 | /* add version number wildcard and try */ | |||
389 | snprintf(tmp, sizeof(tmp), "%s-[0-9]*", name); | |||
390 | return resolvepattern1(tmp); | |||
391 | } | |||
392 | ||||
393 | /* | |||
394 | * Look for filename/pattern "fname" in | |||
395 | * Returns a full path/URL where the pkg can be found | |||
396 | */ | |||
397 | char * | |||
398 | fileFindByPath(const char *fname) | |||
399 | { | |||
400 | char tmp[MaxPathSize]; | |||
401 | struct path *path; | |||
402 | ||||
403 | /* | |||
404 | * 1. if fname is an absolute pathname or a URL, | |||
405 | * just use it. | |||
406 | */ | |||
407 | if (IS_FULLPATH(fname) || IS_URL(fname)) | |||
408 | return resolvepattern(fname); | |||
409 | ||||
410 | /* | |||
411 | * 2. otherwise, use PKG_PATH. | |||
412 | */ | |||
413 | TAILQ_FOREACH(path, &PkgPath, pl_entry) { | |||
414 | char *cp; | |||
415 | const char *cp2 = path->pl_path; | |||
416 | ||||
417 | if (Verbose) | |||
418 | printf("trying PKG_PATH %s\n", cp2); | |||
419 | ||||
420 | if (IS_FULLPATH(cp2) || IS_URL(cp2)) { | |||
421 | snprintf(tmp, sizeof(tmp), "%s/%s", cp2, fname); | |||
422 | } | |||
423 | else { | |||
424 | char cwdtmp[MaxPathSize]; | |||
425 | if (getcwd(cwdtmp, sizeof(cwdtmp)) == NULL) | |||
426 | errx(EXIT_FAILURE, "getcwd"); | |||
427 | snprintf(tmp, sizeof(tmp), "%s/%s/%s", cwdtmp, cp2, fname); | |||
428 | } | |||
429 | cp = resolvepattern(tmp); | |||
430 | if (cp) | |||
431 | return cp; | |||
432 | } | |||
433 | ||||
434 | #if 0 | |||
435 | /* | |||
436 | * 3. finally, search current directory. | |||
437 | */ | |||
438 | snprintf(tmp, sizeof(tmp), "./%s", fname); | |||
439 | return resolvepattern(tmp); | |||
440 | #else | |||
441 | return NULL; | |||
442 | #endif | |||
443 | } | |||
444 | ||||
445 | /* | |||
446 | * Expect "fname" to point at a file, and read it into | |||
447 | * the buffer returned. | |||
448 | */ | |||
449 | char * | |||
450 | fileGetContents(char *fname) | |||
451 | { | |||
452 | char *contents; | |||
453 | struct stat sb; | |||
454 | int fd; | |||
455 | ||||
456 | if (stat(fname, &sb) == FAIL) { | |||
457 | cleanup(0); | |||
458 | errx(2, "can't stat '%s'", fname); | |||
459 | } | |||
460 | ||||
461 | contents = (char *) malloc((size_t) (sb.st_size) + 1); | |||
462 | fd = open(fname, O_RDONLY, 0); | |||
463 | if (fd == FAIL) { | |||
464 | cleanup(0); | |||
465 | errx(2, "unable to open '%s' for reading", fname); | |||
466 | } | |||
467 | if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) { | |||
468 | cleanup(0); | |||
469 | errx(2, "short read on '%s' - did not get %lld bytes", | |||
470 | fname, (long long) sb.st_size); | |||
471 | } | |||
472 | close(fd); | |||
473 | contents[(size_t) sb.st_size] = '\0'; | |||
474 | return contents; | |||
475 | } | |||
476 | ||||
477 | /* | |||
221 | * Takes a filename and package name, returning (in "try") the canonical | 478 | * Takes a filename and package name, returning (in "try") the canonical | |
222 | * "preserve" name for it. | 479 | * "preserve" name for it. | |
223 | */ | 480 | */ | |
224 | Boolean | 481 | Boolean | |
225 | make_preserve_name(char *try, size_t max, char *name, char *file) | 482 | make_preserve_name(char *try, size_t max, char *name, char *file) | |
226 | { | 483 | { | |
227 | int len, i; | 484 | int len, i; | |
228 | 485 | |||
229 | if ((len = strlen(file)) == 0) | 486 | if ((len = strlen(file)) == 0) | |
230 | return FALSE; | 487 | return FALSE; | |
231 | else | 488 | else | |
232 | i = len - 1; | 489 | i = len - 1; | |
233 | strncpy(try, file, max); | 490 | strncpy(try, file, max); | |
@@ -242,26 +499,117 @@ make_preserve_name(char *try, size_t max | @@ -242,26 +499,117 @@ make_preserve_name(char *try, size_t max | |||
242 | } | 499 | } | |
243 | if (!i) { | 500 | if (!i) { | |
244 | try[0] = '.'; | 501 | try[0] = '.'; | |
245 | strncpy(try + 1, file, max - 1); | 502 | strncpy(try + 1, file, max - 1); | |
246 | } | 503 | } | |
247 | /* I should probably be called rude names for these inline assignments */ | 504 | /* I should probably be called rude names for these inline assignments */ | |
248 | strncat(try, ".", max -= strlen(try)); | 505 | strncat(try, ".", max -= strlen(try)); | |
249 | strncat(try, name, max -= strlen(name)); | 506 | strncat(try, name, max -= strlen(name)); | |
250 | strncat(try, ".", max--); | 507 | strncat(try, ".", max--); | |
251 | strncat(try, "backup", max -= 6); | 508 | strncat(try, "backup", max -= 6); | |
252 | return TRUE; | 509 | return TRUE; | |
253 | } | 510 | } | |
254 | 511 | |||
512 | /* | |||
513 | * Write the contents of "str" to a file | |||
514 | */ | |||
515 | void | |||
516 | write_file(char *name, char *str) | |||
517 | { | |||
518 | size_t len; | |||
519 | FILE *fp; | |||
520 | ||||
521 | if ((fp = fopen(name, "w")) == (FILE *) NULL) { | |||
522 | cleanup(0); | |||
523 | errx(2, "cannot fopen '%s' for writing", name); | |||
524 | } | |||
525 | len = strlen(str); | |||
526 | if (fwrite(str, 1, len, fp) != len) { | |||
527 | cleanup(0); | |||
528 | errx(2, "short fwrite on '%s', tried to write %ld bytes", | |||
529 | name, (long) len); | |||
530 | } | |||
531 | if (fclose(fp)) { | |||
532 | cleanup(0); | |||
533 | errx(2, "failure to fclose '%s'", name); | |||
534 | } | |||
535 | } | |||
536 | ||||
537 | void | |||
538 | copy_file(char *dir, char *fname, char *to) | |||
539 | { | |||
540 | char fpath[MaxPathSize]; | |||
541 | ||||
542 | (void) snprintf(fpath, sizeof(fpath), "%s%s%s", | |||
543 | (fname[0] != '/') ? dir : "", | |||
544 | (fname[0] != '/') ? "/" : "", | |||
545 | fname); | |||
546 | if (fexec("cp", "-r", fpath, to, NULL)) { | |||
547 | cleanup(0); | |||
548 | errx(2, "could not perform 'cp -r %s %s'", fpath, to); | |||
549 | } | |||
550 | } | |||
551 | ||||
552 | void | |||
553 | move_file(char *dir, char *fname, char *to) | |||
554 | { | |||
555 | char fpath[MaxPathSize]; | |||
556 | ||||
557 | (void) snprintf(fpath, sizeof(fpath), "%s%s%s", | |||
558 | (fname[0] != '/') ? dir : "", | |||
559 | (fname[0] != '/') ? "/" : "", | |||
560 | fname); | |||
561 | if (fexec("mv", fpath, to, NULL)) { | |||
562 | cleanup(0); | |||
563 | errx(2, "could not perform 'mv %s %s'", fpath, to); | |||
564 | } | |||
565 | } | |||
566 | ||||
567 | void | |||
568 | move_files(const char *dir, const char *pattern, const char *to) | |||
569 | { | |||
570 | char fpath[MaxPathSize]; | |||
571 | glob_t globbed; | |||
572 | size_t i; | |||
573 | ||||
574 | (void) snprintf(fpath, sizeof(fpath), "%s/%s", dir, pattern); | |||
575 | if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) { | |||
576 | switch(i) { | |||
577 | case GLOB_NOMATCH: | |||
578 | warn("no files matching ``%s'' found", fpath); | |||
579 | break; | |||
580 | case GLOB_ABORTED: | |||
581 | warn("globbing aborted"); | |||
582 | break; | |||
583 | case GLOB_NOSPACE: | |||
584 | warn("out-of-memory during globbing"); | |||
585 | break; | |||
586 | default: | |||
587 | warn("unknown error during globbing"); | |||
588 | break; | |||
589 | } | |||
590 | return; | |||
591 | } | |||
592 | ||||
593 | /* Moving globbed files -- we just use mv(1) to do the job */ | |||
594 | for (i=0; i<globbed.gl_pathc; i++) | |||
595 | if (fexec("mv", globbed.gl_pathv[i], to, NULL)) { | |||
596 | cleanup(0); | |||
597 | errx(2, "could not perform 'mv %s %s'", globbed.gl_pathv[i], to); | |||
598 | } | |||
599 | ||||
600 | return; | |||
601 | } | |||
602 | ||||
255 | void | 603 | void | |
256 | remove_files(const char *path, const char *pattern) | 604 | remove_files(const char *path, const char *pattern) | |
257 | { | 605 | { | |
258 | char fpath[MaxPathSize]; | 606 | char fpath[MaxPathSize]; | |
259 | glob_t globbed; | 607 | glob_t globbed; | |
260 | int i; | 608 | int i; | |
261 | 609 | |||
262 | (void) snprintf(fpath, sizeof(fpath), "%s/%s", path, pattern); | 610 | (void) snprintf(fpath, sizeof(fpath), "%s/%s", path, pattern); | |
263 | if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) { | 611 | if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) { | |
264 | switch(i) { | 612 | switch(i) { | |
265 | case GLOB_NOMATCH: | 613 | case GLOB_NOMATCH: | |
266 | warn("no files matching ``%s'' found", fpath); | 614 | warn("no files matching ``%s'' found", fpath); | |
267 | break; | 615 | break; | |
@@ -277,47 +625,115 @@ remove_files(const char *path, const cha | @@ -277,47 +625,115 @@ remove_files(const char *path, const cha | |||
277 | } | 625 | } | |
278 | return; | 626 | return; | |
279 | } | 627 | } | |
280 | 628 | |||
281 | /* deleting globbed files */ | 629 | /* deleting globbed files */ | |
282 | for (i=0; i<globbed.gl_pathc; i++) | 630 | for (i=0; i<globbed.gl_pathc; i++) | |
283 | if (unlink(globbed.gl_pathv[i]) < 0) | 631 | if (unlink(globbed.gl_pathv[i]) < 0) | |
284 | warn("can't delete ``%s''", globbed.gl_pathv[i]); | 632 | warn("can't delete ``%s''", globbed.gl_pathv[i]); | |
285 | 633 | |||
286 | return; | 634 | return; | |
287 | } | 635 | } | |
288 | 636 | |||
289 | /* | 637 | /* | |
638 | * Unpack a tar file | |||
639 | */ | |||
640 | int | |||
641 | unpack(const char *pkg, const lfile_head_t *filesp) | |||
642 | { | |||
643 | const char *decompress_cmd = NULL; | |||
644 | const char *suf; | |||
645 | int count = 0; | |||
646 | lfile_t *lfp; | |||
647 | char **up_argv; | |||
648 | int up_argc = 7; | |||
649 | int i = 0; | |||
650 | int result; | |||
651 | ||||
652 | if (filesp != NULL) | |||
653 | TAILQ_FOREACH(lfp, filesp, lf_link) | |||
654 | count++; | |||
655 | up_argc += count; | |||
656 | up_argv = malloc((count + up_argc + 1) * sizeof(char *)); | |||
657 | if (!IS_STDIN(pkg)) { | |||
658 | suf = suffix_of(pkg); | |||
659 | if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2")) | |||
660 | decompress_cmd = BZIP2_CMD; | |||
661 | else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz")) | |||
662 | decompress_cmd = GZIP_CMD; | |||
663 | else if (!strcmp(suf, "tar")) | |||
664 | ; /* do nothing */ | |||
665 | else | |||
666 | errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg); | |||
667 | } else | |||
668 | decompress_cmd = GZIP_CMD; | |||
669 | ||||
670 | up_argv[i] = (char *)strrchr(TAR_CMD, '/'); | |||
671 | if (up_argv[i] == NULL) | |||
672 | up_argv[i] = TAR_CMD; | |||
673 | else | |||
674 | up_argv[i]++; /* skip / character */ | |||
675 | if (count > 0) | |||
676 | up_argv[++i] = "--fast-read"; | |||
677 | if (decompress_cmd != NULL) { | |||
678 | up_argv[++i] = "--use-compress-program"; | |||
679 | up_argv[++i] = (char *)decompress_cmd; | |||
680 | } | |||
681 | up_argv[++i] = "-xpf"; | |||
682 | up_argv[++i] = (char *)pkg; | |||
683 | if (count > 0) | |||
684 | TAILQ_FOREACH(lfp, filesp, lf_link) | |||
685 | up_argv[++i] = lfp->lf_name; | |||
686 | up_argv[++i] = NULL; | |||
687 | ||||
688 | if (Verbose) { | |||
689 | printf("running: %s", TAR_CMD); | |||
690 | for (i = 1; up_argv[i] != NULL; i++) | |||
691 | printf(" %s", up_argv[i]); | |||
692 | printf("\n"); | |||
693 | } | |||
694 | ||||
695 | result = pfcexec(NULL, TAR_CMD, (const char **)up_argv); | |||
696 | free(up_argv); | |||
697 | if (result != 0) { | |||
698 | warnx("extract of %s failed", pkg); | |||
699 | return 1; | |||
700 | } | |||
701 | ||||
702 | return 0; | |||
703 | } | |||
704 | ||||
705 | /* | |||
290 | * Using fmt, replace all instances of: | 706 | * Using fmt, replace all instances of: | |
291 | * | 707 | * | |
292 | * %F With the parameter "name" | 708 | * %F With the parameter "name" | |
293 | * %D With the parameter "dir" | 709 | * %D With the parameter "dir" | |
294 | * %B Return the directory part ("base") of %D/%F | 710 | * %B Return the directory part ("base") of %D/%F | |
295 | * %f Return the filename part of %D/%F | 711 | * %f Return the filename part of %D/%F | |
296 | * | 712 | * | |
297 | * Check that no overflows can occur. | 713 | * Check that no overflows can occur. | |
298 | */ | 714 | */ | |
299 | int | 715 | void | |
300 | format_cmd(char *buf, size_t size, const char *fmt, const char *dir, const char *name) | 716 | format_cmd(char *buf, size_t size, char *fmt, char *dir, char *name) | |
301 | { | 717 | { | |
302 | char scratch[MaxPathSize * 2]; | 718 | char scratch[MaxPathSize * 2]; | |
303 | char *bufp; | 719 | char *bufp; | |
304 | char *cp; | 720 | char *cp; | |
305 | 721 | |||
306 | for (bufp = buf; (int) (bufp - buf) < size && *fmt;) { | 722 | for (bufp = buf; (int) (bufp - buf) < size && *fmt;) { | |
307 | if (*fmt == '%') { | 723 | if (*fmt == '%') { | |
308 | if (*++fmt != 'D' && name == NULL) { | 724 | if (*++fmt != 'D' && name == NULL) { | |
309 | warnx("no last file available for '%s' command", buf); | 725 | cleanup(0); | |
310 | return -1; | 726 | errx(2, "no last file available for '%s' command", buf); | |
311 | } | 727 | } | |
312 | switch (*fmt) { | 728 | switch (*fmt) { | |
313 | case 'F': | 729 | case 'F': | |
314 | strlcpy(bufp, name, size - (int) (bufp - buf)); | 730 | strlcpy(bufp, name, size - (int) (bufp - buf)); | |
315 | bufp += strlen(bufp); | 731 | bufp += strlen(bufp); | |
316 | break; | 732 | break; | |
317 | 733 | |||
318 | case 'D': | 734 | case 'D': | |
319 | strlcpy(bufp, dir, size - (int) (bufp - buf)); | 735 | strlcpy(bufp, dir, size - (int) (bufp - buf)); | |
320 | bufp += strlen(bufp); | 736 | bufp += strlen(bufp); | |
321 | break; | 737 | break; | |
322 | 738 | |||
323 | case 'B': | 739 | case 'B': | |
@@ -342,15 +758,14 @@ format_cmd(char *buf, size_t size, const | @@ -342,15 +758,14 @@ format_cmd(char *buf, size_t size, const | |||
342 | break; | 758 | break; | |
343 | 759 | |||
344 | default: | 760 | default: | |
345 | *bufp++ = '%'; | 761 | *bufp++ = '%'; | |
346 | *bufp++ = *fmt; | 762 | *bufp++ = *fmt; | |
347 | break; | 763 | break; | |
348 | } | 764 | } | |
349 | ++fmt; | 765 | ++fmt; | |
350 | } else { | 766 | } else { | |
351 | *bufp++ = *fmt++; | 767 | *bufp++ = *fmt++; | |
352 | } | 768 | } | |
353 | } | 769 | } | |
354 | *bufp = '\0'; | 770 | *bufp = '\0'; | |
355 | return 0; | |||
356 | } | 771 | } |
/* $NetBSD: ftpio.c,v 1.28 2008/04/26 17:40:01 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#ifndef lint
__RCSID("$NetBSD: ftpio.c,v 1.28 2008/04/26 17:40:01 joerg Exp $");
#endif
/*-
* Copyright (c) 1999-2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Hubert Feyrer <hubert@feyrer.de> and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_REGEX_H
#include <regex.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_TERMCAP_H
#include <termcap.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "../lib/lib.h"
/*
* Names of environment variables used to pass things to
* subprocesses, for connection caching.
*/
#define PKG_FTPIO_COMMAND "PKG_FTPIO_COMMAND"
#define PKG_FTPIO_ANSWER "PKG_FTPIO_ANSWER"
#define PKG_FTPIO_CNT "PKG_FTPIO_CNT"
#define PKG_FTPIO_CURRENTHOST "PKG_FTPIO_CURRENTHOST"
#define PKG_FTPIO_CURRENTDIR "PKG_FTPIO_CURRENTDIR"
#undef STANDALONE /* define for standalone debugging */
/* File descriptors */
typedef struct {
int command;
int answer;
} fds;
static int needclose=0;
static int ftp_started=0;
static fds ftpio;
static int ftp_pid;
static char term[1024];
static char bold_on[1024];
static char bold_off[1024];
static char *ftp_expand_URL(const char *, char *);
static int hexvalue(char);
static char *http_expand_URL(const char *, char *);
static int http_extract_fn(char *, char *, size_t);
static void URL_decode(char *);
/*
* expect "str" (a regular expression) on file descriptor "fd", storing
* the FTP return code of the command in the integer "ftprc". The "str"
* string is expected to match some FTP return codes after a '\n', e.g.
* "\n(550|226).*\n"
*/
static int
expect(int fd, const char *str, int *ftprc)
{
int rc;
char buf[256];
regex_t rstr;
int done;
struct pollfd set[1];
int retval;
regmatch_t match;
int verbose_expect=0;
if (regcomp(&rstr, str, REG_EXTENDED) != 0)
err(EXIT_FAILURE, "expect: regcomp() failed");
memset(buf, '\n', sizeof(buf));
done=0;
retval=0;
set[0].fd = fd;
set[0].events = POLLIN;
while(!done) {
rc = poll(set, 1, 60*60*1000); /* seconds until next message from tar */
switch (rc) {
case -1:
if (errno == EINTR)
break;
warn("expect: poll() failed (probably ftp died because of bad args)");
done = 1;
retval = -1;
break;
case 0:
warnx("expect: poll() timeout");
/* need to send ftp coprocess SIGINT to make it stop
* downloading into dir that we'll blow away in a second */
kill(ftp_pid, SIGINT);
/* Wait until ftp coprocess is responsive again
* XXX Entering recursion here!
*/
rc = ftp_cmd("cd .\n", "\n(550|250).*\n");
if (rc != 250) {
/* now we have a really good reason to bail out ;) */
}
/* ftp is at command prompt again, and will wait for our
* next command. If we were downloading, we can now safely
* continue and remove the dir that the tar command was
* expanding to */
done = 1; /* hope that's ok */
retval = -1;
break;
default:
if (set[0].revents & POLLHUP) {
done = 1;
retval = -1;
break;
}
rc = read(fd, &buf[sizeof(buf) - 1], 1);
if (rc <= 0) {
done = 1;
retval = -1;
break;
}
if (verbose_expect)
putchar(buf[sizeof(buf)-1]);
if (regexec(&rstr, buf, 1, &match, 0) == 0) {
if (ftprc && isdigit((unsigned char)buf[match.rm_so+1]))
*ftprc = atoi(buf+match.rm_so+1);
done=1;
retval=0;
}
memmove(buf, buf+1, sizeof(buf)-1); /* yes, this is non-performant */
break;
}
}
return retval;
}
/*
* send a certain ftp-command "cmd" to our FTP coprocess, and wait for
* "expectstr" to be returned. Return numeric FTP return code or -1
* in case of an error (usually expect() timeout)
*/
int
ftp_cmd(const char *cmd, const char *expectstr)
{
int rc=0, verbose_ftp=0;
int len;
if (Verbose)
verbose_ftp=1;
if (verbose_ftp)
fprintf(stderr, "\n%sftp> %s%s", bold_on, cmd, bold_off);
fflush(stdout);
len = write(ftpio.command, cmd, strlen(cmd));
if (len == strlen(cmd)) {
if (expectstr) {
/* set "rc" to the FTP error code: */
if (expect(ftpio.answer, expectstr, &rc) == -1)
rc = -1; /* some error occurred */
}
} else {
if (Verbose)
warn("short write");
}
return rc;
}
/*
* Really fire up FTP coprocess
*/
static int
setupCoproc(const char *base)
{
int command_pipe[2];
int answer_pipe[2];
int rc1, rc2;
char buf[20];
char *argv0 = (char *)strrchr(FTP_CMD, '/');
if (argv0 == NULL)
argv0 = FTP_CMD;
else
argv0++;
rc1 = pipe(command_pipe);
rc2 = pipe(answer_pipe);
if(rc1==-1 || rc2==-1) {
warn("setupCoproc: pipe() failed");
return -1;
}
if (command_pipe[0] == -1 || command_pipe[1] == -1 ||
answer_pipe[0] == -1 || answer_pipe[1] == -1 ) {
warn("setupCoproc: pipe() returned bogus descriptor");
return -1;
}
rc1 = fork();
switch (rc1) {
case -1:
/* Error */
warn("setupCoproc: fork() failed");
return -1;
break;
case 0:
/* Child */
(void) close(command_pipe[1]);
rc1 = dup2(command_pipe[0], 0);
if (rc1 == -1) {
err(EXIT_FAILURE, "setupCoproc: dup2 failed (command_pipe[0])");
}
(void) close(command_pipe[0]);
(void) close(answer_pipe[0]);
rc1 = dup2(answer_pipe[1], 1);
if (rc1 == -1) {
err(EXIT_FAILURE, "setupCoproc: dup2 failed (answer_pipe[1])");
}
(void) close(answer_pipe[1]);
setbuf(stdout, NULL);
if (Verbose)
fprintf(stderr, "%sftp -detv %s%s\n", bold_on, base, bold_off);
rc1 = execlp(FTP_CMD, argv0, "-detv", base, NULL);
warn("setupCoproc: execlp() failed");
exit(1);
break;
default:
/* Parent */
(void) close(command_pipe[0]);
(void) close(answer_pipe[1]);
(void) snprintf(buf, sizeof(buf), "%d", command_pipe[1]);
setenv(PKG_FTPIO_COMMAND, buf, 1);
(void) snprintf(buf, sizeof(buf), "%d", answer_pipe[0]);
setenv(PKG_FTPIO_ANSWER, buf, 1);
ftpio.command = command_pipe[1];
ftpio.answer = answer_pipe[0];
ftp_pid = rc1; /* to ^C transfers */
fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
break;
}
return 0;
}
/*
* Dummy signal handler to detect if the ftp(1) coprocess or
* and of the processes of the tar/gzip pipeline dies.
*/
static void
sigchld_handler (int n)
{
/* Make poll(2) return EINTR */
}
/*
* SIGPIPE only happens when there's something wrong with the FTP
* coprocess. In that case, set mark to not try to close shut down
* the coprocess.
*/
static void
sigpipe_handler(int n)
{
/* aparently our ftp companion died */
if (Verbose)
fprintf(stderr, "SIGPIPE!\n");
needclose = 0;
}
/*
* Close the FTP coprocess' current connection, but
* keep the process itself alive.
*/
void
ftp_stop(void)
{
#if defined(__svr4__) && defined(__sun__)
char env[BUFSIZ];
#endif
const char *tmp1, *tmp2;
if (!ftp_started)
return;
tmp1=getenv(PKG_FTPIO_COMMAND);
tmp2=getenv(PKG_FTPIO_ANSWER);
/* (Only) the last one closes the link */
if (tmp1 != NULL && tmp2 != NULL) {
if (needclose)
ftp_cmd("close\n", "\n(221 .*|Not connected.)\n");
(void) close(ftpio.command);
(void) close(ftpio.answer);
}
#if defined(__svr4__) && defined(__sun__)
(void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_COMMAND);
putenv(env);
(void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_ANSWER);
putenv(env);
#else
unsetenv(PKG_FTPIO_COMMAND);
unsetenv(PKG_FTPIO_ANSWER);
#endif
}
/*
* (Start and re-)Connect the FTP coprocess to some host/dir.
* If the requested host/dir is different than the one that the
* coprocess is currently at, close first.
*/
int
ftp_start(const char *base)
{
const char *tmp1, *tmp2;
char *p;
int rc;
char newHost[MAXHOSTNAMELEN];
const char *newDir;
const char *currentHost=getenv(PKG_FTPIO_CURRENTHOST);
const char *currentDir=getenv(PKG_FTPIO_CURRENTDIR);
int urllen;
/* talk to termcap for bold on/off escape sequences */
if (getenv("TERM") != NULL && tgetent(term, getenv("TERM")) > 0) {
p = bold_on; tgetstr("md", &p);
p = bold_off; tgetstr("me", &p);
} else {
bold_on[0] = '\0';
bold_off[0] = '\0';
}
fileURLHost(base, newHost, sizeof(newHost));
urllen = URLlength(base);
if (urllen < 0 || !(newDir = strchr(base + URLlength(base), '/')))
errx(EXIT_FAILURE, "ftp_start: bad URL '%s'", base);
newDir++;
if (currentHost
&& currentDir
&& ( strcmp(newHost, currentHost) != 0
|| strcmp(newDir, currentDir) != 0)) { /* could handle new dir case better here, w/o reconnect */
if (Verbose) {
printf("ftp_start: new host or dir, stopping previous connect...\n");
printf("currentHost='%s', newHost='%s'\n", currentHost, newHost);
printf("currentDir='%s', newDir='%s'\n", currentDir, newDir);
}
ftp_stop();
if (Verbose)
printf("ftp stopped\n");
}
setenv(PKG_FTPIO_CURRENTHOST, newHost, 1); /* need to update this in the environment */
setenv(PKG_FTPIO_CURRENTDIR, newDir, 1); /* for subprocesses to have this available */
tmp1=getenv(PKG_FTPIO_COMMAND);
tmp2=getenv(PKG_FTPIO_ANSWER);
if(tmp1==NULL || tmp2==NULL || *tmp1=='\0' || *tmp2=='\0') {
/* no FTP coprocess running yet */
if (Verbose)
printf("Spawning FTP coprocess\n");
rc = setupCoproc(base);
if (rc == -1) {
warnx("setupCoproc() failed");
return -1;
}
needclose=1;
signal(SIGPIPE, sigpipe_handler);
signal(SIGCHLD, sigchld_handler);
if ((expect(ftpio.answer, "\n(221|250|221|550).*\n", &rc) != 0)
|| rc != 250) {
warnx("expect1 failed, rc=%d", rc);
return -1;
}
/* nbftp now issues a CWD for each part of the path
* and will return a code for each of them. No idea how to
* deal with that other than to issue a 'prompt off' to
* get something that we can wait for and that does NOT
* look like a CWD command's output */
rc = ftp_cmd("prompt off\n", "\n(Interactive mode off|221).*\n");
if ((rc == 221) || (rc == -1)) {
/* something is wrong */
ftp_started=1; /* not really, but for ftp_stop() */
ftp_stop();
warnx("prompt failed - wrong dir?");
return -1;
}
ftp_started=1;
} else {
/* get FDs of our coprocess */
ftpio.command = dup(atoi(tmp1));
if (ftpio.command == -1 ) {
warnx("command dup() failed, increase 'descriptors' limit");
return -1;
}
ftpio.answer = dup(atoi(tmp2));
if (ftpio.answer == -1 ) {
warnx("answer dup() failed, increase 'descriptors' limit");
return -1;
}
if (Verbose)
printf("Reusing FDs %s/%s for communication to FTP coprocess\n", tmp1, tmp2);
fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
}
return 0;
}
/*
* Expand the given wildcard URL "wildcardurl" if possible, and store the
* expanded value into "expandedurl". return 0 if successful, -1 else.
*/
int
expandURL(char *expandedurl, const char *wildcardurl)
{
char *pattern;
char *bestmatch;
char base[MaxPathSize];
pattern=strrchr(wildcardurl, '/');
if (pattern == NULL){
warnx("expandURL: no '/' in URL %s?!", wildcardurl);
return -1;
}
if (pattern-strchr(wildcardurl, '/') < 2) {
/* only one or two slashes in total */
warnx("expandURL: not enough '/' in URL %s", wildcardurl);
return -1;
}
(void) snprintf(base, sizeof(base), "%.*s/",
(int)(pattern-wildcardurl), wildcardurl);
pattern++;
if (strncmp(wildcardurl, "ftp://", 6) == 0)
bestmatch=ftp_expand_URL(base, pattern);
else if (strncmp(wildcardurl, "http://", 7) == 0)
bestmatch=http_expand_URL(base, pattern);
else {
warnx("expandURL: unknown protocol in URL `%s'", wildcardurl);
return -1;
}
/* no match found */
if (bestmatch == NULL)
return -1;
snprintf(expandedurl, MaxPathSize, "%s%s", base, bestmatch);
if (Verbose)
printf("best match: '%s'\n", expandedurl);
return 0;
}
/* for a given wildcard ftp:// URL, find the best matching pkg */
static char *
ftp_expand_URL(const char *base, char *pattern)
{
char *s, buf[MaxPathSize];
char tmpname[MaxPathSize];
char best[MaxPathSize];
char s_best[MaxPathSize];
int rc, got_list, tfd, retry_tbz;
retry_tbz = 0;
best[0]='\0';
s_best[0]='\0';
rc = ftp_start(base);
if (rc == -1) {
warnx("ftp_start() failed");
return NULL;
}
strlcpy(tmpname, "/var/tmp/pkg.XXXXXX", sizeof(tmpname));
tfd=mkstemp(tmpname);
if (tfd == -1) {
warnx("Cannot generate temp file for ftp(1)'s nlist output");
return NULL;
}
close(tfd); /* We don't need the file descriptor, but will use
the file in a second */
s=strpbrk(pattern, "<>[]?*{"); /* Could leave out "[]?*" here;
* ftp(1) is not that stupid */
if (!s) {
/* This should only happen when getting here with (only) a package
* name specified to pkg_add, and PKG_PATH containing some URL.
*/
(void) snprintf(buf, sizeof(buf), "nlist %s %s\n", pattern, tmpname);
} else {
/* replace possible version(wildcard) given with "-*".
* we can't use the pkg wildcards here as dewey compare
* and alternates won't be handled by ftp(1); sort
* out later, using pkg_match() */
if (retry_tbz) {
retry_with_tbz:
(void) snprintf(buf, sizeof(buf), "nlist %.*s*.tbz %s\n",
(int)(s-pattern), pattern, tmpname);
retry_tbz = 0;
} else {
(void) snprintf(buf, sizeof(buf), "nlist %.*s*.tgz %s\n",
(int)(s-pattern), pattern, tmpname);
retry_tbz = 1;
}
}
rc = ftp_cmd(buf, "\n(550|450|226).*\n"); /* catch errors */
if (rc != 226)
got_list = 0;
else
got_list = 1;
/* Sync - don't remove */
rc = ftp_cmd("cd .\n", "\n(550|250|257).*\n");
if (rc != 250) {
warnx("chdir failed!");
unlink(tmpname); /* remove clutter */
return NULL;
}
if (got_list == 1 && access(tmpname, R_OK)==0) {
FILE *f;
char filename[MaxPathSize];
f=fopen(tmpname, "r");
if (f == NULL) {
warn("fopen");
unlink(tmpname); /* remove clutter */
return NULL;
}
/* The following loop is basically the same as the readdir() loop
* in findmatchingname() */
while (fgets(filename, sizeof(filename), f)) {
/*
* We need to strip off any .t[bg]z etc.
* suffix here
*/
char s_filename[MaxPathSize];
char s_pattern[MaxPathSize];
filename[strlen(filename)-1] = '\0';
strip_txz(s_filename, NULL, filename);
strip_txz(s_pattern, NULL, pattern);
if (pkg_order(s_pattern, s_filename,
s_best[0] != '\0' ? s_best : NULL) == 1) {
strlcpy(s_best, s_filename, sizeof(s_best));
strlcpy(best, filename, sizeof(best));
}
}
(void) fclose(f);
}
if (retry_tbz)
goto retry_with_tbz;
if (best[0] == '\0' && Verbose)
warnx("nothing appropriate found");
unlink(tmpname);
if (best[0] == '\0')
return NULL;
return strdup(best);
}
/* for a given wildcard http:// URL, find the best matching pkg */
static char *
http_expand_URL(const char *base, char *pattern)
{
char best[MaxPathSize];
char s_best[MaxPathSize];
char line[BUFSIZ];
char filename[MaxPathSize];
FILE *fp;
int pipefds[2];
int state;
pid_t pid;
*best = '\0';
*s_best = '\0';
/* Set up a pipe for getting the file list */
if (pipe(pipefds) == -1) {
warnx("cannot create pipe");
return NULL;
}
if ((pid = fork()) == -1) {
warnx("cannot fork ftp process");
return NULL;
}
if (pid == 0) { /* The child */
if (dup2(pipefds[1], STDOUT_FILENO) == -1) {
warnx("dup2 failed before starting ftp");
_exit(2);
}
close(pipefds[0]);
close(pipefds[1]);
/* get URL contents to stdout and thus to parent,
* silently */
execlp("ftp", "ftp", "-V", "-o", "-", base, NULL);
warnx("failed to execute ftp");
_exit(2);
}
/* parent */
close(pipefds[1]);
if ((fp=fdopen(pipefds[0], "r")) == NULL)
warn("can't fdopen pipe end");
else {
char s_pattern[MaxPathSize];
int len, offset;
/* strip of .t[bg]z for comparison */
strip_txz(s_pattern, NULL, pattern);
/* initialize http_extract_fn internal state */
http_extract_fn(NULL, NULL, 0);
/* read line from HTTP output and extract filenames */
while (fgets(line, sizeof(line), fp) != NULL) {
len = offset = 0;
while ((len=http_extract_fn(line+offset, filename,
sizeof(filename))) > 0) {
char s_filename[MaxPathSize];
offset += len;
strip_txz(s_filename, NULL, filename);
if (pkg_order(s_pattern, s_filename,
*s_best != '\0' ? s_best : NULL) == 1) {
strlcpy(best, filename, sizeof(best));
strlcpy(s_best, s_filename, sizeof(best));
}
}
}
}
fclose(fp);
/* wait for child to exit */
if (waitpid(pid, &state, 0) < 0) {
/* error has been reported by child */
return NULL;
}
if (best[0] == '\0') {
if (Verbose)
warnx("nothing appropriate found");
return NULL;
}
return strdup(best);
}
enum http_states {
ST_NONE,
ST_LT, ST_LTA, ST_TAGA, ST_H, ST_R, ST_E, ST_F, ST_HREF,
ST_TAG, ST_TAGAX
};
/* return any hrefs found */
static int
http_extract_fn(char *input, char *outbuf, size_t outbuflen)
{
/* partial copied hrefs from previous calls are saved here */
static char tempbuf[MaxPathSize];
/* fill state of tempbuf */
static int tempbuffill = 0;
/* parsing state information */
static enum http_states state;
/* currently in double quotes (in parsing) */
static int dqflag;
char p;
int offset, found;
if (outbuf == NULL) {
/* init */
dqflag = tempbuffill = 0;
state = ST_NONE;
return 0;
}
offset = 0;
found = 0;
while ((p=input[offset++]) != '\0') {
/* handle anything that's inside double quotes */
if (dqflag) {
/* incomplete href */
if (state == ST_HREF) {
/* check if space left in output
* buffer */
if (tempbuffill >= sizeof(tempbuf)) {
warnx("href starting with `%.*s'"
" too long", 60, tempbuf);
/* ignore remainder */
tempbuffill = 0;
/* need space before "href"
* can start again (invalidly,
* of course, but we don't
* care) */
state = ST_TAGAX;
}
/* href complete */
if (p == '\"') {
/* complete */
dqflag = 0;
tempbuf[tempbuffill++] = '\0';
/* need space before "href"
* can start again (invalidly,
* of course, but we don't
* care) */
state = ST_TAGAX;
found = 1;
break;
} else {
/* copy one more char */
tempbuf[tempbuffill++] = p;
}
} else {
/* leaving double quotes */
if (p == '\"')
dqflag = 0;
}
continue;
}
/*
* entering double quotes? (only relevant inside a tag)
*/
if (state != ST_NONE && p == '\"') {
dqflag = 1;
continue;
}
/* other cases */
switch (state) {
case ST_NONE:
/* plain text, not in markup */
if (p == '<')
state = ST_LT;
break;
case ST_LT:
/* in tag -- "<" already found */
if (p == '>')
state = ST_NONE;
else if (p == 'a' || p == 'A')
state = ST_LTA;
else if (!isspace((unsigned char)p))
state = ST_TAG;
break;
case ST_LTA:
/* in tag -- "<a" already found */
if (p == '>')
state = ST_NONE;
else if (isspace((unsigned char)p))
state = ST_TAGA;
else
state = ST_TAG;
break;
case ST_TAG:
/* in tag, but not "<a" -- disregard */
if (p == '>')
state = ST_NONE;
break;
case ST_TAGA:
/* in a-tag -- "<a " already found */
if (p == '>')
state = ST_NONE;
else if (p == 'h' || p == 'H')
state = ST_H;
else if (!isspace((unsigned char)p))
state = ST_TAGAX;
break;
case ST_TAGAX:
/* in unknown keyword in a-tag */
if (p == '>')
state = ST_NONE;
else if (isspace((unsigned char)p))
state = ST_TAGA;
break;
case ST_H:
/* in a-tag -- "<a h" already found */
if (p == '>')
state = ST_NONE;
else if (p == 'r' || p == 'R')
state = ST_R;
else if (isspace((unsigned char)p))
state = ST_TAGA;
else
state = ST_TAGAX;
break;
case ST_R:
/* in a-tag -- "<a hr" already found */
if (p == '>')
state = ST_NONE;
else if (p == 'e' || p == 'E')
state = ST_E;
else if (isspace((unsigned char)p))
state = ST_TAGA;
else
state = ST_TAGAX;
break;
case ST_E:
/* in a-tag -- "<a hre" already found */
if (p == '>')
state = ST_NONE;
else if (p == 'f' || p == 'F')
state = ST_F;
else if (isspace((unsigned char)p))
state = ST_TAGA;
else
state = ST_TAGAX;
break;
case ST_F:
/* in a-tag -- "<a href" already found */
if (p == '>')
state = ST_NONE;
else if (p == '=')
state = ST_HREF;
else if (!isspace((unsigned char)p))
state = ST_TAGAX;
break;
case ST_HREF:
/* in a-tag -- "<a href=" already found */
/* XXX: handle missing double quotes? */
if (p == '>')
state = ST_NONE;
/* skip spaces before URL */
else if (!isspace((unsigned char)p))
state = ST_TAGA;
break;
/* no default case by purpose */
}
}
if (p == '\0')
return -1;
if (found) {
char *q;
URL_decode(tempbuf);
/* strip path (XXX) */
if ((q=strrchr(tempbuf, '/')) == NULL)
q = tempbuf;
(void)strlcpy(outbuf, q, outbuflen);
tempbuffill = 0;
}
return offset;
}
static int
hexvalue(char p)
{
if (p >= '0' && p <= '9')
return (p-'0');
else if (p >= 'a' && p <= 'f')
return (p-'a'+10);
else if (p >= 'A' && p <= 'F')
return (p-'A'+10);
else
return -1;
}
/* fetch and extract URL url into directory path */
static int
http_fetch(const char *url, const char *path)
{
int pipefds[2];
int stateftp, state;
pid_t pidftp, pid;
/* Set up a pipe for passing the fetched contents. */
if (pipe(pipefds) == -1) {
warn("cannot create pipe");
return -1;
}
/* fork ftp child */
if ((pidftp = fork()) == -1) {
warn("cannot fork process for ftp");
return -1;
}
if (pidftp == 0) {
/* child */
if (dup2(pipefds[1], STDOUT_FILENO) == -1) {
warn("dup2 failed before executing ftp");
_exit(2);
}
close(pipefds[0]);
close(pipefds[1]);
execlp(FTP_CMD, FTP_CMD, "-o", "-", url, NULL);
warnx("failed to execute ftp");
_exit(2);
}
/* fork unpack child */
if ((pid = fork()) == -1) {
warn("cannot fork unpack process");
return -1;
}
if (pid == 0) {
/* child */
if (dup2(pipefds[0], STDIN_FILENO) == -1) {
warn("dup2 failed before unpack");
_exit(2);
}
close(pipefds[0]);
close(pipefds[1]);
if ((path != NULL) && (chdir(path) < 0))
_exit(127);
if (unpack("-", NULL) != 0) {
warnx("unpack failed");
_exit(2);
}
_exit(0);
}
close(pipefds[0]);
close(pipefds[1]);
/* wait for unpack to exit */
while (waitpid(pid, &state, 0) < 0) {
if (errno != EINTR) {
(void)waitpid(pidftp, &stateftp, 0);
return -1;
}
}
while (waitpid(pidftp, &stateftp, 0) < 0) {
if (errno != EINTR) {
return -1;
}
}
if (!WIFEXITED(state) || !WIFEXITED(stateftp))
return -1;
if (WEXITSTATUS(state) != 0 || WEXITSTATUS(stateftp) != 0)
return -1;
return 0;
}
static void
URL_decode(char *URL)
{
char *in, *out;
in = out = URL;
while (*in != '\0') {
if (in[0] == '%' && in[1] != '\0' && in[2] != '\0') {
/* URL-decode character */
if (hexvalue(in[1]) != -1 && hexvalue(in[2]) != -1) {
*out++ = hexvalue(in[1])*16+hexvalue(in[2]);
}
/* skip invalid encoded signs too */
in += 3;
}
else
*out++ = *in++;
}
*out = '\0';
return;
}
/*
* extract the given (expanded) URL "url" to the given directory "dir"
* return -1 on error, 0 else;
*/
int
unpackURL(const char *url, const char *dir)
{
char *pkg;
int rc;
char base[MaxPathSize];
char pkg_path[MaxPathSize];
{
/* Verify if the URL is really ok */
char expnd[MaxPathSize];
rc=expandURL(expnd, url);
if (rc == -1) {
warnx("unpackURL: verification expandURL failed");
return -1;
}
if (strcmp(expnd, url) != 0) {
warnx("unpackURL: verification expandURL failed, '%s'!='%s'",
expnd, url);
return -1;
}
}
pkg=strrchr(url, '/');
if (pkg == NULL){
warnx("unpackURL: no '/' in URL %s?!", url);
return -1;
}
(void) snprintf(base, sizeof(base), "%.*s/", (int)(pkg-url), url);
(void) snprintf(pkg_path, sizeof(pkg_path), "%.*s",
(int)(pkg-url), url); /* no trailing '/' */
pkg++;
/* Leave a hint for any depending pkgs that may need it */
if (getenv("PKG_PATH") == NULL) {
setenv("PKG_PATH", pkg_path, 1);
#if 0
path_create(pkg_path); /* XXX */
#endif
if (Verbose)
printf("setenv PKG_PATH='%s'\n", pkg_path);
}
if (strncmp(url, "http://", 7) == 0)
return http_fetch(url, dir);
rc = ftp_start(base);
if (rc == -1) {
warnx("ftp_start() failed");
return -1; /* error */
}
{
char cmd[1024];
const char *decompress_cmd = NULL;
const char *suf;
if (Verbose)
printf("unpackURL '%s' to '%s'\n", url, dir);
suf = suffix_of(pkg);
if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2"))
decompress_cmd = BZIP2_CMD;
else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz"))
decompress_cmd = GZIP_CMD;
else if (!strcmp(suf, "tar"))
; /* do nothing */
else
errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg);
/* yes, this is gross, but needed for borken ftp(1) */
(void) snprintf(cmd, sizeof(cmd), "get %s \"| ( cd %s; " TAR_CMD " %s %s -vvxp -f - | tee %s )\"\n",
pkg, dir,
decompress_cmd != NULL ? "--use-compress-program" : "",
decompress_cmd != NULL ? decompress_cmd : "",
Verbose ? "/dev/stderr" : "/dev/null");
rc = ftp_cmd(cmd, "\n(226|550).*\n");
if (rc != 226) {
warnx("Cannot fetch file (%d!=226)!", rc);
return -1;
}
}
return 0;
}
#ifdef STANDALONE
static void
usage(void)
{
errx(EXIT_FAILURE, "Usage: foo [-v] ftp://-pattern");
}
int
main(int argc, char *argv[])
{
int rc, ch;
char *argv0 = argv[0];
while ((ch = getopt(argc, argv, "v")) != -1) {
switch (ch) {
case 'v':
Verbose=1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc<1)
usage();
while(argv[0] != NULL) {
char newurl[MaxPathSize];
printf("Expand %s:\n", argv[0]);
rc = expandURL(newurl, argv[0]);
if (rc==-1)
warnx("Cannot expand %s", argv[0]);
else
printf("Expanded URL: %s\n", newurl);
/* test out connection caching */
if (1) {
char *s, buf[MaxPathSize];
if ((s=getenv(PKG_FTPIO_CNT)) && atoi(s)>0){
(void) snprintf(buf, sizeof(buf),"%d", atoi(s)-1);
setenv(PKG_FTPIO_CNT, buf, 1);
printf("%s>>> %s -v %s\n", s, argv0, argv[0]);
fexec(argv0, "-v", argv[0], NULL);
}
}
printf("\n\n\n");
argv++;
}
ftp_stop();
return 0;
}
void
cleanup(int i)
{
}
#endif /* STANDALONE */
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: lib.h,v 1.43 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: lib.h,v 1.44 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | /* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */ | 3 | /* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */ | |
4 | 4 | |||
5 | /* | 5 | /* | |
6 | * FreeBSD install - a package for the installation and maintainance | 6 | * FreeBSD install - a package for the installation and maintainance | |
7 | * of non-core utilities. | 7 | * of non-core utilities. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -76,38 +76,68 @@ | @@ -76,38 +76,68 @@ | |||
76 | 76 | |||
77 | #ifndef FALSE | 77 | #ifndef FALSE | |
78 | #define FALSE (0) | 78 | #define FALSE (0) | |
79 | #endif | 79 | #endif | |
80 | 80 | |||
81 | #ifndef OPSYS_NAME | 81 | #ifndef OPSYS_NAME | |
82 | #define OPSYS_NAME "NetBSD" | 82 | #define OPSYS_NAME "NetBSD" | |
83 | #endif | 83 | #endif | |
84 | 84 | |||
85 | #ifndef DEF_UMASK | 85 | #ifndef DEF_UMASK | |
86 | #define DEF_UMASK 022 | 86 | #define DEF_UMASK 022 | |
87 | #endif | 87 | #endif | |
88 | 88 | |||
89 | #define MKDIR_CMD "mkdir" | |||
90 | ||||
91 | /* Usually "rm", but often "echo" during debugging! */ | 89 | /* Usually "rm", but often "echo" during debugging! */ | |
92 | #define REMOVE_CMD "rm" | 90 | #define REMOVE_CMD "rm" | |
93 | 91 | |||
94 | /* Usually "rm", but often "echo" during debugging! */ | 92 | /* Usually "rm", but often "echo" during debugging! */ | |
95 | #define RMDIR_CMD "rmdir" | 93 | #define RMDIR_CMD "rmdir" | |
96 | 94 | |||
95 | /* Define tar as a string, in case it's called gtar or something */ | |||
96 | #ifndef TAR_CMD | |||
97 | #define TAR_CMD "tar" | |||
98 | #endif | |||
99 | ||||
100 | /* Define pax as a string, used to copy files from staging area */ | |||
101 | #ifndef PAX_CMD | |||
102 | #define PAX_CMD "pax" | |||
103 | #endif | |||
104 | ||||
105 | /* Define gzip and bzip2, used to unpack binary packages */ | |||
106 | #ifndef GZIP_CMD | |||
107 | #define GZIP_CMD "gzip" | |||
108 | #endif | |||
109 | ||||
110 | #ifndef BZIP2_CMD | |||
111 | #define BZIP2_CMD "bzip2" | |||
112 | #endif | |||
113 | ||||
114 | /* Define ftp as a string, in case the ftp client is called something else */ | |||
115 | #ifndef FTP_CMD | |||
116 | #define FTP_CMD "ftp" | |||
117 | #endif | |||
118 | ||||
119 | #ifndef CHOWN_CMD | |||
120 | #define CHOWN_CMD "chown" | |||
121 | #endif | |||
122 | ||||
97 | #ifndef CHMOD_CMD | 123 | #ifndef CHMOD_CMD | |
98 | #define CHMOD_CMD "chmod" | 124 | #define CHMOD_CMD "chmod" | |
99 | #endif | 125 | #endif | |
100 | 126 | |||
127 | #ifndef CHGRP_CMD | |||
128 | #define CHGRP_CMD "chgrp" | |||
129 | #endif | |||
130 | ||||
101 | /* some operating systems don't have this */ | 131 | /* some operating systems don't have this */ | |
102 | #ifndef MAXPATHLEN | 132 | #ifndef MAXPATHLEN | |
103 | #define MAXPATHLEN 1024 | 133 | #define MAXPATHLEN 1024 | |
104 | #endif | 134 | #endif | |
105 | 135 | |||
106 | enum { | 136 | enum { | |
107 | MaxPathSize = MAXPATHLEN | 137 | MaxPathSize = MAXPATHLEN | |
108 | }; | 138 | }; | |
109 | 139 | |||
110 | /* The names of our "special" files */ | 140 | /* The names of our "special" files */ | |
111 | #define CONTENTS_FNAME "+CONTENTS" | 141 | #define CONTENTS_FNAME "+CONTENTS" | |
112 | #define COMMENT_FNAME "+COMMENT" | 142 | #define COMMENT_FNAME "+COMMENT" | |
113 | #define DESC_FNAME "+DESC" | 143 | #define DESC_FNAME "+DESC" | |
@@ -118,28 +148,33 @@ enum { | @@ -118,28 +148,33 @@ enum { | |||
118 | #define MTREE_FNAME "+MTREE_DIRS" | 148 | #define MTREE_FNAME "+MTREE_DIRS" | |
119 | #define BUILD_VERSION_FNAME "+BUILD_VERSION" | 149 | #define BUILD_VERSION_FNAME "+BUILD_VERSION" | |
120 | #define BUILD_INFO_FNAME "+BUILD_INFO" | 150 | #define BUILD_INFO_FNAME "+BUILD_INFO" | |
121 | #define INSTALLED_INFO_FNAME "+INSTALLED_INFO" | 151 | #define INSTALLED_INFO_FNAME "+INSTALLED_INFO" | |
122 | #define SIZE_PKG_FNAME "+SIZE_PKG" | 152 | #define SIZE_PKG_FNAME "+SIZE_PKG" | |
123 | #define SIZE_ALL_FNAME "+SIZE_ALL" | 153 | #define SIZE_ALL_FNAME "+SIZE_ALL" | |
124 | #define PRESERVE_FNAME "+PRESERVE" | 154 | #define PRESERVE_FNAME "+PRESERVE" | |
125 | #define VIEWS_FNAME "+VIEWS" | 155 | #define VIEWS_FNAME "+VIEWS" | |
126 | #define DEPOT_FNAME "+DEPOT" | 156 | #define DEPOT_FNAME "+DEPOT" | |
127 | 157 | |||
128 | /* The names of special variables */ | 158 | /* The names of special variables */ | |
129 | #define AUTOMATIC_VARNAME "automatic" | 159 | #define AUTOMATIC_VARNAME "automatic" | |
130 | 160 | |||
131 | /* Prefix for extended PLIST cmd */ | 161 | /* | |
132 | #define CMD_CHAR '@' | 162 | * files which we expect to be in every package, passed to | |
163 | * tar --fast-read. | |||
164 | */ | |||
165 | #define ALL_FNAMES CONTENTS_FNAME" "COMMENT_FNAME" "DESC_FNAME" "MTREE_FNAME" "BUILD_VERSION_FNAME" "BUILD_INFO_FNAME" "SIZE_PKG_FNAME" "SIZE_ALL_FNAME | |||
166 | ||||
167 | #define CMD_CHAR '@' /* prefix for extended PLIST cmd */ | |||
133 | 168 | |||
134 | /* The name of the "prefix" environment variable given to scripts */ | 169 | /* The name of the "prefix" environment variable given to scripts */ | |
135 | #define PKG_PREFIX_VNAME "PKG_PREFIX" | 170 | #define PKG_PREFIX_VNAME "PKG_PREFIX" | |
136 | 171 | |||
137 | /* | 172 | /* | |
138 | * The name of the "metadatadir" environment variable given to scripts. | 173 | * The name of the "metadatadir" environment variable given to scripts. | |
139 | * This variable holds the location of the +-files for this package. | 174 | * This variable holds the location of the +-files for this package. | |
140 | */ | 175 | */ | |
141 | #define PKG_METADATA_DIR_VNAME "PKG_METADATA_DIR" | 176 | #define PKG_METADATA_DIR_VNAME "PKG_METADATA_DIR" | |
142 | 177 | |||
143 | /* | 178 | /* | |
144 | * The name of the environment variable holding the location to the | 179 | * The name of the environment variable holding the location to the | |
145 | * reference-counts database directory. | 180 | * reference-counts database directory. | |
@@ -228,108 +263,143 @@ typedef struct _lfile_head_t lfile_head_ | @@ -228,108 +263,143 @@ typedef struct _lfile_head_t lfile_head_ | |||
228 | lfp = malloc(sizeof(lfile_t)); \ | 263 | lfp = malloc(sizeof(lfile_t)); \ | |
229 | lfp->lf_name = str; \ | 264 | lfp->lf_name = str; \ | |
230 | TAILQ_INSERT_TAIL(lfhead,lfp,lf_link); \ | 265 | TAILQ_INSERT_TAIL(lfhead,lfp,lf_link); \ | |
231 | } while(0) | 266 | } while(0) | |
232 | 267 | |||
233 | /* List of packages */ | 268 | /* List of packages */ | |
234 | typedef struct _lpkg_t { | 269 | typedef struct _lpkg_t { | |
235 | TAILQ_ENTRY(_lpkg_t) lp_link; | 270 | TAILQ_ENTRY(_lpkg_t) lp_link; | |
236 | char *lp_name; | 271 | char *lp_name; | |
237 | } lpkg_t; | 272 | } lpkg_t; | |
238 | TAILQ_HEAD(_lpkg_head_t, _lpkg_t); | 273 | TAILQ_HEAD(_lpkg_head_t, _lpkg_t); | |
239 | typedef struct _lpkg_head_t lpkg_head_t; | 274 | typedef struct _lpkg_head_t lpkg_head_t; | |
240 | 275 | |||
276 | /* This structure describes a pipe to a child process */ | |||
277 | typedef struct { | |||
278 | int fds[2]; /* pipe, 0=child stdin, 1=parent output */ | |||
279 | FILE *fp; /* output from parent process */ | |||
280 | pid_t pid; /* process id of child process */ | |||
281 | void (*cleanup)(void); /* called on non-zero child exit status */ | |||
282 | } pipe_to_system_t; | |||
283 | ||||
241 | struct pkg_vulnerabilities { | 284 | struct pkg_vulnerabilities { | |
242 | size_t entries; | 285 | size_t entries; | |
243 | char **vulnerability; | 286 | char **vulnerability; | |
244 | char **classification; | 287 | char **classification; | |
245 | char **advisory; | 288 | char **advisory; | |
246 | }; | 289 | }; | |
247 | 290 | |||
248 | /* If URLlength()>0, then there is a ftp:// or http:// in the string, | 291 | /* If URLlength()>0, then there is a ftp:// or http:// in the string, | |
249 | * and this must be an URL. Hide this behind a more obvious name. */ | 292 | * and this must be an URL. Hide this behind a more obvious name. */ | |
250 | #define IS_URL(str) (URLlength(str) > 0) | 293 | #define IS_URL(str) (URLlength(str) > 0) | |
251 | 294 | |||
252 | #define IS_STDIN(str) ((str) != NULL && !strcmp((str), "-")) | 295 | #define IS_STDIN(str) ((str) != NULL && !strcmp((str), "-")) | |
253 | #define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/') | 296 | #define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/') | |
254 | 297 | |||
255 | /* Conflict handling (conflicts.c) */ | 298 | /* Conflict handling (conflicts.c) */ | |
256 | int some_installed_package_conflicts_with(const char *, const char *, char **, char **); | 299 | int some_installed_package_conflicts_with(const char *, char **, char **); | |
257 | 300 | |||
258 | 301 | |||
259 | /* Prototypes */ | 302 | /* Prototypes */ | |
260 | /* Misc */ | 303 | /* Misc */ | |
261 | void cleanup(int); | 304 | void cleanup(int); | |
305 | char *make_playpen(char *, size_t, size_t); | |||
306 | char *where_playpen(void); | |||
307 | void leave_playpen(char *); | |||
308 | uint64_t min_free(const char *); | |||
309 | void save_dirs(char **, char **); | |||
310 | void restore_dirs(char *, char *); | |||
262 | void show_version(void); | 311 | void show_version(void); | |
263 | int fexec(const char *, ...); | 312 | int fexec(const char *, ...); | |
264 | int fexec_skipempty(const char *, ...); | 313 | int fexec_skipempty(const char *, ...); | |
265 | int fcexec(const char *, const char *, ...); | 314 | int fcexec(const char *, const char *, ...); | |
266 | int pfcexec(const char *, const char *, const char **); | 315 | int pfcexec(const char *, const char *, const char **); | |
316 | pipe_to_system_t *pipe_to_system_begin(const char *, char *const *, void (*)(void)); | |||
317 | int pipe_to_system_end(pipe_to_system_t *); | |||
267 | 318 | |||
268 | /* variables file handling */ | 319 | /* variables file handling */ | |
269 | 320 | |||
270 | char *var_get(const char *, const char *); | 321 | char *var_get(const char *, const char *); | |
271 | char *var_get_memory(const char *, const char *); | 322 | char *var_get_memory(const char *, const char *); | |
272 | int var_set(const char *, const char *, const char *); | 323 | int var_set(const char *, const char *, const char *); | |
273 | int var_copy_list(const char *, const char **); | 324 | int var_copy_list(const char *, const char **); | |
274 | 325 | |||
275 | /* automatically installed as dependency */ | 326 | /* automatically installed as dependency */ | |
276 | 327 | |||
277 | Boolean is_automatic_installed(const char *); | 328 | Boolean is_automatic_installed(const char *); | |
278 | int mark_as_automatic_installed(const char *, int); | 329 | int mark_as_automatic_installed(const char *, int); | |
279 | 330 | |||
280 | /* String */ | 331 | /* String */ | |
281 | const char *basename_of(const char *); | 332 | const char *basename_of(const char *); | |
282 | const char *dirname_of(const char *); | 333 | const char *dirname_of(const char *); | |
283 | const char *suffix_of(const char *); | 334 | const char *suffix_of(const char *); | |
284 | int pkg_match(const char *, const char *); | 335 | int pkg_match(const char *, const char *); | |
285 | int pkg_order(const char *, const char *, const char *); | 336 | int pkg_order(const char *, const char *, const char *); | |
286 | int ispkgpattern(const char *); | 337 | int ispkgpattern(const char *); | |
338 | void strip_txz(char *, char *, const char *); | |||
287 | 339 | |||
288 | /* Iterator functions */ | 340 | /* Iterator functions */ | |
289 | int iterate_pkg_generic_src(int (*)(const char *, void *), void *, | 341 | int iterate_pkg_generic_src(int (*)(const char *, void *), void *, | |
290 | const char *(*)(void *),void *); | 342 | const char *(*)(void *),void *); | |
291 | int iterate_local_pkg_dir(const char *, int, int, int (*)(const char *, void *), | 343 | int iterate_local_pkg_dir(const char *, int, int, int (*)(const char *, void *), | |
292 | void *); | 344 | void *); | |
293 | int iterate_pkg_db(int (*)(const char *, void *), void *); | 345 | int iterate_pkg_db(int (*)(const char *, void *), void *); | |
294 | 346 | |||
295 | int add_installed_pkgs_by_basename(const char *, lpkg_head_t *); | 347 | int add_installed_pkgs_by_basename(const char *, lpkg_head_t *); | |
296 | int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *); | 348 | int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *); | |
297 | char *find_best_matching_installed_pkg(const char *); | 349 | char *find_best_matching_installed_pkg(const char *); | |
298 | char *find_best_matching_file(const char *, const char *, int, int); | 350 | char *find_best_matching_file(const char *, const char *, int, int); | |
299 | int match_installed_pkgs(const char *, int (*)(const char *, void *), void *); | 351 | int match_installed_pkgs(const char *, int (*)(const char *, void *), void *); | |
300 | int match_local_files(const char *, int, int, const char *, int (*cb)(const char *, void *), void *); | 352 | int match_local_files(const char *, int, int, const char *, int (*cb)(const char *, void *), void *); | |
301 | 353 | |||
302 | /* File */ | 354 | /* File */ | |
303 | Boolean fexists(const char *); | 355 | Boolean fexists(const char *); | |
304 | Boolean isdir(const char *); | 356 | Boolean isdir(const char *); | |
305 | Boolean islinktodir(const char *); | 357 | Boolean islinktodir(const char *); | |
306 | Boolean isemptydir(const char *); | 358 | Boolean isemptydir(const char *); | |
307 | Boolean isemptyfile(const char *); | 359 | Boolean isemptyfile(const char *); | |
308 | Boolean isfile(const char *); | 360 | Boolean isfile(const char *); | |
309 | Boolean isbrokenlink(const char *); | 361 | Boolean isbrokenlink(const char *); | |
310 | Boolean isempty(const char *); | 362 | Boolean isempty(const char *); | |
311 | int URLlength(const char *); | 363 | int URLlength(const char *); | |
364 | char *fileGetURL(const char *); | |||
365 | const char *fileURLFilename(const char *, char *, int); | |||
366 | const char *fileURLHost(const char *, char *, int); | |||
367 | char *fileFindByPath(const char *); | |||
368 | char *fileGetContents(char *); | |||
312 | Boolean make_preserve_name(char *, size_t, char *, char *); | 369 | Boolean make_preserve_name(char *, size_t, char *, char *); | |
370 | void write_file(char *, char *); | |||
371 | void copy_file(char *, char *, char *); | |||
372 | void move_file(char *, char *, char *); | |||
373 | void move_files(const char *, const char *, const char *); | |||
313 | void remove_files(const char *, const char *); | 374 | void remove_files(const char *, const char *); | |
314 | int delete_hierarchy(char *, Boolean, Boolean); | 375 | int delete_hierarchy(char *, Boolean, Boolean); | |
315 | int format_cmd(char *, size_t, const char *, const char *, const char *); | 376 | int unpack(const char *, const lfile_head_t *); | |
377 | void format_cmd(char *, size_t, char *, char *, char *); | |||
378 | ||||
379 | /* ftpio.c: FTP handling */ | |||
380 | int expandURL(char *, const char *); | |||
381 | int unpackURL(const char *, const char *); | |||
382 | int ftp_cmd(const char *, const char *); | |||
383 | int ftp_start(const char *); | |||
384 | void ftp_stop(void); | |||
316 | 385 | |||
317 | /* pkg_io.c: Local and remote archive handling */ | 386 | /* pkg_io.c: Local and remote archive handling */ | |
318 | struct archive; | 387 | struct archive; | |
319 | 388 | |||
320 | struct archive *open_archive(const char *, void **); | 389 | struct archive *open_remote_archive(const char *, void **); | |
321 | void close_archive(void *); | 390 | void close_remote_archive(void *); | |
322 | struct archive *find_archive(const char *, void **); | 391 | struct archive *open_local_archive(const char *, void **); | |
392 | void close_local_archive(void *); | |||
323 | 393 | |||
324 | /* Packing list */ | 394 | /* Packing list */ | |
325 | plist_t *new_plist_entry(void); | 395 | plist_t *new_plist_entry(void); | |
326 | plist_t *last_plist(package_t *); | 396 | plist_t *last_plist(package_t *); | |
327 | plist_t *find_plist(package_t *, pl_ent_t); | 397 | plist_t *find_plist(package_t *, pl_ent_t); | |
328 | char *find_plist_option(package_t *, char *); | 398 | char *find_plist_option(package_t *, char *); | |
329 | void plist_delete(package_t *, Boolean, pl_ent_t, char *); | 399 | void plist_delete(package_t *, Boolean, pl_ent_t, char *); | |
330 | void free_plist(package_t *); | 400 | void free_plist(package_t *); | |
331 | void mark_plist(package_t *); | 401 | void mark_plist(package_t *); | |
332 | void csum_plist_entry(char *, plist_t *); | 402 | void csum_plist_entry(char *, plist_t *); | |
333 | void add_plist(package_t *, pl_ent_t, const char *); | 403 | void add_plist(package_t *, pl_ent_t, const char *); | |
334 | void add_plist_top(package_t *, pl_ent_t, const char *); | 404 | void add_plist_top(package_t *, pl_ent_t, const char *); | |
335 | void delete_plist(package_t *, Boolean, pl_ent_t, char *); | 405 | void delete_plist(package_t *, Boolean, pl_ent_t, char *); |
/* $NetBSD: pen.c,v 1.24 2008/04/26 17:40:01 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: pen.c,v 1.25 1997/10/08 07:48:12 charnier Exp";
#else
__RCSID("$NetBSD: pen.c,v 1.24 2008/04/26 17:40:01 joerg Exp $");
#endif
#endif
/*
* FreeBSD install - a package for the installation and maintainance
* of non-core utilities.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Jordan K. Hubbard
* 18 July 1993
*
* Routines for managing the "play pen".
*
*/
#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#if HAVE_SYS_SIGNAL_H
#include <sys/signal.h>
#endif
/* For keeping track of where we are */
static char Current[MaxPathSize];
static char Previous[MaxPathSize];
static int CurrentSet; /* rm -fr Current only if it's really set! */
/* CurrentSet is set to 0 before strcpy()s
* to prevent rm'ing of a partial string
* when interrupted by ^C */
char *
where_playpen(void)
{
return Current;
}
/*
* Find a good place to play.
*/
static char *
find_play_pen(char *pen, size_t pensize, size_t sz)
{
const char **cp;
struct stat sb;
char *r;
const char *tmpdir[] = {
"PKG_TMPDIR",
"TMPDIR",
"/var/tmp",
"/tmp",
"/usr/tmp",
NULL
};
if (pen == NULL) {
cleanup(0);
errx(2, "find_play_pen(): 'pen' variable is NULL\n"
"(this should not happen, please report!)");
return NULL;
}
if (pen[0] && (r = strrchr(pen, '/')) != NULL) {
*r = '\0';
if (stat(pen, &sb) != FAIL && (min_free(pen) >= sz)) {
*r = '/';
return pen;
}
}
for (cp = tmpdir; *cp; cp++) {
const char *d = (**cp == '/') ? *cp : getenv(*cp);
if (d == NULL || stat(d, &sb) == FAIL || min_free(d) < sz)
continue;
(void)snprintf(pen, pensize, "%s/instmp.XXXXXX", d);
return pen;
}
cleanup(0);
errx(2, "Can't find enough temporary space to extract the files.\n"
"Please set your PKG_TMPDIR environment variable to a location "
"with at least %zu bytes free", sz);
return NULL;
}
/*
* Make a temporary directory to play in and chdir() to it, returning
* pathname of previous working directory.
*/
char *
make_playpen(char *pen, size_t pensize, size_t sz)
{
if (!find_play_pen(pen, pensize, sz))
return NULL;
if (!mkdtemp(pen)) {
cleanup(0);
errx(2, "can't mkdtemp '%s'", pen);
}
/*
* On at least NetBSD, the temporary directory may have a group
* that isn't in the group list of the current user. In that
* case, it is impossible to extract setgid binaries from the
* package, since chmod(2) doesn't allow to set the S_ISGID bit
* for a group that isn't yours.
*/
(void)chown(pen, -1, getegid());
if (Verbose) {
if (sz)
fprintf(stderr,
"Requested space: %lu bytes, free space: %lld bytes in %s\n",
(u_long) sz, (long long) min_free(pen), pen);
}
if (min_free(pen) < sz) {
rmdir(pen);
cleanup(0);
errx(2, "not enough free space to create '%s'.\n"
"Please set your PKG_TMPDIR environment variable to a location\n"
"with more space and\ntry the command again", pen);
}
if (Current[0])
strlcpy(Previous, Current, sizeof(Previous));
else if (!getcwd(Previous, MaxPathSize)) {
cleanup(0);
err(EXIT_FAILURE, "fatal error during execution: getcwd");
}
if (chdir(pen) == FAIL) {
cleanup(0);
errx(2, "can't chdir to '%s'", pen);
}
CurrentSet = 0; strlcpy(Current, pen, sizeof(Current)); CurrentSet = 1;
return Previous;
}
/*
* Convenience routine for getting out of playpen
*/
void
leave_playpen(char *save)
{
void (*oldsig) (int);
/* Make us interruptable while we're cleaning up - just in case... */
oldsig = signal(SIGINT, SIG_DFL);
if (Previous[0] && chdir(Previous) == FAIL) {
cleanup(0);
errx(2, "can't chdir back to '%s'", Previous);
} else if (CurrentSet && Current[0] && strcmp(Current, Previous)) {
if (strcmp(Current, "/") == 0) {
fprintf(stderr, "PANIC: About to rm -fr / (not doing so, aborting)\n");
abort();
}
if (fexec("rm", "-fr", Current, NULL))
warnx("couldn't remove temporary dir '%s'", Current);
strlcpy(Current, Previous, sizeof(Current));
}
if (save)
strlcpy(Previous, save, sizeof(Previous));
else
Previous[0] = '\0';
signal(SIGINT, oldsig);
}
/*
* Return free disk space (in bytes) on given file system.
* Returns size in a uint64_t since off_t isn't 64 bits on all
* operating systems.
*/
uint64_t
min_free(const char *tmpdir)
{
struct statvfs buf;
if (statvfs(tmpdir, &buf) != 0) {
warn("statvfs");
return 0;
}
return (uint64_t)buf.f_bavail * buf.f_bsize;
}
#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);
}
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: pkg_io.c,v 1.2 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | 3 | * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * | 5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | 8 | * are met: | |
9 | * | 9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in | 13 | * notice, this list of conditions and the following disclaimer in | |
14 | * the documentation and/or other materials provided with the | 14 | * the documentation and/or other materials provided with the | |
@@ -26,243 +26,114 @@ | @@ -26,243 +26,114 @@ | |||
26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
28 | * SUCH DAMAGE. | 28 | * SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #if HAVE_CONFIG_H | 31 | #if HAVE_CONFIG_H | |
32 | #include "config.h" | 32 | #include "config.h" | |
33 | #endif | 33 | #endif | |
34 | #include <nbcompat.h> | 34 | #include <nbcompat.h> | |
35 | #if HAVE_SYS_CDEFS_H | 35 | #if HAVE_SYS_CDEFS_H | |
36 | #include <sys/cdefs.h> | 36 | #include <sys/cdefs.h> | |
37 | #endif | 37 | #endif | |
38 | 38 | |||
39 | __RCSID("$NetBSD: pkg_io.c,v 1.2 2008/04/26 14:56:34 joerg Exp $"); | 39 | __RCSID("$NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $"); | |
40 | 40 | |||
41 | #include <archive.h> | 41 | #include <archive.h> | |
42 | #include <archive_entry.h> | 42 | #include <archive_entry.h> | |
43 | #if HAVE_ERR_H | 43 | #if HAVE_ERR_H | |
44 | #include <err.h> | 44 | #include <err.h> | |
45 | #endif | 45 | #endif | |
46 | #if HAVE_ERRNO_H | 46 | #if HAVE_ERRNO_H | |
47 | #include <errno.h> | 47 | #include <errno.h> | |
48 | #endif | 48 | #endif | |
49 | #include <fetch.h> | 49 | #include <fetch.h> | |
50 | #include <stdlib.h> | 50 | #include <stdlib.h> | |
51 | 51 | |||
52 | #include "lib.h" | 52 | #include "lib.h" | |
53 | 53 | |||
54 | struct fetch_archive { | 54 | struct fetch_archive { | |
55 | struct url *url; | 55 | const char *url; | |
56 | fetchIO *fetch; | 56 | fetchIO *fetch; | |
57 | char buffer[32768]; | 57 | char buffer[32768]; | |
58 | }; | 58 | }; | |
59 | 59 | |||
60 | static int | 60 | static int | |
61 | fetch_archive_open(struct archive *a, void *client_data) | 61 | fetch_archive_open(struct archive *a, void *client_data) | |
62 | { | 62 | { | |
63 | struct fetch_archive *f = client_data; | 63 | struct fetch_archive *f = client_data; | |
64 | 64 | |||
65 | f->fetch = fetchGet(f->url, ""); | 65 | f->fetch = fetchGetURL(f->url, ""); | |
66 | if (f->fetch == NULL) | 66 | if (f->fetch == NULL) | |
67 | return ENOENT; | 67 | return ENOENT; | |
68 | return 0; | 68 | return 0; | |
69 | } | 69 | } | |
70 | 70 | |||
71 | static ssize_t | 71 | static ssize_t | |
72 | fetch_archive_read(struct archive *a, void *client_data, | 72 | fetch_archive_read(struct archive *a, void *client_data, | |
73 | const void **buffer) | 73 | const void **buffer) | |
74 | { | 74 | { | |
75 | struct fetch_archive *f = client_data; | 75 | struct fetch_archive *f = client_data; | |
76 | 76 | |||
77 | *buffer = f->buffer; | 77 | *buffer = f->buffer; | |
78 | return fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer)); | 78 | return fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer)); | |
79 | } | 79 | } | |
80 | 80 | |||
81 | static int | 81 | static int | |
82 | fetch_archive_close(struct archive *a, void *client_data) | 82 | fetch_archive_close(struct archive *a, void *client_data) | |
83 | { | 83 | { | |
84 | struct fetch_archive *f = client_data; | 84 | struct fetch_archive *f = client_data; | |
85 | 85 | |||
86 | if (f->fetch != NULL) | 86 | if (f->fetch != NULL) | |
87 | fetchIO_close(f->fetch); | 87 | fetchIO_close(f->fetch); | |
88 | return 0; | 88 | return 0; | |
89 | } | 89 | } | |
90 | 90 | |||
91 | static struct archive * | 91 | struct archive * | |
92 | open_archive_by_url(struct url *url, void **cookie) | 92 | open_remote_archive(const char *url, void **cookie) | |
93 | { | 93 | { | |
94 | struct fetch_archive *f; | 94 | struct fetch_archive *f; | |
95 | struct archive *a; | 95 | struct archive *archive; | |
96 | 96 | |||
97 | f = malloc(sizeof(*f)); | 97 | f = malloc(sizeof(*f)); | |
98 | if (f == NULL) | 98 | if (f == NULL) | |
99 | err(2, "cannot allocate memory for remote archive"); | 99 | err(2, "cannot allocate memory for remote archive"); | |
100 | f->url = url; | 100 | f->url = url; | |
101 | 101 | |||
102 | a = archive_read_new(); | 102 | archive = archive_read_new(); | |
103 | archive_read_support_compression_all(a); | 103 | archive_read_support_compression_all(archive); | |
104 | archive_read_support_format_all(a); | 104 | archive_read_support_format_all(archive); | |
105 | if (archive_read_open(a, f, fetch_archive_open, fetch_archive_read, | 105 | if (archive_read_open(archive, f, fetch_archive_open, fetch_archive_read, | |
106 | fetch_archive_close)) { | 106 | fetch_archive_close)) | |
107 | archive_read_close(a); | 107 | errx(2, "cannot open archive: %s", archive_error_string(archive)); | |
108 | free(f); | |||
109 | return NULL; | |||
110 | } | |||
111 | 108 | |||
112 | *cookie = f; | 109 | *cookie = f; | |
113 | return a; | |||
114 | } | |||
115 | ||||
116 | struct archive * | |||
117 | open_archive(const char *url, void **cookie) | |||
118 | { | |||
119 | struct url *u; | |||
120 | struct archive *a; | |||
121 | ||||
122 | if (!IS_URL(url)) { | |||
123 | a = archive_read_new(); | |||
124 | archive_read_support_compression_all(a); | |||
125 | archive_read_support_format_all(a); | |||
126 | if (archive_read_open_filename(a, url, 1024)) { | |||
127 | archive_read_close(a); | |||
128 | return NULL; | |||
129 | } | |||
130 | *cookie = NULL; | |||
131 | return a; | |||
132 | } | |||
133 | ||||
134 | if ((u = fetchParseURL(url)) == NULL) | |||
135 | return NULL; | |||
136 | ||||
137 | a = open_archive_by_url(u, cookie); | |||
138 | 110 | |||
139 | fetchFreeURL(u); | 111 | return archive; | |
140 | return a; | |||
141 | } | 112 | } | |
142 | 113 | |||
143 | void | 114 | void | |
144 | close_archive(void *cookie) | 115 | close_remote_archive(void *cookie) | |
145 | { | 116 | { | |
146 | free(cookie); | 117 | free(cookie); | |
147 | } | 118 | } | |
148 | 119 | |||
149 | static int | 120 | struct archive * | |
150 | strip_suffix(char *filename) | 121 | open_local_archive(const char *path, void **cookie) | |
151 | { | 122 | { | |
152 | size_t len; | 123 | struct archive *archive; | |
153 | 124 | |||
154 | len = strlen(filename); | 125 | archive = archive_read_new(); | |
155 | if (len <= 4) | 126 | archive_read_support_compression_all(archive); | |
156 | return 0; | 127 | archive_read_support_format_all(archive); | |
157 | if (strcmp(filename + len - 4, ".tgz") == 0 || | 128 | if (archive_read_open_filename(archive, path, 1024)) | |
158 | strcmp(filename + len - 4, ".tbz") == 0) { | 129 | errx(2, "cannot open archive: %s", | |
159 | filename[len - 4] = '\0'; | 130 | archive_error_string(archive)); | |
160 | return 1; | 131 | *cookie = NULL; | |
161 | } else | |||
162 | return 0; | |||
163 | } | |||
164 | 132 | |||
165 | static int | 133 | return archive; | |
166 | find_best_package(struct url *url, const char *pattern, struct url **best_url) | |||
167 | { | |||
168 | char *cur_match, *best_match = NULL; | |||
169 | struct url_list ue; | |||
170 | size_t i; | |||
171 | ||||
172 | if (*best_url) { | |||
173 | if ((best_match = fetchUnquoteFilename(*best_url)) == NULL) | |||
174 | return -1; | |||
175 | } else | |||
176 | best_match = NULL; | |||
177 | ||||
178 | if (best_match && strip_suffix(best_match) == 0) { | |||
179 | free(best_match); | |||
180 | return -1; | |||
181 | } | |||
182 | ||||
183 | fetchInitURLList(&ue); | |||
184 | if (fetchList(&ue, url, NULL, "")) { | |||
185 | fetchFreeURLList(&ue); | |||
186 | return -1; | |||
187 | } | |||
188 | for (i = 0; i < ue.length; ++i) { | |||
189 | cur_match = fetchUnquoteFilename(ue.urls + i); | |||
190 | ||||
191 | if (cur_match == NULL) { | |||
192 | free(best_match); | |||
193 | fetchFreeURLList(&ue); | |||
194 | return -1; | |||
195 | } | |||
196 | if (strip_suffix(cur_match) == 0) { | |||
197 | free(cur_match); | |||
198 | continue; | |||
199 | } | |||
200 | if (pkg_order(pattern, cur_match, best_match) == 1) { | |||
201 | if (*best_url) | |||
202 | fetchFreeURL(*best_url); | |||
203 | *best_url = fetchCopyURL(ue.urls + i); | |||
204 | free(best_match); | |||
205 | best_match = cur_match; | |||
206 | cur_match = NULL; | |||
207 | if (*best_url == NULL) { | |||
208 | free(best_match); | |||
209 | return -1; | |||
210 | } | |||
211 | } | |||
212 | free(cur_match); | |||
213 | } | |||
214 | free(best_match); | |||
215 | fetchFreeURLList(&ue); | |||
216 | return 0; | |||
217 | } | 134 | } | |
218 | 135 | |||
219 | struct archive * | 136 | void | |
220 | find_archive(const char *fname, void **cookie) | 137 | close_local_archive(void *cookie) | |
221 | { | 138 | { | |
222 | struct archive *a; | |||
223 | struct path *path; | |||
224 | const char *cur_path; | |||
225 | struct url *url, *best_match; | |||
226 | char tmp[MaxPathSize]; | |||
227 | ||||
228 | best_match = NULL; | |||
229 | ||||
230 | a = open_archive(fname, cookie); | |||
231 | if (a != NULL) | |||
232 | return a; | |||
233 | ||||
234 | if (strchr(fname, '/') != NULL) { | |||
235 | const char *last_slash; | |||
236 | ||||
237 | last_slash = strrchr(fname, '/'); | |||
238 | snprintf(tmp, sizeof(tmp), "%s%.*s", | |||
239 | IS_URL(fname) ? "" : "file://", | |||
240 | (int)(last_slash - fname + 1), fname); | |||
241 | url = fetchParseURL(tmp); | |||
242 | if (url == NULL) | |||
243 | return NULL; | |||
244 | fname = last_slash + 1; /* XXX fetchUnquoteFilename */ | |||
245 | find_best_package(url, fname, &best_match); | |||
246 | fetchFreeURL(url); | |||
247 | } else { | |||
248 | TAILQ_FOREACH(path, &PkgPath, pl_entry) { | |||
249 | cur_path = path->pl_path; | |||
250 | if (!IS_URL(cur_path)) { | |||
251 | snprintf(tmp, sizeof(tmp), "file://%s", cur_path); | |||
252 | cur_path = tmp; | |||
253 | } | |||
254 | url = fetchParseURL(cur_path); | |||
255 | if (url == NULL) | |||
256 | continue; | |||
257 | find_best_package(url, fname, &best_match); | |||
258 | /* XXX Check return value and complain */ | |||
259 | fetchFreeURL(url); | |||
260 | } | |||
261 | } | |||
262 | ||||
263 | if (best_match == NULL) | |||
264 | return NULL; | |||
265 | a = open_archive_by_url(best_match, cookie); | |||
266 | fetchFreeURL(best_match); | |||
267 | return a; | |||
268 | } | 139 | } |
@@ -1,27 +1,27 @@ | @@ -1,27 +1,27 @@ | |||
1 | /* $NetBSD: plist.c,v 1.18 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: plist.c,v 1.19 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | #ifndef lint | 10 | #ifndef lint | |
11 | #if 0 | 11 | #if 0 | |
12 | static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp"; | 12 | static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp"; | |
13 | #else | 13 | #else | |
14 | __RCSID("$NetBSD: plist.c,v 1.18 2008/04/26 14:56:34 joerg Exp $"); | 14 | __RCSID("$NetBSD: plist.c,v 1.19 2008/04/26 17:40:01 joerg Exp $"); | |
15 | #endif | 15 | #endif | |
16 | #endif | 16 | #endif | |
17 | 17 | |||
18 | /* | 18 | /* | |
19 | * FreeBSD install - a package for the installation and maintainance | 19 | * FreeBSD install - a package for the installation and maintainance | |
20 | * of non-core utilities. | 20 | * of non-core utilities. | |
21 | * | 21 | * | |
22 | * Redistribution and use in source and binary forms, with or without | 22 | * Redistribution and use in source and binary forms, with or without | |
23 | * modification, are permitted provided that the following conditions | 23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | 24 | * are met: | |
25 | * 1. Redistributions of source code must retain the above copyright | 25 | * 1. Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | 26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must reproduce the above copyright | 27 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -529,27 +529,26 @@ delete_package(Boolean ign_err, Boolean | @@ -529,27 +529,26 @@ delete_package(Boolean ign_err, Boolean | |||
529 | p = p->next; | 529 | p = p->next; | |
530 | break; | 530 | break; | |
531 | 531 | |||
532 | case PLIST_CWD: | 532 | case PLIST_CWD: | |
533 | Where = p->name; | 533 | Where = p->name; | |
534 | if (Verbose) | 534 | if (Verbose) | |
535 | printf("Change working directory to %s\n", Where); | 535 | printf("Change working directory to %s\n", Where); | |
536 | break; | 536 | break; | |
537 | 537 | |||
538 | case PLIST_UNEXEC: | 538 | case PLIST_UNEXEC: | |
539 | if (NoDeleteFiles) | 539 | if (NoDeleteFiles) | |
540 | break; | 540 | break; | |
541 | format_cmd(tmp, sizeof(tmp), p->name, Where, last_file); | 541 | format_cmd(tmp, sizeof(tmp), p->name, Where, last_file); | |
542 | /* XXX cleanup(0); */ | |||
543 | printf("Executing `%s'\n", tmp); | 542 | printf("Executing `%s'\n", tmp); | |
544 | if (!Fake && system(tmp)) { | 543 | if (!Fake && system(tmp)) { | |
545 | warnx("unexec command for `%s' failed", tmp); | 544 | warnx("unexec command for `%s' failed", tmp); | |
546 | fail = FAIL; | 545 | fail = FAIL; | |
547 | } | 546 | } | |
548 | break; | 547 | break; | |
549 | 548 | |||
550 | case PLIST_FILE: | 549 | case PLIST_FILE: | |
551 | last_file = p->name; | 550 | last_file = p->name; | |
552 | (void) snprintf(tmp, sizeof(tmp), "%s/%s", Where, p->name); | 551 | (void) snprintf(tmp, sizeof(tmp), "%s/%s", Where, p->name); | |
553 | if (isdir(tmp)) { | 552 | if (isdir(tmp)) { | |
554 | warnx("attempting to delete directory `%s' as a file\n" | 553 | warnx("attempting to delete directory `%s' as a file\n" | |
555 | "this packing list is incorrect - ignoring delete request", tmp); | 554 | "this packing list is incorrect - ignoring delete request", tmp); |
@@ -1,27 +1,27 @@ | @@ -1,27 +1,27 @@ | |||
1 | /* $NetBSD: str.c,v 1.23 2008/04/26 14:56:34 joerg Exp $ */ | 1 | /* $NetBSD: str.c,v 1.24 2008/04/26 17:40:01 joerg Exp $ */ | |
2 | 2 | |||
3 | #if HAVE_CONFIG_H | 3 | #if HAVE_CONFIG_H | |
4 | #include "config.h" | 4 | #include "config.h" | |
5 | #endif | 5 | #endif | |
6 | #include <nbcompat.h> | 6 | #include <nbcompat.h> | |
7 | #if HAVE_SYS_CDEFS_H | 7 | #if HAVE_SYS_CDEFS_H | |
8 | #include <sys/cdefs.h> | 8 | #include <sys/cdefs.h> | |
9 | #endif | 9 | #endif | |
10 | #ifndef lint | 10 | #ifndef lint | |
11 | #if 0 | 11 | #if 0 | |
12 | static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp"; | 12 | static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp"; | |
13 | #else | 13 | #else | |
14 | __RCSID("$NetBSD: str.c,v 1.23 2008/04/26 14:56:34 joerg Exp $"); | 14 | __RCSID("$NetBSD: str.c,v 1.24 2008/04/26 17:40:01 joerg Exp $"); | |
15 | #endif | 15 | #endif | |
16 | #endif | 16 | #endif | |
17 | 17 | |||
18 | /* | 18 | /* | |
19 | * FreeBSD install - a package for the installation and maintainance | 19 | * FreeBSD install - a package for the installation and maintainance | |
20 | * of non-core utilities. | 20 | * of non-core utilities. | |
21 | * | 21 | * | |
22 | * Redistribution and use in source and binary forms, with or without | 22 | * Redistribution and use in source and binary forms, with or without | |
23 | * modification, are permitted provided that the following conditions | 23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | 24 | * are met: | |
25 | * 1. Redistributions of source code must retain the above copyright | 25 | * 1. Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | 26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must reproduce the above copyright | 27 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -96,13 +96,54 @@ dirname_of(const char *path) | @@ -96,13 +96,54 @@ dirname_of(const char *path) | |||
96 | buf[cc] = 0; | 96 | buf[cc] = 0; | |
97 | return buf; | 97 | return buf; | |
98 | } | 98 | } | |
99 | 99 | |||
100 | /* | 100 | /* | |
101 | * Does the pkgname contain any of the special chars ("{[]?*<>")? | 101 | * Does the pkgname contain any of the special chars ("{[]?*<>")? | |
102 | * If so, return 1, else 0 | 102 | * If so, return 1, else 0 | |
103 | */ | 103 | */ | |
104 | int | 104 | int | |
105 | ispkgpattern(const char *pkg) | 105 | ispkgpattern(const char *pkg) | |
106 | { | 106 | { | |
107 | return strpbrk(pkg, "<>[]?*{") != NULL; | 107 | return strpbrk(pkg, "<>[]?*{") != NULL; | |
108 | } | 108 | } | |
109 | ||||
110 | /* | |||
111 | * Strip off any .tgz, .tbz or .t[bg]z suffix from fname, | |||
112 | * and copy into buffer "buf", the suffix is stored in "sfx" | |||
113 | * if "sfx" is not NULL. If no suffix is found, "sfx" is set | |||
114 | * to an empty string. | |||
115 | */ | |||
116 | void | |||
117 | strip_txz(char *buf, char *sfx, const char *fname) | |||
118 | { | |||
119 | static const char *const suffixes[] = { | |||
120 | ".tgz", ".tbz", ".t[bg]z", 0}; | |||
121 | const char *const *suffixp; | |||
122 | size_t len; | |||
123 | ||||
124 | len = strlen(fname); | |||
125 | assert(len < PKG_PATTERN_MAX); | |||
126 | ||||
127 | if (sfx) | |||
128 | sfx[0] = '\0'; | |||
129 | ||||
130 | for (suffixp = suffixes; *suffixp; suffixp++) { | |||
131 | size_t suffixlen = strlen(*suffixp); | |||
132 | ||||
133 | if (memcmp(&fname[len - suffixlen], *suffixp, suffixlen)) | |||
134 | continue; | |||
135 | ||||
136 | /* matched! */ | |||
137 | memcpy(buf, fname, len - suffixlen); | |||
138 | buf[len - suffixlen] = 0; | |||
139 | if (sfx) { | |||
140 | if (suffixlen >= PKG_SUFFIX_MAX) | |||
141 | errx(EXIT_FAILURE, "too long suffix '%s'", fname); | |||
142 | memcpy(sfx, *suffixp, suffixlen+1); | |||
143 | return; | |||
144 | } | |||
145 | } | |||
146 | ||||
147 | /* not found */ | |||
148 | memcpy(buf, fname, len+1); | |||
149 | } |