Import pkg_install from NetBSD

Change-Id: I9a3071b94dd2e9bfe2e3b162994e06ae10077b5a
This commit is contained in:
Jean-Baptiste Boric 2015-09-11 11:07:35 +02:00 committed by Lionel Sambuc
parent ebfedea0ce
commit a824f5a100
79 changed files with 18408 additions and 1 deletions

View file

@ -2340,6 +2340,7 @@
./usr/man/man1/basename.1 minix-sys ./usr/man/man1/basename.1 minix-sys
./usr/man/man1/bdes.1 minix-sys ./usr/man/man1/bdes.1 minix-sys
./usr/man/man1/bg.1 minix-sys ./usr/man/man1/bg.1 minix-sys
./usr/man/man1/bpm.1 minix-sys
./usr/man/man1/break.1 minix-sys obsolete ./usr/man/man1/break.1 minix-sys obsolete
./usr/man/man1/bsdtar.1 minix-sys ./usr/man/man1/bsdtar.1 minix-sys
./usr/man/man1/bsfilt.1 minix-sys ./usr/man/man1/bsfilt.1 minix-sys
@ -2557,6 +2558,11 @@
./usr/man/man1/pathchk.1 minix-sys ./usr/man/man1/pathchk.1 minix-sys
./usr/man/man1/pax.1 minix-sys ./usr/man/man1/pax.1 minix-sys
./usr/man/man1/ping.1 minix-sys obsolete ./usr/man/man1/ping.1 minix-sys obsolete
./usr/man/man1/pkg_add.1 minix-sys
./usr/man/man1/pkg_admin.1 minix-sys
./usr/man/man1/pkg_create.1 minix-sys
./usr/man/man1/pkg_delete.1 minix-sys
./usr/man/man1/pkg_info.1 minix-sys
./usr/man/man1/pkg_view.1 minix-sys obsolete ./usr/man/man1/pkg_view.1 minix-sys obsolete
./usr/man/man1/playwave.1 minix-sys ./usr/man/man1/playwave.1 minix-sys
./usr/man/man1/popd.1 minix-sys ./usr/man/man1/popd.1 minix-sys
@ -5339,10 +5345,13 @@
./usr/preserve minix-sys ./usr/preserve minix-sys
./usr/run minix-sys ./usr/run minix-sys
./usr/sbin minix-sys ./usr/sbin minix-sys
./usr/sbin/audit-packages minix-sys
./usr/sbin/bpm minix-sys
./usr/sbin/btrace minix-sys ./usr/sbin/btrace minix-sys
./usr/sbin/chown minix-sys ./usr/sbin/chown minix-sys
./usr/sbin/chroot minix-sys ./usr/sbin/chroot minix-sys
./usr/sbin/diskctl minix-sys ./usr/sbin/diskctl minix-sys
./usr/sbin/download-vulnerability-list minix-sys
./usr/sbin/fbdctl minix-sys ./usr/sbin/fbdctl minix-sys
./usr/sbin/group minix-sys ./usr/sbin/group minix-sys
./usr/sbin/groupadd minix-sys ./usr/sbin/groupadd minix-sys
@ -5358,6 +5367,11 @@
./usr/sbin/mkproto minix-sys ./usr/sbin/mkproto minix-sys
./usr/sbin/mtree minix-sys ./usr/sbin/mtree minix-sys
./usr/sbin/newfs_mfs minix-sys ./usr/sbin/newfs_mfs minix-sys
./usr/sbin/pkg_add minix-sys
./usr/sbin/pkg_admin minix-sys
./usr/sbin/pkg_create minix-sys
./usr/sbin/pkg_delete minix-sys
./usr/sbin/pkg_info minix-sys
./usr/sbin/postinstall minix-sys ./usr/sbin/postinstall minix-sys
./usr/sbin/pwd_mkdb minix-sys ./usr/sbin/pwd_mkdb minix-sys
./usr/sbin/rdate minix-sys ./usr/sbin/rdate minix-sys

View file

@ -10,7 +10,7 @@ SUBDIR= byacc fetch file flex less \
SUBDIR+= atf SUBDIR+= atf
.endif .endif
.if (${MKCRYPTO} != "no") .if (${MKCRYPTO} != "no")
#SUBDIR+= pkg_install SUBDIR+= pkg_install
.endif .endif
# IP Filter # IP Filter
.if (${MKIPFILTER} != "no") .if (${MKIPFILTER} != "no")

5
external/bsd/pkg_install/Makefile vendored Normal file
View file

@ -0,0 +1,5 @@
# $NetBSD: Makefile,v 1.1 2008/09/30 19:19:56 joerg Exp $
SUBDIR= lib .WAIT sbin
.include <bsd.subdir.mk>

13
external/bsd/pkg_install/Makefile.inc vendored Normal file
View file

@ -0,0 +1,13 @@
# $NetBSD: Makefile.inc,v 1.4 2011/09/16 16:41:20 joerg Exp $
DIST= ${NETBSDSRCDIR}/external/bsd/pkg_install/dist
USE_FORT?=yes # network client
CPPFLAGS+=-I${DIST}/lib
CPPFLAGS+=-I${NETBSDSRCDIR}/external/bsd/pkg_install/lib
CPPFLAGS+=-DHAVE_CONFIG_H -DNETBSD -DHAVE_SSL
CPPFLAGS+=-DSYSCONFDIR='"/etc"'
WARNS= 4
CWARNFLAGS+= -Wno-missing-noreturn

50
external/bsd/pkg_install/dist/add/add.h vendored Normal file
View file

@ -0,0 +1,50 @@
/* $NetBSD: add.h,v 1.1.1.7 2011/02/18 22:32:27 aymeric Exp $ */
/* from FreeBSD Id: add.h,v 1.8 1997/02/22 16:09:15 peter Exp */
/*
* 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
*
* Include and define various things wanted by the add command.
*
*/
#ifndef _INST_ADD_H_INCLUDE
#define _INST_ADD_H_INCLUDE
extern char *Destdir;
extern char *OverrideMachine;
extern char *Prefix;
extern char *View;
extern char *Viewbase;
extern Boolean NoView;
extern Boolean NoInstall;
extern Boolean NoRecord;
extern Boolean Force;
extern Boolean Automatic;
extern int LicenseCheck;
extern int Replace;
extern int ReplaceSame;
extern Boolean ForceDepends;
extern Boolean ForceDepending;
int make_hierarchy(char *);
void apply_perms(char *, char **, int);
int pkg_perform(lpkg_head_t *);
#endif /* _INST_ADD_H_INCLUDE */

221
external/bsd/pkg_install/dist/add/main.c vendored Normal file
View file

@ -0,0 +1,221 @@
/* $NetBSD: main.c,v 1.1.1.10 2011/02/18 22:32:27 aymeric Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: main.c,v 1.1.1.10 2011/02/18 22:32:27 aymeric Exp $");
/*
*
* 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 add module.
*
*/
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include "lib.h"
#include "add.h"
static char Options[] = "AC:DIK:LP:RVW:fhm:np:t:Uuvw:";
char *Destdir = NULL;
char *OverrideMachine = NULL;
char *Prefix = NULL;
char *View = NULL;
char *Viewbase = NULL;
Boolean NoView = FALSE;
Boolean NoInstall = FALSE;
Boolean NoRecord = FALSE;
Boolean Automatic = FALSE;
Boolean ForceDepends = FALSE;
/*
* Normally, updating fails if the dependencies of a depending package
* are not satisfied by the package to be updated. ForceDepending
* turns that failure into a warning.
*/
Boolean ForceDepending = FALSE;
int LicenseCheck = 0;
int Replace = 0;
int ReplaceSame = 0;
static void
usage(void)
{
(void) fprintf(stderr, "%s\n%s\n%s\n%s\n",
"usage: pkg_add [-AfhILnRuVv] [-C config] [-P destdir] [-K pkg_dbdir]",
" [-m machine] [-p prefix] [-s verification-type",
" [-W viewbase] [-w view]\n",
" [[ftp|http]://[user[:password]@]host[:port]][/path/]pkg-name ...");
exit(1);
}
int
main(int argc, char **argv)
{
int ch, error=0;
lpkg_head_t pkgs;
setprogname(argv[0]);
while ((ch = getopt(argc, argv, Options)) != -1) {
switch (ch) {
case 'A':
Automatic = TRUE;
break;
case 'C':
config_file = optarg;
break;
case 'D':
ForceDepending = TRUE;
break;
case 'P':
Destdir = optarg;
break;
case 'f':
Force = TRUE;
ForceDepends = TRUE;
ForceDepending = TRUE;
break;
case 'I':
NoInstall = TRUE;
break;
case 'K':
pkgdb_set_dir(optarg, 3);
break;
case 'L':
NoView = TRUE;
break;
case 'R':
NoRecord = TRUE;
break;
case 'm':
OverrideMachine = optarg;
break;
case 'n':
Fake = TRUE;
Verbose = TRUE;
break;
case 'p':
Prefix = optarg;
break;
case 'U':
ReplaceSame = 1;
Replace = 1;
break;
case 'u':
Replace = 1;
break;
case 'V':
show_version();
/* NOTREACHED */
case 'v':
Verbose = TRUE;
break;
case 'W':
Viewbase = optarg;
break;
case 'w':
View = optarg;
break;
case 'h':
case '?':
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
pkg_install_config();
if (Destdir != NULL) {
char *pkgdbdir;
pkgdbdir = xasprintf("%s/%s", Destdir, config_pkg_dbdir);
pkgdb_set_dir(pkgdbdir, 4);
free(pkgdbdir);
}
process_pkg_path();
TAILQ_INIT(&pkgs);
if (argc == 0) {
/* If no packages, yelp */
warnx("missing package name(s)");
usage();
}
if (strcasecmp(do_license_check, "no") == 0)
LicenseCheck = 0;
else if (strcasecmp(do_license_check, "yes") == 0)
LicenseCheck = 1;
else if (strcasecmp(do_license_check, "always") == 0)
LicenseCheck = 2;
else
errx(1, "Unknown value of the configuration variable"
"CHECK_LICENSE");
if (LicenseCheck)
load_license_lists();
/* Get all the remaining package names, if any */
for (; argc > 0; --argc, ++argv) {
lpkg_t *lpp;
if (IS_STDIN(*argv))
lpp = alloc_lpkg("-");
else
lpp = alloc_lpkg(*argv);
TAILQ_INSERT_TAIL(&pkgs, lpp, lp_link);
}
error += pkg_perform(&pkgs);
if (error != 0) {
warnx("%d package addition%s failed", error, error == 1 ? "" : "s");
exit(1);
}
exit(0);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,448 @@
.\" $NetBSD: pkg_add.1,v 1.1.1.12 2011/02/18 22:32:28 aymeric Exp $
.\"
.\" FreeBSD install - a package for the installation and maintenance
.\" 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
.\"
.\"
.\" @(#)pkg_add.1
.\"
.Dd June 16, 2010
.Dt PKG_ADD 1
.Os
.Sh NAME
.Nm pkg_add
.Nd a utility for installing and upgrading software package distributions
.Sh SYNOPSIS
.Nm
.Op Fl AfILnRUuVv
.Op Fl C Ar config
.Op Fl K Ar pkg_dbdir
.Op Fl m Ar machine
.Op Fl P Ar destdir
.Op Fl p Ar prefix
.Op Fl W Ar viewbase
.Op Fl w Ar view
.Ar Oo Oo Li ftp|http Oc Ns Li :// Ns Oo Ar user Oc Ns \
Oo Li \&: Ns Ar password Oc \
Ns Li @ Oc Ns Ar host Ns Oo Li \&: Ns Ar port Oc Ns \
Oo Li / Ns Ar path/ Oc Ns Ar pkg-name ...
.Sh DESCRIPTION
The
.Nm
command is used to extract and upgrade packages that have been
previously created with the
.Xr pkg_create 1
command.
Packages are prepared collections of pre-built binaries, documentation,
configurations, installation instructions and/or other files.
.Nm
can recursively install other packages that the current package
depends on or requires from both local disk and via FTP or HTTP.
.Sh WARNING
.Bf -emphasis
Since the
.Nm
command may execute scripts or programs contained within a package file,
your system may be susceptible to
.Dq Trojan horses
or other subtle
attacks from miscreants who create dangerous package files.
.Pp
You are advised to verify the competence and identity of those who
provide installable package files.
For extra protection, use the digital signatures provided where possible
(see the
.Xr pkg_install.conf 5 ) ,
or, failing that, use
.Xr tar 1
to extract the package file, and inspect its contents and scripts
to ensure it poses no danger to your system's integrity.
Pay particular attention to any
.Pa +INSTALL
or
.Pa +DEINSTALL
files, and inspect the
.Pa +CONTENTS
file for
.Cm @cwd ,
.Cm @mode
(check for setuid),
.Cm @dirrm ,
.Cm @exec ,
and
.Cm @unexec
directives, and/or use the
.Xr pkg_info 1
command to examine the package file.
.Ef
.Sh OPTIONS
The following command line arguments are supported:
.Bl -tag -width indent
.It Ar pkg-name [ ... ]
The named packages are installed.
.Nm
will first try to use
.Ar pkg-name
as full URL or path name without any wildcard processing.
If that fails,
.Nm
will try to match packages using wildcard processing.
If that fails as well and
.Ar pkg-name
does not contain any /, the entries of the
.Dv PKG_PATH
variable are searched using the wildcard processing rules.
.It Fl A
Mark package as installed automatically, as dependency of another
package.
You can use
.Dl Ic pkg_admin set automatic=YES
to mark packages this way after installation, and
.Dl Ic pkg_admin unset automatic
to remove the mark.
If you
.Nm
a package without specifying
.Fl A
after it had already been automatically installed, the mark is
removed.
.It Fl C Ar config
Read the configuration file from
.Ar config
instead of the system default.
.It Fl f
Force installation to proceed even if prerequisite packages are not
installed or the install script fails.
Although
.Nm
will still try to find and auto-install missing prerequisite packages,
a failure to find one will not be fatal.
This flag also overrides the fatal error when the operating system or
architecture the package was built on differ from that of the host.
.It Fl D
Force updating even if the dependencies of depending packages are not
satisfied by the new package.
This is used by "make replace", after which one would typically
replace the depending packages.
.It Fl I
If an installation script exists for a given package, do not execute it.
.It Fl K Ar pkg_dbdir
Override the value of the
.Dv PKG_DBDIR
configuration option with the value
.Ar pkg_dbdir .
.It Fl L
Don't add the package to any views after installation.
.It Fl m
Override the machine architecture returned by uname with
.Ar machine .
.It Fl n
Don't actually install a package, just report the steps that
would be taken if it was.
.It Fl P Ar destdir
Prefix all file and directory names with
.Ar destdir .
For packages without install scripts this has the same behavior as
using
.Xr chroot 8 .
.It Fl p Ar prefix
Override the prefix stored in the package with
.Ar prefix .
.It Fl R
Do not record the installation of a package.
This implies
.Fl I .
This means that you cannot deinstall it later, so only use this option if
you know what you are doing!
.It Fl U
Replace an already installed version from a package.
Implies
.Fl u .
.It Fl u
If the package that's being installed is already installed,
an update is performed.
Installed dependent packages are updated recursively, if they are too
old to fulfill the dependencies of the to-be-installed version.
See below for a more detailed description of the process.
.It Fl V
Print version number and exit.
.It Fl v
Turn on verbose output.
.It Fl W Ar viewbase
Passed down to
.Xr pkg_view 1
for managed views.
.It Fl w Ar view
Passed down to
.Xr pkg_view 1
for managed views.
.El
.Pp
One or more
.Ar pkg-name
arguments may be specified, each being either a file containing the
package (these usually ending with the
.Dq .tgz
suffix) or a
URL pointing at a file available on an ftp or web site.
Thus you may extract files directly from their anonymous ftp or WWW
locations (e.g.,
.Nm
ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/i386/3.1_2007Q2/shells/bash-3.2.9.tgz
or
.Nm
http://www.example.org/packages/screen-4.0.tbz).
Note: For ftp transfers, if you wish to use
.Bf -emphasis
passive mode
.Ef
ftp in such transfers, set the variable
.Bf -emphasis
FTP_PASSIVE_MODE
.Ef
to some value in your environment.
Otherwise, the more standard ACTIVE mode may be used.
If
.Nm
consistently fails to fetch a package from a site known to work,
it may be because you have a firewall that demands the usage of
.Bf -emphasis
passive mode
.Ef
ftp.
.Sh TECHNICAL DETAILS
.Nm
extracts each package's meta data (including the
.Dq packing list )
to memory and then runs through the following sequence to fully extract
the contents of the package:
.Bl -enum -offset indent
.It
A check is made to determine if the package or another version of it
is already recorded as installed.
If it is,
installation is terminated if the
.Fl u
or
.Fl U
options are not given.
.Pp
If the same version is installed and
.Fl U
is not given, it is marked as manually installed and process stops.
If the
.Fl u
option is given, it's assumed the package should be replaced by the
new version instead.
Before doing so, all packages that depend on the
pkg being upgraded are checked if they also work with the new version.
If that test is not successful, the dependent packages are updated first.
The replacing is then prepared by moving an existing
.Pa +REQUIRED_BY
file aside (if it exists), and running
.Xr pkg_delete 1
on the installed package.
Installation then proceeds as if the package
was not installed, and restores the
.Pa +REQUIRED_BY
file afterwards.
.It
The package build information is extracted from the
.Pa +BUILD_INFO
file and compared against the result of
.Xr uname 3 .
If the operating system or architecture of the package differ from
that of the host, installation is aborted.
This behavior is overridable with the
.Fl f
flag.
.It
The package build information from
.Pa +BUILD_INFO
is then checked for
.Ev USE_ABI_DEPENDS=NO
(or
.Ev IGNORE_RECOMMENDED ) .
If the package was built with ABI dependency recommendations ignored,
a warning will be issued.
.It
A check is made to determine if the package conflicts (from
.Cm @pkgcfl
directives, see
.Xr pkg_create 1 )
with an already recorded as installed package or if an installed package
conflicts with the package.
If it is, installation is terminated.
.It
The file list of the package is compared to the file lists of the
installed packages.
If there is any overlap, the installation is terminated.
.It
All package dependencies (from
.Cm @pkgdep
directives, see
.Xr pkg_create 1 )
are read from the packing list.
If any of these required packages are not currently installed,
an attempt is made to find and install it;
if the missing package cannot be found or installed,
the installation is terminated.
.It
If the package contains an
.Ar install
script, it is executed with the following arguments:
.Bl -tag -width indentindent
.It Ar pkg-name
The name of the package being installed.
.It Cm PRE-INSTALL
Keyword denoting that the script is to perform any actions needed before
the package is installed.
.El
.Pp
If the
.Ar install
script exits with a non-zero status code, the installation is terminated.
.It
The files from the file list are extracted to the chosen prefix.
.It
If an
.Ar install
script exists for the package, it is executed with the following arguments:
.Bl -tag -width indentindent
.It Ar pkg_name
The name of the package being installed.
.It Cm POST-INSTALL
Keyword denoting that the script is to perform any actions needed
after the package has been installed.
.El
.It
After installation is complete, a copy of the packing list,
.Ar deinstall
script, description, and display files are copied into
.Pa \*[Lt]PKG_DBDIR\*[Gt]/\*[Lt]pkg-name\*[Gt]
for subsequent possible use by
.Xr pkg_delete 1 .
Any package dependencies are recorded in the other packages'
.Pa +REQUIRED_BY
file.
.It
If the package is a depoted package, then add it to the registered
by calling
.Xr pkg_view 1
accordingly.
.It
Finally, if we were upgrading a package, any
.Pa +REQUIRED_BY
file that was moved aside before upgrading was started is now moved
back into place.
.El
.Pp
The
.Ar install
script is called with the environment variable
.Ev PKG_PREFIX
set to the installation prefix (see the
.Fl p
option above).
This allows a package author to write a script
that reliably performs some action on the directory where the package
is installed, even if the user might change it with the
.Fl p
flag to
.Cm pkg_add .
The scripts are also called with the
.Ev PKG_METADATA_DIR
environment variable set to the location of the
.Pa +*
meta-data files, and with the
.Ev PKG_REFCOUNT_DBDIR
environment variable set to the location of the package reference counts
database directory.
If the
.Fl P
flag was given to
.Nm ,
.Ev PKG_DESTDIR
will be set to
.Ar destdir .
Additionally,
.Ev PKG_METADATA_DIR
and
.Ev PKG_REFCOUNT_DBDIR
are prefixed with
.Ar destdir .
.Sh ENVIRONMENT
See
.Xr pkg_install.conf 5
for options, that can also be specified using the environment.
Packages using views are also affected by the environment variables
documented for
.Xr pkg_view 1 .
.Sh EXAMPLES
In all cases,
.Nm
will try to install binary packages listed in dependencies list.
.Pp
You can specify a compiled binary package explicitly on the command line.
.Bd -literal
# pkg_add /usr/pkgsrc/packages/All/tcsh-6.14.00.tgz
.Ed
.Pp
If you omit the version number,
.Nm
will install the latest version available.
With
.Fl v ,
.Nm
emits more messages to terminal.
.Bd -literal
# pkg_add -v /usr/pkgsrc/packages/All/unzip
.Ed
.Pp
You can grab a compiled binary package from remote location by specifying
a URL.
The base URL can also be provided by the configuration variable,
.Dv PKG_PATH .
.Bd -literal
# pkg_add -v ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/i386/3.1_2007Q2/All/firefox-2.0.0.4.tgz
# export PKG_PATH=ftp://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/i386/3.1_2007Q2/All
# pkg_add -v firefox
.Ed
.Sh SEE ALSO
.Xr pkg_admin 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Xr pkg_install.conf 5 ,
.Xr pkgsrc 7
.Sh AUTHORS
.Bl -tag -width indent -compact
.It "Jordan Hubbard"
Initial work and ongoing development.
.It "John Kohl"
.Nx
refinements.
.It "Hubert Feyrer"
.Nx
wildcard dependency processing, pkgdb, upgrading, etc.
.It Thomas Klausner
HTTP support.
.It Joerg Sonnenberger
Rewrote most of the code base to work without external commands.
.El
.Sh BUGS
Package upgrading needs a lot more work to be really universal.
.Pp
Sure to be others.

View file

@ -0,0 +1,39 @@
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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.
*/
extern int quiet;
extern int verbose;
void check(char **);
void audit_pkgdb(int, char **);
void audit_pkg(int, char **);
void audit_batch(int, char **);
void audit_history(int, char **);
void check_pkg_vulnerabilities(int, char **);
void fetch_pkg_vulnerabilities(int, char **);
void usage(void);

View file

@ -0,0 +1,66 @@
.\" $NetBSD: audit-packages.8,v 1.1.1.1 2010/04/23 20:54:06 joerg Exp $
.\"
.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by 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.
.\"
.\" 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.
.\"
.Dd March 18, 2010
.Dt AUDIT-PACKAGES 8
.Os
.Sh NAME
.Nm audit-packages
.Nd report vulnerabilities for the installed packages
.Sh SYNOPSIS
.Nm
.Op Fl deqsVv
.Op Fl c Ar config_file
.Op Fl F Ar file
.Op Fl g Ar file
.Op Fl h Ar file
.Op Fl K Ar pkg_dbdir
.Op Fl n Ar package
.Op Fl p Ar package
.Op Fl Q Ar varname
.Op Fl t Ar type
.Sh DESCRIPTION
.Nm
is deprecated.
Please use the
.Cm audit ,
.Cm audit-pkg ,
.Cm audit-batch ,
and
.Cm fetch-pkg-vulnerabilities
commands of
.Xr pkg_admin 1
instead.
.Pp
The
.Nm
script is installed for backwards compatibility only and will
eventually be removed.
.Sh SEE ALSO
.Xr pkg_admin 1

View file

@ -0,0 +1,130 @@
#!/bin/sh
pkg_admin=@PKG_ADMIN@
usage() {
echo 'Usage: audit-packages [-deqsVv] [-c config_file] [-F file]' >& $2
echo ' [-g file] [-h file]' >& $2
echo ' [-K pkg_dbdir] [-n package] [-p package]' >& $2
echo ' [-Q varname] [-t type]' >& $2
echo "Please use the audit, audit-pkg, audit-batch and fetch-pkg-vulnerabilities" >& $2
echo "commands of pkg_admin instead." >& $2
exit $1
}
do_pkgdb=
do_eol=
do_fetch=
do_quiet=
do_sign=
do_verbose=
do_check_file=
do_check_pattern=
do_check_installed=
do_check_vul_file=
do_limit_type=
do_print_var=
args=`getopt F:K:Q:Vc:deg:h:n:p:qst:v $*`
if [ $? -ne 0 ]; then
usage 1 2
fi
set -- $args
while [ $# -gt 0 ]; do
case "$1" in
-F)
do_check_file=$2
shift
;;
-K)
do_pkgdb="$1 $2"
shift
;;
-Q)
do_print_var="$2"
shift
;;
-V)
exec ${pkg_admin} -V
;;
-c)
echo "The audit-packages wrapper does not support -c" >&2
echo "Please use the audit, audit-pkg, audit-batch and fetch-pkg-vulnerabilities" >& 2
echo "commands of pkg_admin instead." >& 2
exit 1
;;
-d)
do_fetch=1
;;
-e)
do_eol=-e
;;
-g)
echo "The audit-packages wrapper does not support -g" >&2
echo "Please switch to \`\`pkg_admin fetch-pkg-vulnerabilities''." >&2
exit 1
;;
-h)
do_check_vul_file=$2
shift
;;
-n)
do_check_pattern=$2
shift
;;
-p)
do_check_installed=$2
shift
;;
-q)
do_quiet=-q
;;
-s)
do_sign=-s
;;
-t)
do_limit_type="-t $2"
shift
;;
-v)
do_verbose="$do_verbose -v"
;;
esac
shift
done
if [ -n "${do_fetch}" ]; then
exec ${pkg_admin} ${do_pkgdb} fetch-pkg-vulnerabilities ${do_sign}
fi
if [ -n "${do_check_vul_file}" ]; then
exec ${pkg_admin} ${do_pkgdb} check-pkg-vulnerabilities ${do_sign} "${do_check_vul_file}"
fi
if [ -n "${do_print_var}" ]; then
exec ${pkg_admin} ${do_pkgdb} config-var "${do_print_var}"
fi
if [ -n "${do_check_file}" ]; then
if [ -n "${do_check_pattern}" -o -n "${do_check_installed}" ]; then
echo "Only one of -F, -n or -p is interpreted at a time." >& 2
usage 1 2
fi
exec ${pkg_admin} ${do_pkgdb} ${do_verbose} ${do_quiet} audit-pkg \
${do_eol} ${do_limit_type} ${do_check_file}
fi
if [ -n "${do_check_pattern}" ]; then
if [ -n "${do_check_installed}" ]; then
echo "Only one of -F, -n or -p is interpreted at a time." >& 2
usage 1 2
fi
exec ${pkg_admin} ${do_pkgdb} ${do_verbose} ${do_quiet} audit-pkg \
${do_eol} ${do_limit_type} ${do_check_pattern}
fi
# If do_check_installed is empty, all packages are checked.
exec ${pkg_admin} ${do_pkgdb} ${do_verbose} ${do_quiet} audit \
${do_eol} ${do_limit_type} ${do_check_installed}

View file

@ -0,0 +1,507 @@
/* $NetBSD: audit.c,v 1.1.1.9 2011/02/18 22:32:28 aymeric Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: audit.c,v 1.1.1.9 2011/02/18 22:32:28 aymeric Exp $");
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.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_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#ifdef NETBSD
#include <unistd.h>
#else
#include <nbcompat/unistd.h>
#endif
#include <fetch.h>
#include "admin.h"
#include "lib.h"
static int check_signature = 0;
static const char *limit_vul_types = NULL;
static int update_pkg_vuln = 0;
static struct pkg_vulnerabilities *pv;
static const char audit_options[] = "est:";
static void
parse_options(int argc, char **argv, const char *options)
{
int ch;
optreset = 1;
/*
* optind == 0 is interpreted as partial reset request
* by GNU getopt, so compensate against this and cleanup
* at the end.
*/
optind = 1;
++argc;
--argv;
while ((ch = getopt(argc, argv, options)) != -1) {
switch (ch) {
case 'e':
check_eol = "yes";
break;
case 's':
check_signature = 1;
break;
case 't':
limit_vul_types = optarg;
break;
case 'u':
update_pkg_vuln = 1;
break;
default:
usage();
/* NOTREACHED */
}
}
--optind; /* See above comment. */
}
static int
check_exact_pkg(const char *pkg)
{
return audit_package(pv, pkg, limit_vul_types, quiet ? 0 : 1);
}
static int
check_batch_exact_pkgs(const char *fname)
{
FILE *f;
char buf[4096], *line, *eol;
int ret;
ret = 0;
if (strcmp(fname, "-") == 0)
f = stdin;
else {
f = fopen(fname, "r");
if (f == NULL)
err(EXIT_FAILURE, "Failed to open input file %s",
fname);
}
while ((line = fgets(buf, sizeof(buf), f)) != NULL) {
eol = line + strlen(line);
if (eol == line)
continue;
--eol;
if (*eol == '\n') {
if (eol == line)
continue;
*eol = '\0';
}
ret |= check_exact_pkg(line);
}
if (f != stdin)
fclose(f);
return ret;
}
static int
check_one_installed_pkg(const char *pkg, void *cookie)
{
int *ret = cookie;
*ret |= check_exact_pkg(pkg);
return 0;
}
static int
check_installed_pattern(const char *pattern)
{
int ret = 0;
match_installed_pkgs(pattern, check_one_installed_pkg, &ret);
return ret;
}
static void
check_and_read_pkg_vulnerabilities(void)
{
struct stat st;
time_t now;
if (pkg_vulnerabilities_file == NULL)
errx(EXIT_FAILURE, "PKG_VULNERABILITIES is not set");
if (verbose >= 1) {
if (stat(pkg_vulnerabilities_file, &st) == -1) {
if (errno == ENOENT)
errx(EXIT_FAILURE,
"pkg-vulnerabilities not found, run %s -d",
getprogname());
errx(EXIT_FAILURE, "pkg-vulnerabilities not readable");
}
now = time(NULL);
now -= st.st_mtime;
if (now < 0)
warnx("pkg-vulnerabilities is from the future");
else if (now > 86400 * 7)
warnx("pkg-vulnerabilities is out of date (%ld days old)",
(long)(now / 86400));
else if (verbose >= 2)
warnx("pkg-vulnerabilities is %ld day%s old",
(long)(now / 86400), now / 86400 == 1 ? "" : "s");
}
pv = read_pkg_vulnerabilities_file(pkg_vulnerabilities_file, 0, check_signature);
}
void
audit_pkgdb(int argc, char **argv)
{
int rv;
parse_options(argc, argv, audit_options);
argv += optind;
check_and_read_pkg_vulnerabilities();
rv = 0;
if (*argv == NULL)
rv |= check_installed_pattern("*");
else {
for (; *argv != NULL; ++argv)
rv |= check_installed_pattern(*argv);
}
free_pkg_vulnerabilities(pv);
if (rv == 0 && verbose >= 1)
fputs("No vulnerabilities found\n", stderr);
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
}
void
audit_pkg(int argc, char **argv)
{
int rv;
parse_options(argc, argv, audit_options);
argv += optind;
check_and_read_pkg_vulnerabilities();
rv = 0;
for (; *argv != NULL; ++argv)
rv |= check_exact_pkg(*argv);
free_pkg_vulnerabilities(pv);
if (rv == 0 && verbose >= 1)
fputs("No vulnerabilities found\n", stderr);
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
}
void
audit_batch(int argc, char **argv)
{
int rv;
parse_options(argc, argv, audit_options);
argv += optind;
check_and_read_pkg_vulnerabilities();
rv = 0;
for (; *argv != NULL; ++argv)
rv |= check_batch_exact_pkgs(*argv);
free_pkg_vulnerabilities(pv);
if (rv == 0 && verbose >= 1)
fputs("No vulnerabilities found\n", stderr);
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
}
void
check_pkg_vulnerabilities(int argc, char **argv)
{
parse_options(argc, argv, "s");
if (argc != optind + 1)
usage();
pv = read_pkg_vulnerabilities_file(argv[optind], 0, check_signature);
free_pkg_vulnerabilities(pv);
}
void
fetch_pkg_vulnerabilities(int argc, char **argv)
{
struct pkg_vulnerabilities *pv_check;
char *buf;
size_t buf_len, buf_fetched;
ssize_t cur_fetched;
struct url *url;
struct url_stat st;
fetchIO *f;
int fd;
struct stat sb;
char my_flags[20];
const char *flags;
parse_options(argc, argv, "su");
if (argc != optind)
usage();
if (verbose >= 2)
fprintf(stderr, "Fetching %s\n", pkg_vulnerabilities_url);
url = fetchParseURL(pkg_vulnerabilities_url);
if (url == NULL)
errx(EXIT_FAILURE,
"Could not parse location of pkg_vulnerabilities: %s",
fetchLastErrString);
flags = fetch_flags;
if (update_pkg_vuln) {
fd = open(pkg_vulnerabilities_file, O_RDONLY);
if (fd != -1 && fstat(fd, &sb) != -1) {
url->last_modified = sb.st_mtime;
snprintf(my_flags, sizeof(my_flags), "%si",
fetch_flags);
flags = my_flags;
} else
update_pkg_vuln = 0;
if (fd != -1)
close(fd);
}
f = fetchXGet(url, &st, flags);
if (f == NULL && update_pkg_vuln &&
fetchLastErrCode == FETCH_UNCHANGED) {
if (verbose >= 1)
fprintf(stderr, "%s is not newer\n",
pkg_vulnerabilities_url);
exit(EXIT_SUCCESS);
}
if (f == NULL)
errx(EXIT_FAILURE, "Could not fetch vulnerability file: %s",
fetchLastErrString);
if (st.size > SSIZE_MAX - 1)
errx(EXIT_FAILURE, "pkg-vulnerabilities is too large");
buf_len = st.size;
buf = xmalloc(buf_len + 1);
buf_fetched = 0;
while (buf_fetched < buf_len) {
cur_fetched = fetchIO_read(f, buf + buf_fetched,
buf_len - buf_fetched);
if (cur_fetched == 0)
errx(EXIT_FAILURE,
"Truncated pkg-vulnerabilities received");
else if (cur_fetched == -1)
errx(EXIT_FAILURE,
"IO error while fetching pkg-vulnerabilities: %s",
fetchLastErrString);
buf_fetched += cur_fetched;
}
buf[buf_len] = '\0';
pv_check = read_pkg_vulnerabilities_memory(buf, buf_len, check_signature);
free_pkg_vulnerabilities(pv_check);
fd = open(pkg_vulnerabilities_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
err(EXIT_FAILURE, "Cannot create pkg-vulnerability file %s",
pkg_vulnerabilities_file);
if (write(fd, buf, buf_len) != (ssize_t)buf_len)
err(EXIT_FAILURE, "Cannot write pkg-vulnerability file");
if (close(fd) == -1)
err(EXIT_FAILURE, "Cannot close pkg-vulnerability file after write");
free(buf);
exit(EXIT_SUCCESS);
}
static int
check_pkg_history_pattern(const char *pkg, const char *pattern)
{
const char *delim, *end_base;
if (strpbrk(pattern, "*[") != NULL) {
end_base = NULL;
for (delim = pattern;
*delim != '\0' && *delim != '['; delim++) {
if (*delim == '-')
end_base = delim;
}
if (end_base == NULL)
errx(EXIT_FAILURE, "Missing - in wildcard pattern %s",
pattern);
if ((delim = strchr(pattern, '>')) != NULL ||
(delim = strchr(pattern, '<')) != NULL)
errx(EXIT_FAILURE,
"Mixed relational and wildcard patterns in %s",
pattern);
} else if ((delim = strchr(pattern, '>')) != NULL) {
end_base = delim;
if ((delim = strchr(pattern, '<')) != NULL && delim < end_base)
errx(EXIT_FAILURE, "Inverted operators in %s",
pattern);
} else if ((delim = strchr(pattern, '<')) != NULL) {
end_base = delim;
} else if ((end_base = strrchr(pattern, '-')) == NULL) {
errx(EXIT_FAILURE, "Missing - in absolute pattern %s",
pattern);
}
if (strncmp(pkg, pattern, end_base - pattern) != 0)
return 0;
if (pkg[end_base - pattern] != '\0')
return 0;
return 1;
}
static int
check_pkg_history1(const char *pkg, const char *pattern)
{
const char *open_brace, *close_brace, *inner_brace, *suffix, *iter;
size_t prefix_len, suffix_len, middle_len;
char *expanded_pkg;
open_brace = strchr(pattern, '{');
if (open_brace == NULL) {
if ((close_brace = strchr(pattern, '}')) != NULL)
errx(EXIT_FAILURE, "Unbalanced {} in pattern %s",
pattern);
return check_pkg_history_pattern(pkg, pattern);
}
close_brace = strchr(open_brace, '}');
if (strchr(pattern, '}') != close_brace)
errx(EXIT_FAILURE, "Unbalanced {} in pattern %s",
pattern);
while ((inner_brace = strchr(open_brace + 1, '{')) != NULL) {
if (inner_brace >= close_brace)
break;
open_brace = inner_brace;
}
expanded_pkg = xmalloc(strlen(pattern)); /* {} are going away... */
prefix_len = open_brace - pattern;
suffix = close_brace + 1;
suffix_len = strlen(suffix) + 1;
memcpy(expanded_pkg, pattern, prefix_len);
++open_brace;
do {
iter = strchr(open_brace, ',');
if (iter == NULL || iter > close_brace)
iter = close_brace;
middle_len = iter - open_brace;
memcpy(expanded_pkg + prefix_len, open_brace, middle_len);
memcpy(expanded_pkg + prefix_len + middle_len, suffix,
suffix_len);
if (check_pkg_history1(pkg, expanded_pkg)) {
free(expanded_pkg);
return 1;
}
open_brace = iter + 1;
} while (iter < close_brace);
free(expanded_pkg);
return 0;
}
static void
check_pkg_history(const char *pkg)
{
size_t i;
for (i = 0; i < pv->entries; ++i) {
if (!quick_pkg_match(pv->vulnerability[i], pkg))
continue;
if (strcmp("eol", pv->classification[i]) == 0)
continue;
if (check_pkg_history1(pkg, pv->vulnerability[i]) == 0)
continue;
printf("%s %s %s\n", pv->vulnerability[i],
pv->classification[i], pv->advisory[i]);
}
}
void
audit_history(int argc, char **argv)
{
parse_options(argc, argv, "st:");
argv += optind;
check_and_read_pkg_vulnerabilities();
for (; *argv != NULL; ++argv)
check_pkg_history(*argv);
free_pkg_vulnerabilities(pv);
exit(EXIT_SUCCESS);
}

View file

@ -0,0 +1,259 @@
/* $NetBSD: check.c,v 1.1.1.4 2010/01/30 21:33:23 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: check.c,v 1.1.1.4 2010/01/30 21:33:23 joerg Exp $");
/*-
* 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>.
*
* 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.
*
* 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_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_DIRENT_H
#include <dirent.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
#ifndef NETBSD
#include <nbcompat/md5.h>
#else
#include <md5.h>
#endif
#if HAVE_LIMITS_H
#include <limits.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#include "admin.h"
#include "lib.h"
static int checkpattern_fn(const char *, void *);
/*
* Assumes CWD is in /var/db/pkg/<pkg>!
*/
static void
check1pkg(const char *pkgdir, int *filecnt, int *pkgcnt)
{
FILE *f;
plist_t *p;
package_t Plist;
char *PkgName, *dirp = NULL, *md5file;
char file[MaxPathSize];
char *content;
content = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME);
f = fopen(content, "r");
if (f == NULL)
err(EXIT_FAILURE, "can't open %s", content);
free(content);
read_plist(&Plist, f);
p = find_plist(&Plist, PLIST_NAME);
if (p == NULL)
errx(EXIT_FAILURE, "Package %s has no @name, aborting.",
pkgdir);
PkgName = p->name;
for (p = Plist.head; p; p = p->next) {
switch (p->type) {
case PLIST_FILE:
if (dirp == NULL) {
warnx("dirp not initialized, please send-pr!");
abort();
}
(void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name);
if (isfile(file) || islinktodir(file)) {
if (p->next && p->next->type == PLIST_COMMENT) {
if (strncmp(p->next->name, CHECKSUM_HEADER, ChecksumHeaderLen) == 0) {
if ((md5file = MD5File(file, NULL)) != NULL) {
/* Mismatch? */
if (strcmp(md5file, p->next->name + ChecksumHeaderLen) != 0)
printf("%s fails MD5 checksum\n", file);
free(md5file);
}
} else if (strncmp(p->next->name, SYMLINK_HEADER, SymlinkHeaderLen) == 0) {
char buf[MaxPathSize + SymlinkHeaderLen];
int cc;
(void) strlcpy(buf, SYMLINK_HEADER, sizeof(buf));
if ((cc = readlink(file, &buf[SymlinkHeaderLen],
sizeof(buf) - SymlinkHeaderLen - 1)) < 0) {
warnx("can't readlink `%s'", file);
} else {
buf[SymlinkHeaderLen + cc] = 0x0;
if (strcmp(buf, p->next->name) != 0) {
printf("symlink (%s) is not same as recorded value, %s: %s\n",
file, buf, p->next->name);
}
}
}
}
(*filecnt)++;
} else if (isbrokenlink(file)) {
warnx("%s: Symlink `%s' exists and is in %s but target does not exist!", PkgName, file, CONTENTS_FNAME);
} else {
warnx("%s: File `%s' is in %s but not on filesystem!", PkgName, file, CONTENTS_FNAME);
}
break;
case PLIST_CWD:
if (strcmp(p->name, ".") != 0)
dirp = p->name;
else
dirp = pkgdb_pkg_dir(pkgdir);
break;
case PLIST_IGNORE:
p = p->next;
break;
case PLIST_SHOW_ALL:
case PLIST_SRC:
case PLIST_CMD:
case PLIST_CHMOD:
case PLIST_CHOWN:
case PLIST_CHGRP:
case PLIST_COMMENT:
case PLIST_NAME:
case PLIST_UNEXEC:
case PLIST_DISPLAY:
case PLIST_PKGDEP:
case PLIST_DIR_RM:
case PLIST_OPTION:
case PLIST_PKGCFL:
case PLIST_BLDDEP:
case PLIST_PKGDIR:
break;
}
}
free_plist(&Plist);
fclose(f);
(*pkgcnt)++;
}
struct checkpattern_arg {
int filecnt;
int pkgcnt;
int got_match;
};
static int
checkpattern_fn(const char *pkg, void *vp)
{
struct checkpattern_arg *arg = vp;
check1pkg(pkg, &arg->filecnt, &arg->pkgcnt);
if (!quiet)
printf(".");
arg->got_match = 1;
return 0;
}
static void
check_pkg(const char *pkg, int *filecnt, int *pkgcnt, int allow_unmatched)
{
struct checkpattern_arg arg;
char *pattern;
arg.filecnt = *filecnt;
arg.pkgcnt = *pkgcnt;
arg.got_match = 0;
if (match_installed_pkgs(pkg, checkpattern_fn, &arg) == -1)
errx(EXIT_FAILURE, "Cannot process pkdbdb");
if (arg.got_match != 0) {
*filecnt = arg.filecnt;
*pkgcnt = arg.pkgcnt;
return;
}
if (ispkgpattern(pkg)) {
if (allow_unmatched)
return;
errx(EXIT_FAILURE, "No matching pkg for %s.", pkg);
}
pattern = xasprintf("%s-[0-9]*", pkg);
if (match_installed_pkgs(pattern, checkpattern_fn, &arg) == -1)
errx(EXIT_FAILURE, "Cannot process pkdbdb");
if (arg.got_match == 0)
errx(EXIT_FAILURE, "cannot find package %s", pkg);
free(pattern);
*filecnt = arg.filecnt;
*pkgcnt = arg.pkgcnt;
}
void
check(char **argv)
{
int filecnt, pkgcnt;
filecnt = 0;
pkgcnt = 0;
setbuf(stdout, NULL);
if (*argv == NULL) {
check_pkg("*", &filecnt, &pkgcnt, 1);
} else {
for (; *argv != NULL; ++argv)
check_pkg(*argv, &filecnt, &pkgcnt, 0);
}
printf("\n");
printf("Checked %d file%s from %d package%s.\n",
filecnt, (filecnt == 1) ? "" : "s",
pkgcnt, (pkgcnt == 1) ? "" : "s");
}

View file

@ -0,0 +1,54 @@
.\" $NetBSD: download-vulnerability-list.8,v 1.1.1.1 2010/04/23 20:54:06 joerg Exp $
.\"
.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by 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.
.\"
.\" 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.
.\"
.Dd March 18, 2010
.Dt DOWNLOAD-VULNERABILITY-LIST 8
.Os
.Sh NAME
.Nm download-vulnerability-list
.Nd download vulnerability list used for checking installed packages
.Sh SYNOPSIS
.Nm
.Op Fl hs
.Op Fl c Ar config_file
.Sh DESCRIPTION
.Nm
is deprecated.
Please use the
.Cm fetch-pkg-vulnerabilities
command of
.Xr pkg_admin 1
instead.
.Pp
The
.Nm
script is installed for backwards compatibility only and will
eventually be removed.
.Sh SEE ALSO
.Xr pkg_admin 1

View file

@ -0,0 +1,37 @@
#!/bin/sh
pkg_admin=@PKG_ADMIN@
usage() {
echo 'Usage: download-vulnerability-list [-hs] [-c config_file]' >& $2
echo "Please use \`\`pkg_admin fetch-pkg-vulnerabilities'' instead." >& $2
exit $1
}
do_sign=
args=`getopt c:hs $*`
if [ $? -ne 0 ]; then
usage 1 2
fi
set -- $args
while [ $# -gt 0 ]; do
case "$1" in
-c)
echo "The download-vulnerability-list wrapper does not support -c" >&2
echo "Please switch to \`\`pkg_admin fetch-pkg-vulnerabilities''." >&2
exit 1
;;
-h)
usage 0 1
;;
-s)
do_sign=-s
;;
esac
shift
done
exec ${pkg_admin} fetch-pkg-vulnerabilities ${do_sign}

View file

@ -0,0 +1,754 @@
/* $NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 joerg Exp $");
/*-
* Copyright (c) 1999-2009 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
* by Joerg Sonnenberger <joerg@NetBSD.org>.
*
* 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.
*
* 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_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_DIRENT_H
#include <dirent.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
#ifndef NETBSD
#include <nbcompat/md5.h>
#else
#include <md5.h>
#endif
#if HAVE_LIMITS_H
#include <limits.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#ifndef BOOTSTRAP
#include <archive.h>
#include <fetch.h>
#endif
#include "admin.h"
#include "lib.h"
#define DEFAULT_SFX ".t[bg]z" /* default suffix for ls{all,best} */
struct pkgdb_count {
size_t files;
size_t directories;
size_t packages;
};
static const char Options[] = "C:K:SVbd:qs:v";
int quiet, verbose;
static void set_unset_variable(char **, Boolean);
/* print usage message and exit */
void
usage(void)
{
(void) fprintf(stderr, "usage: %s [-bqSVv] [-C config] [-d lsdir] [-K pkg_dbdir] [-s sfx] command [args ...]\n"
"Where 'commands' and 'args' are:\n"
" rebuild - rebuild pkgdb from +CONTENTS files\n"
" rebuild-tree - rebuild +REQUIRED_BY files from forward deps\n"
" check [pkg ...] - check md5 checksum of installed files\n"
" add pkg ... - add pkg files to database\n"
" delete pkg ... - delete file entries for pkg in database\n"
" set variable=value pkg ... - set installation variable for package\n"
" unset variable pkg ... - unset installation variable for package\n"
" lsall /path/to/pkgpattern - list all pkgs matching the pattern\n"
" lsbest /path/to/pkgpattern - list pkgs matching the pattern best\n"
" dump - dump database\n"
" pmatch pattern pkg - returns true if pkg matches pattern, otherwise false\n"
" fetch-pkg-vulnerabilities [-s] - fetch new vulnerability file\n"
" check-pkg-vulnerabilities [-s] <file> - check syntax and checksums of the vulnerability file\n"
" audit [-es] [-t type] ... - check installed packages for vulnerabilities\n"
" audit-pkg [-es] [-t type] ... - check listed packages for vulnerabilities\n"
" audit-batch [-es] [-t type] ... - check packages in listed files for vulnerabilities\n"
" audit-history [-t type] ... - print all advisories for package names\n"
" check-license <condition> - check if condition is acceptable\n"
" check-single-license <license> - check if license is acceptable\n"
" config-var name - print current value of the configuration variable\n"
" check-signature ... - verify the signature of packages\n"
" x509-sign-package pkg spkg key cert - create X509 signature\n"
" gpg-sign-package pkg spkg - create GPG signature\n",
getprogname());
exit(EXIT_FAILURE);
}
/*
* add1pkg(<pkg>)
* adds the files listed in the +CONTENTS of <pkg> into the
* pkgdb.byfile.db database file in the current package dbdir. It
* returns the number of files added to the database file.
*/
static int
add_pkg(const char *pkgdir, void *vp)
{
FILE *f;
plist_t *p;
package_t Plist;
char *contents;
char *PkgName, *dirp;
char file[MaxPathSize];
struct pkgdb_count *count;
if (!pkgdb_open(ReadWrite))
err(EXIT_FAILURE, "cannot open pkgdb");
count = vp;
++count->packages;
contents = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME);
if ((f = fopen(contents, "r")) == NULL)
errx(EXIT_FAILURE, "%s: can't open `%s'", pkgdir, CONTENTS_FNAME);
free(contents);
read_plist(&Plist, f);
if ((p = find_plist(&Plist, PLIST_NAME)) == NULL) {
errx(EXIT_FAILURE, "Package `%s' has no @name, aborting.", pkgdir);
}
PkgName = p->name;
dirp = NULL;
for (p = Plist.head; p; p = p->next) {
switch(p->type) {
case PLIST_FILE:
if (dirp == NULL) {
errx(EXIT_FAILURE, "@cwd not yet found, please send-pr!");
}
(void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name);
if (!(isfile(file) || islinktodir(file))) {
if (isbrokenlink(file)) {
warnx("%s: Symlink `%s' exists and is in %s but target does not exist!",
PkgName, file, CONTENTS_FNAME);
} else {
warnx("%s: File `%s' is in %s but not on filesystem!",
PkgName, file, CONTENTS_FNAME);
}
} else {
pkgdb_store(file, PkgName);
++count->files;
}
break;
case PLIST_PKGDIR:
add_pkgdir(PkgName, dirp, p->name);
++count->directories;
break;
case PLIST_CWD:
if (strcmp(p->name, ".") != 0)
dirp = p->name;
else
dirp = pkgdb_pkg_dir(pkgdir);
break;
case PLIST_IGNORE:
p = p->next;
break;
case PLIST_SHOW_ALL:
case PLIST_SRC:
case PLIST_CMD:
case PLIST_CHMOD:
case PLIST_CHOWN:
case PLIST_CHGRP:
case PLIST_COMMENT:
case PLIST_NAME:
case PLIST_UNEXEC:
case PLIST_DISPLAY:
case PLIST_PKGDEP:
case PLIST_DIR_RM:
case PLIST_OPTION:
case PLIST_PKGCFL:
case PLIST_BLDDEP:
break;
}
}
free_plist(&Plist);
fclose(f);
pkgdb_close();
return 0;
}
static void
delete1pkg(const char *pkgdir)
{
if (!pkgdb_open(ReadWrite))
err(EXIT_FAILURE, "cannot open pkgdb");
(void) pkgdb_remove_pkg(pkgdir);
pkgdb_close();
}
static void
rebuild(void)
{
char *cachename;
struct pkgdb_count count;
count.files = 0;
count.directories = 0;
count.packages = 0;
cachename = pkgdb_get_database();
if (unlink(cachename) != 0 && errno != ENOENT)
err(EXIT_FAILURE, "unlink %s", cachename);
setbuf(stdout, NULL);
iterate_pkg_db(add_pkg, &count);
printf("\n");
printf("Stored %" PRIzu " file%s and %zu explicit director%s"
" from %"PRIzu " package%s in %s.\n",
count.files, count.files == 1 ? "" : "s",
count.directories, count.directories == 1 ? "y" : "ies",
count.packages, count.packages == 1 ? "" : "s",
cachename);
}
static int
lspattern(const char *pkg, void *vp)
{
const char *dir = vp;
printf("%s/%s\n", dir, pkg);
return 0;
}
static int
lsbasepattern(const char *pkg, void *vp)
{
puts(pkg);
return 0;
}
static int
remove_required_by(const char *pkgname, void *cookie)
{
char *path;
path = pkgdb_pkg_file(pkgname, REQUIRED_BY_FNAME);
if (unlink(path) == -1 && errno != ENOENT)
err(EXIT_FAILURE, "Cannot remove %s", path);
free(path);
return 0;
}
static void
add_required_by(const char *pattern, const char *required_by)
{
char *best_installed, *path;
int fd;
size_t len;
best_installed = find_best_matching_installed_pkg(pattern);
if (best_installed == NULL) {
warnx("Dependency %s of %s unresolved", pattern, required_by);
return;
}
path = pkgdb_pkg_file(best_installed, REQUIRED_BY_FNAME);
free(best_installed);
if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644)) == -1)
errx(EXIT_FAILURE, "Cannot write to %s", path);
free(path);
len = strlen(required_by);
if (write(fd, required_by, len) != (ssize_t)len ||
write(fd, "\n", 1) != 1 ||
close(fd) == -1)
errx(EXIT_FAILURE, "Cannot write to %s", path);
}
static int
add_depends_of(const char *pkgname, void *cookie)
{
FILE *fp;
plist_t *p;
package_t plist;
char *path;
path = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
if ((fp = fopen(path, "r")) == NULL)
errx(EXIT_FAILURE, "Cannot read %s of package %s",
CONTENTS_FNAME, pkgname);
free(path);
read_plist(&plist, fp);
fclose(fp);
for (p = plist.head; p; p = p->next) {
if (p->type == PLIST_PKGDEP)
add_required_by(p->name, pkgname);
}
free_plist(&plist);
return 0;
}
static void
rebuild_tree(void)
{
if (iterate_pkg_db(remove_required_by, NULL) == -1)
errx(EXIT_FAILURE, "cannot iterate pkgdb");
if (iterate_pkg_db(add_depends_of, NULL) == -1)
errx(EXIT_FAILURE, "cannot iterate pkgdb");
}
int
main(int argc, char *argv[])
{
Boolean use_default_sfx = TRUE;
Boolean show_basename_only = FALSE;
char lsdir[MaxPathSize];
char sfx[MaxPathSize];
char *lsdirp = NULL;
int ch;
setprogname(argv[0]);
if (argc < 2)
usage();
while ((ch = getopt(argc, argv, Options)) != -1)
switch (ch) {
case 'C':
config_file = optarg;
break;
case 'K':
pkgdb_set_dir(optarg, 3);
break;
case 'S':
sfx[0] = 0x0;
use_default_sfx = FALSE;
break;
case 'V':
show_version();
/* NOTREACHED */
case 'b':
show_basename_only = TRUE;
break;
case 'd':
(void) strlcpy(lsdir, optarg, sizeof(lsdir));
lsdirp = lsdir;
break;
case 'q':
quiet = 1;
break;
case 's':
(void) strlcpy(sfx, optarg, sizeof(sfx));
use_default_sfx = FALSE;
break;
case 'v':
++verbose;
break;
default:
usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
if (argc <= 0) {
usage();
}
/*
* config-var is reading the config file implicitly,
* so skip it here.
*/
if (strcasecmp(argv[0], "config-var") != 0)
pkg_install_config();
if (use_default_sfx)
(void) strlcpy(sfx, DEFAULT_SFX, sizeof(sfx));
if (strcasecmp(argv[0], "pmatch") == 0) {
char *pattern, *pkg;
argv++; /* "pmatch" */
if (argv[0] == NULL || argv[1] == NULL) {
usage();
}
pattern = argv[0];
pkg = argv[1];
if (pkg_match(pattern, pkg)){
return 0;
} else {
return 1;
}
} else if (strcasecmp(argv[0], "rebuild") == 0) {
rebuild();
printf("Done.\n");
} else if (strcasecmp(argv[0], "rebuild-tree") == 0) {
rebuild_tree();
printf("Done.\n");
} else if (strcasecmp(argv[0], "check") == 0) {
argv++; /* "check" */
check(argv);
if (!quiet) {
printf("Done.\n");
}
} else if (strcasecmp(argv[0], "lsall") == 0) {
argv++; /* "lsall" */
while (*argv != NULL) {
/* args specified */
int rc;
const char *basep, *dir;
dir = lsdirp ? lsdirp : dirname_of(*argv);
basep = basename_of(*argv);
if (show_basename_only)
rc = match_local_files(dir, use_default_sfx, 1, basep, lsbasepattern, NULL);
else
rc = match_local_files(dir, use_default_sfx, 1, basep, lspattern, __UNCONST(dir));
if (rc == -1)
errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)",
dir, basep);
argv++;
}
} else if (strcasecmp(argv[0], "lsbest") == 0) {
argv++; /* "lsbest" */
while (*argv != NULL) {
/* args specified */
const char *basep, *dir;
char *p;
dir = lsdirp ? lsdirp : dirname_of(*argv);
basep = basename_of(*argv);
p = find_best_matching_file(dir, basep, use_default_sfx, 1);
if (p) {
if (show_basename_only)
printf("%s\n", p);
else
printf("%s/%s\n", dir, p);
free(p);
}
argv++;
}
} else if (strcasecmp(argv[0], "list") == 0 ||
strcasecmp(argv[0], "dump") == 0) {
pkgdb_dump();
} else if (strcasecmp(argv[0], "add") == 0) {
struct pkgdb_count count;
count.files = 0;
count.directories = 0;
count.packages = 0;
for (++argv; *argv != NULL; ++argv)
add_pkg(*argv, &count);
} else if (strcasecmp(argv[0], "delete") == 0) {
argv++; /* "delete" */
while (*argv != NULL) {
delete1pkg(*argv);
argv++;
}
} else if (strcasecmp(argv[0], "set") == 0) {
argv++; /* "set" */
set_unset_variable(argv, FALSE);
} else if (strcasecmp(argv[0], "unset") == 0) {
argv++; /* "unset" */
set_unset_variable(argv, TRUE);
} else if (strcasecmp(argv[0], "config-var") == 0) {
argv++;
if (argv == NULL || argv[1] != NULL)
errx(EXIT_FAILURE, "config-var takes exactly one argument");
pkg_install_show_variable(argv[0]);
} else if (strcasecmp(argv[0], "check-license") == 0) {
if (argv[1] == NULL)
errx(EXIT_FAILURE, "check-license takes exactly one argument");
load_license_lists();
switch (acceptable_pkg_license(argv[1])) {
case 0:
puts("no");
return 0;
case 1:
puts("yes");
return 0;
case -1:
errx(EXIT_FAILURE, "invalid license condition");
}
} else if (strcasecmp(argv[0], "check-single-license") == 0) {
if (argv[1] == NULL)
errx(EXIT_FAILURE, "check-license takes exactly one argument");
load_license_lists();
switch (acceptable_license(argv[1])) {
case 0:
puts("no");
return 0;
case 1:
puts("yes");
return 0;
case -1:
errx(EXIT_FAILURE, "invalid license");
}
}
#ifndef BOOTSTRAP
else if (strcasecmp(argv[0], "findbest") == 0) {
struct url *url;
char *output;
int rc;
process_pkg_path();
rc = 0;
for (++argv; *argv != NULL; ++argv) {
url = find_best_package(NULL, *argv, 1);
if (url == NULL) {
rc = 1;
continue;
}
output = fetchStringifyURL(url);
puts(output);
fetchFreeURL(url);
free(output);
}
return rc;
} else if (strcasecmp(argv[0], "fetch-pkg-vulnerabilities") == 0) {
fetch_pkg_vulnerabilities(--argc, ++argv);
} else if (strcasecmp(argv[0], "check-pkg-vulnerabilities") == 0) {
check_pkg_vulnerabilities(--argc, ++argv);
} else if (strcasecmp(argv[0], "audit") == 0) {
audit_pkgdb(--argc, ++argv);
} else if (strcasecmp(argv[0], "audit-pkg") == 0) {
audit_pkg(--argc, ++argv);
} else if (strcasecmp(argv[0], "audit-batch") == 0) {
audit_batch(--argc, ++argv);
} else if (strcasecmp(argv[0], "audit-history") == 0) {
audit_history(--argc, ++argv);
} else if (strcasecmp(argv[0], "check-signature") == 0) {
struct archive *pkg;
int rc;
rc = 0;
for (--argc, ++argv; argc > 0; --argc, ++argv) {
char *archive_name;
pkg = open_archive(*argv, &archive_name);
if (pkg == NULL) {
warnx("%s could not be opened", *argv);
continue;
}
if (pkg_full_signature_check(archive_name, &pkg))
rc = 1;
free(archive_name);
if (!pkg)
archive_read_finish(pkg);
}
return rc;
} else if (strcasecmp(argv[0], "x509-sign-package") == 0) {
#ifdef HAVE_SSL
--argc;
++argv;
if (argc != 4)
errx(EXIT_FAILURE, "x509-sign-package takes exactly four arguments");
pkg_sign_x509(argv[0], argv[1], argv[2], argv[3]);
#else
errx(EXIT_FAILURE, "OpenSSL support is not included");
#endif
} else if (strcasecmp(argv[0], "gpg-sign-package") == 0) {
--argc;
++argv;
if (argc != 2)
errx(EXIT_FAILURE, "gpg-sign-package takes exactly two arguments");
pkg_sign_gpg(argv[0], argv[1]);
}
#endif
else {
usage();
}
return 0;
}
struct set_installed_info_arg {
char *variable;
char *value;
int got_match;
};
static int
set_installed_info_var(const char *name, void *cookie)
{
struct set_installed_info_arg *arg = cookie;
char *filename;
int retval;
filename = pkgdb_pkg_file(name, INSTALLED_INFO_FNAME);
retval = var_set(filename, arg->variable, arg->value);
free(filename);
arg->got_match = 1;
return retval;
}
static void
set_unset_variable(char **argv, Boolean unset)
{
struct set_installed_info_arg arg;
char *eq;
char *variable;
int ret = 0;
if (argv[0] == NULL || argv[1] == NULL)
usage();
variable = NULL;
if (unset) {
arg.variable = argv[0];
arg.value = NULL;
} else {
eq = NULL;
if ((eq=strchr(argv[0], '=')) == NULL)
usage();
variable = xmalloc(eq-argv[0]+1);
strlcpy(variable, argv[0], eq-argv[0]+1);
arg.variable = variable;
arg.value = eq+1;
if (strcmp(variable, AUTOMATIC_VARNAME) == 0 &&
strcasecmp(arg.value, "yes") != 0 &&
strcasecmp(arg.value, "no") != 0) {
errx(EXIT_FAILURE,
"unknown value `%s' for " AUTOMATIC_VARNAME,
arg.value);
}
}
if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) {
free(variable);
errx(EXIT_FAILURE,
"variable name must not contain uppercase letters");
}
argv++;
while (*argv != NULL) {
arg.got_match = 0;
if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
errx(EXIT_FAILURE, "Cannot process pkdbdb");
if (arg.got_match == 0) {
char *pattern;
if (ispkgpattern(*argv)) {
warnx("no matching pkg for `%s'", *argv);
ret++;
} else {
pattern = xasprintf("%s-[0-9]*", *argv);
if (match_installed_pkgs(pattern, set_installed_info_var, &arg) == -1)
errx(EXIT_FAILURE, "Cannot process pkdbdb");
if (arg.got_match == 0) {
warnx("cannot find package %s", *argv);
++ret;
}
free(pattern);
}
}
argv++;
}
if (ret > 0)
exit(EXIT_FAILURE);
free(variable);
return;
}

View file

@ -0,0 +1,324 @@
.\" $NetBSD: pkg_admin.1,v 1.1.1.12 2013/04/20 15:26:52 wiz Exp $
.\"
.\" Copyright (c) 1999-2010 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Hubert Feyrer <hubert@feyrer.de>.
.\"
.\" 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.
.\"
.Dd December 14, 2012
.Dt PKG_ADMIN 1
.Os
.Sh NAME
.Nm pkg_admin
.Nd perform various administrative tasks to the pkg system
.Sh SYNOPSIS
.Nm
.Op Fl bqSVv
.Op Fl C Ar config
.Op Fl d Ar lsdir
.Op Fl K Ar pkg_dbdir
.Op Fl s Ar sfx_pattern
.Ar command Op args ...
.Sh DESCRIPTION
This command performs various administrative tasks around the
.Nx
Packages System.
.Sh OPTIONS
The following command-line options are supported:
.Bl -tag -width indent
.It Fl b
Print only the base names when matching package names for
.Cm lsall
and
.Cm lsbest .
.It Fl C Ar config
Read the configuration file from
.Ar config
instead of the system default.
.It Fl d Ar lsdir
Set
.Ar lsdir
as the path to the directory in which to find matching package names for
.Cm lsall
and
.Cm lsbest .
.It Fl K Ar pkg_dbdir
Override the value of the
.Dv PKG_DBDIR
configuration option with the value
.Ar pkg_dbdir .
.It Fl q
Perform checks in a quiet manner.
In normal operation,
.Nm
prints a
.Sq \&.
to standard output to indicate progress.
This option suppresses this progress indicator.
.It Fl S
Set the shell glob pattern for package suffixes when matching package
names for
.Cm lsall
and
.Cm lsbest
to be the null suffix.
.It Fl s Ar sfx_pattern
Set the shell glob pattern for package suffixes when matching package
names for
.Cm lsall
and
.Cm lsbest .
The default pattern is ".t[bg]z".
.It Fl V
Print version number and exit.
.It Fl v
Be more verbose.
.El
.Pp
The following commands are supported:
.Bl -tag -width indent
.It Cm add Ar pkg ...
For each listed package, write the absolute pathnames of the files listed in
its
.Pa +CONTENTS
file together with the package they belong to into the package database.
This should be used only by
.Xr pkg_view 1 .
.It Cm audit Oo Fl es Oc Oo Fl t Ar type Oc Oo Ar pkg Oc ...
Check the listed installed packages for vulnerabilities.
If no package is given, check all installed packages.
If
.Fl e
is given, override the
.Dv CHECK_END_OF_LIFE
option from
.Xr pkg_install.conf 5
with
.Qq Li yes .
If
.Fl s
is given, check the signature of the pkg-vulnerabilities file before using it.
.Fl t
restricts the reported vulnerabilities to type
.Ar type .
.It Cm audit-pkg Oo Fl es Oc Oo Fl t Ar type Oc Oo Ar pkg Oc ...
Like
.Cm audit ,
but check only the given package names or patterns.
.It Cm audit-batch Oo Fl es Oc Oo Fl t Ar type Oc Oo Ar pkg-list Oc ...
Like
.Cm audit-pkg ,
but read the package names or patterns one per line from the given files.
.It Cm audit-history Oo Fl s Oc Oo Fl t Ar type Oc Oo Ar pkgbase Oc ...
Print all vulnerabilities for the given base package names.
.It Cm check Op Ar pkg ...
Use this command to check the files belonging to some or all of the
packages installed on the local machine against the checksum
which was recorded in the
.Pa +CONTENTS
files at package installation time.
Symbolic links also have their integrity checked against the recorded
value at package installation time.
If no additional argument is given, the files of all installed packages
are checked, else only the named packages will be checked (wildcards can
be used here, see
.Xr pkg_info 1 ) .
.Pp
The packages'
.Pa +CONTENTS
files will be parsed and the
checksum will be checked for every file found.
A warning message is printed if the expected checksum differs from the
checksum of the file on disk.
Symbolic links are also checked, ensuring that the targets on disk are
the same as the contents recorded at package installation time.
.It Cm check-license Ar condition
Check if
.Ar condition
can be fulfilled with the currently set of accepted licenses.
Prints either yes or no to stdout if the condition can be parsed,
otherwise it exits with error.
.It Cm check-pkg-vulnerabilities Oo Fl s Oc Ar file
Check format and hashes in the pkg-vulnerabilities file
.Ar file .
If
.Fl s
is given, also check the embedded signature.
.It Cm check-signature Ar file ...
Reports if
.Ar file
is a correctly signed package.
.It Cm check-single-license Ar license
Check if
.Ar license
is a valid license name and if it is in the set of acceptable licenses.
Prints either yes or no to stdout if the condition can be parsed,
otherwise it exits with error.
.It Cm config-var Ar variable
Print the current value of
.Ar variable
as used after parsing the configuration file.
.It Cm delete Ar pkg ...
For each listed package, remove all file entries in the package database that
belong to the package.
This should be used only by
.Xr pkg_view 1 .
.It Cm dump
Dump the contents of the package database, similar to
.Cm pkg_info -F .
Columns are printed for the key field used in the pkgdb - the filename -,
and the data field - the package the file belongs to.
.It Cm fetch-pkg-vulnerabilities Oo Fl su Oc
Fetch a new pkg-vulnerabilities file, check the format and if
.Fl s
is given the signature.
If all checks are passed, write it to pkgdb.
If
.Fl u
is given, the fetch is conditional and the file transfer is only done if
the remote version is newer than the one in pkgdb.
.It Cm findbest Ar pattern ...
Search the entries of
.Dv PKG_PATH
for packages matching
.Ar pattern .
Print the URL of the best matching package to stdout for each pattern.
If a pattern is not matched, it is skipped and the command will return
a failure.
.It Cm lsall Ar /dir/pkgpattern
.It Cm lsbest Ar /dir/pkgpattern
List all/best package matching pattern in the given directory
.Pa /dir .
If the
.Fl d
flag is given, then that directory path overrides
.Pa /dir .
Can be used to work around limitations of /bin/sh and other
filename globbing mechanisms.
This option implements matching of
pkg-wildcards against arbitrary files and directories, useful mainly in
the build system itself.
See
.Xr pkg_info 1
for a description of the pattern.
.Pp
Example:
.Bd -literal
yui# cd /usr/pkgsrc/packages/i386ELF/All/
yui# ls unzip*
unzip-5.40.tgz unzip-5.41.tgz
yui# pkg_admin lsall 'unzip*'
/usr/pkgsrc/packages/i386ELF/All/unzip-5.40.tgz
/usr/pkgsrc/packages/i386ELF/All/unzip-5.41.tgz
yui# pkg_admin lsall 'unzip\*[Ge]5.40'
/usr/pkgsrc/packages/i386ELF/All/unzip-5.40.tgz
/usr/pkgsrc/packages/i386ELF/All/unzip-5.41.tgz
yui# pkg_admin lsall 'unzip\*[Ge]5.41'
/usr/pkgsrc/packages/i386ELF/All/unzip-5.41.tgz
yui# pkg_admin lsbest 'unzip\*[Ge]5.40'
/usr/pkgsrc/packages/i386ELF/All/unzip-5.41.tgz
yui# pkg_admin lsall /usr/pkgsrc/packages/i386ELF/All/'{mit,unproven}-pthread*'
/usr/pkgsrc/packages/i386ELF/All/mit-pthreads-1.60b6.tgz
/usr/pkgsrc/packages/i386ELF/All/unproven-pthreads-0.15.tgz
.Ed
.It Cm pmatch Ar pattern Ar pkg
Returns true if
.Ar pkg
matches
.Ar pattern ,
otherwise returns false.
.It Cm rebuild
Rebuild the package database mapping from scratch, using the
.Pa +CONTENTS
files of the installed packages.
This option is only intended for recovery after system crashes
during package installation and removal.
.It Cm rebuild-tree
Rebuild the +REQUIRED_BY files from scratch by reresolving all dependencies.
.Pp
This option is intended to be used for fixing inconsistencies between
the records of depending and depended-on packages, such as can arise
by the use of
.Cm pkg_delete -f .
.It Cm set Ar variable=value pkg ...
Set variable with information about the installed package.
Use
.Cm unset
to remove a variable.
.Pp
Packages that are not installed directly by the user but pulled in as
dependencies are marked by setting
.Dq automatic=YES .
.It Cm gpg-sign-package pkg spkg
Sign the binary package
.Ar pkg
using GPG and write the result to
.Ar spkg .
.It Cm x509-sign-package pkg spkg key cert
Sign the binary package
.Ar pkg
using the key
.Ar key
and the certificate
.Ar cert ,
using
.Ar spkg
as output file.
.It Cm unset Ar variable pkg ...
Remove an installation variable.
.El
.Sh ENVIRONMENT
See
.Xr pkg_install.conf 5
for options, that can also be specified using the environment.
.Sh FILES
.Bl -tag -width /var/db/pkg/pkgdb.byfile.db -compact
.It Pa /var/db/pkg/pkgdb.byfile.db
.It Pa /var/db/pkg/\*[Lt]pkg\*[Gt]/+CONTENTS
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Xr pkg_view 1 ,
.Xr pkg_install.conf 5 ,
.Xr pkgsrc 7
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 1.4 .
.Sh AUTHORS
The
.Nm
command was written by Hubert Feyrer.

114
external/bsd/pkg_install/dist/bpm/bpm.1 vendored Normal file
View file

@ -0,0 +1,114 @@
.\" $NetBSD: bpm.1,v 1.4 2013/07/20 21:40:04 wiz Exp $ */
.\"
.\" Copyright (c) 2003,2009 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Alistair Crooks (agc@NetBSD.org)
.\"
.\" 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.
.\"
.\" 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.
.\"
.Dd August 3, 2007
.Dt BPM 1
.Os
.Sh NAME
.Nm bpm
.Nd menu-based binary package manager
.Sh SYNOPSIS
.Nm
.Op Fl hnVv
.Op Fl b Ar baseURL
.Op Fl m Ar machine
.Op Fl r Ar release
.Op Fl w Ar seconds
.Sh DESCRIPTION
The
.Nm
command is used to locate and install binary packages from any
reachable URL.
.Pp
The following command-line options are supported:
.Bl -tag -width indent
.It Fl b Ar baseURL
Specify a base URL from which to download binary packages.
The default URL is
.Pa ftp://ftp.NetBSD.org/pub/pkgsrc/packages .
.It Fl h
Print a help message and then exit.
.It Fl m Ar machine
Use
.Ar machine
as the machine architecture to be used, instead of that returned by
.Xr uname 1 .
.It Fl n
Don't actually execute the commands to add the package.
.It Fl r Ar release
Use
.Ar release
as the operating system release to be used, instead of that returned by
.Xr uname 1 .
.It Fl V
Print version number and exit.
.It Fl v
Turn on verbose output.
.It Fl w Ar seconds
The number of
.Ar seconds
to wait after displaying an error message and returning to
normal menu operations.
.El
.Pp
.Nm
provides a menu-based binary package manager for
.Nx .
.Nm
first connects to the URL using
.Xr ftp 1 ,
and displays a list of categories for which binary packages exist.
If no categories are displayed, it could
be that the machine architecture or operating system release string
have been wrongly interpreted, and that it will be necessary to override
this values by means of the command line options.
Within a category, a list of packages will be displayed, and by selecting
one using the number assigned to it, the package will be downloaded
automatically, and installed, using the
.Xr pkg_add 1
utility.
It is also possible to change the category currently being examined,
and to quit from the utility, simply by selecting the appropriate choices
on the menu.
.Sh ENVIRONMENT
The environment variables which govern the behavior of
.Xr ftp 1
and
.Xr pkg_add 1
are valid for
.Nm .
.Sh SEE ALSO
.Xr ftp 1 ,
.Xr pkg_add 1 ,
.Xr uname 1
.Sh AUTHORS
The
.Nm
utility was written by
.An Alistair Crooks Aq Mt agc@NetBSD.org .

View file

@ -0,0 +1,220 @@
#! /bin/sh
#
# $NetBSD: bpm.sh.in,v 1.3 2012/02/21 18:36:16 wiz Exp $
#
# Copyright (c) 2003,2009 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Alistair Crooks (agc@NetBSD.org)
#
# 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.
#
# 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.
#
die()
{
echo >&2 "$@"
exit 1
}
check_prog()
{
_var="$1"; _name="$2"
eval _tmp=\"\$$_var\"
if [ "x$_tmp" != "x" ]; then
# Variable is already set (by the user, for example)
return 0
fi
for _d in `echo $PATH | tr ':' ' '`; do
if [ -x "$_d/$_name" ]; then
# Program found
eval $_var=\""$_d/$_name"\"
return 1
fi
done
die "$_name not found in path."
}
check_prog awkprog awk
check_prog echoprog echo
check_prog ftpprog ftp
check_prog idprog id
check_prog moreprog more
check_prog pkg_addprog pkg_add
check_prog rmprog rm
check_prog sedprog sed
check_prog suprog su
check_prog unameprog uname
# print version and exit
version() {
$pkg_addprog -V
exit 0
}
# temporary files
tmpcategories=/tmp/categories.$$
tmppackages=/tmp/packages.$$
# some base parameters
base=ftp://ftp.NetBSD.org/pub/pkgsrc/packages
release=`${unameprog} -r | ${sedprog} -e 's/_STABLE//'`
machine=`${unameprog} -m`
sleepsecs=1
doit=""
while [ $# -gt 0 ]; do
case $1 in
-V) version ;;
-b) base=$2; shift ;;
-h) ${echoprog} "$0 [-b BaseURL] [-h] [-m machine] [-n] [-r release] [-v] [-w secs]"; exit 0;;
-m) machine=$2; shift ;;
-n) doit=":" ;;
-r) release=$2; shift ;;
-v) set -x ;;
-w) sleepsecs=$2; shift ;;
*) break ;;
esac
shift
done
category=""
while true; do
# if we don't have a packages file, then we need to choose a category
case "$category" in
"") # get possible categories
if [ ! -f $tmpcategories ]; then
${echoprog} "Downloading package categories from ${base}..."
${echoprog} "** QUIT" > $tmpcategories
${echoprog} ls | ${ftpprog} ${base}/${release}/${machine}/ 2>/dev/null | \
${awkprog} 'NF == 9 { if ($9 != "All") print $9 }' >> $tmpcategories
fi
# check for bad release numbering
# - it usually shows with 0 categories being displayed
${awkprog} 'END { if (NR == 1) { print "\n\n\n*** No categories found - is the OS release set properly? ***\n\n\n" } }' < $tmpcategories
# display possible categories
${awkprog} '{ print NR ". " $0 }' < $tmpcategories | ${moreprog}
# read a category number from the user
${echoprog} -n "Please type the category number: "
read choice
# validate user's choice
case "$choice" in
0|1) ${rmprog} -f $tmpcategories $tmppackages; exit 0 ;;
[2-9]|[0-9]*) category=`${awkprog} 'NR == '$choice' { print }' < $tmpcategories` ;;
*) category="" ;;
esac
case "$category" in
"") ${echoprog} "No such category \"$choice\""
sleep $sleepsecs
continue
;;
esac
# get possible packages
${echoprog} ""
${echoprog} "Downloading package names from ${base}/${category}..."
${echoprog} "** QUIT" > $tmppackages
${echoprog} "** Change category" >> $tmppackages
${echoprog} ls | ${ftpprog} ${base}/${release}/${machine}/${category}/ 2>/dev/null \
| ${awkprog} 'NF == 11 { print $9 }' >> $tmppackages
;;
esac
# display possible packages
${awkprog} '{ print NR ". " $0 }' < $tmppackages | ${moreprog}
# read a package number from the user
${echoprog} -n "Please type the package number: "
read choice
# validate user's choice
case "$choice" in
1) ${rmprog} -f $tmppackages $tmpcategories; exit 0 ;;
2) category=""; continue ;; # no package to install - choose new category
[3-9]|[0-9]*) package=`${awkprog} 'NR == '$choice' { print }' < $tmppackages` ;;
*) package="" ;;
esac
case "$package" in
"") ${echoprog} "No such package \"$choice\""
sleep $sleepsecs
continue
;;
esac
# check it's not already installed
pkgbase=`${echoprog} ${package} | ${sedprog} -e 's|-[0-9].*||'`
installed=`pkg_info -e $pkgbase`
case "$installed" in
"") ;;
*) ${echoprog} "$package selected, but $installed already installed"
sleep $sleepsecs
continue
;;
esac
# Tell people what we're doing
${echoprog} ""
${echoprog} "Adding package ${base}/${release}/${machine}/${category}/${package}"
cmd="env PKG_PATH=${base}/${release}/${machine}/All ${pkg_addprog} ${package}"
# check if we need to become root for this
if [ `${idprog} -u` != 0 ]; then
${echoprog} "Becoming root@`/bin/hostname` to add a binary package"
${echoprog} -n "`${echoprog} ${suprog} | $awkprog '{ print $1 }'` "
$doit ${suprog} root -c "$cmd"
success=$?
else
$doit $cmd
success=$?
fi
# give feedback after adding the package
case $success in
0) ${echoprog} "$package successfully installed" ;;
*) ${echoprog} "Problems when installing $package - please try again" ;;
esac
${echoprog} ""
${echoprog} -n "[Q]uit, [C]hange category, [I]nstall another package: "
read choice
case "$choice" in
[Qq]) break ;;
[Cc]) category="" ;;
[Ii]) ;;
esac
done
${rmprog} -f $tmpcategories $tmppackages
exit 0

View file

@ -0,0 +1,422 @@
/* $NetBSD: build.c,v 1.1.1.8 2010/04/23 20:54:07 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: build.c,v 1.1.1.8 2010/04/23 20:54:07 joerg Exp $");
/*-
* Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* This code was developed as part of Google's Summer of Code 2007 program.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* 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 main body of the create module.
*
*/
#include "lib.h"
#include "create.h"
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_GRP_H
#include <grp.h>
#endif
#if HAVE_PWD_H
#include <pwd.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <archive.h>
#include <archive_entry.h>
static struct memory_file *contents_file;
static struct memory_file *comment_file;
static struct memory_file *desc_file;
static struct memory_file *install_file;
static struct memory_file *deinstall_file;
static struct memory_file *display_file;
static struct memory_file *build_version_file;
static struct memory_file *build_info_file;
static struct memory_file *size_pkg_file;
static struct memory_file *size_all_file;
static struct memory_file *preserve_file;
static struct memory_file *views_file;
static void
write_meta_file(struct memory_file *file, struct archive *archive)
{
struct archive_entry *entry;
entry = archive_entry_new();
archive_entry_set_pathname(entry, file->name);
archive_entry_copy_stat(entry, &file->st);
archive_entry_set_uname(entry, file->owner);
archive_entry_set_gname(entry, file->group);
if (archive_write_header(archive, entry))
errx(2, "cannot write to archive: %s", archive_error_string(archive));
archive_write_data(archive, file->data, file->len);
archive_entry_free(entry);
}
static void
write_entry(struct archive *archive, struct archive_entry *entry)
{
char buf[16384];
const char *name;
int fd;
off_t len;
ssize_t buf_len;
if (archive_entry_pathname(entry) == NULL) {
warnx("entry with NULL path");
return;
}
if (archive_write_header(archive, entry)) {
errx(2, "cannot write %s to archive: %s",
archive_entry_pathname(entry),
archive_error_string(archive));
}
/* Only regular files can have data. */
if (archive_entry_filetype(entry) != AE_IFREG ||
archive_entry_size(entry) == 0) {
archive_entry_free(entry);
return;
}
name = archive_entry_pathname(entry);
if ((fd = open(name, O_RDONLY)) == -1)
err(2, "cannot open data file %s", name);
len = archive_entry_size(entry);
while (len > 0) {
buf_len = (len > (off_t)sizeof(buf)) ? (ssize_t)sizeof(buf) : (ssize_t)len;
if ((buf_len = read(fd, buf, buf_len)) == 0)
break;
else if (buf_len < 0)
err(2, "cannot read from %s", name);
archive_write_data(archive, buf, (size_t)buf_len);
len -= buf_len;
}
close(fd);
archive_entry_free(entry);
}
static void
write_normal_file(const char *name, struct archive *archive,
struct archive_entry_linkresolver *resolver,
const char *owner, const char *group)
{
char buf[16384];
ssize_t buf_len;
struct archive_entry *entry, *sparse_entry;
struct stat st;
if (lstat(name, &st) == -1)
err(2, "lstat failed for file %s", name);
entry = archive_entry_new();
archive_entry_set_pathname(entry, name);
archive_entry_copy_stat(entry, &st);
if (owner != NULL) {
uid_t uid;
archive_entry_set_uname(entry, owner);
if (uid_from_user(owner, &uid) == -1)
errx(2, "user %s unknown", owner);
archive_entry_set_uid(entry, uid);
} else {
archive_entry_set_uname(entry, user_from_uid(st.st_uid, 1));
}
if (group != NULL) {
gid_t gid;
archive_entry_set_gname(entry, group);
if (gid_from_group(group, &gid) == -1)
errx(2, "group %s unknown", group);
archive_entry_set_gid(entry, gid);
} else {
archive_entry_set_gname(entry, group_from_gid(st.st_gid, 1));
}
if ((st.st_mode & S_IFMT) == S_IFLNK) {
buf_len = readlink(name, buf, sizeof buf);
if (buf_len < 0)
err(2, "cannot read symlink %s", name);
buf[buf_len] = '\0';
archive_entry_set_symlink(entry, buf);
}
archive_entry_linkify(resolver, &entry, &sparse_entry);
if (entry != NULL)
write_entry(archive, entry);
if (sparse_entry != NULL)
write_entry(archive, sparse_entry);
}
static void
make_dist(const char *pkg, const char *suffix, const package_t *plist)
{
char *archive_name;
const char *owner, *group;
const plist_t *p;
struct archive *archive;
struct archive_entry *entry, *sparse_entry;
struct archive_entry_linkresolver *resolver;
char *initial_cwd;
archive = archive_write_new();
archive_write_set_format_pax_restricted(archive);
if ((resolver = archive_entry_linkresolver_new()) == NULL)
errx(2, "cannot create link resolver");
archive_entry_linkresolver_set_strategy(resolver,
archive_format(archive));
if (CompressionType == NULL) {
if (strcmp(suffix, "tbz") == 0 ||
strcmp(suffix, "tar.bz2") == 0)
CompressionType = "bzip2";
else if (strcmp(suffix, "tgz") == 0 ||
strcmp(suffix, "tar.gz") == 0)
CompressionType = "gzip";
else
CompressionType = "none";
}
if (strcmp(CompressionType, "bzip2") == 0)
archive_write_set_compression_bzip2(archive);
else if (strcmp(CompressionType, "gzip") == 0)
archive_write_set_compression_gzip(archive);
else if (strcmp(CompressionType, "xz") == 0)
archive_write_set_compression_xz(archive);
else if (strcmp(CompressionType, "none") == 0)
archive_write_set_compression_none(archive);
else
errx(1, "Unspported compression type for -F: %s",
CompressionType);
archive_name = xasprintf("%s.%s", pkg, suffix);
if (archive_write_open_file(archive, archive_name))
errx(2, "cannot create archive: %s", archive_error_string(archive));
free(archive_name);
owner = DefaultOwner;
group = DefaultGroup;
write_meta_file(contents_file, archive);
write_meta_file(comment_file, archive);
write_meta_file(desc_file, archive);
if (Install)
write_meta_file(install_file, archive);
if (DeInstall)
write_meta_file(deinstall_file, archive);
if (Display)
write_meta_file(display_file, archive);
if (BuildVersion)
write_meta_file(build_version_file, archive);
if (BuildInfo)
write_meta_file(build_info_file, archive);
if (SizePkg)
write_meta_file(size_pkg_file, archive);
if (SizeAll)
write_meta_file(size_all_file, archive);
if (Preserve)
write_meta_file(preserve_file, archive);
if (create_views)
write_meta_file(views_file, archive);
initial_cwd = getcwd(NULL, 0);
for (p = plist->head; p; p = p->next) {
if (p->type == PLIST_FILE) {
write_normal_file(p->name, archive, resolver, owner, group);
} else if (p->type == PLIST_CWD) {
chdir(p->name);
} else if (p->type == PLIST_IGNORE) {
p = p->next;
} else if (p->type == PLIST_CHOWN) {
if (p->name != NULL)
owner = p->name;
else
owner = DefaultOwner;
} else if (p->type == PLIST_CHGRP) {
if (p->name != NULL)
group = p->name;
else
group = DefaultGroup;
}
}
entry = NULL;
archive_entry_linkify(resolver, &entry, &sparse_entry);
while (entry != NULL) {
write_entry(archive, entry);
entry = NULL;
archive_entry_linkify(resolver, &entry, &sparse_entry);
}
archive_entry_linkresolver_free(resolver);
if (archive_write_close(archive))
errx(2, "cannot finish archive: %s", archive_error_string(archive));
archive_write_finish(archive);
free(initial_cwd);
}
static struct memory_file *
load_and_add(package_t *plist, const char *input_name,
const char *target_name, mode_t perm)
{
struct memory_file *file;
file = load_memory_file(input_name, target_name, DefaultOwner,
DefaultGroup, perm);
add_plist(plist, PLIST_IGNORE, NULL);
add_plist(plist, PLIST_FILE, target_name);
return file;
}
static struct memory_file *
make_and_add(package_t *plist, const char *target_name,
char *content, mode_t perm)
{
struct memory_file *file;
file = make_memory_file(target_name, content, strlen(content),
DefaultOwner, DefaultGroup, perm);
add_plist(plist, PLIST_IGNORE, NULL);
add_plist(plist, PLIST_FILE, target_name);
return file;
}
int
pkg_build(const char *pkg, const char *full_pkg, const char *suffix,
package_t *plist)
{
char *plist_buf;
size_t plist_len;
/* Now put the release specific items in */
add_plist(plist, PLIST_CWD, ".");
comment_file = make_and_add(plist, COMMENT_FNAME, Comment, 0444);
desc_file = make_and_add(plist, DESC_FNAME, Desc, 0444);
if (Install) {
install_file = load_and_add(plist, Install, INSTALL_FNAME,
0555);
}
if (DeInstall) {
deinstall_file = load_and_add(plist, DeInstall,
DEINSTALL_FNAME, 0555);
}
if (Display) {
display_file = load_and_add(plist, Display,
DISPLAY_FNAME, 0444);
add_plist(plist, PLIST_DISPLAY, DISPLAY_FNAME);
}
if (BuildVersion) {
build_version_file = load_and_add(plist, BuildVersion,
BUILD_VERSION_FNAME, 0444);
}
if (BuildInfo) {
build_info_file = load_and_add(plist, BuildInfo,
BUILD_INFO_FNAME, 0444);
}
if (SizePkg) {
size_pkg_file = load_and_add(plist, SizePkg,
SIZE_PKG_FNAME, 0444);
}
if (SizeAll) {
size_all_file = load_and_add(plist, SizeAll,
SIZE_ALL_FNAME, 0444);
}
if (Preserve) {
preserve_file = load_and_add(plist, Preserve,
PRESERVE_FNAME, 0444);
}
if (create_views)
views_file = make_and_add(plist, VIEWS_FNAME, xstrdup(""), 0444);
/* Finally, write out the packing list */
stringify_plist(plist, &plist_buf, &plist_len, realprefix);
contents_file = make_memory_file(CONTENTS_FNAME, plist_buf, plist_len,
DefaultOwner, DefaultGroup, 0644);
/* And stick it into a tar ball */
make_dist(pkg, suffix, plist);
return TRUE; /* Success */
}

View file

@ -0,0 +1,77 @@
/* $NetBSD: create.h,v 1.1.1.5 2009/11/05 18:39:02 joerg Exp $ */
/* from FreeBSD Id: create.h,v 1.13 1997/10/08 07:46:19 charnier Exp */
/*
* 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
*
* Include and define various things wanted by the create command.
*
*/
#ifndef _INST_CREATE_H_INCLUDE
#define _INST_CREATE_H_INCLUDE
struct memory_file {
struct stat st;
const char *name;
const char *owner;
const char *group;
mode_t mode;
char *data;
size_t len;
};
extern char *Prefix;
extern char *Comment;
extern char *Desc;
extern char *Display;
extern char *Install;
extern char *DeInstall;
extern char *Contents;
extern char *Pkgdeps;
extern char *BuildPkgdeps;
extern char *Pkgcfl;
extern char *BuildVersion;
extern char *BuildInfo;
extern char *SizePkg;
extern char *SizeAll;
extern char *Preserve;
extern char *realprefix;
extern char *DefaultOwner;
extern char *DefaultGroup;
extern const char *CompressionType;
extern int PlistOnly;
extern int RelativeLinks;
extern int update_pkgdb;
extern int create_views;
void check_list(package_t *, const char *);
void copy_plist(char *, package_t *);
struct memory_file
*load_memory_file(const char *, const char *,
const char *, const char *, mode_t);
struct memory_file
*make_memory_file(const char *, void *, size_t,
const char *, const char *, mode_t);
void free_memory_file(struct memory_file *);
int pkg_perform(const char *);
int pkg_build(const char *, const char *, const char *, package_t *plist);
#endif /* _INST_CREATE_H_INCLUDE */

View file

@ -0,0 +1,217 @@
/* $NetBSD: main.c,v 1.1.1.7 2010/01/30 21:33:31 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: main.c,v 1.1.1.7 2010/01/30 21:33:31 joerg Exp $");
/*
* FreeBSD install - a package for the installation and maintainance
* of non-core utilities.
*
* Jordan K. Hubbard
* 18 July 1993
*
* This is the create module.
*
*/
#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#include "create.h"
static const char Options[] = "B:C:D:EF:I:K:L:OP:S:T:UVb:c:d:f:g:i:k:ln:p:r:s:u:v";
char *Prefix = NULL;
char *Comment = NULL;
char *Desc = NULL;
char *Display = NULL;
char *Install = NULL;
char *DeInstall = NULL;
char *Contents = NULL;
char *Pkgdeps = NULL;
char *BuildPkgdeps = NULL;
char *Pkgcfl = NULL;
char *BuildVersion = NULL;
char *BuildInfo = NULL;
char *SizePkg = NULL;
char *SizeAll = NULL;
char *Preserve = NULL;
char *DefaultOwner = NULL;
char *DefaultGroup = NULL;
char *realprefix = NULL;
const char *CompressionType = NULL;
int update_pkgdb = 1;
int create_views = 0;
int PlistOnly = 0;
int RelativeLinks = 0;
Boolean File2Pkg = FALSE;
static void
usage(void)
{
fprintf(stderr,
"usage: pkg_create [-ElOUVv] [-B build-info-file] [-b build-version-file]\n"
" [-C cpkgs] [-D displayfile] [-F compression] \n"
" [-I realprefix] [-i iscript]\n"
" [-K pkg_dbdir] [-k dscript]\n"
" [-n preserve-file] [-P dpkgs] [-p prefix] [-r rscript]\n"
" [-S size-all-file] [-s size-pkg-file]\n"
" [-T buildpkgs] [-u owner] [-g group]\n"
" -c comment -d description -f packlist\n"
" pkg-name\n");
exit(1);
}
int
main(int argc, char **argv)
{
int ch;
setprogname(argv[0]);
while ((ch = getopt(argc, argv, Options)) != -1)
switch (ch) {
case 'v':
Verbose = TRUE;
break;
case 'E':
create_views = 1;
break;
case 'F':
CompressionType = optarg;
break;
case 'I':
realprefix = optarg;
break;
case 'O':
PlistOnly = 1;
break;
case 'U':
update_pkgdb = 0;
break;
case 'p':
Prefix = optarg;
break;
case 's':
SizePkg = optarg;
break;
case 'S':
SizeAll = optarg;
break;
case 'f':
Contents = optarg;
break;
case 'c':
Comment = optarg;
break;
case 'd':
Desc = optarg;
break;
case 'g':
DefaultGroup = optarg;
break;
case 'i':
Install = optarg;
break;
case 'K':
pkgdb_set_dir(optarg, 3);
break;
case 'k':
DeInstall = optarg;
break;
case 'l':
RelativeLinks = 1;
break;
case 'L':
warnx("Obsolete -L option ignored");
break;
case 'u':
DefaultOwner = optarg;
break;
case 'D':
Display = optarg;
break;
case 'n':
Preserve = optarg;
break;
case 'P':
Pkgdeps = optarg;
break;
case 'T':
BuildPkgdeps = optarg;
break;
case 'C':
Pkgcfl = optarg;
break;
case 'b':
BuildVersion = optarg;
break;
case 'B':
BuildInfo = optarg;
break;
case 'V':
show_version();
/* NOTREACHED */
case '?':
default:
usage();
break;
}
argc -= optind;
argv += optind;
pkg_install_config();
if (argc == 0) {
warnx("missing package name");
usage();
}
if (argc != 1) {
warnx("only one package name allowed");
usage();
}
if (pkg_perform(*argv))
return 0;
if (Verbose) {
if (PlistOnly)
warnx("package registration failed");
else
warnx("package creation failed");
}
return 1;
}

View file

@ -0,0 +1,244 @@
/* $NetBSD: perform.c,v 1.1.1.5 2009/11/05 18:39:02 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: perform.c,v 1.1.1.5 2009/11/05 18:39:02 joerg Exp $");
/*
* 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 main body of the create module.
*
*/
#include "lib.h"
#include "create.h"
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
static void
sanity_check(void)
{
if (!Comment)
errx(2, "required package comment string is missing (-c comment)");
if (!Desc)
errx(2, "required package description string is missing (-d desc)");
if (!Contents)
errx(2, "required package contents list is missing (-f [-]file)");
}
static void
register_depends(package_t *plist, char *deps, int build_only)
{
char *cp;
if (Verbose && !PlistOnly) {
if (build_only)
printf("Registering build depends:");
else
printf("Registering depends:");
}
while (deps) {
cp = strsep(&deps, " \t\n");
if (*cp) {
char *best_installed;
best_installed = find_best_matching_installed_pkg(cp);
if (best_installed != NULL) {
add_plist(plist, PLIST_BLDDEP, best_installed);
if (Verbose && !PlistOnly && build_only)
printf(" %s", cp);
} else
warnx("No matching package installed for %s", cp);
free(best_installed);
if (!build_only) {
add_plist(plist, PLIST_PKGDEP, cp);
if (Verbose && !PlistOnly)
printf(" %s", cp);
}
}
}
if (Verbose && !PlistOnly)
printf(".\n");
}
/*
* Expect "fname" to point at a file, and read it into
* the buffer returned.
*/
static char *
fileGetContents(char *fname)
{
char *contents;
struct stat sb;
int fd;
if (stat(fname, &sb) == FAIL) {
errx(2, "can't stat '%s'", fname);
}
contents = xmalloc((size_t) (sb.st_size) + 1);
fd = open(fname, O_RDONLY, 0);
if (fd == FAIL) {
errx(2, "unable to open '%s' for reading", fname);
}
if (read(fd, contents, (size_t) sb.st_size) != (ssize_t) sb.st_size) {
errx(2, "short read on '%s' - did not get %lld bytes",
fname, (long long) sb.st_size);
}
close(fd);
contents[(size_t) sb.st_size] = '\0';
return contents;
}
/*
* Get a string parameter as a file spec or as a "contents follow -" spec
*/
static void
get_dash_string(char **s)
{
if (**s == '-')
*s = xstrdup(*s + 1);
else
*s = fileGetContents(*s);
}
int
pkg_perform(const char *pkg)
{
char *cp;
FILE *pkg_in;
package_t plist;
const char *full_pkg, *suffix;
char *allocated_pkg;
int retval;
/* Break the package name into base and desired suffix (if any) */
if ((cp = strrchr(pkg, '.')) != NULL) {
allocated_pkg = xmalloc(cp - pkg + 1);
memcpy(allocated_pkg, pkg, cp - pkg);
allocated_pkg[cp - pkg] = '\0';
suffix = cp + 1;
full_pkg = pkg;
pkg = allocated_pkg;
} else {
allocated_pkg = NULL;
full_pkg = pkg;
suffix = "tgz";
}
/* Preliminary setup */
sanity_check();
if (Verbose && !PlistOnly)
printf("Creating package %s\n", pkg);
get_dash_string(&Comment);
get_dash_string(&Desc);
if (IS_STDIN(Contents))
pkg_in = stdin;
else {
pkg_in = fopen(Contents, "r");
if (!pkg_in)
errx(2, "unable to open contents file '%s' for input", Contents);
}
plist.head = plist.tail = NULL;
/* Stick the dependencies, if any, at the top */
if (Pkgdeps)
register_depends(&plist, Pkgdeps, 0);
/*
* Put the build dependencies after the dependencies.
* This works due to the evaluation order in pkg_add.
*/
if (BuildPkgdeps)
register_depends(&plist, BuildPkgdeps, 1);
/* Put the conflicts directly after the dependencies, if any */
if (Pkgcfl) {
if (Verbose && !PlistOnly)
printf("Registering conflicts:");
while (Pkgcfl) {
cp = strsep(&Pkgcfl, " \t\n");
if (*cp) {
add_plist(&plist, PLIST_PKGCFL, cp);
if (Verbose && !PlistOnly)
printf(" %s", cp);
}
}
if (Verbose && !PlistOnly)
printf(".\n");
}
/* Slurp in the packing list */
append_plist(&plist, pkg_in);
if (pkg_in != stdin)
fclose(pkg_in);
/* Prefix should override the packing list */
if (Prefix) {
delete_plist(&plist, FALSE, PLIST_CWD, NULL);
add_plist_top(&plist, PLIST_CWD, Prefix);
}
/*
* Run down the list and see if we've named it, if not stick in a name
* at the top.
*/
if (find_plist(&plist, PLIST_NAME) == NULL) {
add_plist_top(&plist, PLIST_NAME, basename_of(pkg));
}
/* Make first "real contents" pass over it */
check_list(&plist, basename_of(pkg));
/*
* We're just here for to dump out a revised plist for the FreeBSD ports
* hack. It's not a real create in progress.
*/
if (PlistOnly) {
write_plist(&plist, stdout, realprefix);
retval = TRUE;
} else {
#ifdef BOOTSTRAP
warnx("Package building is not supported in bootstrap mode");
retval = FALSE;
#else
retval = pkg_build(pkg, full_pkg, suffix, &plist);
#endif
}
/* Cleanup */
free(Comment);
free(Desc);
free_plist(&plist);
free(allocated_pkg);
return retval;
}

View file

@ -0,0 +1,504 @@
.\" $NetBSD: pkg_create.1,v 1.1.1.8 2010/04/23 20:54:08 joerg Exp $
.\"
.\" FreeBSD install - a package for the installation and maintenance
.\" 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
.\"
.\"
.\" @(#)pkg_create.1
.\" from FreeBSD Id: pkg_create.1,v 1.19 1997/05/02 22:00:05 max Exp
.\"
.\" hacked up by John Kohl for NetBSD--fixed a few bugs, extended keywords,
.\" added dependency tracking, etc.
.\"
.\" [jkh] Took John's changes back and made some additional extensions for
.\" better integration with FreeBSD's new ports collection.
.\"
.Dd January 20, 2010
.Dt PKG_CREATE 1
.Os
.Sh NAME
.Nm pkg_create
.Nd a utility for creating software package distributions
.Sh SYNOPSIS
.Nm
.Op Fl ElOUVv
.Bk -words
.Op Fl B Ar build-info-file
.Ek
.Bk -words
.Op Fl b Ar build-version-file
.Ek
.Bk -words
.Op Fl C Ar cpkgs
.Ek
.Bk -words
.Op Fl D Ar displayfile
.Ek
.Bk -words
.Op Fl F Ar compression
.Ek
.Bk -words
.Op Fl g Ar group
.Ek
.Bk -words
.Op Fl I Ar realprefix
.Ek
.Bk -words
.Op Fl i Ar iscript
.Ek
.Bk -words
.Op Fl K Ar pkg_dbdir
.Ek
.Bk -words
.Op Fl k Ar dscript
.Ek
.Bk -words
.Op Fl n Ar preserve-file
.Ek
.Bk -words
.Op Fl P Ar dpkgs
.Ek
.Bk -words
.Op Fl T Ar buildpkgs
.Ek
.Bk -words
.Op Fl p Ar prefix
.Ek
.Bk -words
.Op Fl S Ar size-all-file
.Ek
.Bk -words
.Op Fl s Ar size-pkg-file
.Ek
.Bk -words
.Op Fl t Ar template
.Ek
.Bk -words
.Op Fl u Ar owner
.Ek
.Bk -words
.Fl c Ar comment
.Ek
.Bk -words
.Fl d Ar description
.Ek
.Bk -words
.Fl f Ar packlist
.Ek
.Ar pkg-name
.Sh DESCRIPTION
The
.Nm
command is used to create packages that will subsequently be fed to
one of the package extraction/info utilities.
The input description and command line arguments for the creation of a
package are not really meant to be human-generated, though it is easy
enough to do so.
It is more expected that you will use a front-end tool for
the job rather than muddling through it yourself.
Nonetheless, a short description of the input syntax is included in this
document.
.Sh OPTIONS
The following command line options are supported:
.Bl -tag -width indent
.It Fl B Ar build-info-file
Install the file
.Ar build-info-file
so that users of binary packages can see what
.Xr make 1
definitions
were used to control the build when creating the
binary package.
This allows various build definitions to be retained in a binary package
and viewed wherever it is installed, using
.Xr pkg_info 1 .
.It Fl b Ar build-version-file
Install the file
.Ar build-version-file
so that users of binary packages can see what versions of
the files used to control the build were used when creating the
binary package.
This allows some fine-grained version control information to be retained
in a binary package and viewed wherever it is installed, using
.Xr pkg_info 1 .
.It Fl C Ar cpkgs
Set the initial package conflict list to
.Ar cpkgs .
This is assumed to be a whitespace separated list of package names
and is meant as a convenient shorthand for specifying multiple
.Cm @pkgcfl
directives in the packing list (see PACKING LIST DETAILS section below).
.It Fl c Ar [-]desc
Fetch package
.Pq one line description
from file
.Ar desc
or, if preceded by
.Cm - ,
the argument itself.
This string should also give some idea of which version of the product
(if any) the package represents.
.It Fl D Ar displayfile
Display the file after installing the package.
Useful for things like legal notices on almost-free software, etc.
.It Fl d Ar [-]desc
Fetch long description for package from file
.Ar desc
or, if preceded by
.Cm - ,
the argument itself.
.It Fl E
Add an empty views file to the package.
.It Fl F Ar compression
Use
.Ar compression
as compression algorithm.
This overrides the heuristic to guess the compression type from the
output name.
Currently supported values are bzip2, gzip, none and xz.
.It Fl f Ar packlist
Fetch
.Pq packing list
for package from the file
.Ar packlist
or
.Cm stdin
if
.Ar packlist
is a
.Cm -
(dash).
.It Fl g Ar group
Make
.Ar group
the default group ownership instead of extracting it from the file system.
.It Fl I Ar realprefix
Provide the real prefix, as opposed to the staging prefix, for use in
staged installations of packages.
.It Fl i Ar iscript
Set
.Ar iscript
to be the install procedure for the package.
This can be any executable program (or shell script).
It will be invoked automatically when the package is later installed.
.It Fl K Ar pkg_dbdir
Override the value of the
.Dv PKG_DBDIR
configuration option with the value
.Ar pkg_dbdir .
.It Fl k Ar dscript
Set
.Ar dscript
to be the de-install procedure for the package.
This can be any executable program (or shell script).
It will be invoked automatically
when the package is later (if ever) de-installed.
.It Fl l
Check that any symbolic links which are to be placed in the package are
relative to the current prefix.
This means using
.Xr unlink 2
and
.Xr symlink 2
to remove and re-link
any symbolic links which are targeted at full path names.
.It Fl n Ar preserve-file
The file is used to denote that the package should not be deleted.
This is intended for use where the deletion of packages may present
a bootstrap problem.
.It Fl O
Go into a
.Pq packing list only
mode.
This is used to do
.Pq fake pkg_add
operations when a package is installed.
In such cases, it is necessary to know what the final, adjusted packing
list will look like.
.It Fl P Ar dpkgs
Set the initial package dependency list to
.Ar dpkgs .
This is assumed to be a whitespace separated list of package names
and is meant as a convenient shorthand for specifying multiple
.Cm @pkgdep
directives in the packing list (see PACKING LIST DETAILS section below).
In addition, the exact versions of the packages referred to in the
.Ar dpkgs
list will be added to the packing list in the form of
.Cm @blddep
directives.
.It Fl T Ar buildpkgs
The exact versions of the packages referred to in the
.Ar buildpkgs
list will be added to the packing list in the form of
.Cm @blddep
directives.
This directives are stored after those created by the
.Fl P
option.
.Ar buildpkgs
is assumed to be a whitespace separated list of package names.
.It Fl p Ar prefix
Set
.Ar prefix
as the initial directory
.Pq base
to start from in selecting files for
the package.
.It Fl S Ar size-all-file
Store the given file for later querying with the
.Xr pkg_info 1
.Fl S
flag.
The file is expected to contain the size (in bytes) of all files of
this package plus any required packages added up and stored as a
ASCII string, terminated by a newline.
.It Fl s Ar size-pkg-file
Store the given file for later querying with the
.Xr pkg_info 1
.Fl s
flag.
The file is expected to contain the size (in bytes) of all files of
this package added up and stored as a ASCII string, terminated by a newline.
.It Fl t Ar template
Use
.Ar template
as the input to
.Xr mktemp 3 .
By default, this is the string
.Pa /tmp/instmp.XXXXXX ,
but it may be necessary to override it in the situation where
space in your
.Pa /tmp
directory is limited.
Be sure to leave some number of
.Sq X
characters for
.Xr mktemp 3
to fill in with a unique ID.
.It Fl U
Do not update the package file database with any file information.
.It Fl u Ar owner
Make
.Ar owner
the default owner instead of extracting it from the file system.
.It Fl V
Print version number and exit.
.It Fl v
Turn on verbose output.
.El
.Sh PACKING LIST DETAILS
The
.Pq packing list
format (see
.Fl f )
is fairly simple, being
nothing more than a single column of filenames to include in the
package.
However, since absolute pathnames are generally a bad idea
for a package that could be installed potentially anywhere, there is
another method of specifying where things are supposed to go
and, optionally, what ownership and mode information they should be
installed with.
This is done by embedding specialized command sequences
in the packing list.
Briefly described, these sequences are:
.Bl -tag -width indent -compact
.It Cm @cwd Ar directory
Set the internal directory pointer to point to
.Ar directory .
All subsequent filenames will be assumed relative to this directory.
Note:
.Cm @cd
is also an alias for this command.
.It Cm @src Ar directory
This command is supported for compatibility only.
It was formerly used to override
.Cm @cwd
during package creation.
.It Cm @exec Ar command
Execute
.Ar command
as part of the unpacking process.
If
.Ar command
contains any of the following sequences somewhere in it, they will
be expanded inline.
For the following examples, assume that
.Cm @cwd
is set to
.Pa /usr/local
and the last extracted file was
.Pa bin/emacs .
.Bl -tag -width indent -compact
.It Cm "\&%F"
Expands to the last filename extracted (as specified), in the example case
.Pa bin/emacs
.It Cm "\&%D"
Expand to the current directory prefix, as set with
.Cm @cwd ,
in the example case
.Pa /usr/local .
.It Cm "\&%B"
Expand to the
.Pq basename
of the fully qualified filename, that
is the current directory prefix, plus the last filespec, minus
the trailing filename.
In the example case, that would be
.Pa /usr/local/bin .
.It Cm "\&%f"
Expand to the
.Pq filename
part of the fully qualified name, or
the converse of
.Cm \&%B ,
being in the example case,
.Pa emacs .
.El
.It Cm @unexec Ar command
Execute
.Ar command
as part of the deinstallation process.
Expansion of special
.Cm \&%
sequences is the same as for
.Cm @exec .
This command is not executed during the package add, as
.Cm @exec
is, but rather when the package is deleted.
This is useful for deleting links and other ancillary files that were created
as a result of adding the package, but not directly known to the package's
table of contents (and hence not automatically removable).
The advantage of using
.Cm @unexec
over a deinstallation script is that you can use the
.Pq special sequence expansion
to get at files regardless of where they've
been potentially redirected (see
.Fl p ) .
.It Cm @mode Ar mode
Set default permission for all subsequently extracted files to
.Ar mode .
Format is the same as that used by the
.Cm chmod
command (well, considering that it's later handed off to it, that's
no surprise).
Use without an arg to set back to default (extraction) permissions.
.It Cm @option Ar option
Set internal package options, the only currently supported one
being
.Ar preserve ,
which tells pkg_add to move any existing files out of the way,
preserving the previous contents (which are also resurrected on
pkg_delete, so caveat emptor).
.It Cm @owner Ar user
Set default ownership for all subsequently extracted files to
.Ar user .
Use without an arg to set back to default (extraction)
ownership.
.It Cm @group Ar group
Set default group ownership for all subsequently extracted files to
.Ar group .
Use without an arg to set back to default (extraction)
group ownership.
.It Cm @comment Ar string
Embed a comment in the packing list.
Useful in trying to document some particularly hairy sequence that
may trip someone up later.
.It Cm @ignore
Used internally to tell extraction to ignore the next file (don't
copy it anywhere), as it's used for some special purpose.
.It Cm @name Ar name
Set the name of the package.
This is mandatory and is usually put at the top.
This name is potentially different than the name of the file it came in,
and is used when keeping track of the package for later deinstallation.
Note that
.Nm
will derive this field from the
.Ar pkg-name
and add it automatically if none is given.
.It Cm @pkgdir Ar name
Declare directory
.Pa name
as managed.
If it does not exist at installation time, it is created.
If this directory is no longer referenced by packages and the last
file or directory in it is deleted, the directory is removed as well.
.It Cm @dirrm Ar name
This command is supported for compatibility only.
If directory
.Pa name
exists, it will be deleted at deinstall time.
.It Cm @display Ar name
Declare
.Pa name
as the file to be displayed at install time (see
.Fl D
above).
.It Cm @pkgdep Ar pkgname
Declare a dependency on the
.Ar pkgname
package.
The
.Ar pkgname
package must be installed before this package may be
installed, and this package must be deinstalled before the
.Ar pkgname
package is deinstalled.
Multiple
.Cm @pkgdep
directives may be used if the package depends on multiple other packages.
.It Cm @blddep Ar pkgname
Declare that this package was built with the exact version
of
.Ar pkgname
(since the
.Cm @pkgdep
directive may contain wildcards or relational
package version information).
.It Cm @pkgcfl Ar pkgcflname
Declare a conflict with the
.Ar pkgcflname
package, as the two packages contain references to the same files,
and so cannot co-exist on the same system.
.El
.Sh ENVIRONMENT
See
.Xr pkg_install.conf 5
for options, that can also be specified using the environment.
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_admin 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Xr pkg_install.conf 5
.Xr pkgsrc 7
.Sh HISTORY
The
.Nm
command first appeared in
.Fx .
.Sh AUTHORS
.Bl -tag -width indent -compact
.It Jordan Hubbard
most of the work
.It John Kohl
refined it for
.Nx
.It Hubert Feyrer
.Nx
wildcard dependency processing, pkgdb, pkg size recording etc.
.El

View file

@ -0,0 +1,211 @@
/* $NetBSD: pl.c,v 1.1.1.4 2009/11/05 18:39:03 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pl.c,v 1.1.1.4 2009/11/05 18:39:03 joerg Exp $");
/*
* 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 dealing with the packing list.
*
*/
#include "lib.h"
#include "create.h"
#if HAVE_ERR_H
#include <err.h>
#endif
#ifndef NETBSD
#include <nbcompat/md5.h>
#else
#include <md5.h>
#endif
/*
* Check that any symbolic link is relative to the prefix
*/
static void
CheckSymlink(char *name, char *prefix, size_t prefixcc)
{
char newtgt[MaxPathSize];
char oldtgt[MaxPathSize];
char *slash;
int slashc;
int cc;
int i;
if ((cc = readlink(name, oldtgt, sizeof(oldtgt) - 1)) > 0) {
oldtgt[cc] = 0;
if (strncmp(oldtgt, prefix, prefixcc) == 0 && oldtgt[prefixcc] == '/') {
for (slashc = 0, slash = &name[prefixcc + 1]; (slash = strchr(slash, '/')) != (char *) NULL; slash++, slashc++) {
}
for (cc = i = 0; i < slashc; i++) {
strlcpy(&newtgt[cc], "../", sizeof(newtgt) - cc);
cc += 3;
}
strlcpy(&newtgt[cc], &oldtgt[prefixcc + 1], sizeof(newtgt) - cc);
(void) fprintf(stderr, "Full pathname symlink `%s' is target of `%s' - adjusting to `%s'\n", oldtgt, name, newtgt);
if (unlink(name) != 0) {
warn("can't unlink `%s'", name);
} else if (symlink(newtgt, name) != 0) {
warn("can't symlink `%s' called `%s'", newtgt, name);
}
}
}
}
/*
* Check a list for files that require preconversion
*/
void
check_list(package_t *pkg, const char *PkgName)
{
struct stat st;
plist_t *tmp;
plist_t *p;
char buf[ChecksumHeaderLen + LegibleChecksumLen];
char target[MaxPathSize + SymlinkHeaderLen];
char name[MaxPathSize];
char *cwd = NULL;
char *pkgname = NULL;
int cc;
/* Open Package Database for writing */
if (update_pkgdb && !pkgdb_open(ReadWrite))
err(EXIT_FAILURE, "can't open pkgdb");
for (p = pkg->head; p; p = p->next) {
switch (p->type) {
case PLIST_CWD:
cwd = p->name;
break;
case PLIST_NAME:
pkgname = p->name;
break;
case PLIST_IGNORE:
p = p->next;
break;
case PLIST_PKGDIR:
if (cwd == NULL)
errx(2, "@pkgdir without preceding @cwd found");
if (pkgname == NULL)
errx(2, "@pkgdir without preceding @name found");
if (update_pkgdb) {
add_pkgdir(pkgname, cwd, p->name);
/* mkdir_p(cwd, p->name); */
}
break;
case PLIST_FILE:
/*
* pkgdb handling - usually, we enter files
* into the pkgdb as soon as they hit the disk,
* but as they are present before pkg_create
* starts, it's ok to do this somewhere here
*/
if (cwd == NULL)
errx(2, "file without preceding @cwd found");
if (update_pkgdb) {
char *s, t[MaxPathSize];
(void) snprintf(t, sizeof(t), "%s%s%s",
cwd,
(strcmp(cwd, "/") == 0) ? "" : "/",
p->name);
s = pkgdb_retrieve(t);
if (s && PlistOnly)
warnx("Overwriting %s - "
"pkg %s bogus/conflicting?", t, s);
else {
pkgdb_store(t, PkgName);
}
}
/* prepend DESTDIR if set? - HF */
(void) snprintf(name, sizeof(name), "%s%s%s",
cwd,
(strcmp(cwd, "/") == 0) ? "" : "/",
p->name);
if (lstat(name, &st) < 0) {
warnx("can't stat `%s'", name);
continue;
}
switch (st.st_mode & S_IFMT) {
case S_IFDIR:
warnx("Warning - directory `%s' in PLIST", name);
break;
case S_IFLNK:
if (RelativeLinks) {
CheckSymlink(name, cwd, strlen(cwd));
}
(void) strlcpy(target, SYMLINK_HEADER,
sizeof(target));
if ((cc = readlink(name, &target[SymlinkHeaderLen],
sizeof(target) - SymlinkHeaderLen - 1)) < 0) {
warnx("can't readlink `%s'", name);
continue;
}
target[SymlinkHeaderLen + cc] = 0x0;
tmp = new_plist_entry();
tmp->name = xstrdup(target);
tmp->type = PLIST_COMMENT;
tmp->next = p->next;
tmp->prev = p;
if (p == pkg->tail) {
pkg->tail = tmp;
}
p->next = tmp;
p = tmp;
break;
case S_IFCHR:
warnx("Warning - char special device `%s' in PLIST", name);
break;
case S_IFBLK:
warnx("Warning - block special device `%s' in PLIST", name);
break;
default:
(void) strlcpy(buf, CHECKSUM_HEADER,
sizeof(buf));
if (MD5File(name, &buf[ChecksumHeaderLen]) != (char *) NULL) {
tmp = new_plist_entry();
tmp->name = xstrdup(buf);
tmp->type = PLIST_COMMENT; /* PLIST_MD5 - HF */
tmp->next = p->next;
tmp->prev = p;
if (p == pkg->tail) {
pkg->tail = tmp;
}
p->next = tmp;
p = tmp;
}
break;
}
break;
default:
break;
}
}
if (update_pkgdb) {
pkgdb_close();
}
}

View file

@ -0,0 +1,163 @@
/*-
* Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_PWD_H
#include <grp.h>
#endif
#if HAVE_PWD_H
#include <pwd.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "lib.h"
#include "create.h"
static void
update_ids(struct memory_file *file)
{
if (file->owner != NULL) {
uid_t uid;
if (uid_from_user(file->owner, &uid) == -1)
errx(2, "user %s unknown", file->owner);
file->st.st_uid = uid;
} else {
file->owner = user_from_uid(file->st.st_uid, 1);
}
if (file->group != NULL) {
gid_t gid;
if (gid_from_group(file->group, &gid) == -1)
errx(2, "group %s unknown", file->group);
file->group = file->group;
file->st.st_gid = gid;
} else {
file->group = group_from_gid(file->st.st_gid, 1);
}
}
struct memory_file *
make_memory_file(const char *archive_name, void *data, size_t len,
const char *owner, const char *group, mode_t mode)
{
struct memory_file *file;
file = xmalloc(sizeof(*file));
file->name = archive_name;
file->owner = owner;
file->group = group;
file->data = data;
file->len = len;
memset(&file->st, 0, sizeof(file->st));
file->st.st_atime = file->st.st_ctime = file->st.st_mtime = time(NULL);
file->st.st_nlink = 1;
file->st.st_size = len;
file->st.st_mode = mode | S_IFREG;
update_ids(file);
return file;
}
struct memory_file *
load_memory_file(const char *disk_name,
const char *archive_name, const char *owner, const char *group,
mode_t mode)
{
struct memory_file *file;
int fd;
file = xmalloc(sizeof(*file));
file->name = archive_name;
file->owner = owner;
file->group = group;
file->mode = mode;
fd = open(disk_name, O_RDONLY);
if (fd == -1)
err(2, "cannot open file %s", disk_name);
if (fstat(fd, &file->st) == -1)
err(2, "cannot stat file %s", disk_name);
update_ids(file);
if ((file->st.st_mode & S_IFMT) != S_IFREG)
errx(1, "meta data file %s is not regular file", disk_name);
if (file->st.st_size > SSIZE_MAX)
errx(2, "meta data file too large: %s", disk_name);
file->data = xmalloc(file->st.st_size);
if (read(fd, file->data, file->st.st_size) != file->st.st_size)
err(2, "cannot read file into memory %s", disk_name);
file->len = file->st.st_size;
close(fd);
return file;
}
void
free_memory_file(struct memory_file *file)
{
if (file != NULL) {
free(file->data);
free(file);
}
}

View file

@ -0,0 +1,300 @@
.\" $NetBSD: pkg_delete.1,v 1.1.1.8 2010/04/23 20:54:08 joerg Exp $
.\"
.\" FreeBSD install - a package for the installation and maintenance
.\" 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
.\"
.\"
.\" from FreeBSD: @(#)pkg_delete.1
.\"
.Dd January 20, 2010
.Dt PKG_DELETE 1
.Os
.Sh NAME
.Nm pkg_delete
.Nd a utility for deleting previously installed software package distributions
.Sh SYNOPSIS
.Nm
.Op Fl ADFfkNnORrVv
.Op Fl K Ar pkg_dbdir
.Op Fl P Ar destdir
.Op Fl p Ar prefix
.Ar pkg-name ...
.Sh DESCRIPTION
The
.Nm
command is used to delete packages that have been previously installed
with the
.Xr pkg_add 1
command.
The given packages are sorted, so that the dependencies needed by a
package are deleted after the package.
Before any action is executed,
.Nm
checks for packages that are marked as
.Cm preserved
or have depending packages left.
If the
.Fl k
flag is given, preserved packages are skipped and not removed.
Unless the
.Fl f
flag is given,
.Nm
stops on the first error.
.Sh WARNING
.Bf -emphasis
Since the
.Nm
command may execute scripts or programs provided by a package file,
your system may be susceptible to
.Dq Trojan horses
or other subtle
attacks from miscreants who create dangerous package files.
.Pp
You are advised to verify the competence and identity of those who
provide installable package files.
For extra protection, examine all the package control files in the
package record directory
.Pa \*[Lt]PKG_DBDIR\*[Gt]/\*[Lt]pkg-name\*[Gt]/ ) .
Pay particular
attention to any
.Pa +INSTALL
or
.Pa +DEINSTALL
files, and inspect the
.Pa +CONTENTS
file for
.Cm @cwd ,
.Cm @mode
(check for setuid),
.Cm @dirrm ,
.Cm @exec ,
and
.Cm @unexec
directives, and/or use the
.Xr pkg_info 1
command to examine the installed package control files.
.Ef
.Sh OPTIONS
The following command line options are supported:
.Bl -tag -width indent
.It Ar pkg-name ...
The named packages are deinstalled, wildcards can be used, see
.Xr pkg_info 1 .
If no version is given, the one currently installed
will be removed.
If the
.Fl F
flag is given, one or more (absolute) filenames may be specified and
the package database will be consulted for the package to which the
given file belongs.
These packages are then deinstalled.
.It Fl A
Recursively remove all automatically installed packages that were needed
by the given packages and are no longer required.
Does not remove manually installed packages; see also the
.Fl R
flag.
.It Fl D
If a deinstallation script exists for a given package, do not execute it.
.It Fl F
Any
.Ar pkg-name
given will be interpreted as pathname which is
subsequently transformed in a (real) package name via the package
database.
That way, packages can be deleted by giving a filename
instead of the package-name.
.It Fl f
Force removal of the package, even if a dependency is recorded or the
deinstall script fails.
This might break the package database; see
.Xr pkg_admin 1
on how to repair it.
.It Fl ff
Force removal of the package, even if the package is marked as a
.Cm preserved
package.
Note that this is a dangerous operation.
See also the
.Fl k
option.
.It Fl K Ar pkg_dbdir
Override the value of the
.Dv PKG_DBDIR
configuration option with the value
.Ar pkg_dbdir .
.It Fl k
Silently skip all packages that are marked as
.Cm preserved .
.It Fl N
Remove the package's registration and its entries from the package database,
but leave the files installed.
Don't run any deinstall scripts or
.Cm @unexec
lines either.
.It Fl n
Don't actually deinstall a package, just report the steps that
would be taken.
.It Fl O
Only delete the package's entries from the package database; do not
touch the package or its files itself.
.It Fl P Ar destdir
Prefix all file and directory names with
.Ar destdir .
For packages without install scripts this has the same behavior as
using
.Xr chroot 8 .
.It Fl p Ar prefix
Set
.Ar prefix
as the directory in which to delete files from any installed packages
which do not explicitly set theirs.
For most packages, the prefix will
be set automatically to the installed location by
.Xr pkg_add 1 .
.It Fl R
Recursively remove all packages that were needed by the given packages
and are no longer required.
This option overrides the
.Fl A
flag.
.It Fl r
Recursively remove all packages that require one of the packages given.
.It Fl V
Print version number and exit.
.It Fl v
Turn on verbose output.
.El
.Sh TECHNICAL DETAILS
.Nm
does pretty much what it says.
It examines installed package records in
.Pa \*[Lt]PKG_DBDIR\*[Gt]/\*[Lt]pkg-name\*[Gt] ,
deletes the package contents, and finally removes the package records.
.Pp
If a package is required by other installed packages,
.Nm
will list those dependent packages and refuse to delete the package
(unless the
.Fl f
option is given).
.Pp
If a package has been marked as a
.Cm preserved
package, it will not be able to be deleted
(unless more than one occurrence of the
.Fl f
option is given).
.Pp
If a filename is given instead of a package name, the package of which
the given file belongs to can be deleted if the
.Fl F
flag is given.
The filename needs to be absolute, see the output produced by the
.Xr pkg_info 1
.Fl aF
command.
.Pp
If a
.Cm deinstall
script exists for the package, it is executed before and after
any files are removed.
It is this script's responsibility to clean up any additional messy details
around the package's installation, since all
.Nm
knows how to do is delete the files created in the original distribution.
The
.Ic deinstall
script is called as:
.Bd -filled -offset indent -compact
.Cm deinstall
.Aq Ar pkg-name
.Ar VIEW-DEINSTALL
.Ed
before removing the package from a view, and as:
.Bd -filled -offset indent -compact
.Cm deinstall
.Aq Ar pkg-name
.Ar DEINSTALL
.Ed
before deleting all files and as:
.Bd -filled -offset indent -compact
.Cm deinstall
.Aq Ar pkg-name
.Ar POST-DEINSTALL
.Ed
after deleting them.
Passing the keywords
.Ar VIEW-DEINSTALL ,
.Ar DEINSTALL ,
and
.Ar POST-DEINSTALL
lets you potentially write only one program/script that handles all
aspects of installation and deletion.
.Pp
All scripts are called with the environment variable
.Ev PKG_PREFIX
set to the installation prefix (see the
.Fl p
option above).
This allows a package author to write a script
that reliably performs some action on the directory where the package
is installed, even if the user might have changed it by specifying the
.Fl p
option when running
.Nm
or
.Xr pkg_add 1 .
The scripts are also called with the
.Ev PKG_METADATA_DIR
environment variable set to the location of the
.Pa +*
meta-data files, and with the
.Ev PKG_REFCOUNT_DBDIR
environment variable set to the location of the package reference counts
database directory.
If the
.Fl P
flag was given to
.Nm ,
.Ev PKG_DESTDIR
will be set to
.Ar destdir .
.Sh ENVIRONMENT
See
.Xr pkg_install.conf 5
for options, that can also be specified using the environment.
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_admin 1 ,
.Xr pkg_create 1 ,
.Xr pkg_info 1 ,
.Xr pkg_install.conf 5
.Xr pkgsrc 7
.Sh AUTHORS
.Bl -tag -width indent -compact
.It "Jordan Hubbard"
most of the work
.It "John Kohl"
refined it for
.Nx
.It "Hubert Feyrer"
.Nx
wildcard dependency processing, pkgdb, recursive "down"
delete, etc.
.It Joerg Sonnenberger
Rewrote most of the code to compute correct order of deinstallation
and to improve error handling.
.El

View file

@ -0,0 +1,928 @@
/*-
* Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* Copyright (c) 2003 Johnny Lam <jlam@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pkg_delete.c,v 1.1.1.8 2012/02/19 17:46:46 tron Exp $");
#if HAVE_ERR_H
#include <err.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "lib.h"
static const char *pkgdb;
static const char *destdir;
static const char *prefix;
static int keep_preserve;
static int no_deinstall;
static int find_by_filename;
static int unregister_only;
static int pkgdb_update_only;
static int delete_recursive;
static int delete_new_leaves;
static int delete_automatic_leaves;
static void
usage(void)
{
fprintf(stderr, "usage: pkg_delete [-DFfkNnORrVv] [-K pkg_dbdir]"
" [-P destdir] [-p prefix] pkg-name ...\n");
exit(1);
}
static int
add_by_filename(lpkg_head_t *pkgs, const char *filename)
{
lpkg_t *lpp;
char *s;
if ((s = pkgdb_retrieve(filename)) == NULL) {
warnx("No matching package for file `%s' in pkgdb", filename);
return 1;
}
/* XXX Verify that pkgdb is consistent? Trust it for now... */
lpp = alloc_lpkg(s);
TAILQ_INSERT_TAIL(pkgs, lpp, lp_link);
return 0;
}
static int
add_by_pattern(lpkg_head_t *pkgs, const char *pattern)
{
switch (add_installed_pkgs_by_pattern(pattern, pkgs)) {
case 0:
warnx("No package matching `%s' found", pattern);
return 1;
case -1:
warnx("Error while iterating package database for `%s'",
pattern);
return 1;
default:
return 0;
}
}
/*
* The argument is either a fixed package name or an absolute path.
* The latter is recognized for legacy compatibility and must point
* into the package database.
*/
static int
add_by_pkgname(lpkg_head_t *pkgs, char *pkg)
{
char *s;
lpkg_t *lpp;
size_t l;
const char *orig_pkg = pkg;
if (pkg[0] == '/') {
l = strlen(pkgdb);
if (strncmp(pkg, pkgdb, l) || pkg[l] != '/') {
warnx("Absolute path is not relative to "
"package database, skipping: %s", pkg);
return 1;
}
pkg += l + 1;
}
l = strcspn(pkg, "/");
if (pkg[l + strspn(pkg + l, "/")] != '\0') {
warnx("`%s' is not a package name, skipping", orig_pkg);
return 1;
}
pkg[l] = '\0';
s = pkgdb_pkg_file(pkg, CONTENTS_FNAME);
if (fexists(s)) {
free(s);
lpp = alloc_lpkg(pkg);
TAILQ_INSERT_TAIL(pkgs, lpp, lp_link);
return 0;
}
free(s);
switch (add_installed_pkgs_by_basename(pkg, pkgs)) {
case 0:
warnx("No matching package for basename `%s' of `%s'",
pkg, orig_pkg);
return 1;
case -1:
warnx("Error expanding basename `%s' of `%s'",
pkg, orig_pkg);
return 1;
default:
return 0;
}
}
/*
* Evaluate +REQUIRED_BY. This function is used for four different
* tasks:
* 0: check if no depending packages remain
* 1: like 0, but prepend the depending packages to pkgs if they exist
* 2: print remaining packages to stderr
* 3: check all and at least one depending packages have been removed
*/
static int
process_required_by(const char *pkg, lpkg_head_t *pkgs,
lpkg_head_t *sorted_pkgs, int action)
{
char line[MaxPathSize], *eol, *fname;
FILE *fp;
lpkg_t *lpp;
int got_match, got_miss;
fname = pkgdb_pkg_file(pkg, REQUIRED_BY_FNAME);
if (!fexists(fname)) {
free(fname);
return 0;
}
if ((fp = fopen(fname, "r")) == NULL) {
warn("Failed to open `%s'", fname);
free(fname);
return -1;
}
free(fname);
got_match = 0;
got_miss = 0;
while (fgets(line, sizeof(line), fp)) {
if ((eol = strrchr(line, '\n')) != NULL)
*eol = '\0';
TAILQ_FOREACH(lpp, sorted_pkgs, lp_link) {
if (strcmp(lpp->lp_name, line) == 0)
break;
}
if (lpp != NULL) {
got_match = 1;
continue;
}
got_miss = 1;
if (pkgs) {
TAILQ_FOREACH(lpp, pkgs, lp_link) {
if (strcmp(lpp->lp_name, line) == 0)
break;
}
if (lpp != NULL)
continue;
}
switch (action) {
case 0:
fclose(fp);
return 1;
case 1:
lpp = alloc_lpkg(line);
TAILQ_INSERT_HEAD(pkgs, lpp, lp_link);
break;
case 2:
fprintf(stderr, "\t%s\n", line);
break;
case 3:
fclose(fp);
return 0;
}
}
fclose(fp);
return (action == 3 ? got_match : got_miss);
}
/*
* Main function to order the patterns from the command line and
* add the subtrees for -r processing as needed.
*
* The first part ensures that all packages are listed at most once
* in pkgs. Afterwards the list is scanned for packages without depending
* packages. Each such package is moved to sorted_pkgs in order.
* If -r is given, all dependencies are inserted at the head of pkgs.
* The loop has to continue as long as progress is made. This can happen
* either because another package has been added to pkgs due to recursion
* (head of pkgs changed) or because a package has no more depending packages
* (tail of sorted_pkgs changed).
*
* If no progress is made, the remaining packages are moved to sorted_pkgs
* and an error is returned for the !Force case.
*/
static int
sort_and_recurse(lpkg_head_t *pkgs, lpkg_head_t *sorted_pkgs)
{
lpkg_t *lpp, *lpp2, *lpp_next, *lpp_old_tail, *lpp_old_head;
int rv;
TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) {
TAILQ_FOREACH(lpp2, pkgs, lp_link) {
if (lpp != lpp2 &&
strcmp(lpp->lp_name, lpp2->lp_name) == 0)
break;
}
if (lpp2 == NULL)
continue;
TAILQ_REMOVE(pkgs, lpp, lp_link);
free_lpkg(lpp);
}
while (!TAILQ_EMPTY(pkgs)) {
lpp_old_tail = TAILQ_LAST(sorted_pkgs, _lpkg_head_t);
lpp_old_head = TAILQ_FIRST(pkgs);
TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) {
rv = process_required_by(lpp->lp_name, pkgs,
sorted_pkgs, delete_recursive ? 1 : 0);
if (rv)
continue;
TAILQ_REMOVE(pkgs, lpp, lp_link);
TAILQ_INSERT_TAIL(sorted_pkgs, lpp, lp_link);
}
if (lpp_old_tail == TAILQ_LAST(sorted_pkgs, _lpkg_head_t) &&
lpp_old_head == TAILQ_FIRST(pkgs))
break;
}
if (TAILQ_EMPTY(pkgs))
return 0;
while (!TAILQ_EMPTY(pkgs)) {
lpp = TAILQ_FIRST(pkgs);
TAILQ_REMOVE(pkgs, lpp, lp_link);
fprintf(stderr,
"Package `%s' is still required by other packages:\n",
lpp->lp_name);
process_required_by(lpp->lp_name, NULL, sorted_pkgs, 2);
if (Force) {
TAILQ_INSERT_TAIL(sorted_pkgs, lpp, lp_link);
} else
free_lpkg(lpp);
}
return !Force;
}
struct find_leaves_data {
lpkg_head_t *pkgs;
int progress;
};
/*
* Iterator for finding leaf packages.
* Packages that are marked as not for deletion are not considered as
* leaves. For all other packages it is checked if at least one package
* that depended on them is to be removed AND no depending package remains.
* If that is the case, the package is appended to the sorted list.
* As this package can't have depending packages left, the topological order
* remains consistent.
*/
static int
find_new_leaves_iter(const char *pkg, void *cookie)
{
char *fname;
struct find_leaves_data *data = cookie;
lpkg_t *lpp;
fname = pkgdb_pkg_file(pkg, PRESERVE_FNAME);
if (fexists(fname)) {
free(fname);
return 0;
}
free(fname);
if (delete_automatic_leaves && !delete_new_leaves &&
!is_automatic_installed(pkg))
return 0;
/* Check whether this package is already on the list first. */
TAILQ_FOREACH(lpp, data->pkgs, lp_link) {
if (strcmp(lpp->lp_name, pkg) == 0)
return 0;
}
if (process_required_by(pkg, NULL, data->pkgs, 3) == 1) {
lpp = alloc_lpkg(pkg);
TAILQ_INSERT_TAIL(data->pkgs, lpp, lp_link);
data->progress = 1;
}
return 0;
}
/*
* Iterate over all installed packages and look for new leaf packages.
* As long as the loop adds one new leaf package, processing continues.
*/
static void
find_new_leaves(lpkg_head_t *pkgs)
{
struct find_leaves_data data;
data.pkgs = pkgs;
do {
data.progress = 0;
iterate_pkg_db(find_new_leaves_iter, &data);
} while (data.progress);
}
/*
* Check that no entry on the package list is marked as not for deletion.
*/
static int
find_preserve_pkgs(lpkg_head_t *pkgs)
{
lpkg_t *lpp, *lpp_next;
char *fname;
int found_preserve;
found_preserve = 0;
TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) {
fname = pkgdb_pkg_file(lpp->lp_name, PRESERVE_FNAME);
if (!fexists(fname)) {
free(fname);
continue;
}
free(fname);
if (keep_preserve) {
TAILQ_REMOVE(pkgs, lpp, lp_link);
free_lpkg(lpp);
continue;
}
if (!found_preserve)
warnx("The following packages are marked as not "
"for deletion:");
found_preserve = 1;
fprintf(stderr, "\t%s\n", lpp->lp_name);
}
if (!found_preserve)
return 0;
if (Force == 0 || (!unregister_only && Force == 1))
return 1;
fprintf(stderr, "...but will delete them anyway\n");
return 0;
}
/*
* Remove package from view. This is calling pkg_deinstall again.
*/
static int
remove_pkg_from_view(const char *pkg)
{
char line[MaxPathSize], *fname, *eol;
FILE *fp;
fname = pkgdb_pkg_file(pkg, VIEWS_FNAME);
if (isemptyfile(fname)) {
free(fname);
return 0;
}
if ((fp = fopen(fname, "r")) == NULL) {
warn("Unable to open `%s', aborting", fname);
free(fname);
return 1;
}
free(fname);
while (fgets(line, sizeof(line), fp) != NULL) {
if ((eol = strrchr(line, '\n')) != NULL)
*eol = '\0';
if (Verbose || Fake)
printf("Deleting package `%s' instance from `%s' view\n",
pkg, line);
if (Fake)
continue;
if (fexec_skipempty(BINDIR "/pkg_delete", "-K", line,
Fake ? "-n" : "",
(Force > 1) ? "-f" : "",
(Force > 0) ? "-f" : "",
pkg, NULL) != 0) {
warnx("Unable to delete package `%s' from view `%s'",
pkg, line);
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
/*
* Run the +DEINSTALL script. Depending on whether this is
* a depoted package and whether this pre- or post-deinstall phase,
* different arguments are passed down.
*/
static int
run_deinstall_script(const char *pkg, int do_postdeinstall)
{
const char *target, *text;
char *fname, *fname2, *pkgdir;
int rv;
fname = pkgdb_pkg_file(pkg, DEINSTALL_FNAME);
if (!fexists(fname)) {
free(fname);
return 0;
}
fname2 = pkgdb_pkg_file(pkg, DEPOT_FNAME);
if (fexists(fname2)) {
if (do_postdeinstall) {
free(fname);
free(fname2);
return 0;
}
target = "VIEW-DEINSTALL";
text = "view deinstall";
} else if (do_postdeinstall) {
target = "POST-DEINSTALL";
text = "post-deinstall";
} else {
target = "DEINSTALL";
text = "deinstall";
}
free(fname2);
if (Fake) {
printf("Would execute %s script with argument %s now\n",
text, target);
free(fname);
return 0;
}
pkgdir = pkgdb_pkg_dir(pkg);
if (chmod(fname, 0555))
warn("chmod of `%s' failed", fname);
rv = fcexec(pkgdir, fname, pkg, target, NULL);
if (rv)
warnx("%s script returned error status", text);
free(pkgdir);
free(fname);
return rv;
}
/*
* Copy lines from fname to fname_tmp, filtering out lines equal to text.
* Afterwards rename fname_tmp to fname;
*/
static int
remove_line(const char *fname, const char *fname_tmp, const char *text)
{
FILE *fp, *fp_out;
char line[MaxPathSize], *eol;
int rv;
if ((fp = fopen(fname, "r")) == NULL) {
warn("Unable to open `%s'", fname);
return 1;
}
if ((fp_out = fopen(fname_tmp, "w")) == NULL) {
warn("Unable to open `%s'", fname_tmp);
fclose(fp);
return 1;
}
while (fgets(line, sizeof(line), fp) != NULL) {
if ((eol = strrchr(line, '\n')) != NULL)
*eol = '\0';
if (strcmp(line, text) == 0)
continue;
fprintf(fp_out, "%s\n", line);
}
fclose(fp);
if (fclose(fp_out) == EOF) {
remove(fname_tmp);
warnx("Failure while closing `%s' temp file", fname_tmp);
return 1;
}
if (rename(fname_tmp, fname) == -1) {
warn("Unable to rename `%s' to `%s'", fname_tmp, fname);
rv = 1;
} else
rv = 0;
remove(fname_tmp);
return rv;
}
/*
* Unregister the package from the depot it is registered in.
*/
static int
remove_pkg_from_depot(const char *pkg)
{
FILE *fp;
char line[MaxPathSize], *eol;
char *fname, *fname2;
int rv;
fname = pkgdb_pkg_file(pkg, DEPOT_FNAME);
if (isemptyfile(fname)) {
free(fname);
return 0;
}
if (Verbose)
printf("Attempting to remove the `%s' registration "
"on package `%s'\n", fname, pkg);
if (Fake) {
free(fname);
return 1;
}
if ((fp = fopen(fname, "r")) == NULL) {
warn("Unable to open `%s' file", fname);
free(fname);
return 1;
}
if (fgets(line, sizeof(line), fp) == NULL) {
fclose(fp);
warnx("Empty depot file `%s'", fname);
free(fname);
return 1;
}
if ((eol = strrchr(line, '\n')) != NULL)
*eol = '\0';
fclose(fp);
free(fname);
fname = pkgdb_pkg_file(pkg, VIEWS_FNAME);
fname2 = pkgdb_pkg_file(pkg, VIEWS_FNAME_TMP);
rv = remove_line(fname, fname2, line);
free(fname2);
free(fname);
return rv;
}
/*
* remove_depend is used as iterator function below.
* The passed-in package name should be removed from the
* +REQUIRED_BY list of the dependency. Such an entry
* can miss in a fully correct package database, if the pattern
* matches more than one package.
*/
static int
remove_depend(const char *cur_pkg, void *cookie)
{
const char *pkg = cookie;
char *fname, *fname2;
int rv;
fname = pkgdb_pkg_file(cur_pkg, REQUIRED_BY_FNAME);
if (isemptyfile(fname)) {
free(fname);
return 0;
}
fname2 = pkgdb_pkg_file(cur_pkg, REQUIRED_BY_FNAME_TMP);
rv = remove_line(fname, fname2, pkg);
free(fname2);
free(fname);
return rv;
}
static int
remove_pkg(const char *pkg)
{
FILE *fp;
char *fname, *pkgdir;
package_t plist;
plist_t *p;
int is_depoted_pkg, rv, late_error;
if (pkgdb_update_only)
return pkgdb_remove_pkg(pkg) ? 0 : 1;
fname = pkgdb_pkg_file(pkg, CONTENTS_FNAME);
if (!fexists(fname)) {
warnx("package `%s' is not installed, `%s' missing", pkg, fname);
free(fname);
return 1;
}
free(fname);
/* +REQUIRED_BY and +PRESERVE already checked */
if (remove_pkg_from_view(pkg))
return 1;
/*
* The views related code has bad error handling, if e.g.
* the deinstall script fails, the package remains unregistered.
*/
fname = pkgdb_pkg_file(pkg, CONTENTS_FNAME);
if ((fp = fopen(fname, "r")) == NULL) {
warnx("Failed to open `%s'", fname);
free(fname);
return 1;
}
read_plist(&plist, fp);
fclose(fp);
/*
* If a prefix has been provided, remove the first @cwd and
* prepend that prefix. This allows removing packages without
* @cwd if really necessary. pkg_admin rebuild is likely needed
* afterwards though.
*/
if (prefix) {
delete_plist(&plist, FALSE, PLIST_CWD, NULL);
add_plist_top(&plist, PLIST_CWD, prefix);
}
if ((p = find_plist(&plist, PLIST_CWD)) == NULL) {
warnx("Package `%s' doesn't have a prefix", pkg);
return 1;
}
if (find_plist(&plist, PLIST_NAME) == NULL) {
/* Cheat a bit to allow removal of such bad packages. */
warnx("Package `%s' doesn't have a name", pkg);
add_plist_top(&plist, PLIST_NAME, pkg);
}
setenv(PKG_REFCOUNT_DBDIR_VNAME, config_pkg_refcount_dbdir, 1);
fname = pkgdb_pkg_dir(pkg);
setenv(PKG_METADATA_DIR_VNAME, fname, 1);
free(fname);
setenv(PKG_PREFIX_VNAME, p->name, 1);
if (!no_deinstall && !unregister_only) {
if (run_deinstall_script(pkg, 0) && !Force)
return 1;
}
late_error = 0;
if (Fake)
printf("Attempting to delete package `%s'\n", pkg);
else if (delete_package(FALSE, &plist, unregister_only,
destdir) == FAIL) {
warnx("couldn't entirely delete package `%s'", pkg);
/*
* XXX It could be nice to error out here explicitly,
* XXX but this is problematic for missing or changed files.
* XXX At least the inability to remove files at all should
* XXX be handled though.
*/
}
/*
* Past the point of no return. Files are gone, all that is left
* is cleaning up registered dependencies and removing the meta data.
* Errors in the remaining part are counted, but don't stop the
* processing.
*/
fname = pkgdb_pkg_file(pkg, DEPOT_FNAME);
if (fexists(fname)) {
late_error |= remove_pkg_from_depot(pkg);
/* XXX error checking */
} else {
for (p = plist.head; p; p = p->next) {
if (p->type != PLIST_PKGDEP)
continue;
if (Verbose)
printf("Attempting to remove dependency "
"on package `%s'\n", p->name);
if (Fake)
continue;
match_installed_pkgs(p->name, remove_depend,
__UNCONST(pkg));
}
}
free(fname);
free_plist(&plist);
if (!no_deinstall && !unregister_only)
late_error |= run_deinstall_script(pkg, 1);
fname = pkgdb_pkg_file(pkg, VIEWS_FNAME);
if (fexists(fname))
is_depoted_pkg = TRUE;
else
is_depoted_pkg = FALSE;
free(fname);
if (Fake)
return 0;
/*
* Kill the pkgdb subdirectory. The files have been removed, so
* this is way beyond the point of no return.
*/
pkgdir = pkgdb_pkg_dir(pkg);
(void) remove_files(pkgdir, "+*");
rv = 1;
if (isemptydir(pkgdir)&& rmdir(pkgdir) == 0)
rv = 0;
else if (is_depoted_pkg)
warnx("Depot directory `%s' is not empty", pkgdir);
else if (!Force)
warnx("Couldn't remove package directory in `%s'", pkgdir);
else if (recursive_remove(pkgdir, 1))
warn("Couldn't remove package directory `%s'", pkgdir);
else
warnx("Package directory `%s' forcefully removed", pkgdir);
free(pkgdir);
return rv | late_error;
}
int
main(int argc, char *argv[])
{
lpkg_head_t pkgs, sorted_pkgs;
int ch, r, has_error;
unsigned long bad_count;
TAILQ_INIT(&pkgs);
TAILQ_INIT(&sorted_pkgs);
setprogname(argv[0]);
while ((ch = getopt(argc, argv, "ADFfK:kNnOP:p:RrVv")) != -1) {
switch (ch) {
case 'A':
delete_automatic_leaves = 1;
break;
case 'D':
no_deinstall = 1;
break;
case 'F':
find_by_filename = 1;
break;
case 'f':
++Force;
break;
case 'K':
pkgdb_set_dir(optarg, 3);
break;
case 'k':
keep_preserve = 1;
break;
case 'N':
unregister_only = 1;
break;
case 'n':
Fake = 1;
break;
case 'O':
pkgdb_update_only = 1;
break;
case 'P':
destdir = optarg;
break;
case 'p':
prefix = optarg;
break;
case 'R':
delete_new_leaves = 1;
break;
case 'r':
delete_recursive = 1;
break;
case 'V':
show_version();
/* NOTREACHED */
case 'v':
++Verbose;
break;
default:
usage();
break;
}
}
pkg_install_config();
pkgdb = xstrdup(pkgdb_get_dir());
if (destdir != NULL) {
char *pkgdbdir;
pkgdbdir = xasprintf("%s/%s", destdir, pkgdb);
pkgdb_set_dir(pkgdbdir, 4);
free(pkgdbdir);
}
argc -= optind;
argv += optind;
if (argc == 0) {
if (find_by_filename)
warnx("Missing filename(s)");
else
warnx("Missing package name(s)");
usage();
}
if (Fake)
r = pkgdb_open(ReadOnly);
else
r = pkgdb_open(ReadWrite);
if (!r)
errx(EXIT_FAILURE, "Opening pkgdb failed");
/* First, process all command line options. */
has_error = 0;
for (; argc != 0; --argc, ++argv) {
if (find_by_filename)
has_error |= add_by_filename(&pkgs, *argv);
else if (ispkgpattern(*argv))
has_error |= add_by_pattern(&pkgs, *argv);
else
has_error |= add_by_pkgname(&pkgs, *argv);
}
if (has_error && !Force) {
pkgdb_close();
return EXIT_FAILURE;
}
/* Second, reorder and recursive if necessary. */
if (sort_and_recurse(&pkgs, &sorted_pkgs)) {
pkgdb_close();
return EXIT_FAILURE;
}
/* Third, add leaves if necessary. */
if (delete_new_leaves || delete_automatic_leaves)
find_new_leaves(&sorted_pkgs);
/*
* Now that all packages to remove are known, check
* if all are removable. After that, start the actual
* removal.
*/
if (find_preserve_pkgs(&sorted_pkgs)) {
pkgdb_close();
return EXIT_FAILURE;
}
setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1);
bad_count = 0;
while (!TAILQ_EMPTY(&sorted_pkgs)) {
lpkg_t *lpp;
lpp = TAILQ_FIRST(&sorted_pkgs);
TAILQ_REMOVE(&sorted_pkgs, lpp, lp_link);
if (remove_pkg(lpp->lp_name)) {
++bad_count;
if (!Force)
break;
}
free_lpkg(lpp);
}
pkgdb_close();
if (Force && bad_count && Verbose)
warnx("Removal of %lu packages failed", bad_count);
return bad_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View file

@ -0,0 +1,134 @@
/* $NetBSD: info.h,v 1.1.1.5 2009/10/07 13:19:42 joerg Exp $ */
/* from FreeBSD Id: info.h,v 1.10 1997/02/22 16:09:40 peter Exp */
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* 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
* 23 August 1993
*
* Include and define various things wanted by the info command.
*
*/
#ifndef _INST_INFO_H_INCLUDE
#define _INST_INFO_H_INCLUDE
struct pkg_meta {
char *meta_contents;
char *meta_comment;
char *meta_desc;
char *meta_mtree;
char *meta_build_version;
char *meta_build_info;
char *meta_size_pkg;
char *meta_size_all;
char *meta_required_by;
char *meta_display;
char *meta_install;
char *meta_deinstall;
char *meta_preserve;
char *meta_views;
char *meta_installed_info;
int is_installed;
};
#ifndef MAXINDEXSIZE
#define MAXINDEXSIZE 60
#endif
#ifndef MAXNAMESIZE
#define MAXNAMESIZE 20
#endif
#define SHOW_COMMENT 0x00001
#define SHOW_DESC 0x00002
#define SHOW_PLIST 0x00004
#define SHOW_INSTALL 0x00008
#define SHOW_DEINSTALL 0x00010
#define SHOW_PREFIX 0x00040
#define SHOW_INDEX 0x00080
#define SHOW_FILES 0x00100
#define SHOW_DISPLAY 0x00200
#define SHOW_REQBY 0x00400
#define SHOW_MTREE 0x00800
#define SHOW_BUILD_VERSION 0x01000
#define SHOW_BUILD_INFO 0x02000
#define SHOW_DEPENDS 0x04000
#define SHOW_PKG_SIZE 0x08000
#define SHOW_ALL_SIZE 0x10000
#define SHOW_BLD_DEPENDS 0x20000
#define SHOW_BI_VAR 0x40000
#define SHOW_SUMMARY 0x80000
#define SHOW_FULL_REQBY 0x100000
enum which {
WHICH_ALL,
WHICH_USER,
WHICH_LIST
};
extern int Flags;
extern enum which Which;
extern Boolean File2Pkg;
extern Boolean Quiet;
extern const char *InfoPrefix;
extern const char *BuildInfoVariable;
extern lpkg_head_t pkgs;
int CheckForPkg(const char *);
int CheckForBestPkg(const char *);
void show_file(const char *, const char *, Boolean);
void show_var(const char *, const char *);
void show_plist(const char *, package_t *, pl_ent_t);
void show_files(const char *, package_t *);
void show_depends(const char *, package_t *);
void show_bld_depends(const char *, package_t *);
void show_index(const char *, const char *);
void show_summary(struct pkg_meta *, package_t *, const char *);
void show_list(lpkg_head_t *, const char *);
int pkg_perform(lpkg_head_t *);
#endif /* _INST_INFO_H_INCLUDE */

View file

@ -0,0 +1,328 @@
/* $NetBSD: main.c,v 1.1.1.9 2013/04/20 15:26:53 wiz Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: main.c,v 1.1.1.9 2013/04/20 15:26:53 wiz Exp $");
/*
*
* 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 add module.
*
*/
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
#include "info.h"
static const char Options[] = ".aBbcDde:E:fFhIiK:kLl:mNnpQ:qrRsSuvVX";
int Flags = 0;
enum which Which = WHICH_LIST;
Boolean File2Pkg = FALSE;
Boolean Quiet = FALSE;
const char *InfoPrefix = "";
const char *BuildInfoVariable = "";
lpkg_head_t pkgs;
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n",
"usage: pkg_info [-BbcDdFfhIikLmNnpqRrSsVvX] [-E pkg-name] [-e pkg-name]",
" [-K pkg_dbdir] [-l prefix] pkg-name ...",
" pkg_info [-a | -u] [flags]",
" pkg_info [-Q variable] pkg-name ...");
exit(1);
}
int
main(int argc, char **argv)
{
char *CheckPkg = NULL;
char *BestCheckPkg = NULL;
lpkg_t *lpp;
int ch;
int rc;
setprogname(argv[0]);
while ((ch = getopt(argc, argv, Options)) != -1)
switch (ch) {
case '.': /* for backward compatibility */
break;
case 'a':
Which = WHICH_ALL;
break;
case 'B':
Flags |= SHOW_BUILD_INFO;
break;
case 'b':
Flags |= SHOW_BUILD_VERSION;
break;
case 'c':
Flags |= SHOW_COMMENT;
break;
case 'D':
Flags |= SHOW_DISPLAY;
break;
case 'd':
Flags |= SHOW_DESC;
break;
case 'E':
BestCheckPkg = optarg;
break;
case 'e':
CheckPkg = optarg;
break;
case 'f':
Flags |= SHOW_PLIST;
break;
case 'F':
File2Pkg = 1;
break;
case 'I':
Flags |= SHOW_INDEX;
break;
case 'i':
Flags |= SHOW_INSTALL;
break;
case 'K':
pkgdb_set_dir(optarg, 3);
break;
case 'k':
Flags |= SHOW_DEINSTALL;
break;
case 'L':
Flags |= SHOW_FILES;
break;
case 'l':
InfoPrefix = optarg;
break;
case 'm':
Flags |= SHOW_MTREE;
break;
case 'N':
Flags |= SHOW_BLD_DEPENDS;
break;
case 'n':
Flags |= SHOW_DEPENDS;
break;
case 'p':
Flags |= SHOW_PREFIX;
break;
case 'Q':
Flags |= SHOW_BI_VAR;
BuildInfoVariable = optarg;
break;
case 'q':
Quiet = TRUE;
break;
case 'r':
Flags |= SHOW_FULL_REQBY;
break;
case 'R':
Flags |= SHOW_REQBY;
break;
case 's':
Flags |= SHOW_PKG_SIZE;
break;
case 'S':
Flags |= SHOW_ALL_SIZE;
break;
case 'u':
Which = WHICH_USER;
break;
case 'v':
Verbose = TRUE;
/* Reasonable definition of 'everything' */
Flags = SHOW_COMMENT | SHOW_DESC | SHOW_PLIST | SHOW_INSTALL |
SHOW_DEINSTALL | SHOW_DISPLAY | SHOW_MTREE |
SHOW_REQBY | SHOW_BLD_DEPENDS | SHOW_DEPENDS | SHOW_PKG_SIZE | SHOW_ALL_SIZE;
break;
case 'V':
show_version();
/* NOTREACHED */
case 'X':
Flags |= SHOW_SUMMARY;
break;
case 'h':
case '?':
default:
usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
pkg_install_config();
if (argc == 0 && !Flags && !CheckPkg) {
/* No argument or relevant flags specified - assume -I */
Flags = SHOW_INDEX;
/* assume -a if neither -u nor -a is given */
if (Which == WHICH_LIST)
Which = WHICH_ALL;
}
if (CheckPkg != NULL && BestCheckPkg != NULL) {
warnx("-E and -e are mutally exlusive");
usage();
}
if (argc != 0 && CheckPkg != NULL) {
warnx("can't give any additional arguments to -e");
usage();
}
if (argc != 0 && BestCheckPkg != NULL) {
warnx("can't give any additional arguments to -E");
usage();
}
if (argc != 0 && Which != WHICH_LIST) {
warnx("can't use both -a/-u and package name");
usage();
}
/* Set some reasonable defaults */
if (!Flags)
Flags = SHOW_COMMENT | SHOW_DESC | SHOW_REQBY
| SHOW_DEPENDS | SHOW_DISPLAY;
/* -Fe /filename -> change CheckPkg to real packagename */
if (CheckPkg) {
if (File2Pkg) {
char *s;
if (!pkgdb_open(ReadOnly))
err(EXIT_FAILURE, "cannot open pkgdb");
s = pkgdb_retrieve(CheckPkg);
if (s == NULL)
errx(EXIT_FAILURE, "No matching pkg for %s.", CheckPkg);
CheckPkg = xstrdup(s);
pkgdb_close();
}
return CheckForPkg(CheckPkg);
}
if (BestCheckPkg)
return CheckForBestPkg(BestCheckPkg);
TAILQ_INIT(&pkgs);
/* Get all the remaining package names, if any */
if (File2Pkg && Which == WHICH_LIST)
if (!pkgdb_open(ReadOnly)) {
err(EXIT_FAILURE, "cannot open pkgdb");
}
while (*argv) {
/* pkgdb: if -F flag given, don't add pkgnames to the "pkgs"
* queue but rather resolve the given filenames to pkgnames
* using pkgdb_retrieve, then add them. */
if (File2Pkg) {
char *s;
s = pkgdb_retrieve(*argv);
if (s) {
lpp = alloc_lpkg(s);
TAILQ_INSERT_TAIL(&pkgs, lpp, lp_link);
} else
errx(EXIT_FAILURE, "No matching pkg for %s.", *argv);
} else {
if (ispkgpattern(*argv)) {
switch (add_installed_pkgs_by_pattern(*argv, &pkgs)) {
case 0:
errx(EXIT_FAILURE, "No matching pkg for %s.", *argv);
case -1:
errx(EXIT_FAILURE, "Error during search in pkgdb for %s", *argv);
}
} else {
const char *dbdir;
dbdir = pkgdb_get_dir();
if (**argv == '/' && strncmp(*argv, dbdir, strlen(dbdir)) == 0) {
*argv += strlen(dbdir) + 1;
if ((*argv)[strlen(*argv) - 1] == '/') {
(*argv)[strlen(*argv) - 1] = 0;
}
}
lpp = alloc_lpkg(*argv);
TAILQ_INSERT_TAIL(&pkgs, lpp, lp_link);
}
}
argv++;
}
if (File2Pkg)
pkgdb_close();
/* If no packages, yelp */
if (TAILQ_FIRST(&pkgs) == NULL && Which == WHICH_LIST && !CheckPkg)
warnx("missing package name(s)"), usage();
rc = pkg_perform(&pkgs);
exit(rc);
/* NOTREACHED */
}

View file

@ -0,0 +1,665 @@
/* $NetBSD: perform.c,v 1.1.1.13 2010/02/20 04:41:55 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
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
__RCSID("$NetBSD: perform.c,v 1.1.1.13 2010/02/20 04:41:55 joerg Exp $");
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* 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
* 23 Aug 1993
*
* This is the main body of the info module.
*
*/
#include "lib.h"
#include "info.h"
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifndef BOOTSTRAP
#include <archive.h>
#include <archive_entry.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_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_DIRENT_H
#include <dirent.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <stddef.h>
#define LOAD_CONTENTS (1 << 0)
#define LOAD_COMMENT (1 << 1)
#define LOAD_DESC (1 << 2)
#define LOAD_INSTALL (1 << 3)
#define LOAD_DEINSTALL (1 << 4)
#define LOAD_DISPLAY (1 << 5)
#define LOAD_MTREE (1 << 6)
#define LOAD_BUILD_VERSION (1 << 7)
#define LOAD_BUILD_INFO (1 << 8)
#define LOAD_SIZE_PKG (1 << 9)
#define LOAD_SIZE_ALL (1 << 10)
#define LOAD_PRESERVE (1 << 11)
#define LOAD_VIEWS (1 << 12)
#define LOAD_REQUIRED_BY (1 << 13)
#define LOAD_INSTALLED_INFO (1 << 14)
static const struct pkg_meta_desc {
size_t entry_offset;
const char *entry_filename;
int entry_mask;
int required_file;
} pkg_meta_descriptors[] = {
{ offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME,
LOAD_CONTENTS, 1},
{ offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME,
LOAD_COMMENT, 1 },
{ offsetof(struct pkg_meta, meta_desc), DESC_FNAME,
LOAD_DESC, 1 },
{ offsetof(struct pkg_meta, meta_install), INSTALL_FNAME,
LOAD_INSTALL, 0 },
{ offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME,
LOAD_DEINSTALL, 0 },
{ offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME,
LOAD_DISPLAY, 0 },
{ offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME,
LOAD_MTREE, 0 },
{ offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME,
LOAD_BUILD_VERSION, 0 },
{ offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME,
LOAD_BUILD_INFO, 0 },
{ offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME,
LOAD_SIZE_PKG, 0 },
{ offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME,
LOAD_SIZE_ALL, 0 },
{ offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME,
LOAD_PRESERVE, 0 },
{ offsetof(struct pkg_meta, meta_views), VIEWS_FNAME,
LOAD_VIEWS, 0 },
{ offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME,
LOAD_REQUIRED_BY, 0 },
{ offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME,
LOAD_INSTALLED_INFO, 0 },
{ 0, NULL, 0, 0 },
};
static int desired_meta_data;
static void
free_pkg_meta(struct pkg_meta *meta)
{
const struct pkg_meta_desc *descr;
for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr)
free(*(char **)((char *)meta + descr->entry_offset));
free(meta);
}
#ifndef BOOTSTRAP
static struct pkg_meta *
read_meta_data_from_archive(struct archive *archive,
struct archive_entry *entry)
{
struct pkg_meta *meta;
const char *fname;
const struct pkg_meta_desc *descr, *last_descr;
char **target;
int64_t size;
int r, found_required;
found_required = 0;
meta = xcalloc(1, sizeof(*meta));
last_descr = 0;
if (entry != NULL) {
r = ARCHIVE_OK;
goto has_entry;
}
while ((r = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
has_entry:
fname = archive_entry_pathname(entry);
for (descr = pkg_meta_descriptors; descr->entry_filename;
++descr) {
if (strcmp(descr->entry_filename, fname) == 0)
break;
}
if (descr->entry_filename == NULL)
break;
if (descr->required_file)
++found_required;
target = (char **)((char *)meta + descr->entry_offset);
if (*target)
errx(2, "duplicate entry, package corrupt");
if (descr < last_descr)
warnx("misordered package, continuing");
else
last_descr = descr;
if ((descr->entry_mask & desired_meta_data) == 0) {
if (archive_read_data_skip(archive))
errx(2, "cannot read package meta data");
continue;
}
size = archive_entry_size(entry);
if (size > SSIZE_MAX - 1)
errx(2, "package meta data too large to process");
*target = xmalloc(size + 1);
if (archive_read_data(archive, *target, size) != size)
errx(2, "cannot read package meta data");
(*target)[size] = '\0';
}
for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
if (descr->required_file)
--found_required;
}
meta->is_installed = 0;
if (found_required != 0 || (r != ARCHIVE_OK && r != ARCHIVE_EOF)) {
free_pkg_meta(meta);
meta = NULL;
}
return meta;
}
#endif
static struct pkg_meta *
read_meta_data_from_pkgdb(const char *pkg)
{
struct pkg_meta *meta;
const struct pkg_meta_desc *descr;
char **target;
char *fname;
int fd;
struct stat st;
meta = xcalloc(1, sizeof(*meta));
for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) {
if ((descr->entry_mask & desired_meta_data) == 0)
continue;
fname = pkgdb_pkg_file(pkg, descr->entry_filename);
fd = open(fname, O_RDONLY, 0);
free(fname);
if (fd == -1) {
if (errno == ENOENT && descr->required_file == 0)
continue;
err(2, "cannot read meta data file %s of package %s",
descr->entry_filename, pkg);
}
target = (char **)((char *)meta + descr->entry_offset);
if (fstat(fd, &st) == -1)
err(2, "cannot stat meta data");
if ((st.st_mode & S_IFMT) != S_IFREG)
errx(1, "meta data is not regular file");
if (st.st_size > SSIZE_MAX - 1)
err(2, "meta data file too large to process");
*target = xmalloc(st.st_size + 1);
if (read(fd, *target, st.st_size) != st.st_size)
err(2, "cannot read meta data");
(*target)[st.st_size] = '\0';
close(fd);
}
meta->is_installed = 1;
return meta;
}
static void
build_full_reqby(lpkg_head_t *reqby, struct pkg_meta *meta, int limit)
{
char *iter, *eol, *next;
lpkg_t *lpp;
struct pkg_meta *meta_dep;
if (limit == 65536)
errx(1, "Cycle in the dependency tree, bailing out");
if (meta->is_installed == 0 || meta->meta_required_by == NULL)
return;
for (iter = meta->meta_required_by; *iter != '\0'; iter = next) {
eol = iter + strcspn(iter, "\n");
if (*eol == '\n')
next = eol + 1;
else
next = eol;
if (iter == eol)
continue;
TAILQ_FOREACH(lpp, reqby, lp_link) {
if (strlen(lpp->lp_name) + iter != eol)
continue;
if (memcmp(lpp->lp_name, iter, eol - iter) == 0)
break;
}
if (lpp != NULL)
continue;
*eol = '\0';
lpp = alloc_lpkg(iter);
if (next != eol)
*eol = '\n';
meta_dep = read_meta_data_from_pkgdb(lpp->lp_name);
if (meta_dep == NULL)
continue;
build_full_reqby(reqby, meta_dep, limit + 1);
free_pkg_meta(meta_dep);
TAILQ_INSERT_HEAD(reqby, lpp, lp_link);
}
}
static lfile_head_t files;
static int
pkg_do(const char *pkg)
{
struct pkg_meta *meta;
int code = 0;
const char *binpkgfile = NULL;
char *pkgdir;
if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) {
#ifdef BOOTSTRAP
errx(2, "Binary packages not supported during bootstrap");
#else
struct archive *archive;
struct archive_entry *entry;
char *archive_name, *pkgname;
archive = open_archive(pkg, &archive_name);
if (archive == NULL) {
warnx("can't find package `%s', skipped", pkg);
return -1;
}
pkgname = NULL;
entry = NULL;
pkg_verify_signature(archive_name, &archive, &entry, &pkgname);
if (archive == NULL)
return -1;
free(pkgname);
meta = read_meta_data_from_archive(archive, entry);
archive_read_finish(archive);
if (!IS_URL(pkg))
binpkgfile = pkg;
#endif
} else {
/*
* It's not an uninstalled package, try and find it among the
* installed
*/
pkgdir = pkgdb_pkg_dir(pkg);
if (!fexists(pkgdir) || !(isdir(pkgdir) || islinktodir(pkgdir))) {
switch (add_installed_pkgs_by_basename(pkg, &pkgs)) {
case 1:
return 0;
case 0:
/* No match */
warnx("can't find package `%s'", pkg);
return 1;
case -1:
errx(EXIT_FAILURE, "Error during search in pkgdb for %s", pkg);
}
}
free(pkgdir);
meta = read_meta_data_from_pkgdb(pkg);
}
if (meta == NULL) {
warnx("invalid package `%s' skipped", pkg);
return 1;
}
/*
* Index is special info type that has to override all others to make
* any sense.
*/
if (Flags & SHOW_INDEX) {
char tmp[MaxPathSize];
(void) snprintf(tmp, sizeof(tmp), "%-19s ", pkg);
show_index(meta->meta_comment, tmp);
} else if (Flags & SHOW_BI_VAR) {
if (strcspn(BuildInfoVariable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
== strlen(BuildInfoVariable)) {
if (meta->meta_installed_info)
show_var(meta->meta_installed_info, BuildInfoVariable);
} else {
if (meta->meta_build_info)
show_var(meta->meta_build_info, BuildInfoVariable);
else
warnx("Build information missing");
}
} else {
package_t plist;
/* Read the contents list */
parse_plist(&plist, meta->meta_contents);
/* Start showing the package contents */
if (!Quiet && !(Flags & SHOW_SUMMARY)) {
printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
if (meta->meta_preserve) {
printf("*** PACKAGE MAY NOT BE DELETED ***\n");
}
}
if (Flags & SHOW_SUMMARY) {
show_summary(meta, &plist, binpkgfile);
}
if (Flags & SHOW_COMMENT) {
show_file(meta->meta_comment, "Comment:\n", TRUE);
}
if (Flags & SHOW_DEPENDS) {
show_depends("Requires:\n", &plist);
}
if (Flags & SHOW_BLD_DEPENDS) {
show_bld_depends("Built using:\n", &plist);
}
if ((Flags & SHOW_REQBY) && meta->meta_required_by) {
show_file(meta->meta_required_by, "Required by:\n", TRUE);
}
if ((Flags & SHOW_FULL_REQBY) && meta->is_installed) {
lpkg_head_t reqby;
TAILQ_INIT(&reqby);
build_full_reqby(&reqby, meta, 0);
show_list(&reqby, "Full required by list:\n");
}
if (Flags & SHOW_DESC) {
show_file(meta->meta_desc, "Description:\n", TRUE);
}
if ((Flags & SHOW_DISPLAY) && meta->meta_display) {
show_file(meta->meta_display, "Install notice:\n",
TRUE);
}
if (Flags & SHOW_PLIST) {
show_plist("Packing list:\n", &plist, PLIST_SHOW_ALL);
}
if ((Flags & SHOW_INSTALL) && meta->meta_install) {
show_file(meta->meta_install, "Install script:\n",
TRUE);
}
if ((Flags & SHOW_DEINSTALL) && meta->meta_deinstall) {
show_file(meta->meta_deinstall, "De-Install script:\n",
TRUE);
}
if ((Flags & SHOW_MTREE) && meta->meta_mtree) {
show_file(meta->meta_mtree, "mtree file:\n", TRUE);
}
if (Flags & SHOW_PREFIX) {
show_plist("Prefix(s):\n", &plist, PLIST_CWD);
}
if (Flags & SHOW_FILES) {
show_files("Files:\n", &plist);
}
if ((Flags & SHOW_BUILD_VERSION) && meta->meta_build_version) {
show_file(meta->meta_build_version, "Build version:\n",
TRUE);
}
if (Flags & SHOW_BUILD_INFO) {
if (meta->meta_build_info) {
show_file(meta->meta_build_info, "Build information:\n",
TRUE);
}
if (meta->meta_installed_info) {
show_file(meta->meta_installed_info, "Installed information:\n",
TRUE);
}
}
if ((Flags & SHOW_PKG_SIZE) && meta->meta_size_pkg) {
show_file(meta->meta_size_pkg, "Size of this package in bytes: ",
TRUE);
}
if ((Flags & SHOW_ALL_SIZE) && meta->meta_size_all) {
show_file(meta->meta_size_all, "Size in bytes including required pkgs: ",
TRUE);
}
if (!Quiet && !(Flags & SHOW_SUMMARY)) {
if (meta->meta_preserve) {
printf("*** PACKAGE MAY NOT BE DELETED ***\n\n");
}
puts(InfoPrefix);
}
free_plist(&plist);
}
free_pkg_meta(meta);
return code;
}
struct print_matching_arg {
const char *pattern;
int got_match;
};
static int
print_matching_pkg(const char *pkgname, void *cookie)
{
struct print_matching_arg *arg= cookie;
if (pkg_match(arg->pattern, pkgname)) {
if (!Quiet)
puts(pkgname);
arg->got_match = 1;
}
return 0;
}
/*
* Returns 0 if at least one package matching pkgname.
* Returns 1 otherwise.
*
* If -q was not specified, print all matching packages to stdout.
*/
int
CheckForPkg(const char *pkgname)
{
struct print_matching_arg arg;
arg.pattern = pkgname;
arg.got_match = 0;
if (iterate_pkg_db(print_matching_pkg, &arg) == -1) {
warnx("cannot iterate pkgdb");
return 1;
}
if (arg.got_match == 0 && !ispkgpattern(pkgname)) {
char *pattern;
pattern = xasprintf("%s-[0-9]*", pkgname);
arg.pattern = pattern;
arg.got_match = 0;
if (iterate_pkg_db(print_matching_pkg, &arg) == -1) {
free(pattern);
warnx("cannot iterate pkgdb");
return 1;
}
free(pattern);
}
if (arg.got_match)
return 0;
else
return 1;
}
/*
* Returns 0 if at least one package matching pkgname.
* Returns 1 otherwise.
*
* If -q was not specified, print best match to stdout.
*/
int
CheckForBestPkg(const char *pkgname)
{
char *pattern, *best_match;
best_match = find_best_matching_installed_pkg(pkgname);
if (best_match == NULL) {
if (ispkgpattern(pkgname))
return 1;
pattern = xasprintf("%s-[0-9]*", pkgname);
best_match = find_best_matching_installed_pkg(pattern);
free(pattern);
}
if (best_match == NULL)
return 1;
if (!Quiet)
puts(best_match);
free(best_match);
return 0;
}
static int
perform_single_pkg(const char *pkg, void *cookie)
{
int *err_cnt = cookie;
if (Which == WHICH_ALL || !is_automatic_installed(pkg))
*err_cnt += pkg_do(pkg);
return 0;
}
int
pkg_perform(lpkg_head_t *pkghead)
{
int err_cnt = 0;
TAILQ_INIT(&files);
desired_meta_data = 0;
if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0)
desired_meta_data |= LOAD_PRESERVE;
if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0)
desired_meta_data |= LOAD_CONTENTS;
if (Flags & (SHOW_COMMENT | SHOW_INDEX | SHOW_SUMMARY))
desired_meta_data |= LOAD_COMMENT;
if (Flags & (SHOW_BI_VAR | SHOW_BUILD_INFO | SHOW_SUMMARY))
desired_meta_data |= LOAD_BUILD_INFO | LOAD_INSTALLED_INFO;
if (Flags & (SHOW_SUMMARY | SHOW_PKG_SIZE))
desired_meta_data |= LOAD_SIZE_PKG;
if (Flags & SHOW_ALL_SIZE)
desired_meta_data |= LOAD_SIZE_ALL;
if (Flags & (SHOW_SUMMARY | SHOW_DESC))
desired_meta_data |= LOAD_DESC;
if (Flags & (SHOW_REQBY | SHOW_FULL_REQBY))
desired_meta_data |= LOAD_REQUIRED_BY;
if (Flags & SHOW_DISPLAY)
desired_meta_data |= LOAD_DISPLAY;
if (Flags & SHOW_INSTALL)
desired_meta_data |= LOAD_INSTALL;
if (Flags & SHOW_DEINSTALL)
desired_meta_data |= LOAD_DEINSTALL;
if (Flags & SHOW_MTREE)
desired_meta_data |= LOAD_MTREE;
if (Flags & SHOW_BUILD_VERSION)
desired_meta_data |= LOAD_BUILD_VERSION;
if (Which != WHICH_LIST) {
if (File2Pkg) {
/* Show all files with the package they belong to */
if (pkgdb_dump() == -1)
err_cnt = 1;
} else {
if (iterate_pkg_db(perform_single_pkg, &err_cnt) == -1)
err_cnt = 1;
}
} else {
/* Show info on individual pkg(s) */
lpkg_t *lpp;
while ((lpp = TAILQ_FIRST(pkghead)) != NULL) {
TAILQ_REMOVE(pkghead, lpp, lp_link);
err_cnt += pkg_do(lpp->lp_name);
free_lpkg(lpp);
}
}
return err_cnt;
}

View file

@ -0,0 +1,349 @@
.\" $NetBSD: pkg_info.1,v 1.1.1.6 2013/04/20 15:26:53 wiz Exp $
.\"
.\" FreeBSD install - a package for the installation and maintenance
.\" 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
.\"
.\"
.\" @(#)pkg_info.1
.\"
.Dd December 14, 2012
.Dt PKG_INFO 1
.Os
.Sh NAME
.Nm pkg_info
.Nd a utility for displaying information on software packages
.Sh SYNOPSIS
.Nm
.Op Fl BbcDdFfhIikLmNnpqRrSsVvX
.Op Fl E Ar pkg-name
.Op Fl e Ar pkg-name
.Op Fl K Ar pkg_dbdir
.Op Fl l Ar prefix
.Ar pkg-name ...
.Nm
.Op Fl a | Fl u
.Op flags
.Nm
.Op Fl Q Ar variable
.Ar pkg-name ...
.Sh DESCRIPTION
The
.Nm
command is used to dump out information for packages, which may be either
packed up in files or already installed on the system with the
.Xr pkg_create 1
command.
.Pp
The
.Ar pkg-name
may be the name of an installed package (with our without version), a
pattern matching several installed packages (see the
.Sx PACKAGE WILDCARDS
section for a description of possible patterns),
the pathname to a
binary package, a filename belonging to an installed
package (with
.Fl F ) ,
or a URL to an FTP-available package.
.Pp
The following command line options are available:
.Bl -tag -width indent
.It Fl a
Show information for all currently installed packages.
See also
.Fl u .
When neither
.Fl a
nor
.Fl u
is given, the former is assumed.
.It Fl B
Show some of the important definitions used when building
the binary package (the
.Dq Build information )
for each package.
Additionally, any installation information variables
(lowercase) can be queried, too.
In particular,
.Ar automatic
tells if a package was installed automatically
as a dependency of another package.
.It Fl b
Show the
.Nx
RCS Id strings from the files used in the construction
of the binary package (the
.Dq Build version )
for each package.
These files are the package Makefile, any patch files, any checksum
files, and the packing list file.
.It Fl c
Show the one-line comment field for each package.
.It Fl D
Show the install-message file (if any) for each package.
.It Fl d
Show the long-description field for each package.
.It Fl E Ar pkg-name
This option
allows you to test for the existence of a given package.
If a package identified by
.Ar pkg-name
is currently installed, return code is 0, otherwise 1.
The name of the best matching package found installed is printed to
stdout unless turned off using the
.Fl q
option.
.Ar pkg-name
can contain wildcards (see the
.Sx PACKAGE WILDCARDS
section below).
.It Fl e Ar pkg-name
This option
allows you to test for the existence of a given package.
If a package identified by
.Ar pkg-name
is currently installed, return code is 0, otherwise 1.
The names of any package(s) found installed are printed to
stdout unless turned off using the
.Fl q
option.
.Ar pkg-name
can contain wildcards (see the
.Sx PACKAGE WILDCARDS
section below).
.It Fl F
Interpret any
.Ar pkg-name
given as filename, and query information on the package that
file belongs to.
This can be used to query information on a per-file basis.
See the
.Sx TECHNICAL DETAILS
section below for more information.
.It Fl f
Show the packing list instructions for each package.
.It Fl h
Print usage message and exit.
.It Fl I
Show the index entry for each package.
This option is assumed when no arguments or relevant flags are specified.
.It Fl i
Show the install script (if any) for each package.
.It Fl K Ar pkg_dbdir
Override the value of the
.Dv PKG_DBDIR
configuration option with the value
.Ar pkg_dbdir .
.It Fl k
Show the de-install script (if any) for each package.
.It Fl L
Show the files within each package.
This is different from just viewing the packing list, since full pathnames
for everything are generated.
Files that were created dynamically during installation of the package
are not listed.
.It Fl l Ar prefix
Prefix each information category header (see
.Fl q )
shown with
.Ar prefix .
This is primarily of use to front-end programs that want to request a
lot of different information fields at once for a package, but don't
necessary want the output intermingled in such a way that they can't
organize it.
This lets you add a special token to the start of each field.
.It Fl m
Show the mtree file (if any) for each package.
.It Fl N
Show which packages each package was built with (exact dependencies), if any.
.It Fl n
Show which packages each package needs (depends upon), if any.
.It Fl p
Show the installation prefix for each package.
.It Fl Q Ar variable
Show the definition of
.Ar variable
from the build information for each package.
An empty string is returned if no such variable definition is found for
the package(s).
.It Fl q
Be
.Dq quiet
in emitting report headers and such, just dump the
raw info (basically, assume a non-human reading).
.It Fl R
For each package, show the packages that require it.
.It Fl r
For each package, show the packages that require it.
Continue recursively to show all dependents.
.It Fl S
Show the size of this package and all the packages it requires,
in bytes.
.It Fl s
Show the size of this package in bytes.
The size is calculated by adding up the size of each file of the package.
.It Fl u
Show information for all user-installed packages:
automatically installed packages (as dependencies
of other packages) are not displayed.
See also
.Fl a .
.It Fl V
Print version number and exit.
.It Fl v
Turn on verbose output.
.It Fl X
Print summary information for each package.
The summary format is
described in
.Xr pkg_summary 5 .
Its primary use is to contain all information about the contents of a
(remote) binary package repository needed by package managing software.
.El
.Sh TECHNICAL DETAILS
Package info is either extracted from package files named on the
command line, or from already installed package information
in
.Pa \*[Lt]PKG_DBDIR\*[Gt]/\*[Lt]pkg-name\*[Gt] .
.Pp
When the
.Fl F
option is used,
a filename can be given instead of a package name to query
information on the (installed) package that file belongs to.
The filename is resolved to a package name using the package database.
The filename must be absolute, as in the output of
.Dl pkg_info -aF .
For example,
.Dl pkg_info -eF /path/to/file
can be used to display the package the given file belongs to, and
.Dl pkg_info -LF /path/to/file
can be used to display all files belonging to the package the given
file belongs to.
.Sh PACKAGE WILDCARDS
In the places where a package name/version is expected, e.g., for the
.Fl e
option, several forms can be used.
Either use a package name with or without version, or specify a
package wildcard that gets matched against all installed packages.
.Pp
Package wildcards use
.Xr fnmatch 3 .
In addition,
.Xr csh 1
style {,} alternates have been implemented.
Package version numbers can also be matched in a relational manner
using the
.Dq \*[Ge] ,
.Dq \*[Le] ,
.Dq \*[Gt] ,
and
.Dq \*[Lt]
operators.
For example,
.Dl pkg_info -e 'name\*[Ge]1.3'
will match versions 1.3 and later of the
.Dq name
package.
(Make sure to use shell quoting.)
Additionally, ranges can be defined, by giving both a lower bound
.Po with
.Dq \*[Gt]
or
.Dq \*[Ge]
.Pc
as well as an upper bound
.Po with
.Dq \*[Lt]
or
. Dq \*[Le]
.Pc .
The lower bound has to come first.
For example,
.Dl pkg_info -e 'name\*[Ge]1.3\*[Lt]2.0'
will match versions 1.3 (inclusive) to 2.0 (exclusive) of package
.Dq name .
.Pp
The collating sequence of the various package version numbers is
unusual, but strives to be consistent.
The magic string
.Dq alpha
equates to
.Dq alpha version ,
and sorts before a beta version.
The magic string
.Dq beta
equates to
.Dq beta version ,
and sorts before a release candidate.
The magic string
.Dq rc
equates to
.Dq release candidate ,
and sorts before a release.
The magic string
.Dq pre ,
short for
.Dq pre-release ,
is a synonym for
.Dq rc .
For example,
.Dq name-1.3alpha2
will sort before
.Dq name-1.3beta1 ,
and they both sort before
.Dq name-1.3rc1 .
Similarly,
.Dq name-1.3rc3
will sort before
.Dq name-1.3 ,
and after
.Dq name-1.2.9 .
The magic string
.Dq pl
equates to
.Dq patch level ,
and has the same value as a dot
.Pq Sq \&.
in the dewey-decimal ordering schemes,
as does the underscore
.Pq Sq _ .
Additionally, alphabetic characters sort in the same place as
their numeric counterparts, so that
.Dq name-1.2e
has the same sorting value as
.Dq name-1.2.5 .
.Sh ENVIRONMENT
See
.Xr pkg_install.conf 5
for options, that can also be specified using the environment.
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_admin 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_install.conf 5
.Xr pkgsrc 7
.Sh AUTHORS
.Bl -tag -width indent -compact
.It "Jordan Hubbard"
most of the work
.It "John Kohl"
refined it for
.Nx
.It "Hubert Feyrer"
.Nx
wildcard dependency processing, pkgdb, depends displaying,
pkg size display, and more.
.El

View file

@ -0,0 +1,430 @@
/* $NetBSD: show.c,v 1.3 2012/02/21 18:36:16 wiz Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: show.c,v 1.3 2012/02/21 18:36:16 wiz Exp $");
/*
* 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
* 23 Aug 1993
*
* Various display routines for the info module.
*
*/
/*-
* 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>.
*
* 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.
*
* 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_ERR_H
#include <err.h>
#endif
#include "defs.h"
#include "lib.h"
#include "info.h"
/* Structure to define entries for the "show table" */
typedef struct show_t {
pl_ent_t sh_type; /* type of entry */
const char *sh_quiet; /* message when quiet */
const char *sh_verbose; /* message when verbose */
} show_t;
/*
* The entries in this table must be ordered the same as
* pl_ent_t constants
*/
static const show_t showv[] = {
{PLIST_FILE, "", "\tFile: "},
{PLIST_CWD, "@cwd ", "\tCWD to: "},
{PLIST_CMD, "@exec ", "\tEXEC ''"},
{PLIST_CHMOD, "@chmod ", "\tCHMOD to "},
{PLIST_CHOWN, "@chown ", "\tCHOWN to "},
{PLIST_CHGRP, "@chgrp ", "\tCHGRP to "},
{PLIST_COMMENT, "@comment ", "\tComment: "},
{PLIST_IGNORE, "@ignore", "Ignore next file:"},
{PLIST_NAME, "@name ", "\tPackage name: "},
{PLIST_UNEXEC, "@unexec ", "\tUNEXEC ''"},
{PLIST_SRC, "@src: ", "\tSRC to: "},
{PLIST_DISPLAY, "@display ", "\tInstall message file: "},
{PLIST_PKGDEP, "@pkgdep ", "\tPackage depends on: "},
{PLIST_DIR_RM, "@dirrm ", "\tObsolete deinstall directory removal hint: "},
{PLIST_OPTION, "@option ", "\tPackage has option: "},
{PLIST_PKGCFL, "@pkgcfl ", "\tPackage conflicts with: "},
{PLIST_BLDDEP, "@blddep ", "\tPackage depends exactly on: "},
{PLIST_PKGDIR, "@pkgdir ", "\tManaged directory: "},
{-1, NULL, NULL}
};
static int print_string_as_var(const char *, const char *);
void
show_file(const char *buf, const char *title, Boolean separator)
{
size_t len;
if (!Quiet)
printf("%s%s", InfoPrefix, title);
len = strlen(buf);
if (len == 0 || buf[len - 1] != '\n')
puts(buf);
else
fputs(buf, stdout);
if (!Quiet || separator)
printf("\n");
}
void
show_var(const char *buf, const char *variable)
{
char *value;
if (buf == NULL)
return;
if ((value = var_get_memory(buf, variable)) != NULL) {
(void) printf("%s\n", value);
free(value);
}
}
void
show_index(const char *buf, const char *title)
{
size_t len;
if (!Quiet)
printf("%s%s", InfoPrefix, title);
len = strlen(buf);
if (len == 0 || buf[len - 1] != '\n')
puts(buf);
else
fputs(buf, stdout);
}
/*
* Show a packing list item type. If type is PLIST_SHOW_ALL, show all
*/
void
show_plist(const char *title, package_t *plist, pl_ent_t type)
{
plist_t *p;
Boolean ign;
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
}
for (ign = FALSE, p = plist->head; p; p = p->next) {
if (p->type == type || type == PLIST_SHOW_ALL) {
switch (p->type) {
case PLIST_FILE:
printf("%s%s",
Quiet ? showv[p->type].sh_quiet :
showv[p->type].sh_verbose, p->name);
if (ign) {
if (!Quiet) {
printf(" (ignored)");
}
ign = FALSE;
}
break;
case PLIST_CHMOD:
case PLIST_CHOWN:
case PLIST_CHGRP:
printf("%s%s",
Quiet ? showv[p->type].sh_quiet :
showv[p->type].sh_verbose,
p->name ? p->name : "(clear default)");
break;
case PLIST_IGNORE:
printf("%s", Quiet ? showv[p->type].sh_quiet :
showv[p->type].sh_verbose);
ign = TRUE;
break;
case PLIST_CWD:
case PLIST_CMD:
case PLIST_SRC:
case PLIST_UNEXEC:
case PLIST_COMMENT:
case PLIST_NAME:
case PLIST_DISPLAY:
case PLIST_PKGDEP:
case PLIST_DIR_RM:
case PLIST_OPTION:
case PLIST_PKGCFL:
case PLIST_BLDDEP:
case PLIST_PKGDIR:
printf("%s%s",
Quiet ? showv[p->type].sh_quiet :
showv[p->type].sh_verbose,
p->name ? p->name : "(null)");
break;
default:
warnx("unknown command type %d (%s)", p->type, p->name);
}
(void) fputc('\n', stdout);
}
}
}
/*
* Show all files in the packing list (except ignored ones)
*/
void
show_files(const char *title, package_t *plist)
{
plist_t *p;
Boolean ign;
const char *dir = ".";
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
}
for (ign = FALSE, p = plist->head; p; p = p->next) {
switch (p->type) {
case PLIST_FILE:
if (!ign) {
printf("%s%s%s\n", dir,
(strcmp(dir, "/") == 0) ? "" : "/", p->name);
}
ign = FALSE;
break;
case PLIST_CWD:
dir = p->name;
break;
case PLIST_IGNORE:
ign = TRUE;
break;
default:
break;
}
}
}
/*
* Show dependencies (packages this pkg requires)
*/
void
show_depends(const char *title, package_t *plist)
{
plist_t *p;
int nodepends;
nodepends = 1;
for (p = plist->head; p && nodepends; p = p->next) {
switch (p->type) {
case PLIST_PKGDEP:
nodepends = 0;
break;
default:
break;
}
}
if (nodepends)
return;
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
}
for (p = plist->head; p; p = p->next) {
switch (p->type) {
case PLIST_PKGDEP:
printf("%s\n", p->name);
break;
default:
break;
}
}
printf("\n");
}
/*
* Show exact dependencies (packages this pkg was built with)
*/
void
show_bld_depends(const char *title, package_t *plist)
{
plist_t *p;
int nodepends;
nodepends = 1;
for (p = plist->head; p && nodepends; p = p->next) {
switch (p->type) {
case PLIST_BLDDEP:
nodepends = 0;
break;
default:
break;
}
}
if (nodepends)
return;
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
}
for (p = plist->head; p; p = p->next) {
switch (p->type) {
case PLIST_BLDDEP:
printf("%s\n", p->name);
break;
default:
break;
}
}
printf("\n");
}
/*
* Show entry for pkg_summary.txt file.
*/
void
show_summary(struct pkg_meta *meta, package_t *plist, const char *binpkgfile)
{
static const char *bi_vars[] = {
"PKGPATH",
"CATEGORIES",
"PROVIDES",
"REQUIRES",
"PKG_OPTIONS",
"OPSYS",
"OS_VERSION",
"MACHINE_ARCH",
"LICENSE",
"HOMEPAGE",
"PKGTOOLS_VERSION",
"BUILD_DATE",
"PREV_PKGPATH",
"SUPERSEDES",
NULL
};
plist_t *p;
struct stat st;
for (p = plist->head; p; p = p->next) {
switch (p->type) {
case PLIST_NAME:
printf("PKGNAME=%s\n", p->name);
break;
case PLIST_PKGDEP:
printf("DEPENDS=%s\n", p->name);
break;
case PLIST_PKGCFL:
printf("CONFLICTS=%s\n", p->name);
break;
default:
break;
}
}
print_string_as_var("COMMENT", meta->meta_comment);
if (meta->meta_size_pkg)
print_string_as_var("SIZE_PKG", meta->meta_size_pkg);
if (meta->meta_build_info)
var_copy_list(meta->meta_build_info, bi_vars);
else
warnx("Build information missing");
if (binpkgfile != NULL && stat(binpkgfile, &st) == 0) {
const char *base;
base = strrchr(binpkgfile, '/');
if (base == NULL)
base = binpkgfile;
else
base++;
printf("FILE_NAME=%s\n", base);
printf("FILE_SIZE=%" MY_PRIu64 "\n", (uint64_t)st.st_size);
/* XXX: DIGETS */
}
print_string_as_var("DESCRIPTION", meta->meta_desc);
putc('\n', stdout);
}
/*
* Print the contents of file fname as value of variable var to stdout.
*/
static int
print_string_as_var(const char *var, const char *str)
{
const char *eol;
while ((eol = strchr(str, '\n')) != NULL) {
printf("%s=%.*s\n", var, (int)(eol - str), str);
str = eol + 1;
}
if (*str)
printf("%s=%s\n", var, str);
return 0;
}
void
show_list(lpkg_head_t *pkghead, const char *title)
{
lpkg_t *lpp;
if (!Quiet)
printf("%s%s", InfoPrefix, title);
while ((lpp = TAILQ_FIRST(pkghead)) != NULL) {
TAILQ_REMOVE(pkghead, lpp, lp_link);
puts(lpp->lp_name);
free_lpkg(lpp);
}
if (!Quiet)
printf("\n");
}

View file

@ -0,0 +1,105 @@
/* $NetBSD: automatic.c,v 1.1.1.2 2009/02/02 20:44:05 joerg Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron 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. 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_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: automatic.c,v 1.1.1.2 2009/02/02 20:44:05 joerg Exp $");
#if HAVE_ASSERT_H
#include <assert.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_STRING_H
#include <string.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include "lib.h"
Boolean
is_automatic_installed(const char *pkg)
{
char *filename, *value;
Boolean ret;
assert(pkg[0] != '/');
filename = pkgdb_pkg_file(pkg, INSTALLED_INFO_FNAME);
value = var_get(filename, AUTOMATIC_VARNAME);
if (value && strcasecmp(value, "yes") == 0)
ret = TRUE;
else
ret = FALSE;
free(value);
free(filename);
return ret;
}
int
mark_as_automatic_installed(const char *pkg, int value)
{
char *filename;
int retval;
assert(pkg[0] != '/');
filename = pkgdb_pkg_file(pkg, INSTALLED_INFO_FNAME);
retval = var_set(filename, AUTOMATIC_VARNAME, value ? "yes" : NULL);
free(filename);
return retval;
}

View file

@ -0,0 +1,196 @@
/* lib/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <assert.h> header file. */
#undef HAVE_ASSERT_H
/* Define to 1 if you have the <ctype.h> header file. */
#undef HAVE_CTYPE_H
/* Define to 1 if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H
/* Define to 1 if you have the <fnctl.h> header file. */
#undef HAVE_FNCTL_H
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the <glob.h> header file. */
#undef HAVE_GLOB_H
/* Define to 1 if you have the <grp.h> header file. */
#undef HAVE_GRP_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `db' library (-ldb). */
#undef HAVE_LIBDB
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <pwd.h> header file. */
#undef HAVE_PWD_H
/* Define to 1 if you have the <signal.h> header file. */
#undef HAVE_SIGNAL_H
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#undef HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#undef HAVE_SYS_CDEFS_H
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/queue.h> header file. */
#undef HAVE_SYS_QUEUE_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `vfork' function. */
#undef HAVE_VFORK
/* Define to 1 if you have the <vis.h> header file. */
#undef HAVE_VIS_H
/* Define to 1 if the `z' modifider for printf is missing. */
#undef MISSING_SIZE_T_SUPPORT
/* Defined when PRIu64 is missing or broken */
#undef NEED_PRI_MACRO
/* Defined when to retain only the numeric OS version */
#undef NUMERIC_VERSION_ONLY
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
/* The size of `size_t', as computed by sizeof. */
#undef SIZEOF_SIZE_T
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT32_T
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT64_T
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT8_T
/* Define to the type of an unsigned integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
#undef uint16_t
/* Define to the type of an unsigned integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef uint32_t
/* Define to the type of an unsigned integer type of width exactly 64 bits if
such a type exists and the standard includes do not define it. */
#undef uint64_t
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
#undef uint8_t
#if !HAVE_VFORK
# define vfork fork
#endif
#ifndef MISSING_SIZE_T_SUPPORT
# define PRIzu "zu"
#elif SIZEOF_SIZE_T == SIZEOF_INT
# define PRIzu "u"
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define PRIzu "lu"
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define PRIzu "llu"
#else
# errror "Unknown size_t size"
#endif

View file

@ -0,0 +1,166 @@
/* $NetBSD: conflicts.c,v 1.1.1.4 2010/01/30 21:33:43 joerg Exp $ */
/*-
* Copyright (c) 2007 Roland Illig <rillig@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* XXX: Reading the +CONTENTS files of all installed packages is
* rather slow. Since this check is necessary to avoid conflicting
* packages, it should not be removed.
*
* TODO: Put all the information that is currently in the +CONTENTS
* files into one large file or another database.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: conflicts.c,v 1.1.1.4 2010/01/30 21:33:43 joerg Exp $");
#if HAVE_ERR_H
#include <err.h>
#endif
#include "dewey.h"
#include "lib.h"
/**
* Data structure to keep the intermediate result of the conflict
* search. ''pkgname'' is the package in question. The first
* installed package that conflicts is filled into
* ''conflicting_pkgname''. The pattern that leads to the conflict is
* also filled in to help the user in deciding what to do with the
* conflict.
*/
struct package_conflict {
const char *pkgname;
const char *skip_pkgname;
char **conflicting_pkgname;
char **conflicting_pattern;
};
static FILE *
fopen_contents(const char *pkgname, const char *mode)
{
char *fname;
FILE *f;
fname = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
f = fopen(fname, mode);
if (f == NULL) {
err(EXIT_FAILURE, "%s", fname);
/* NOTREACHED */
}
free(fname);
return f;
}
static int
check_package_conflict(const char *pkgname, void *v)
{
struct package_conflict *conflict = v;
package_t pkg;
plist_t *p;
FILE *f;
int rv;
if (conflict->skip_pkgname != NULL &&
strcmp(conflict->skip_pkgname, pkgname) == 0)
return 0;
rv = 0;
f = fopen_contents(pkgname, "r");
read_plist(&pkg, f);
(void)fclose(f);
for (p = pkg.head; p; p = p->next) {
if (p->type != PLIST_PKGCFL)
continue;
if (pkg_match(p->name, conflict->pkgname) == 1) {
*(conflict->conflicting_pkgname) = xstrdup(pkgname);
*(conflict->conflicting_pattern) = xstrdup(p->name);
rv = 1 /* nonzero, stop iterating */;
break;
}
}
free_plist(&pkg);
return rv;
}
/**
* Checks if some installed package has a pkgcfl entry that matches
* PkgName. If such an entry is found, the package name is returned in
* inst_pkgname, the matching pattern in inst_pattern, and the function
* returns a non-zero value. Otherwise, zero is returned and the result
* variables are set to NULL.
*/
int
some_installed_package_conflicts_with(const char *pkgname,
const char *skip_pkgname, char **inst_pkgname, char **inst_pattern)
{
struct package_conflict cfl;
int rv;
cfl.pkgname = pkgname;
cfl.skip_pkgname = skip_pkgname;
*inst_pkgname = NULL;
*inst_pattern = NULL;
cfl.conflicting_pkgname = inst_pkgname;
cfl.conflicting_pattern = inst_pattern;
rv = iterate_pkg_db(check_package_conflict, &cfl);
if (rv == -1) {
errx(EXIT_FAILURE, "Couldn't read list of installed packages.");
/* NOTREACHED */
}
return *inst_pkgname != NULL;
}
#if 0
int main(int argc, char **argv)
{
char *pkg, *patt;
if (some_installed_package_conflicts_with(argv[1], &pkg, &patt))
printf("yes: package %s conflicts with %s, pattern %s\n", pkg, argv[1], patt);
else
printf("no\n");
return 0;
}
#endif

View file

@ -0,0 +1,75 @@
/* $NetBSD: defs.h,v 1.3 2012/02/21 18:36:17 wiz Exp $ */
/*-
* Copyright (c) 1999,2000,2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Alistair Crooks (agc@NetBSD.org)
*
* 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.
*
* 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.
*/
#ifndef DEFS_H_
#define DEFS_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
/*
* Some systems such as OpenBSD-3.6 do not provide PRIu64.
* Others such as AIX-4.3.2 have a broken PRIu64 which includes
* a leading "%".
*/
#ifdef NEED_PRI_MACRO
# if SIZEOF_INT == 8
# define MY_PRIu64 "u"
# elif SIZEOF_LONG == 8
# define MY_PRIu64 "lu"
# elif SIZEOF_LONG_LONG == 8
# define MY_PRIu64 "llu"
# else
# error "unable to find a suitable PRIu64"
# endif
#else
# define MY_PRIu64 PRIu64
#endif
#endif /* !DEFS_H_ */

View file

@ -0,0 +1,320 @@
/* $NetBSD: dewey.c,v 1.3 2009/03/08 14:53:16 joerg Exp $ */
/*
* Copyright © 2002 Alistair G. Crooks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "defs.h"
#include "dewey.h"
#define PKG_PATTERN_MAX 1024
/* do not modify these values, or things will NOT work */
enum {
Alpha = -3,
Beta = -2,
RC = -1,
Dot = 0,
Patch = 1
};
/* this struct defines a version number */
typedef struct arr_t {
unsigned c; /* # of version numbers */
unsigned size; /* size of array */
int *v; /* array of decimal numbers */
int netbsd; /* any "nb" suffix */
} arr_t;
/* this struct describes a test */
typedef struct test_t {
const char *s; /* string representation */
unsigned len; /* length of string */
int t; /* enumerated type of test */
} test_t;
/* the tests that are recognised. */
const test_t tests[] = {
{ "<=", 2, DEWEY_LE },
{ "<", 1, DEWEY_LT },
{ ">=", 2, DEWEY_GE },
{ ">", 1, DEWEY_GT },
{ "==", 2, DEWEY_EQ },
{ "!=", 2, DEWEY_NE },
{ NULL, 0, 0 }
};
const test_t modifiers[] = {
{ "alpha", 5, Alpha },
{ "beta", 4, Beta },
{ "pre", 3, RC },
{ "rc", 2, RC },
{ "pl", 2, Dot },
{ "_", 1, Dot },
{ ".", 1, Dot },
{ NULL, 0, 0 }
};
/* locate the test in the tests array */
int
dewey_mktest(int *op, const char *test)
{
const test_t *tp;
for (tp = tests ; tp->s ; tp++) {
if (strncasecmp(test, tp->s, tp->len) == 0) {
*op = tp->t;
return tp->len;
}
}
return -1;
}
/*
* make a component of a version number.
* '.' encodes as Dot which is '0'
* '_' encodes as 'patch level', or 'Dot', which is 0.
* 'pl' encodes as 'patch level', or 'Dot', which is 0.
* 'alpha' encodes as 'alpha version', or Alpha, which is -3.
* 'beta' encodes as 'beta version', or Beta, which is -2.
* 'rc' encodes as 'release candidate', or RC, which is -1.
* 'nb' encodes as 'netbsd version', which is used after all other tests
*/
static int
mkcomponent(arr_t *ap, const char *num)
{
static const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
const test_t *modp;
int n;
const char *cp;
if (ap->c == ap->size) {
if (ap->size == 0) {
ap->size = 62;
if ((ap->v = malloc(ap->size * sizeof(int))) == NULL)
err(EXIT_FAILURE, "mkver malloc failed");
} else {
ap->size *= 2;
if ((ap->v = realloc(ap->v, ap->size * sizeof(int)))
== NULL)
err(EXIT_FAILURE, "mkver realloc failed");
}
}
if (isdigit((unsigned char)*num)) {
for (cp = num, n = 0 ; isdigit((unsigned char)*num) ; num++) {
n = (n * 10) + (*num - '0');
}
ap->v[ap->c++] = n;
return (int)(num - cp);
}
for (modp = modifiers ; modp->s ; modp++) {
if (strncasecmp(num, modp->s, modp->len) == 0) {
ap->v[ap->c++] = modp->t;
return modp->len;
}
}
if (strncasecmp(num, "nb", 2) == 0) {
for (cp = num, num += 2, n = 0 ; isdigit((unsigned char)*num) ; num++) {
n = (n * 10) + (*num - '0');
}
ap->netbsd = n;
return (int)(num - cp);
}
if (isalpha((unsigned char)*num)) {
ap->v[ap->c++] = Dot;
cp = strchr(alphas, tolower((unsigned char)*num));
if (ap->c == ap->size) {
ap->size *= 2;
if ((ap->v = realloc(ap->v, ap->size * sizeof(int))) == NULL)
err(EXIT_FAILURE, "mkver realloc failed");
}
ap->v[ap->c++] = (int)(cp - alphas) + 1;
return 1;
}
return 1;
}
/* make a version number string into an array of comparable ints */
static int
mkversion(arr_t *ap, const char *num)
{
ap->c = 0;
ap->size = 0;
ap->v = NULL;
ap->netbsd = 0;
while (*num) {
num += mkcomponent(ap, num);
}
return 1;
}
static void
freeversion(arr_t *ap)
{
free(ap->v);
ap->v = NULL;
ap->c = 0;
ap->size = 0;
}
#define DIGIT(v, c, n) (((n) < (c)) ? v[n] : 0)
/* compare the result against the test we were expecting */
static int
result(int cmp, int tst)
{
switch(tst) {
case DEWEY_LT:
return cmp < 0;
case DEWEY_LE:
return cmp <= 0;
case DEWEY_GT:
return cmp > 0;
case DEWEY_GE:
return cmp >= 0;
case DEWEY_EQ:
return cmp == 0;
case DEWEY_NE:
return cmp != 0;
default:
return 0;
}
}
/* do the test on the 2 vectors */
static int
vtest(arr_t *lhs, int tst, arr_t *rhs)
{
int cmp;
unsigned int c, i;
for (i = 0, c = MAX(lhs->c, rhs->c) ; i < c ; i++) {
if ((cmp = DIGIT(lhs->v, lhs->c, i) - DIGIT(rhs->v, rhs->c, i)) != 0) {
return result(cmp, tst);
}
}
return result(lhs->netbsd - rhs->netbsd, tst);
}
/*
* Compare two dewey decimal numbers
*/
int
dewey_cmp(const char *lhs, int op, const char *rhs)
{
arr_t right;
arr_t left;
int retval;
if (!mkversion(&left, lhs))
return 0;
if (!mkversion(&right, rhs)) {
freeversion(&left);
return 0;
}
retval = vtest(&left, op, &right);
freeversion(&left);
freeversion(&right);
return retval;
}
/*
* Perform dewey match on "pkg" against "pattern".
* Return 1 on match, 0 on non-match, -1 on error.
*/
int
dewey_match(const char *pattern, const char *pkg)
{
const char *version;
const char *sep, *sep2;
int op, op2;
int n;
/* compare names */
if ((version=strrchr(pkg, '-')) == NULL) {
return 0;
}
if ((sep = strpbrk(pattern, "<>")) == NULL)
return -1;
/* compare name lengths */
if ((sep-pattern != version-pkg) ||
strncmp(pkg, pattern, (size_t)(version-pkg)) != 0)
return 0;
version++;
/* extract comparison operator */
if ((n = dewey_mktest(&op, sep)) < 0) {
return 0;
}
/* skip operator */
sep += n;
/* if greater than, look for less than */
sep2 = NULL;
if (op == DEWEY_GT || op == DEWEY_GE) {
if ((sep2 = strchr(sep, '<')) != NULL) {
if ((n = dewey_mktest(&op2, sep2)) < 0) {
return 0;
}
/* compare upper limit */
if (!dewey_cmp(version, op2, sep2+n))
return 0;
}
}
/* compare only pattern / lower limit */
if (sep2) {
char ver[PKG_PATTERN_MAX];
strlcpy(ver, sep, MIN((ssize_t)sizeof(ver), sep2-sep+1));
if (dewey_cmp(version, op, ver))
return 1;
}
else {
if (dewey_cmp(version, op, sep))
return 1;
}
return 0;
}

View file

@ -0,0 +1,19 @@
/* $NetBSD: dewey.h,v 1.1.1.1 2008/09/30 19:00:27 joerg Exp $ */
#ifndef _INST_LIB_DEWEY_H_
#define _INST_LIB_DEWEY_H_
int dewey_cmp(const char *, int, const char *);
int dewey_match(const char *, const char *);
int dewey_mktest(int *, const char *);
enum {
DEWEY_LT,
DEWEY_LE,
DEWEY_EQ,
DEWEY_GE,
DEWEY_GT,
DEWEY_NE
};
#endif /* _INST_LIB_DEWEY_H_ */

View file

@ -0,0 +1,167 @@
/* $NetBSD: fexec.c,v 1.1.1.3 2009/08/06 16:55:26 joerg Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matthias Scheler.
*
* 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.
*
* 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_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#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_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "lib.h"
__RCSID("$NetBSD: fexec.c,v 1.1.1.3 2009/08/06 16:55:26 joerg Exp $");
static int vfcexec(const char *, int, const char *, va_list);
/*
* fork, then change current working directory to path and
* execute the command and arguments in the argv array.
* wait for the command to finish, then return the exit status.
*/
int
pfcexec(const char *path, const char *file, const char **argv)
{
pid_t child;
int status;
child = vfork();
switch (child) {
case 0:
if ((path != NULL) && (chdir(path) < 0))
_exit(127);
(void)execvp(file, __UNCONST(argv));
_exit(127);
/* NOTREACHED */
case -1:
return -1;
}
while (waitpid(child, &status, 0) < 0) {
if (errno != EINTR)
return -1;
}
if (!WIFEXITED(status))
return -1;
return WEXITSTATUS(status);
}
static int
vfcexec(const char *path, int skipempty, const char *arg, va_list ap)
{
const char **argv;
size_t argv_size, argc;
int retval;
argv_size = 16;
argv = xcalloc(argv_size, sizeof(*argv));
argv[0] = arg;
argc = 1;
do {
if (argc == argv_size) {
argv_size *= 2;
argv = xrealloc(argv, argv_size * sizeof(*argv));
}
arg = va_arg(ap, const char *);
if (skipempty && arg && strlen(arg) == 0)
continue;
argv[argc++] = arg;
} while (arg != NULL);
retval = pfcexec(path, argv[0], argv);
free(argv);
return retval;
}
int
fexec(const char *arg, ...)
{
va_list ap;
int result;
va_start(ap, arg);
result = vfcexec(NULL, 0, arg, ap);
va_end(ap);
return result;
}
int
fexec_skipempty(const char *arg, ...)
{
va_list ap;
int result;
va_start(ap, arg);
result = vfcexec(NULL, 1, arg, ap);
va_end(ap);
return result;
}
int
fcexec(const char *path, const char *arg, ...)
{
va_list ap;
int result;
va_start(ap, arg);
result = vfcexec(path, 0, arg, ap);
va_end(ap);
return result;
}

374
external/bsd/pkg_install/dist/lib/file.c vendored Normal file
View file

@ -0,0 +1,374 @@
/* $NetBSD: file.c,v 1.1.1.6 2011/02/18 22:32:30 aymeric 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_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
__RCSID("$NetBSD: file.c,v 1.1.1.6 2011/02/18 22:32:30 aymeric Exp $");
/*
* 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.
*
*/
#include "lib.h"
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_GLOB_H
#include <glob.h>
#endif
#if HAVE_PWD_H
#include <pwd.h>
#endif
#if HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
/*
* Quick check to see if a file (or dir ...) exists
*/
Boolean
fexists(const char *fname)
{
struct stat dummy;
if (!lstat(fname, &dummy))
return TRUE;
return FALSE;
}
/*
* Quick check to see if something is a directory
*/
Boolean
isdir(const char *fname)
{
struct stat sb;
if (lstat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
return TRUE;
else
return FALSE;
}
/*
* Check if something is a link to a directory
*/
Boolean
islinktodir(const char *fname)
{
struct stat sb;
if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode)) {
if (stat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
return TRUE; /* link to dir! */
else
return FALSE; /* link to non-dir */
} else
return FALSE; /* non-link */
}
/*
* Check if something is a link that points to nonexistant target.
*/
Boolean
isbrokenlink(const char *fname)
{
struct stat sb;
if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode)) {
if (stat(fname, &sb) != FAIL)
return FALSE; /* link target exists! */
else
return TRUE; /* link target missing*/
} else
return FALSE; /* non-link */
}
/*
* Check to see if file is a dir, and is empty
*/
Boolean
isemptydir(const char *fname)
{
if (isdir(fname) || islinktodir(fname)) {
DIR *dirp;
struct dirent *dp;
dirp = opendir(fname);
if (!dirp)
return FALSE; /* no perms, leave it alone */
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
closedir(dirp);
return FALSE;
}
}
(void) closedir(dirp);
return TRUE;
}
return FALSE;
}
/*
* Check if something is a regular file
*/
Boolean
isfile(const char *fname)
{
struct stat sb;
if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode))
return TRUE;
return FALSE;
}
/*
* Check to see if file is a file and is empty. If nonexistent or not
* a file, say "it's empty", otherwise return TRUE if zero sized.
*/
Boolean
isemptyfile(const char *fname)
{
struct stat sb;
if (stat(fname, &sb) != FAIL && S_ISREG(sb.st_mode)) {
if (sb.st_size != 0)
return FALSE;
}
return TRUE;
}
/* This struct defines the leading part of a valid URL name */
typedef struct url_t {
const char *u_s; /* the leading part of the URL */
int u_len; /* its length */
} url_t;
/* A table of valid leading strings for URLs */
static const url_t urls[] = {
#define STR_AND_SIZE(str) { str, sizeof(str) - 1 }
STR_AND_SIZE("file://"),
STR_AND_SIZE("ftp://"),
STR_AND_SIZE("http://"),
STR_AND_SIZE("https://"),
#undef STR_AND_SIZE
{NULL, 0}
};
/*
* Returns length of leading part of any URL from urls table, or -1
*/
int
URLlength(const char *fname)
{
const url_t *up;
int i;
if (fname != (char *) NULL) {
for (i = 0; isspace((unsigned char) *fname); i++) {
fname++;
}
for (up = urls; up->u_s; up++) {
if (strncmp(fname, up->u_s, up->u_len) == 0) {
return i + up->u_len; /* ... + sizeof(up->u_s); - HF */
}
}
}
return -1;
}
/*
* Takes a filename and package name, returning (in "try") the canonical
* "preserve" name for it.
*/
Boolean
make_preserve_name(char *try, size_t max, const char *name, const char *file)
{
size_t len, i;
if ((len = strlen(file)) == 0)
return FALSE;
i = len - 1;
strncpy(try, file, max);
if (try[i] == '/') /* Catch trailing slash early and save checking in the loop */
--i;
for (; i; i--) {
if (try[i] == '/') {
try[i + 1] = '.';
strncpy(&try[i + 2], &file[i + 1], max - i - 2);
break;
}
}
if (!i) {
try[0] = '.';
strncpy(try + 1, file, max - 1);
}
/* I should probably be called rude names for these inline assignments */
strncat(try, ".", max -= strlen(try));
strncat(try, name, max -= strlen(name));
strncat(try, ".", max--);
strncat(try, "backup", max -= 6);
return TRUE;
}
void
remove_files(const char *path, const char *pattern)
{
char fpath[MaxPathSize];
glob_t globbed;
int i;
size_t j;
(void) snprintf(fpath, sizeof(fpath), "%s/%s", path, pattern);
if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) {
switch(i) {
case GLOB_NOMATCH:
warn("no files matching ``%s'' found", fpath);
break;
case GLOB_ABORTED:
warn("globbing aborted");
break;
case GLOB_NOSPACE:
warn("out-of-memory during globbing");
break;
default:
warn("unknown error during globbing");
break;
}
return;
}
/* deleting globbed files */
for (j = 0; j < globbed.gl_pathc; j++)
if (unlink(globbed.gl_pathv[j]) < 0)
warn("can't delete ``%s''", globbed.gl_pathv[j]);
return;
}
/*
* Using fmt, replace all instances of:
*
* %F With the parameter "name"
* %D With the parameter "dir"
* %B Return the directory part ("base") of %D/%F
* %f Return the filename part of %D/%F
*
* Check that no overflows can occur.
*/
int
format_cmd(char *buf, size_t size, const char *fmt, const char *dir, const char *name)
{
size_t remaining, quoted;
char *bufp, *tmp;
char *cp;
for (bufp = buf, remaining = size; remaining > 1 && *fmt;) {
if (*fmt != '%') {
*bufp++ = *fmt++;
--remaining;
continue;
}
if (*++fmt != 'D' && name == NULL) {
warnx("no last file available for '%s' command", buf);
return -1;
}
switch (*fmt) {
case 'F':
quoted = shquote(name, bufp, remaining);
if (quoted >= remaining) {
warnx("overflow during quoting");
return -1;
}
bufp += quoted;
remaining -= quoted;
break;
case 'D':
quoted = shquote(dir, bufp, remaining);
if (quoted >= remaining) {
warnx("overflow during quoting");
return -1;
}
bufp += quoted;
remaining -= quoted;
break;
case 'B':
tmp = xasprintf("%s/%s", dir, name);
cp = strrchr(tmp, '/');
*cp = '\0';
quoted = shquote(tmp, bufp, remaining);
free(tmp);
if (quoted >= remaining) {
warnx("overflow during quoting");
return -1;
}
bufp += quoted;
remaining -= quoted;
break;
case 'f':
tmp = xasprintf("%s/%s", dir, name);
cp = strrchr(tmp, '/') + 1;
quoted = shquote(cp, bufp, remaining);
free(tmp);
if (quoted >= remaining) {
warnx("overflow during quoting");
return -1;
}
bufp += quoted;
remaining -= quoted;
break;
default:
if (remaining == 1) {
warnx("overflow during quoting");
return -1;
}
*bufp++ = '%';
*bufp++ = *fmt;
remaining -= 2;
break;
}
++fmt;
}
*bufp = '\0';
return 0;
}

View file

@ -0,0 +1,38 @@
/* $NetBSD: global.c,v 1.1.1.2 2009/02/02 20:44:06 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: global.c,v 1.1.1.2 2009/02/02 20:44:06 joerg Exp $");
/*
* 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
*
* Semi-convenient place to stick some needed globals.
*
*/
#include "lib.h"
/* These are global for all utils */
Boolean Verbose = FALSE;
Boolean Fake = FALSE;
Boolean Force = FALSE;

View file

@ -0,0 +1,248 @@
/* $NetBSD: gpgsig.c,v 1.1.1.2 2009/08/06 16:55:27 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: gpgsig.c,v 1.1.1.2 2009/08/06 16:55:27 joerg Exp $");
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/wait.h>
#ifndef NETBSD
#include <nbcompat/err.h>
#else
#include <err.h>
#endif
#ifndef NETBSD
#include <nbcompat/stdlib.h>
#else
#include <stdlib.h>
#endif
#include "lib.h"
static void
verify_signature(const char *input, size_t input_len, const char *keyring,
const char *detached_signature)
{
const char *argv[8], **argvp;
pid_t child;
int fd[2], status;
if (pipe(fd) == -1)
err(EXIT_FAILURE, "cannot create input pipes");
child = vfork();
if (child == -1)
err(EXIT_FAILURE, "cannot fork GPG process");
if (child == 0) {
close(fd[1]);
close(STDIN_FILENO);
if (dup2(fd[0], STDIN_FILENO) == -1) {
static const char err_msg[] =
"cannot redirect stdin of GPG process\n";
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
_exit(255);
}
close(fd[0]);
argvp = argv;
*argvp++ = gpg_cmd;
*argvp++ = "--verify";
if (keyring != NULL) {
*argvp++ = "--no-default-keyring";
*argvp++ = "--keyring";
*argvp++ = keyring;
}
if (detached_signature != NULL)
*argvp++ = detached_signature;
*argvp++ = "-";
*argvp = NULL;
execvp(gpg_cmd, __UNCONST(argv));
_exit(255);
}
close(fd[0]);
if (write(fd[1], input, input_len) != (ssize_t)input_len)
errx(EXIT_FAILURE, "Short read from GPG");
close(fd[1]);
waitpid(child, &status, 0);
if (status)
errx(EXIT_FAILURE, "GPG could not verify the signature");
}
int
inline_gpg_verify(const char *content, size_t len, const char *keyring)
{
verify_signature(content, len, keyring, NULL);
return 0;
}
int
detached_gpg_verify(const char *content, size_t len,
const char *signature, size_t signature_len, const char *keyring)
{
int fd;
const char *tmpdir;
char *tempsig;
ssize_t ret;
if (gpg_cmd == NULL) {
warnx("GPG variable not set, failing signature check");
return -1;
}
if ((tmpdir = getenv("TMPDIR")) == NULL)
tmpdir = "/tmp";
tempsig = xasprintf("%s/pkg_install.XXXXXX", tmpdir);
fd = mkstemp(tempsig);
if (fd == -1) {
warnx("Creating temporary file for GPG signature failed");
return -1;
}
while (signature_len) {
ret = write(fd, signature, signature_len);
if (ret == -1)
err(EXIT_FAILURE, "Write to GPG failed");
if (ret == 0)
errx(EXIT_FAILURE, "Short write to GPG");
signature_len -= ret;
signature += ret;
}
verify_signature(content, len, keyring, tempsig);
unlink(tempsig);
close(fd);
free(tempsig);
return 0;
}
int
detached_gpg_sign(const char *content, size_t len, char **sig, size_t *sig_len,
const char *keyring, const char *user)
{
const char *argv[12], **argvp;
pid_t child;
int fd_in[2], fd_out[2], status;
size_t allocated;
ssize_t ret;
if (gpg_cmd == NULL)
errx(EXIT_FAILURE, "GPG variable not set");
if (pipe(fd_in) == -1)
err(EXIT_FAILURE, "cannot create input pipes");
if (pipe(fd_out) == -1)
err(EXIT_FAILURE, "cannot create output pipes");
child = fork();
if (child == -1)
err(EXIT_FAILURE, "cannot fork GPG process");
if (child == 0) {
close(fd_in[1]);
close(STDIN_FILENO);
if (dup2(fd_in[0], STDIN_FILENO) == -1) {
static const char err_msg[] =
"cannot redirect stdin of GPG process\n";
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
_exit(255);
}
close(fd_in[0]);
close(fd_out[0]);
close(STDOUT_FILENO);
if (dup2(fd_out[1], STDOUT_FILENO) == -1) {
static const char err_msg[] =
"cannot redirect stdout of GPG process\n";
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
_exit(255);
}
close(fd_out[1]);
argvp = argv;
*argvp++ = gpg_cmd;
*argvp++ = "--detach-sign";
*argvp++ = "--armor";
*argvp++ = "--output";
*argvp++ = "-";
if (user != NULL) {
*argvp++ = "--local-user";
*argvp++ = user;
}
if (keyring != NULL) {
*argvp++ = "--no-default-keyring";
*argvp++ = "--secret-keyring";
*argvp++ = keyring;
}
*argvp++ = "-";
*argvp = NULL;
execvp(gpg_cmd, __UNCONST(argv));
_exit(255);
}
close(fd_in[0]);
if (write(fd_in[1], content, len) != (ssize_t)len)
errx(EXIT_FAILURE, "Short read from GPG");
close(fd_in[1]);
allocated = 1024;
*sig = xmalloc(allocated);
*sig_len = 0;
close(fd_out[1]);
while ((ret = read(fd_out[0], *sig + *sig_len,
allocated - *sig_len)) > 0) {
*sig_len += ret;
if (*sig_len == allocated) {
allocated *= 2;
*sig = xrealloc(*sig, allocated);
}
}
close(fd_out[0]);
waitpid(child, &status, 0);
if (status)
errx(EXIT_FAILURE, "GPG could not create signature");
return 0;
}

View file

@ -0,0 +1,485 @@
/* $NetBSD: iterate.c,v 1.1.1.4 2010/01/30 21:33:47 joerg Exp $ */
/*-
* Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include "lib.h"
/*
* Generic iteration function:
* - get new entries from srciter, stop on NULL
* - call matchiter for those entries, stop on non-null return value.
*/
int
iterate_pkg_generic_src(int (*matchiter)(const char *, void *),
void *match_cookie, const char *(*srciter)(void *), void *src_cookie)
{
int retval;
const char *entry;
retval = 0;
while ((entry = (*srciter)(src_cookie)) != NULL) {
if ((retval = (*matchiter)(entry, match_cookie)) != 0)
break;
}
return retval;
}
struct pkg_dir_iter_arg {
DIR *dirp;
int filter_suffix;
int allow_nonfiles;
};
static const char *
pkg_dir_iter(void *cookie)
{
struct pkg_dir_iter_arg *arg = cookie;
struct dirent *dp;
size_t len;
while ((dp = readdir(arg->dirp)) != NULL) {
#if defined(DT_UNKNOWN) && defined(DT_DIR)
if (arg->allow_nonfiles == 0 &&
dp->d_type != DT_UNKNOWN && dp->d_type != DT_REG)
continue;
#endif
len = strlen(dp->d_name);
/* .tbz or .tgz suffix length + some prefix*/
if (len < 5)
continue;
if (arg->filter_suffix == 0 ||
memcmp(dp->d_name + len - 4, ".tgz", 4) == 0 ||
memcmp(dp->d_name + len - 4, ".tbz", 4) == 0)
return dp->d_name;
}
return NULL;
}
/*
* Call matchiter for every package in the directory.
*/
int
iterate_local_pkg_dir(const char *dir, int filter_suffix, int allow_nonfiles,
int (*matchiter)(const char *, void *), void *cookie)
{
struct pkg_dir_iter_arg arg;
int retval;
if ((arg.dirp = opendir(dir)) == NULL)
return -1;
arg.filter_suffix = filter_suffix;
arg.allow_nonfiles = allow_nonfiles;
retval = iterate_pkg_generic_src(matchiter, cookie, pkg_dir_iter, &arg);
if (closedir(arg.dirp) == -1)
return -1;
return retval;
}
static const char *
pkg_db_iter(void *cookie)
{
DIR *dirp = cookie;
struct dirent *dp;
while ((dp = readdir(dirp)) != NULL) {
if (strcmp(dp->d_name, ".") == 0)
continue;
if (strcmp(dp->d_name, "..") == 0)
continue;
if (strcmp(dp->d_name, "pkgdb.byfile.db") == 0)
continue;
if (strcmp(dp->d_name, ".cookie") == 0)
continue;
if (strcmp(dp->d_name, "pkg-vulnerabilities") == 0)
continue;
#if defined(DT_UNKNOWN) && defined(DT_DIR)
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_DIR)
continue;
#endif
return dp->d_name;
}
return NULL;
}
/*
* Call matchiter for every installed package.
*/
int
iterate_pkg_db(int (*matchiter)(const char *, void *), void *cookie)
{
DIR *dirp;
int retval;
if ((dirp = opendir(pkgdb_get_dir())) == NULL) {
if (errno == ENOENT)
return 0; /* No pkgdb directory == empty pkgdb */
return -1;
}
retval = iterate_pkg_generic_src(matchiter, cookie, pkg_db_iter, dirp);
if (closedir(dirp) == -1)
return -1;
return retval;
}
static int
match_by_basename(const char *pkg, void *cookie)
{
const char *target = cookie;
const char *pkg_version;
if ((pkg_version = strrchr(pkg, '-')) == NULL) {
warnx("Entry %s in pkgdb is not a valid package name", pkg);
return 0;
}
if (strncmp(pkg, target, pkg_version - pkg) == 0 &&
pkg + strlen(target) == pkg_version)
return 1;
else
return 0;
}
static int
match_by_pattern(const char *pkg, void *cookie)
{
const char *pattern = cookie;
return pkg_match(pattern, pkg);
}
struct add_matching_arg {
lpkg_head_t *pkghead;
int got_match;
int (*match_fn)(const char *pkg, void *cookie);
void *cookie;
};
static int
match_and_add(const char *pkg, void *cookie)
{
struct add_matching_arg *arg = cookie;
lpkg_t *lpp;
if ((*arg->match_fn)(pkg, arg->cookie) == 1) {
arg->got_match = 1;
lpp = alloc_lpkg(pkg);
TAILQ_INSERT_TAIL(arg->pkghead, lpp, lp_link);
}
return 0;
}
/*
* Find all installed packages with the given basename and add them
* to pkghead.
* Returns -1 on error, 0 if no match was found and 1 otherwise.
*/
int
add_installed_pkgs_by_basename(const char *pkgbase, lpkg_head_t *pkghead)
{
struct add_matching_arg arg;
arg.pkghead = pkghead;
arg.got_match = 0;
arg.match_fn = match_by_basename;
arg.cookie = __UNCONST(pkgbase);
if (iterate_pkg_db(match_and_add, &arg) == -1) {
warnx("could not process pkgdb");
return -1;
}
return arg.got_match;
}
/*
* Match all installed packages against pattern, add the matches to pkghead.
* Returns -1 on error, 0 if no match was found and 1 otherwise.
*/
int
add_installed_pkgs_by_pattern(const char *pattern, lpkg_head_t *pkghead)
{
struct add_matching_arg arg;
arg.pkghead = pkghead;
arg.got_match = 0;
arg.match_fn = match_by_pattern;
arg.cookie = __UNCONST(pattern);
if (iterate_pkg_db(match_and_add, &arg) == -1) {
warnx("could not process pkgdb");
return -1;
}
return arg.got_match;
}
struct best_installed_match_arg {
const char *pattern;
char *best_current_match;
};
static int
match_best_installed(const char *pkg, void *cookie)
{
struct best_installed_match_arg *arg = cookie;
switch (pkg_order(arg->pattern, pkg, arg->best_current_match)) {
case 0:
case 2:
/*
* Either current package doesn't match or
* the older match is better. Nothing to do.
*/
break;
case 1:
/* Current package is better, remember it. */
free(arg->best_current_match);
arg->best_current_match = xstrdup(pkg);
break;
}
return 0;
}
/*
* Returns a copy of the name of best matching package.
* If no package matched the pattern or an error occured, return NULL.
*/
char *
find_best_matching_installed_pkg(const char *pattern)
{
struct best_installed_match_arg arg;
arg.pattern = pattern;
arg.best_current_match = NULL;
if (iterate_pkg_db(match_best_installed, &arg) == -1) {
warnx("could not process pkgdb");
return NULL;
}
return arg.best_current_match;
}
struct call_matching_arg {
const char *pattern;
int (*call_fn)(const char *pkg, void *cookie);
void *cookie;
};
static int
match_and_call(const char *pkg, void *cookie)
{
struct call_matching_arg *arg = cookie;
if (pkg_match(arg->pattern, pkg) == 1) {
return (*arg->call_fn)(pkg, arg->cookie);
} else
return 0;
}
/*
* Find all packages that match the given pattern and call the function
* for each of them. Iteration stops if the callback return non-0.
* Returns -1 on error, 0 if the iteration finished or whatever the
* callback returned otherwise.
*/
int
match_installed_pkgs(const char *pattern, int (*cb)(const char *, void *),
void *cookie)
{
struct call_matching_arg arg;
arg.pattern = pattern;
arg.call_fn = cb;
arg.cookie = cookie;
return iterate_pkg_db(match_and_call, &arg);
}
struct best_file_match_arg {
const char *pattern;
char *best_current_match_filtered;
char *best_current_match;
int filter_suffix;
};
static int
match_best_file(const char *filename, void *cookie)
{
struct best_file_match_arg *arg = cookie;
const char *active_filename;
char *filtered_filename;
if (arg->filter_suffix) {
size_t len;
len = strlen(filename);
if (len < 5 ||
(memcmp(filename + len - 4, ".tgz", 4) != 0 &&
memcmp(filename + len - 4, ".tbz", 4) != 0)) {
warnx("filename %s does not contain a recognized suffix", filename);
return -1;
}
filtered_filename = xmalloc(len - 4 + 1);
memcpy(filtered_filename, filename, len - 4);
filtered_filename[len - 4] = '\0';
active_filename = filtered_filename;
} else {
filtered_filename = NULL;
active_filename = filename;
}
switch (pkg_order(arg->pattern, active_filename, arg->best_current_match_filtered)) {
case 0:
case 2:
/*
* Either current package doesn't match or
* the older match is better. Nothing to do.
*/
free(filtered_filename);
return 0;
case 1:
/* Current package is better, remember it. */
free(arg->best_current_match);
free(arg->best_current_match_filtered);
arg->best_current_match = xstrdup(filename);
if (filtered_filename != NULL)
arg->best_current_match_filtered = filtered_filename;
else
arg->best_current_match_filtered = xstrdup(active_filename);
return 0;
default:
errx(EXIT_FAILURE, "Invalid error from pkg_order");
/* NOTREACHED */
}
}
/*
* Returns a copy of the name of best matching file.
* If no package matched the pattern or an error occured, return NULL.
*/
char *
find_best_matching_file(const char *dir, const char *pattern, int filter_suffix, int allow_nonfiles)
{
struct best_file_match_arg arg;
arg.filter_suffix = filter_suffix;
arg.pattern = pattern;
arg.best_current_match = NULL;
arg.best_current_match_filtered = NULL;
if (iterate_local_pkg_dir(dir, filter_suffix, allow_nonfiles, match_best_file, &arg) == -1) {
warnx("could not process directory");
return NULL;
}
free(arg.best_current_match_filtered);
return arg.best_current_match;
}
struct call_matching_file_arg {
const char *pattern;
int (*call_fn)(const char *pkg, void *cookie);
void *cookie;
int filter_suffix;
};
static int
match_file_and_call(const char *filename, void *cookie)
{
struct call_matching_file_arg *arg = cookie;
const char *active_filename;
char *filtered_filename;
int ret;
if (arg->filter_suffix) {
size_t len;
len = strlen(filename);
if (len < 5 ||
(memcmp(filename + len - 4, ".tgz", 4) != 0 &&
memcmp(filename + len - 4, ".tbz", 4) != 0)) {
warnx("filename %s does not contain a recognized suffix", filename);
return -1;
}
filtered_filename = xmalloc(len - 4 + 1);
memcpy(filtered_filename, filename, len - 4);
filtered_filename[len - 4] = '\0';
active_filename = filtered_filename;
} else {
filtered_filename = NULL;
active_filename = filename;
}
ret = pkg_match(arg->pattern, active_filename);
free(filtered_filename);
if (ret == 1)
return (*arg->call_fn)(filename, arg->cookie);
else
return 0;
}
/*
* Find all packages that match the given pattern and call the function
* for each of them. Iteration stops if the callback return non-0.
* Returns -1 on error, 0 if the iteration finished or whatever the
* callback returned otherwise.
*/
int
match_local_files(const char *dir, int filter_suffix, int allow_nonfiles, const char *pattern,
int (*cb)(const char *, void *), void *cookie)
{
struct call_matching_file_arg arg;
arg.pattern = pattern;
arg.call_fn = cb;
arg.cookie = cookie;
arg.filter_suffix = filter_suffix;
return iterate_local_pkg_dir(dir, filter_suffix, allow_nonfiles, match_file_and_call, &arg);
}

457
external/bsd/pkg_install/dist/lib/lib.h vendored Normal file
View file

@ -0,0 +1,457 @@
/* $NetBSD: lib.h,v 1.6 2010/06/26 00:17:13 joerg Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
/*
* 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
*
* Include and define various things wanted by the library routines.
*
*/
#ifndef _INST_LIB_LIB_H_
#define _INST_LIB_LIB_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_DIRENT_H
#include <dirent.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
/* Macros */
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
#define SUCCESS (0)
#define FAIL (-1)
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef OPSYS_NAME
#define OPSYS_NAME "NetBSD"
#endif
#ifndef DEF_UMASK
#define DEF_UMASK 022
#endif
#ifndef PATH_MAX
# ifdef MAXPATHLEN
# define PATH_MAX MAXPATHLEN
# else
# define PATH_MAX 1024
# endif
#endif
enum {
MaxPathSize = PATH_MAX
};
/* The names of our "special" files */
#define CONTENTS_FNAME "+CONTENTS"
#define COMMENT_FNAME "+COMMENT"
#define DESC_FNAME "+DESC"
#define INSTALL_FNAME "+INSTALL"
#define DEINSTALL_FNAME "+DEINSTALL"
#define REQUIRED_BY_FNAME "+REQUIRED_BY"
#define REQUIRED_BY_FNAME_TMP "+REQUIRED_BY.tmp"
#define DISPLAY_FNAME "+DISPLAY"
#define MTREE_FNAME "+MTREE_DIRS"
#define BUILD_VERSION_FNAME "+BUILD_VERSION"
#define BUILD_INFO_FNAME "+BUILD_INFO"
#define INSTALLED_INFO_FNAME "+INSTALLED_INFO"
#define SIZE_PKG_FNAME "+SIZE_PKG"
#define SIZE_ALL_FNAME "+SIZE_ALL"
#define PRESERVE_FNAME "+PRESERVE"
#define VIEWS_FNAME "+VIEWS"
#define VIEWS_FNAME_TMP "+VIEWS.tmp"
#define DEPOT_FNAME "+DEPOT"
/* The names of special variables */
#define AUTOMATIC_VARNAME "automatic"
/* Prefix for extended PLIST cmd */
#define CMD_CHAR '@'
/* The name of the "prefix" environment variable given to scripts */
#define PKG_PREFIX_VNAME "PKG_PREFIX"
/* The name of the "destdir" environment variable given to scripts */
#define PKG_DESTDIR_VNAME "PKG_DESTDIR"
/*
* The name of the "metadatadir" environment variable given to scripts.
* This variable holds the location of the +-files for this package.
*/
#define PKG_METADATA_DIR_VNAME "PKG_METADATA_DIR"
/*
* The name of the environment variable holding the location to the
* reference-counts database directory.
*/
#define PKG_REFCOUNT_DBDIR_VNAME "PKG_REFCOUNT_DBDIR"
#define PKG_PATTERN_MAX MaxPathSize /* max length of pattern, including nul */
#define PKG_SUFFIX_MAX 10 /* max length of suffix, including nul */
enum {
ReadWrite,
ReadOnly
};
/* Enumerated constants for plist entry types */
typedef enum pl_ent_t {
PLIST_SHOW_ALL = -1,
PLIST_FILE, /* 0 */
PLIST_CWD, /* 1 */
PLIST_CMD, /* 2 */
PLIST_CHMOD, /* 3 */
PLIST_CHOWN, /* 4 */
PLIST_CHGRP, /* 5 */
PLIST_COMMENT, /* 6 */
PLIST_IGNORE, /* 7 */
PLIST_NAME, /* 8 */
PLIST_UNEXEC, /* 9 */
PLIST_SRC, /* 10 */
PLIST_DISPLAY, /* 11 */
PLIST_PKGDEP, /* 12 */
PLIST_DIR_RM, /* 13 */
PLIST_OPTION, /* 14 */
PLIST_PKGCFL, /* 15 */
PLIST_BLDDEP, /* 16 */
PLIST_PKGDIR /* 17 */
} pl_ent_t;
/* Enumerated constants for build info */
typedef enum bi_ent_t {
BI_OPSYS, /* 0 */
BI_OS_VERSION, /* 1 */
BI_MACHINE_ARCH, /* 2 */
BI_IGNORE_RECOMMENDED, /* 3 */
BI_USE_ABI_DEPENDS, /* 4 */
BI_LICENSE, /* 5 */
BI_PKGTOOLS_VERSION, /* 6 */
BI_ENUM_COUNT /* 7 */
} bi_ent_t;
/* Types */
typedef unsigned int Boolean;
/* This structure describes a packing list entry */
typedef struct plist_t {
struct plist_t *prev; /* previous entry */
struct plist_t *next; /* next entry */
char *name; /* name of entry */
Boolean marked; /* whether entry has been marked */
pl_ent_t type; /* type of entry */
} plist_t;
/* This structure describes a package's complete packing list */
typedef struct package_t {
plist_t *head; /* head of list */
plist_t *tail; /* tail of list */
} package_t;
#define SYMLINK_HEADER "Symlink:"
#define CHECKSUM_HEADER "MD5:"
enum {
ChecksumHeaderLen = 4, /* strlen(CHECKSUM_HEADER) */
SymlinkHeaderLen = 8, /* strlen(SYMLINK_HEADER) */
ChecksumLen = 16,
LegibleChecksumLen = 33
};
/* List of files */
typedef struct _lfile_t {
TAILQ_ENTRY(_lfile_t) lf_link;
char *lf_name;
} lfile_t;
TAILQ_HEAD(_lfile_head_t, _lfile_t);
typedef struct _lfile_head_t lfile_head_t;
#define LFILE_ADD(lfhead,lfp,str) do { \
lfp = xmalloc(sizeof(lfile_t)); \
lfp->lf_name = str; \
TAILQ_INSERT_TAIL(lfhead,lfp,lf_link); \
} while(0)
/* List of packages */
typedef struct _lpkg_t {
TAILQ_ENTRY(_lpkg_t) lp_link;
char *lp_name;
} lpkg_t;
TAILQ_HEAD(_lpkg_head_t, _lpkg_t);
typedef struct _lpkg_head_t lpkg_head_t;
struct pkg_vulnerabilities {
size_t entries;
char **vulnerability;
char **classification;
char **advisory;
};
/* If URLlength()>0, then there is a ftp:// or http:// in the string,
* and this must be an URL. Hide this behind a more obvious name. */
#define IS_URL(str) (URLlength(str) > 0)
#define IS_STDIN(str) ((str) != NULL && !strcmp((str), "-"))
#define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/')
/* Conflict handling (conflicts.c) */
int some_installed_package_conflicts_with(const char *, const char *, char **, char **);
/* Prototypes */
/* Misc */
void show_version(void);
int fexec(const char *, ...);
int fexec_skipempty(const char *, ...);
int fcexec(const char *, const char *, ...);
int pfcexec(const char *, const char *, const char **);
/* variables file handling */
char *var_get(const char *, const char *);
char *var_get_memory(const char *, const char *);
int var_set(const char *, const char *, const char *);
int var_copy_list(const char *, const char **);
/* automatically installed as dependency */
Boolean is_automatic_installed(const char *);
int mark_as_automatic_installed(const char *, int);
/* String */
const char *basename_of(const char *);
const char *dirname_of(const char *);
const char *suffix_of(const char *);
int pkg_match(const char *, const char *);
int pkg_order(const char *, const char *, const char *);
int ispkgpattern(const char *);
int quick_pkg_match(const char *, const char *);
/* Iterator functions */
int iterate_pkg_generic_src(int (*)(const char *, void *), void *,
const char *(*)(void *),void *);
int iterate_local_pkg_dir(const char *, int, int, int (*)(const char *, void *),
void *);
int iterate_pkg_db(int (*)(const char *, void *), void *);
int add_installed_pkgs_by_basename(const char *, lpkg_head_t *);
int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *);
char *find_best_matching_installed_pkg(const char *);
char *find_best_matching_file(const char *, const char *, int, int);
int match_installed_pkgs(const char *, int (*)(const char *, void *), void *);
int match_local_files(const char *, int, int, const char *, int (*cb)(const char *, void *), void *);
/* File */
Boolean fexists(const char *);
Boolean isdir(const char *);
Boolean islinktodir(const char *);
Boolean isemptydir(const char *);
Boolean isemptyfile(const char *);
Boolean isfile(const char *);
Boolean isbrokenlink(const char *);
Boolean isempty(const char *);
int URLlength(const char *);
Boolean make_preserve_name(char *, size_t, const char *, const char *);
void remove_files(const char *, const char *);
int format_cmd(char *, size_t, const char *, const char *, const char *);
int recursive_remove(const char *, int);
void add_pkgdir(const char *, const char *, const char *);
void delete_pkgdir(const char *, const char *, const char *);
int has_pkgdir(const char *);
/* pkg_io.c: Local and remote archive handling */
struct archive;
struct archive_entry;
struct archive *open_archive(const char *, char **);
struct archive *find_archive(const char *, int, char **);
void process_pkg_path(void);
struct url *find_best_package(const char *, const char *, int);
/* Packing list */
plist_t *new_plist_entry(void);
plist_t *last_plist(package_t *);
plist_t *find_plist(package_t *, pl_ent_t);
char *find_plist_option(package_t *, const char *);
void plist_delete(package_t *, Boolean, pl_ent_t, char *);
void free_plist(package_t *);
void mark_plist(package_t *);
void csum_plist_entry(char *, plist_t *);
void add_plist(package_t *, pl_ent_t, const char *);
void add_plist_top(package_t *, pl_ent_t, const char *);
void delete_plist(package_t *, Boolean, pl_ent_t, char *);
void write_plist(package_t *, FILE *, char *);
void stringify_plist(package_t *, char **, size_t *, const char *);
void parse_plist(package_t *, const char *);
void read_plist(package_t *, FILE *);
void append_plist(package_t *, FILE *);
int delete_package(Boolean, package_t *, Boolean, const char *);
/* Package Database */
int pkgdb_open(int);
void pkgdb_close(void);
int pkgdb_store(const char *, const char *);
char *pkgdb_retrieve(const char *);
int pkgdb_dump(void);
int pkgdb_remove(const char *);
int pkgdb_remove_pkg(const char *);
char *pkgdb_refcount_dir(void);
char *pkgdb_get_database(void);
const char *pkgdb_get_dir(void);
/*
* Priorities:
* 0 builtin default
* 1 config file
* 2 environment
* 3 command line
* 4 destdir/views reset
*/
void pkgdb_set_dir(const char *, int);
char *pkgdb_pkg_dir(const char *);
char *pkgdb_pkg_file(const char *, const char *);
/* List of packages functions */
lpkg_t *alloc_lpkg(const char *);
lpkg_t *find_on_queue(lpkg_head_t *, const char *);
void free_lpkg(lpkg_t *);
/* Read pkg_vulnerabilities from file */
struct pkg_vulnerabilities *read_pkg_vulnerabilities_file(const char *, int, int);
/* Read pkg_vulnerabilities from memory */
struct pkg_vulnerabilities *read_pkg_vulnerabilities_memory(void *, size_t, int);
void free_pkg_vulnerabilities(struct pkg_vulnerabilities *);
int audit_package(struct pkg_vulnerabilities *, const char *, const char *,
int);
/* Parse configuration file */
void pkg_install_config(void);
/* Print configuration variable */
void pkg_install_show_variable(const char *);
/* Package signature creation and validation */
int pkg_verify_signature(const char *, struct archive **, struct archive_entry **, char **);
int pkg_full_signature_check(const char *, struct archive **);
#ifdef HAVE_SSL
void pkg_sign_x509(const char *, const char *, const char *, const char *);
#endif
void pkg_sign_gpg(const char *, const char *);
#ifdef HAVE_SSL
/* PKCS7 signing/verification */
int easy_pkcs7_verify(const char *, size_t, const char *, size_t,
const char *, int);
int easy_pkcs7_sign(const char *, size_t, char **, size_t *, const char *,
const char *);
#endif
int inline_gpg_verify(const char *, size_t, const char *);
int detached_gpg_verify(const char *, size_t, const char *, size_t,
const char *);
int detached_gpg_sign(const char *, size_t, char **, size_t *, const char *,
const char *);
/* License handling */
int add_licenses(const char *);
int acceptable_license(const char *);
int acceptable_pkg_license(const char *);
void load_license_lists(void);
/* Helper functions for memory allocation */
char *xstrdup(const char *);
void *xrealloc(void *, size_t);
void *xcalloc(size_t, size_t);
void *xmalloc(size_t);
char *xasprintf(const char *, ...);
/* Externs */
extern Boolean Verbose;
extern Boolean Fake;
extern Boolean Force;
extern const char *cert_chain_file;
extern const char *certs_packages;
extern const char *certs_pkg_vulnerabilities;
extern const char *check_eol;
extern const char *check_vulnerabilities;
extern const char *config_file;
extern const char *config_pkg_dbdir;
extern const char *config_pkg_path;
extern const char *config_pkg_refcount_dbdir;
extern const char *do_license_check;
extern const char *verified_installation;
extern const char *gpg_cmd;
extern const char *gpg_keyring_pkgvuln;
extern const char *gpg_keyring_sign;
extern const char *gpg_keyring_verify;
extern const char *gpg_sign_as;
extern char fetch_flags[];
extern const char *pkg_vulnerabilities_dir;
extern const char *pkg_vulnerabilities_file;
extern const char *pkg_vulnerabilities_url;
extern const char *ignore_advisories;
extern const char tnf_vulnerability_base[];
extern const char *acceptable_licenses;
extern const char *default_acceptable_licenses;
#endif /* _INST_LIB_LIB_H_ */

View file

@ -0,0 +1,318 @@
/* $NetBSD: license.c,v 1.4 2013/04/20 15:29:23 wiz Exp $ */
/*-
* Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "lib.h"
#define HASH_SIZE 521
const char *default_acceptable_licenses =
"apache-1.1 apache-2.0 "
"arphic-public "
"artistic artistic-2.0 "
"boost-license "
"cc-by-sa-v3.0 "
"cddl-1.0 "
"cpl-1.0 "
"epl-v1.0 "
"gnu-fdl-v1.1 gnu-fdl-v1.2 gnu-fdl-v1.3 "
"gnu-gpl-v1 "
"gnu-gpl-v2 gnu-lgpl-v2 gnu-lgpl-v2.1 "
"gnu-gpl-v3 gnu-lgpl-v3 "
"ibm-public-license-1.0 "
"ipafont "
"isc "
"lppl-1.3c "
"lucent "
"miros "
"mit "
"mpl-1.0 mpl-1.1 mpl-2.0 "
"mplusfont "
"ofl-v1.0 ofl-v1.1 "
"original-bsd modified-bsd 2-clause-bsd "
"php "
"png-license "
"postgresql-license "
"public-domain "
"python-software-foundation "
"qpl-v1.0 "
"sleepycat-public "
"unlicense "
"x11 "
"zlib "
"zpl";
#ifdef DEBUG
static size_t hash_collisions;
#endif
static char **license_hash[HASH_SIZE];
static const char license_spaces[] = " \t\n";
static const char license_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
static size_t
hash_license(const char *license, size_t len)
{
size_t hash;
for (hash = 0; *license && len; ++license, --len)
hash = *license + hash * 32;
return hash % HASH_SIZE;
}
static void
add_license_internal(const char *license, size_t len)
{
char *new_license;
size_t slot, i;
slot = hash_license(license, len);
new_license = malloc(len + 1);
memcpy(new_license, license, len);
new_license[len] = '\0';
if (license_hash[slot] == NULL) {
license_hash[slot] = calloc(sizeof(char *), 2);
license_hash[slot][0] = new_license;
} else {
for (i = 0; license_hash[slot][i]; ++i) {
if (!memcmp(license_hash[slot][i], license, len) &&
license_hash[slot][i][len] == '\0') {
free(new_license);
return;
}
}
#ifdef DEBUG
++hash_collisions;
#endif
license_hash[slot] = realloc(license_hash[slot],
sizeof(char *) * (i + 2));
license_hash[slot][i] = new_license;
license_hash[slot][i + 1] = NULL;
}
}
int
add_licenses(const char *line)
{
const char *next;
if (line == NULL)
return 0;
for (line += strspn(line, license_spaces); line; ) {
next = line + strspn(line, license_chars);
if (next == line)
return *line ? -1 : 0;
add_license_internal(line, next - line);
line = next + strspn(next, license_spaces);
if (next == line)
return *line ? -1 : 0;
}
return 0;
}
static int
acceptable_license_internal(const char *license, size_t len)
{
size_t slot, i;
slot = hash_license(license, len);
if (license_hash[slot] == NULL)
return 0;
for (i = 0; license_hash[slot][i]; ++i) {
if (strncmp(license_hash[slot][i], license, len) == 0 &&
license_hash[slot][i][len] == '\0')
return 1;
}
return 0;
}
int
acceptable_license(const char *license)
{
size_t len;
len = strlen(license);
if (strspn(license, license_chars) != len) {
warnx("Invalid character in license name at position %" PRIzu, len);
return -1;
}
return acceptable_license_internal(license, len);
}
static int
acceptable_pkg_license_internal(const char **licensep, int toplevel, const char *start)
{
const char *license = *licensep;
int need_parenthesis, is_true = 0;
int expr_type = 0; /* 0: unset, 1: or, 2: and */
size_t len;
license += strspn(license, license_spaces);
if (*license == '(' && !toplevel) {
need_parenthesis = 1;
++license;
license += strspn(license, license_spaces);
} else {
need_parenthesis = 0;
}
for (;;) {
if (*license == '(') {
switch (acceptable_pkg_license_internal(&license, 0, start)) {
case -1:
return -1;
case 0:
if (expr_type == 2)
is_true = 0;
break;
case 1:
is_true = 1;
break;
}
license += strspn(license, license_spaces);
} else {
len = strspn(license, license_chars);
if (len == 0) {
warnx("Invalid character in license name at position %" PRIzu, license - start + 1);
return -1;
}
if (acceptable_license_internal(license, len)) {
if (expr_type != 2)
is_true = 1;
} else if (expr_type == 2) {
is_true = 0;
}
license += len;
len = strspn(license, license_spaces);
if (len == 0 && *license && *license != ')') {
warnx("Missing space at position %" PRIzu, license - start + 1);
return -1;
}
license += len;
}
if (*license == ')') {
if (!need_parenthesis) {
warnx("Missing open parenthesis at position %" PRIzu, license - start + 1);
return -1;
}
*licensep = license + 1;
return is_true;
}
if (*license == '\0') {
if (need_parenthesis) {
warnx("Unbalanced parenthesis at position %" PRIzu, license - start + 1);
return -1;
}
*licensep = license;
return is_true;
}
if (strncmp(license, "AND", 3) == 0) {
if (expr_type == 1) {
warnx("Invalid operator in OR expression at position %" PRIzu, license - start + 1);
return -1;
}
expr_type = 2;
license += 3;
} else if (strncmp(license, "OR", 2) == 0) {
if (expr_type == 2) {
warnx("Invalid operator in AND expression at position %" PRIzu, license - start + 1);
return -1;
}
expr_type = 1;
license += 2;
} else {
warnx("Invalid operator at position %" PRIzu, license - start + 1);
return -1;
}
len = strspn(license, license_spaces);
if (len == 0 && *license != '(') {
warnx("Missing space at position %" PRIzu, license - start + 1);
return -1;
}
license += len;
}
}
int
acceptable_pkg_license(const char *license)
{
int ret;
ret = acceptable_pkg_license_internal(&license, 1, license);
if (ret == -1)
return -1;
license += strspn(license, license_spaces);
if (*license) {
warnx("Trailing garbage in license specification");
return -1;
}
return ret;
}
void
load_license_lists(void)
{
if (add_licenses(getenv("PKGSRC_ACCEPTABLE_LICENSES")))
errx(EXIT_FAILURE, "syntax error in PKGSRC_ACCEPTABLE_LICENSES");
if (add_licenses(acceptable_licenses))
errx(EXIT_FAILURE, "syntax error in ACCEPTABLE_LICENSES");
if (add_licenses(getenv("PKGSRC_DEFAULT_ACCEPTABLE_LICENSES")))
errx(EXIT_FAILURE, "syntax error in PKGSRC_DEFAULT_ACCEPTABLE_LICENSES");
if (add_licenses(default_acceptable_licenses))
errx(EXIT_FAILURE, "syntax error in DEFAULT_ACCEPTABLE_LICENSES");
}

View file

@ -0,0 +1,70 @@
/* $NetBSD: lpkg.c,v 1.1.1.2 2009/02/02 20:44:06 joerg Exp $ */
/*
* Copyright (c) 1999 Christian E. Hopps
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* Package-list auxiliary functions
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#include "lib.h"
/*
* Add a package to the (add/recursive delete) list
*/
lpkg_t *
alloc_lpkg(const char *pkgname)
{
lpkg_t *lpp;
lpp = xmalloc(sizeof(*lpp));
lpp->lp_name = xstrdup(pkgname);
return (lpp);
}
void
free_lpkg(lpkg_t *lpp)
{
free(lpp->lp_name);
free(lpp);
}
lpkg_t *
find_on_queue(lpkg_head_t *qp, const char *name)
{
lpkg_t *lpp;
for (lpp = TAILQ_FIRST(qp); lpp; lpp = TAILQ_NEXT(lpp, lp_link))
if (!strcmp(name, lpp->lp_name))
return (lpp);
return (0);
}

View file

@ -0,0 +1,213 @@
/* $NetBSD: opattern.c,v 1.1.1.3 2012/02/19 17:46:47 tron Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: opattern.c,v 1.1.1.3 2012/02/19 17:46:47 tron Exp $");
/*
* 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 string utilities.
*
*/
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
#include "lib.h"
#include "dewey.h"
/* pull in definitions and macros for resizing arrays as we go */
#include "defs.h"
/*
* Perform alternate match on "pkg" against "pattern",
* calling pkg_match (recursively) to resolve any other patterns.
* Return 1 on match, 0 otherwise
*/
static int
alternate_match(const char *pattern, const char *pkg)
{
char *sep;
char buf[MaxPathSize];
char *last;
char *alt;
char *cp;
int cnt;
int found;
if ((sep = strchr(pattern, '{')) == (char *) NULL) {
errx(EXIT_FAILURE, "alternate_match(): '{' expected in `%s'", pattern);
}
(void) strncpy(buf, pattern, (size_t) (sep - pattern));
alt = &buf[sep - pattern];
last = (char *) NULL;
for (cnt = 0, cp = sep; *cp && last == (char *) NULL; cp++) {
if (*cp == '{') {
cnt++;
} else if (*cp == '}' && --cnt == 0 && last == (char *) NULL) {
last = cp + 1;
}
}
if (cnt != 0) {
errx(EXIT_FAILURE, "Malformed alternate `%s'", pattern);
}
for (found = 0, cp = sep + 1; *sep != '}'; cp = sep + 1) {
for (cnt = 0, sep = cp; cnt > 0 || (cnt == 0 && *sep != '}' && *sep != ','); sep++) {
if (*sep == '{') {
cnt++;
} else if (*sep == '}') {
cnt--;
}
}
(void) snprintf(alt, sizeof(buf) - (alt - buf), "%.*s%s", (int) (sep - cp), cp, last);
if (pkg_match(buf, pkg) == 1) {
found = 1;
}
}
return found;
}
/*
* Perform glob match on "pkg" against "pattern".
* Return 1 on match, 0 otherwise
*/
static int
glob_match(const char *pattern, const char *pkg)
{
return fnmatch(pattern, pkg, FNM_PERIOD) == 0;
}
/*
* Perform simple match on "pkg" against "pattern".
* Return 1 on match, 0 otherwise
*/
static int
simple_match(const char *pattern, const char *pkg)
{
return strcmp(pattern, pkg) == 0;
}
/*
* Performs a fast check if pattern can ever match pkg.
* Returns 1 if a match is possible and 0 otherwise.
*/
int
quick_pkg_match(const char *pattern, const char *pkg)
{
#define simple(x) (isalnum((unsigned char)(x)) || (x) == '-')
if (!simple(pattern[0]))
return 1;
if (pattern[0] != pkg[0])
return 0;
if (!simple(pattern[1]))
return 1;
if (pattern[1] != pkg[1])
return 0;
return 1;
#undef simple
}
/*
* Match pkg against pattern, return 1 if matching, 0 else
*/
int
pkg_match(const char *pattern, const char *pkg)
{
if (!quick_pkg_match(pattern, pkg))
return 0;
if (strchr(pattern, '{') != (char *) NULL) {
/* emulate csh-type alternates */
return alternate_match(pattern, pkg);
}
if (strpbrk(pattern, "<>") != (char *) NULL) {
int ret;
/* perform relational dewey match on version number */
ret = dewey_match(pattern, pkg);
if (ret < 0)
errx(EXIT_FAILURE, "dewey_match returned error");
return ret;
}
if (strpbrk(pattern, "*?[]") != (char *) NULL) {
/* glob match */
if (glob_match(pattern, pkg))
return 1;
}
/* no alternate, dewey or glob match -> simple compare */
if (simple_match(pattern, pkg))
return 1;
/* globbing patterns and simple matches may be specified with or
* without the version number, so check for both cases. */
{
char *pattern_ver;
int retval;
pattern_ver = xasprintf("%s-[0-9]*", pattern);
retval = glob_match(pattern_ver, pkg);
free(pattern_ver);
return retval;
}
}
int
pkg_order(const char *pattern, const char *first_pkg, const char *second_pkg)
{
const char *first_version;
const char *second_version;
if (first_pkg == NULL && second_pkg == NULL)
return 0;
if (first_pkg == NULL)
return pkg_match(pattern, second_pkg) ? 2 : 0;
if (second_pkg == NULL)
return pkg_match(pattern, first_pkg) ? 1 : 0;
first_version = strrchr(first_pkg, '-');
second_version = strrchr(second_pkg, '-');
if (first_version == NULL || !pkg_match(pattern, first_pkg))
return pkg_match(pattern, second_pkg) ? 2 : 0;
if (second_version == NULL || !pkg_match(pattern, second_pkg))
return pkg_match(pattern, first_pkg) ? 1 : 0;
if (dewey_cmp(first_version + 1, DEWEY_GT, second_version + 1))
return 1;
else if (dewey_cmp(first_version + 1, DEWEY_LT, second_version + 1))
return 2;
else if (strcmp(first_pkg, second_pkg) < 0)
return 1;
else
return 2;
}

View file

@ -0,0 +1,271 @@
/* $NetBSD: parse-config.c,v 1.1.1.11 2010/06/26 00:14:31 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: parse-config.c,v 1.1.1.11 2010/06/26 00:14:31 joerg Exp $");
/*-
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_ERR_H
#include <err.h>
#endif
#include <errno.h>
#if HAVE_STRING_H
#include <string.h>
#endif
#ifndef BOOTSTRAP
#include <fetch.h>
#endif
#include "lib.h"
static int cache_connections = 16;
static int cache_connections_host = 4;
const char *config_file = SYSCONFDIR"/pkg_install.conf";
char fetch_flags[10] = ""; /* Workaround Mac OS X linker issues with BSS */
static const char *active_ftp;
static const char *verbose_netio;
static const char *ignore_proxy;
const char *cache_index = "yes";
const char *cert_chain_file;
const char *certs_packages;
const char *certs_pkg_vulnerabilities;
const char *check_eol = "yes";
const char *check_vulnerabilities;
static const char *config_cache_connections;
static const char *config_cache_connections_host;
const char *config_pkg_dbdir;
const char *config_pkg_path;
const char *config_pkg_refcount_dbdir;
const char *do_license_check;
const char *verified_installation;
const char *gpg_cmd;
const char *gpg_keyring_pkgvuln;
const char *gpg_keyring_sign;
const char *gpg_keyring_verify;
const char *gpg_sign_as;
const char *pkg_vulnerabilities_dir;
const char *pkg_vulnerabilities_file;
const char *pkg_vulnerabilities_url;
const char *ignore_advisories = NULL;
const char tnf_vulnerability_base[] = "http://ftp.NetBSD.org/pub/NetBSD/packages/vulns";
const char *acceptable_licenses = NULL;
static struct config_variable {
const char *name;
const char **var;
} config_variables[] = {
{ "ACCEPTABLE_LICENSES", &acceptable_licenses },
{ "ACTIVE_FTP", &active_ftp },
{ "CACHE_INDEX", &cache_index },
{ "CACHE_CONNECTIONS", &config_cache_connections },
{ "CACHE_CONNECTIONS_HOST", &config_cache_connections_host },
{ "CERTIFICATE_ANCHOR_PKGS", &certs_packages },
{ "CERTIFICATE_ANCHOR_PKGVULN", &certs_pkg_vulnerabilities },
{ "CERTIFICATE_CHAIN", &cert_chain_file },
{ "CHECK_LICENSE", &do_license_check },
{ "CHECK_END_OF_LIFE", &check_eol },
{ "CHECK_VULNERABILITIES", &check_vulnerabilities },
{ "DEFAULT_ACCEPTABLE_LICENSES", &default_acceptable_licenses },
{ "GPG", &gpg_cmd },
{ "GPG_KEYRING_PKGVULN", &gpg_keyring_pkgvuln },
{ "GPG_KEYRING_SIGN", &gpg_keyring_sign },
{ "GPG_KEYRING_VERIFY", &gpg_keyring_verify },
{ "GPG_SIGN_AS", &gpg_sign_as },
{ "IGNORE_PROXY", &ignore_proxy },
{ "IGNORE_URL", &ignore_advisories },
{ "PKG_DBDIR", &config_pkg_dbdir },
{ "PKG_PATH", &config_pkg_path },
{ "PKG_REFCOUNT_DBDIR", &config_pkg_refcount_dbdir },
{ "PKGVULNDIR", &pkg_vulnerabilities_dir },
{ "PKGVULNURL", &pkg_vulnerabilities_url },
{ "VERBOSE_NETIO", &verbose_netio },
{ "VERIFIED_INSTALLATION", &verified_installation },
{ NULL, NULL }, /* For use by pkg_install_show_variable */
{ NULL, NULL }
};
char *config_tmp_variables[sizeof config_variables/sizeof config_variables[0]];
static void
parse_pkg_install_conf(void)
{
struct config_variable *var;
FILE *fp;
char *line, *value;
size_t len, var_len, i;
fp = fopen(config_file, "r");
if (!fp) {
if (errno != ENOENT)
warn("Can't open '%s' for reading", config_file);
return;
}
while ((line = fgetln(fp, &len)) != (char *) NULL) {
if (line[len - 1] == '\n')
--len;
for (i = 0; (var = &config_variables[i])->name != NULL; ++i) {
var_len = strlen(var->name);
if (strncmp(var->name, line, var_len) != 0)
continue;
if (line[var_len] != '=')
continue;
line += var_len + 1;
len -= var_len + 1;
if (config_tmp_variables[i])
value = xasprintf("%s\n%.*s",
config_tmp_variables[i], (int)len, line);
else
value = xasprintf("%.*s", (int)len, line);
free(config_tmp_variables[i]);
config_tmp_variables[i] = value;
break;
}
}
for (i = 0; (var = &config_variables[i])->name != NULL; ++i) {
if (config_tmp_variables[i] == NULL)
continue;
*var->var = config_tmp_variables[i];
config_tmp_variables[i] = NULL;
}
fclose(fp);
}
void
pkg_install_config(void)
{
int do_cache_index;
char *value;
parse_pkg_install_conf();
if ((value = getenv("PKG_DBDIR")) != NULL)
pkgdb_set_dir(value, 2);
else if (config_pkg_dbdir != NULL)
pkgdb_set_dir(config_pkg_dbdir, 1);
config_pkg_dbdir = xstrdup(pkgdb_get_dir());
if ((value = getenv("PKG_REFCOUNT_DBDIR")) != NULL)
config_pkg_refcount_dbdir = value;
else if (config_pkg_refcount_dbdir == NULL)
config_pkg_refcount_dbdir = xasprintf("%s.refcount",
pkgdb_get_dir());
if (pkg_vulnerabilities_dir == NULL)
pkg_vulnerabilities_dir = pkgdb_get_dir();
pkg_vulnerabilities_file = xasprintf("%s/pkg-vulnerabilities",
pkg_vulnerabilities_dir);
if (pkg_vulnerabilities_url == NULL) {
pkg_vulnerabilities_url = xasprintf("%s/pkg-vulnerabilities.gz",
tnf_vulnerability_base);
}
if (verified_installation == NULL)
verified_installation = "never";
if (check_vulnerabilities == NULL)
check_vulnerabilities = "never";
if (do_license_check == NULL)
do_license_check = "no";
if ((value = getenv("PKG_PATH")) != NULL)
config_pkg_path = value;
if (strcasecmp(cache_index, "yes") == 0)
do_cache_index = 1;
else {
if (strcasecmp(cache_index, "no"))
warnx("Invalid value for configuration option "
"CACHE_INDEX");
do_cache_index = 0;
}
if (config_cache_connections && *config_cache_connections) {
long v = strtol(config_cache_connections, &value, 10);
if (*value == '\0') {
if (v >= INT_MAX || v < 0)
v = -1;
cache_connections = v;
}
}
config_cache_connections = xasprintf("%d", cache_connections);
if (config_cache_connections_host) {
long v = strtol(config_cache_connections_host, &value, 10);
if (*value == '\0') {
if (v >= INT_MAX || v < 0)
v = -1;
cache_connections_host = v;
}
}
config_cache_connections_host = xasprintf("%d", cache_connections_host);
#ifndef BOOTSTRAP
fetchConnectionCacheInit(cache_connections, cache_connections_host);
#endif
snprintf(fetch_flags, sizeof(fetch_flags), "%s%s%s%s",
(do_cache_index) ? "c" : "",
(verbose_netio && *verbose_netio) ? "v" : "",
(active_ftp && *active_ftp) ? "a" : "",
(ignore_proxy && *ignore_proxy) ? "d" : "");
}
void
pkg_install_show_variable(const char *var_name)
{
struct config_variable *var;
const char *tmp_value = NULL;
for (var = config_variables; var->name != NULL; ++var) {
if (strcmp(var->name, var_name) == 0)
break;
}
if (var->name == NULL) {
var->name = var_name;
var->var = &tmp_value;
}
pkg_install_config();
if (*var->var != NULL)
puts(*var->var);
}

View file

@ -0,0 +1,332 @@
/* $NetBSD: pkcs7.c,v 1.1.1.4 2009/08/06 16:55:27 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pkcs7.c,v 1.1.1.4 2009/08/06 16:55:27 joerg Exp $");
/*-
* Copyright (c) 2004, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Love Hörnquist Åstrand <lha@it.su.se>
*
* 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.
*
* 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_ERR_H
#include <err.h>
#endif
#include <openssl/pkcs7.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include "lib.h"
#ifndef NS_ANY_CA
#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
#endif
static const unsigned int pkg_key_usage = XKU_CODE_SIGN | XKU_SMIME;
static int
check_ca(X509 *cert)
{
if ((cert->ex_flags & EXFLAG_KUSAGE) != 0 &&
(cert->ex_kusage & KU_KEY_CERT_SIGN) != KU_KEY_CERT_SIGN)
return 0;
if ((cert->ex_flags & EXFLAG_BCONS) != 0)
return (cert->ex_flags & EXFLAG_CA) == EXFLAG_CA;
if ((cert->ex_flags & (EXFLAG_V1|EXFLAG_SS)) == (EXFLAG_V1|EXFLAG_SS))
return 1;
if ((cert->ex_flags & EXFLAG_KUSAGE) != 0)
return 1;
if ((cert->ex_flags & EXFLAG_NSCERT) != 0 &&
(cert->ex_nscert & NS_ANY_CA) != 0)
return 1;
return 0;
}
static STACK_OF(X509) *
file_to_certs(const char *file)
{
unsigned long ret;
STACK_OF(X509) *certs;
FILE *f;
if ((f = fopen(file, "r")) == NULL) {
warn("open failed %s", file);
return NULL;
}
certs = sk_X509_new_null();
for (;;) {
X509 *cert;
cert = PEM_read_X509(f, NULL, NULL, NULL);
if (cert == NULL) {
ret = ERR_GET_REASON(ERR_peek_error());
if (ret == PEM_R_NO_START_LINE) {
/* End of file reached. no error */
ERR_clear_error();
break;
}
sk_X509_free(certs);
warnx("Can't read certificate in file: %s", file);
fclose(f);
return NULL;
}
sk_X509_insert(certs, cert, sk_X509_num(certs));
}
fclose(f);
if (sk_X509_num(certs) == 0) {
sk_X509_free(certs);
certs = NULL;
warnx("No certificate found in file %s", file);
}
return certs;
}
int
easy_pkcs7_verify(const char *content, size_t len,
const char *signature, size_t signature_len,
const char *anchor, int is_pkg)
{
STACK_OF(X509) *cert_chain, *signers;
X509_STORE *store;
BIO *sig, *in;
PKCS7 *p7;
int i, status;
X509_NAME *name;
char *subject;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
status = -1;
if (cert_chain_file)
cert_chain = file_to_certs(cert_chain_file);
else
cert_chain = NULL;
store = X509_STORE_new();
if (store == NULL) {
sk_X509_free(cert_chain);
warnx("Failed to create certificate store");
return -1;
}
X509_STORE_load_locations(store, anchor, NULL);
in = BIO_new_mem_buf(__UNCONST(content), len);
sig = BIO_new_mem_buf(__UNCONST(signature), signature_len);
signers = NULL;
p7 = PEM_read_bio_PKCS7(sig, NULL, NULL, NULL);
if (p7 == NULL) {
warnx("Failed to parse the signature");
goto cleanup;
}
if (PKCS7_verify(p7, cert_chain, store, in, NULL, 0) != 1) {
warnx("Failed to verify signature");
goto cleanup;
}
signers = PKCS7_get0_signers(p7, NULL, 0);
if (signers == NULL) {
warnx("Failed to get signers");
goto cleanup;
}
if (sk_X509_num(signers) == 0) {
warnx("No signers found");
goto cleanup;
}
for (i = 0; i < sk_X509_num(signers); i++) {
/* Compute ex_xkusage */
X509_check_purpose(sk_X509_value(signers, i), -1, -1);
if (check_ca(sk_X509_value(signers, i))) {
warnx("CA keys are not valid for signatures");
goto cleanup;
}
if (is_pkg) {
if (sk_X509_value(signers, i)->ex_xkusage != pkg_key_usage) {
warnx("Certificate must have CODE SIGNING "
"and EMAIL PROTECTION property");
goto cleanup;
}
} else {
if (sk_X509_value(signers, i)->ex_xkusage != 0) {
warnx("Certificate must not have any property");
goto cleanup;
}
}
}
printf("Sigature ok, signed by:\n");
for (i = 0; i < sk_X509_num(signers); i++) {
name = X509_get_subject_name(sk_X509_value(signers, i));
subject = X509_NAME_oneline(name, NULL, 0);
printf("\t%s\n", subject);
OPENSSL_free(subject);
}
status = 0;
cleanup:
sk_X509_free(cert_chain);
sk_X509_free(signers);
X509_STORE_free(store);
PKCS7_free(p7);
BIO_free(in);
BIO_free(sig);
return status;
}
static int
ssl_pass_cb(char *buf, int size, int rwflag, void *u)
{
if (EVP_read_pw_string(buf, size, "Passphrase :", 0)) {
#if OPENSSL_VERSION >= 0x0090608fL
OPENSSL_cleanse(buf, size);
#else
memset(buf, 0, size);
#endif
return 0;
}
return strlen(buf);
}
int
easy_pkcs7_sign(const char *content, size_t len,
char **signature, size_t *signature_len,
const char *key_file, const char *cert_file)
{
FILE *f;
X509 *certificate;
STACK_OF(X509) *c, *cert_chain;
EVP_PKEY *private_key;
char *tmp_sig;
BIO *out, *in;
PKCS7 *p7;
int status;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
status = -1;
private_key = NULL;
cert_chain = NULL;
in = NULL;
c = file_to_certs(cert_file);
if (sk_X509_num(c) != 1) {
warnx("More then one certificate in the certificate file");
goto cleanup;
}
certificate = sk_X509_value(c, 0);
/* Compute ex_kusage */
X509_check_purpose(certificate, -1, 0);
if (check_ca(certificate)) {
warnx("CA keys are not valid for signatures");
goto cleanup;
}
if (certificate->ex_xkusage != pkg_key_usage) {
warnx("Certificate must have CODE SIGNING "
"and EMAIL PROTECTION property");
goto cleanup;
}
if (cert_chain_file)
cert_chain = file_to_certs(cert_chain_file);
if ((f = fopen(key_file, "r")) == NULL) {
warn("Failed to open private key file %s", key_file);
goto cleanup;
}
private_key = PEM_read_PrivateKey(f, NULL, ssl_pass_cb, NULL);
fclose(f);
if (private_key == NULL) {
warnx("Can't read private key: %s", key_file);
goto cleanup;
}
if (X509_check_private_key(certificate, private_key) != 1) {
warnx("The private key %s doesn't match the certificate %s",
key_file, cert_file);
goto cleanup;
}
in = BIO_new_mem_buf(__UNCONST(content), len);
p7 = PKCS7_sign(certificate, private_key, cert_chain, in,
PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
if (p7 == NULL) {
warnx("Failed to create signature structure");
goto cleanup;
}
out = BIO_new(BIO_s_mem());
PEM_write_bio_PKCS7(out, p7);
*signature_len = BIO_get_mem_data(out, &tmp_sig);
*signature = xmalloc(*signature_len);
memcpy(*signature, tmp_sig, *signature_len);
BIO_free_all(out);
PKCS7_free(p7);
status = 0;
cleanup:
sk_X509_free(c);
sk_X509_free(cert_chain);
EVP_PKEY_free(private_key);
BIO_free(in);
return status;
}

View file

@ -0,0 +1,216 @@
.\" $NetBSD: pkg_install.conf.5.in,v 1.1.1.13 2013/04/20 15:26:53 wiz Exp $
.\"
.\" Copyright (c) 2008, 2009, 2012 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by 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.
.\"
.\" 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.
.\"
.Dd February 22, 2012
.Dt PKG_INSTALL.CONF 5
.Os
.Sh NAME
.Nm pkg_install.conf
.Nd configuration file for package installation tools
.Sh DESCRIPTION
The file
.Nm
contains system defaults for the package installation tools
as a list of variable-value pairs.
Each line has the format
.Ev VARIABLE=VALUE .
If the value consists of more than one line, each line is prefixed with
.Ev VARIABLE= .
.Pp
The current value of a variable can be checked by running
.Dl Ic pkg_admin config-var VARIABLE
.Pp
Some variables are overriden by environmental variables of the same name.
Those are marked by (*).
.Pp
The following variables are supported:
.Bl -tag -width indent
.It Dv ACCEPTABLE_LICENSES
Space-separated list of licenses packages are allowed to carry.
License names are case-sensitive.
.It Dv ACTIVE_FTP
Force the use of active FTP.
.It Dv CACHE_INDEX
Cache directory listenings in memory.
This avoids retransfers of the large directory index for HTTP and is
enabled by default.
.It Dv CERTIFICATE_ANCHOR_PKGS
Path to the file containing the certificates used for validating
binary packages.
A package is trusted when a certificate chain ends in one of the
certificates contained in this file.
The certificates must be PEM-encoded.
.It Dv CERTIFICATE_ANCHOR_PKGVULN
Analogous to
.Dv CERTIFICATE_ANCHOR_PKGS .
The
.Pa pkg-vulnerabilities
is trusted when a certificate chain ends in one of the certificates
contained in this file.
.It Dv CERTIFICATE_CHAIN
Path to a file containing additional certificates that can be used
for completing certificate chains when validating binary packages or
pkg-vulnerabilities files.
.It Dv CHECK_LICENSE
Check the license conditions of packages before installing them.
Supported values are:
.Bl -tag -width interactiveXX
.It Dv no
The check is not performed.
.It Dv yes
The check is performed if the package has license conditions set.
.It Dv always
Passing the license check is required.
Missing license conditions are considered an error.
.El
.It Dv CHECK_END_OF_LIFE
During vulnerability checks, consider packages that have reached end-of-life
as vulnerable.
This option is enabled by default.
.It Dv CHECK_VULNERABILITIES
Check for vulnerabilities when installing packages.
Supported values are:
.Bl -tag -width interactiveXX
.It Dv never
No check is performed.
.It Dv always
Passing the vulnerability check is required.
A missing pkg-vulnerabilities file is considered an error.
.It Dv interactive
The user is always asked to confirm installation of vulnerable packages.
.El
.It Dv CONFIG_CACHE_CONNECTIONS
Limit the global connection cache to this value.
For FTP, this is the number of sessions without active command.
For HTTP, this is the number of connections open with keep-alive.
.It Dv CONFIG_CACHE_CONNECTIONS_HOST
Like
.Dv CONFIG_CACHE_CONNECTIONS ,
but limit the number of connections to the host as well.
See
.Xr fetch 3
for further details
.It Dv DEFAULT_ACCEPTABLE_LICENSES
Space-separated list of common Free and Open Source licenses packages are
allowed to carry.
The default value contains all OSI approved licenses in pkgsrc on the date
pkg_install was released.
License names are case-sensitive.
.It Dv GPG
Path to
.Xr gpg 1 ,
which can be used to verify the signature in the
.Pa pkg-vulnerabilities
file when running
.Dl Ic pkg_admin check-pkg-vulnerabilities -s
or
.Dl Ic pkg_admin fetch-pkg-vulnerabilities -s
It can also be used to verify and sign binary packages.
.It Dv GPG_KEYRING_PKGVULN
Non-default keyring to use for verifying GPG signatures of
.Pa pkg-vulnerabilities .
.It Dv GPG_KEYRING_SIGN
Non-default keyring to use for signing packages with GPG.
.It Dv GPG_KEYRING_VERIFY
Non-default keyring to use for verifying GPG signature of packages.
.It Dv GPG_SIGN_AS
User-id to use for signing packages.
.It Dv IGNORE_PROXY
Use direct connections and ignore
.Ev FTP_PROXY
and
.Ev HTTP_PROXY .
.It Dv IGNORE_URL
One line per advisory which should be ignored when running
.Dl Ic pkg_admin audit
The URL from the
.Pa pkg-vulnerabilities
file should be used as value.
.It Dv PKG_DBDIR (*)
Location of the packages database.
This option is always overriden by the argument of the
.Fl K
option.
.It Dv PKG_PATH (*)
Search path for packages.
The entries are separated by semicolon.
Each entry specifies a directory or URL to search for packages.
.It Dv PKG_REFCOUNT_DBDIR (*)
Location of the package reference counts database directory.
The default value is
.Pa ${PKG_DBDIR}.refcount .
.It Dv PKGVULNDIR
Directory name in which the
.Pa pkg-vulnerabilities
file resides.
Default is
.Pa ${PKG_DBDIR} .
.It Dv PKGVULNURL
URL which is used for updating the local
.Pa pkg-vulnerabilities
file when running
.Dl Ic pkg_admin fetch-pkg-vulnerabilities
The default location is ftp.NetBSD.org using HTTP.
.Em Note :
Usually, only the compression type should be changed.
Currently supported are uncompressed files and files compressed by
.Xr bzip2 1
.Pq Pa .bz2
or
.Xr gzip 1
.Pq Pa .gz .
.It Dv VERBOSE_NETIO
Log details of network IO to stderr.
.It Dv VERIFIED_INSTALLATION
Set trust level used when installation.
Supported values are:
.Bl -tag -width interactiveXX
.It Dv never
No signature checks are performed.
.It Dv always
A valid signature is required.
If the binary package can not be verified, the installation is terminated
.It Dv trusted
A valid signature is required.
If the binary package can not be verified, the user is asked interactively.
.It Dv interactive
The user is always asked interactively when installing a package.
.El
.El
.Sh FILES
.Bl -tag -width ".Pa @SYSCONFDIR@/pkg_install.conf"
.It Pa @SYSCONFDIR@/pkg_install.conf
Default location for the file described in this manual page.
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_admin 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1

View file

@ -0,0 +1,383 @@
/* $NetBSD: pkg_io.c,v 1.1.1.9 2010/04/23 20:54:11 joerg Exp $ */
/*-
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pkg_io.c,v 1.1.1.9 2010/04/23 20:54:11 joerg Exp $");
#include <archive.h>
#include <archive_entry.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fetch.h>
#include <stdlib.h>
#include "lib.h"
struct pkg_path {
TAILQ_ENTRY(pkg_path) pl_link;
char *pl_path;
};
static char *orig_cwd, *last_toplevel;
static TAILQ_HEAD(, pkg_path) pkg_path = TAILQ_HEAD_INITIALIZER(pkg_path);
struct fetch_archive {
struct url *url;
fetchIO *fetch;
char buffer[32768];
off_t size;
int restart;
};
static int
fetch_archive_open(struct archive *a, void *client_data)
{
struct fetch_archive *f = client_data;
struct url_stat us;
f->fetch = fetchXGet(f->url, &us, fetch_flags);
if (f->fetch == NULL)
return ENOENT;
f->size = us.size;
f->restart = 1;
f->url->offset = 0;
return 0;
}
static ssize_t
fetch_archive_read(struct archive *a, void *client_data,
const void **buffer)
{
struct fetch_archive *f = client_data;
struct url_stat us;
ssize_t rv;
*buffer = f->buffer;
rv = fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
if (rv > 0) {
f->url->offset += rv;
return rv;
}
if (f->restart == 0)
return rv;
if (rv == 0) {
if (f->size == -1)
return 0;
if (f->url->offset == f->size)
return 0;
}
f->restart = 0;
if (1) {
char *url = fetchStringifyURL(f->url);
fprintf(stderr, "Trying to reconnect %s\n", url);
free(url);
}
fetchIO_close(f->fetch);
f->fetch = fetchXGet(f->url, &us, fetch_flags);
if (f->fetch == NULL)
return -1;
if (us.size != f->size)
return -1;
rv = fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
if (rv > 0)
f->url->offset += rv;
return rv;
}
static int
fetch_archive_close(struct archive *a, void *client_data)
{
struct fetch_archive *f = client_data;
if (f->fetch != NULL)
fetchIO_close(f->fetch);
fetchFreeURL(f->url);
free(f);
return 0;
}
static struct archive *
open_archive_by_url(struct url *url, char **archive_name)
{
struct fetch_archive *f;
struct archive *a;
f = xmalloc(sizeof(*f));
f->url = fetchCopyURL(url);
*archive_name = fetchStringifyURL(url);
a = archive_read_new();
archive_read_support_compression_all(a);
archive_read_support_format_all(a);
if (archive_read_open(a, f, fetch_archive_open, fetch_archive_read,
fetch_archive_close)) {
free(*archive_name);
*archive_name = NULL;
archive_read_finish(a);
return NULL;
}
return a;
}
struct archive *
open_archive(const char *url, char **archive_name)
{
struct url *u;
struct archive *a;
*archive_name = NULL;
if (!IS_URL(url)) {
a = archive_read_new();
archive_read_support_compression_all(a);
archive_read_support_format_all(a);
if (archive_read_open_filename(a, url, 1024)) {
archive_read_close(a);
return NULL;
}
*archive_name = xstrdup(url);
return a;
}
if ((u = fetchParseURL(url)) == NULL)
return NULL;
a = open_archive_by_url(u, archive_name);
fetchFreeURL(u);
return a;
}
static int
strip_suffix(char *filename)
{
size_t len;
len = strlen(filename);
if (len <= 4)
return 0;
if (strcmp(filename + len - 4, ".tgz") == 0 ||
strcmp(filename + len - 4, ".tbz") == 0) {
filename[len - 4] = '\0';
return 1;
} else
return 0;
}
static int
find_best_package_int(struct url *url, const char *pattern,
struct url **best_url)
{
char *cur_match, *url_pattern, *best_match = NULL;
struct url_list ue;
size_t i;
if (*best_url) {
if ((best_match = fetchUnquoteFilename(*best_url)) == NULL)
return -1;
} else
best_match = NULL;
if (best_match && strip_suffix(best_match) == 0) {
free(best_match);
return -1;
}
for (i = 0; pattern[i] != '\0'; ++i) {
if (!isalnum((unsigned char)(pattern[i])) &&
(pattern[i]) != '-')
break;
}
url_pattern = xasprintf("%*.*s*", (int)i, (int)i, pattern);
fetchInitURLList(&ue);
if (fetchList(&ue, url, url_pattern, fetch_flags)) {
char *base_url;
base_url = fetchStringifyURL(url);
warnx("Can't process %s/%s: %s", base_url, url_pattern,
fetchLastErrString);
free(base_url);
free(url_pattern);
fetchFreeURLList(&ue);
return -1;
}
free(url_pattern);
for (i = 0; i < ue.length; ++i) {
cur_match = fetchUnquoteFilename(ue.urls + i);
if (cur_match == NULL) {
free(best_match);
fetchFreeURLList(&ue);
return -1;
}
if (strip_suffix(cur_match) == 0) {
free(cur_match);
continue;
}
if (pkg_order(pattern, cur_match, best_match) == 1) {
if (*best_url)
fetchFreeURL(*best_url);
*best_url = fetchCopyURL(ue.urls + i);
free(best_match);
best_match = cur_match;
cur_match = NULL;
if (*best_url == NULL) {
free(best_match);
return -1;
}
}
free(cur_match);
}
free(best_match);
fetchFreeURLList(&ue);
return 0;
}
void
process_pkg_path(void)
{
char cwd[PATH_MAX];
int relative_path;
struct pkg_path *pl;
const char *start, *next;
size_t len;
if (getcwd(cwd, sizeof(cwd)) == NULL)
errx(EXIT_FAILURE, "getcwd failed");
orig_cwd = xstrdup(cwd);
if (config_pkg_path == NULL)
return;
for (start = config_pkg_path; *start; start = next) {
len = strcspn(start, ";");
if (*(next = start + len) != '\0')
++next;
relative_path = !IS_FULLPATH(start) && !IS_URL(start);
pl = xmalloc(sizeof(*pl));
pl->pl_path = xasprintf("%s%s%*.*s",
relative_path ? cwd : "", len && relative_path ? "/" : "",
(int)len, (int)len, start);
TAILQ_INSERT_TAIL(&pkg_path, pl, pl_link);
}
}
struct url *
find_best_package(const char *toplevel, const char *pattern, int do_path)
{
struct url *url, *best_match = NULL;
struct pkg_path *pl;
if (toplevel) {
url = fetchParseURL(last_toplevel);
if (url != NULL) {
find_best_package_int(url, pattern, &best_match);
/* XXX Check return value and complain */
fetchFreeURL(url);
}
}
if (!do_path)
return best_match;
TAILQ_FOREACH(pl, &pkg_path, pl_link) {
url = fetchParseURL(pl->pl_path);
if (url != NULL) {
find_best_package_int(url, pattern, &best_match);
/* XXX Check return value and complain */
fetchFreeURL(url);
}
}
return best_match;
}
struct archive *
find_archive(const char *fname, int top_level, char **archive_name)
{
struct archive *a;
struct url *best_match;
char *full_fname, *last_slash;
int search_path;
search_path = 0;
if (IS_FULLPATH(fname) || IS_URL(fname)) {
full_fname = xstrdup(fname);
} else {
if (strchr(fname, '/') == NULL)
search_path = 1;
full_fname = xasprintf("%s/%s", orig_cwd, fname);
}
last_slash = strrchr(full_fname, '/');
if (top_level) {
free(last_toplevel);
*last_slash = '\0';
last_toplevel = xstrdup(full_fname);
*last_slash = '/';
}
a = open_archive(full_fname, archive_name);
if (a != NULL) {
free(full_fname);
return a;
}
fname = last_slash + 1;
*last_slash = '\0';
best_match = find_best_package(full_fname, fname, 0);
if (search_path && best_match == NULL)
best_match = find_best_package(last_toplevel, fname, 1);
free(full_fname);
if (best_match == NULL)
return NULL;
a = open_archive_by_url(best_match, archive_name);
fetchFreeURL(best_match);
return a;
}

View file

@ -0,0 +1,710 @@
/* $NetBSD: pkg_signature.c,v 1.2 2013/09/11 12:59:19 khorben Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pkg_signature.c,v 1.2 2013/09/11 12:59:19 khorben Exp $");
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <ctype.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#ifndef NETBSD
#include <nbcompat/sha2.h>
#else
#include <sha2.h>
#endif
#include <signal.h>
#ifdef NETBSD
#include <unistd.h>
#else
#include <nbcompat/unistd.h>
#endif
#include <archive.h>
#include <archive_entry.h>
#include "lib.h"
#define HASH_FNAME "+PKG_HASH"
#define SIGNATURE_FNAME "+PKG_SIGNATURE"
#define GPG_SIGNATURE_FNAME "+PKG_GPG_SIGNATURE"
struct signature_archive {
struct archive *archive;
off_t pkg_size;
size_t sign_block_len, sign_block_number, sign_cur_block;
char **sign_blocks;
unsigned char *sign_buf;
};
static void
hash_block(unsigned char *buf, size_t buf_len,
char hash[SHA512_DIGEST_STRING_LENGTH])
{
unsigned char digest[SHA512_DIGEST_LENGTH];
SHA512_CTX hash_ctx;
int i;
SHA512_Init(&hash_ctx);
SHA512_Update(&hash_ctx, buf, buf_len);
SHA512_Final(digest, &hash_ctx);
for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
unsigned char c;
c = digest[i] / 16;
if (c < 10)
hash[2 * i] = '0' + c;
else
hash[2 * i] = 'a' - 10 + c;
c = digest[i] % 16;
if (c < 10)
hash[2 * i + 1] = '0' + c;
else
hash[2 * i + 1] = 'a' - 10 + c;
}
hash[2 * i] = '\0';
}
static ssize_t
verify_signature_read_cb(struct archive *archive, void *cookie, const void **buf)
{
struct signature_archive *state = cookie;
char hash[SHA512_DIGEST_STRING_LENGTH];
ssize_t len, expected;
if (state->sign_cur_block >= state->sign_block_number)
return 0;
/* The following works for sign_block_len > 1 */
if (state->sign_cur_block + 1 == state->sign_block_number)
expected = state->pkg_size % state->sign_block_len;
else
expected = state->sign_block_len;
len = archive_read_data(state->archive, state->sign_buf, expected);
if (len != expected) {
warnx("Short read from package");
return -1;
}
hash_block(state->sign_buf, len, hash);
if (strcmp(hash, state->sign_blocks[state->sign_cur_block]) != 0) {
warnx("Invalid signature of block %llu",
(unsigned long long)state->sign_cur_block);
return -1;
}
++state->sign_cur_block;
*buf = state->sign_buf;
return len;
}
static void
free_signature_int(struct signature_archive *state)
{
size_t i;
if (state->sign_blocks != NULL) {
for (i = 0; i < state->sign_block_number; ++i)
free(state->sign_blocks[i]);
}
free(state->sign_blocks);
free(state->sign_buf);
free(state);
}
static int
verify_signature_close_cb(struct archive *archive, void *cookie)
{
struct signature_archive *state = cookie;
archive_read_finish(state->archive);
free_signature_int(state);
return 0;
}
static int
read_file_from_archive(const char *archive_name, struct archive *archive,
struct archive_entry **entry,
const char *fname, char **content, size_t *len)
{
int r;
*content = NULL;
*len = 0;
retry:
if (*entry == NULL &&
(r = archive_read_next_header(archive, entry)) != ARCHIVE_OK) {
if (r == ARCHIVE_FATAL) {
warnx("Cannot read from archive `%s': %s",
archive_name, archive_error_string(archive));
} else {
warnx("Premature end of archive `%s'", archive_name);
}
*entry = NULL;
return -1;
}
if (strcmp(archive_entry_pathname(*entry), "//") == 0) {
archive_read_data_skip(archive);
*entry = NULL;
goto retry;
}
if (strcmp(fname, archive_entry_pathname(*entry)) != 0)
return 1;
if (archive_entry_size(*entry) > SSIZE_MAX - 1) {
warnx("Signature of archive `%s' too large to process",
archive_name);
return 1;
}
*len = archive_entry_size(*entry);
*content = xmalloc(*len + 1);
if (archive_read_data(archive, *content, *len) != (ssize_t)*len) {
warnx("Cannot read complete %s from archive `%s'", fname,
archive_name);
free(*content);
*len = 0;
*content = NULL;
return 1;
}
(*content)[*len] = '\0';
*entry = NULL;
return 0;
}
static int
parse_hash_file(const char *hash_file, char **pkgname,
struct signature_archive *state)
{
static const char block1[] = "pkgsrc signature\n\nversion: 1\npkgname: ";
static const char block2[] = "algorithm: SHA512\nblock size: ";
static const char block3[] = "file size: ";
static const char block4[] = "end pkgsrc signature\n";
char *next;
size_t i, len;
*pkgname = NULL;
if (strncmp(hash_file, block1, strlen(block1)) != 0)
goto cleanup;
hash_file += strlen(block1);
len = strcspn(hash_file, "\n");
*pkgname = xmalloc(len + 1);
memcpy(*pkgname, hash_file, len);
(*pkgname)[len] = '\0';
for (i = 0; i < len; ++i) {
if (!isgraph((unsigned char)(*pkgname)[i]))
goto cleanup;
}
hash_file += len + 1;
if (strncmp(hash_file, block2, strlen(block2)) != 0)
goto cleanup;
hash_file += strlen(block2);
errno = 0;
if (!isdigit((unsigned char)*hash_file))
goto cleanup;
state->sign_block_len = strtoul(hash_file, &next, 10);
hash_file = next;
/* Assert sane minimum block size of 1KB */
if (*hash_file++ != '\n' || errno == ERANGE || state->sign_block_len < 1024)
goto cleanup;
if (strncmp(hash_file, block3, strlen(block3)) != 0)
goto cleanup;
hash_file += strlen(block3);
errno = 0;
if (!isdigit((unsigned char)*hash_file))
goto cleanup;
if (/* CONSTCOND */sizeof(off_t) >= sizeof(long long))
state->pkg_size = strtoll(hash_file, &next, 10);
else
state->pkg_size = strtol(hash_file, &next, 10);
hash_file = next;
if (*hash_file++ != '\n' || errno == ERANGE || state->pkg_size < 1)
goto cleanup;
if (*hash_file++ != '\n')
goto cleanup;
if (state->pkg_size / state->sign_block_len > SSIZE_MAX)
goto cleanup;
state->sign_block_number = (state->pkg_size +
state->sign_block_len - 1) / state->sign_block_len;
state->sign_buf = xmalloc(state->sign_block_len);
state->sign_blocks = xcalloc(state->sign_block_number, sizeof(char *));
for (i = 0; i < state->sign_block_number; ++i) {
len = strspn(hash_file, "01234567889abcdef");
if (len != SHA512_DIGEST_LENGTH * 2 || hash_file[len] != '\n')
goto cleanup_hashes;
state->sign_blocks[i] = xmalloc(len + 1);
memcpy(state->sign_blocks[i], hash_file, len);
state->sign_blocks[i][len] = '\0';
hash_file += len + 1;
}
if (strcmp(hash_file, block4) != 0)
goto cleanup_hashes;
return 0;
cleanup_hashes:
for (i = 0; i < state->sign_block_number; ++i)
free(state->sign_blocks[i]);
free(state->sign_blocks);
state->sign_blocks = NULL;
cleanup:
warnx("Unknown format of hash file");
free(*pkgname);
*pkgname = NULL;
return -1;
}
int
pkg_verify_signature(const char *archive_name, struct archive **archive,
struct archive_entry **entry, char **pkgname)
{
struct signature_archive *state;
struct archive_entry *my_entry;
struct archive *a;
char *hash_file, *signature_file;
size_t hash_len, signature_len;
int r, has_sig;
*pkgname = NULL;
state = xcalloc(sizeof(*state), 1);
r = read_file_from_archive(archive_name, *archive, entry, HASH_FNAME,
&hash_file, &hash_len);
if (r == -1) {
archive_read_finish(*archive);
*archive = NULL;
free(state);
goto no_valid_signature;
} else if (r == 1) {
free(state);
goto no_valid_signature;
}
if (parse_hash_file(hash_file, pkgname, state))
goto no_valid_signature;
r = read_file_from_archive(archive_name, *archive, entry, SIGNATURE_FNAME,
&signature_file, &signature_len);
if (r == -1) {
archive_read_finish(*archive);
*archive = NULL;
free(state);
free(hash_file);
goto no_valid_signature;
} else if (r != 0) {
if (*entry != NULL)
r = read_file_from_archive(archive_name, *archive,
entry, GPG_SIGNATURE_FNAME,
&signature_file, &signature_len);
if (r == -1) {
archive_read_finish(*archive);
*archive = NULL;
free(state);
free(hash_file);
goto no_valid_signature;
} else if (r != 0) {
free(hash_file);
free(state);
goto no_valid_signature;
}
has_sig = !detached_gpg_verify(hash_file, hash_len,
signature_file, signature_len, gpg_keyring_verify);
free(signature_file);
} else {
#ifdef HAVE_SSL
has_sig = !easy_pkcs7_verify(hash_file, hash_len, signature_file,
signature_len, certs_packages, 1);
free(signature_file);
#else
warnx("No OpenSSL support compiled in, skipping signature");
has_sig = 0;
free(signature_file);
#endif
}
r = archive_read_next_header(*archive, &my_entry);
if (r != ARCHIVE_OK) {
warnx("Cannot read inner package: %s",
archive_error_string(*archive));
free_signature_int(state);
goto no_valid_signature;
}
if (archive_entry_size(my_entry) != state->pkg_size) {
warnx("Package size doesn't match signature");
free_signature_int(state);
goto no_valid_signature;
}
state->archive = *archive;
a = archive_read_new();
archive_read_support_compression_all(a);
archive_read_support_format_all(a);
if (archive_read_open(a, state, NULL, verify_signature_read_cb,
verify_signature_close_cb)) {
warnx("Can't open signed package file");
archive_read_finish(a);
goto no_valid_signature;
}
*archive = a;
*entry = NULL;
return has_sig ? 0 : -1;
no_valid_signature:
return -1;
}
int
pkg_full_signature_check(const char *archive_name, struct archive **archive)
{
struct archive_entry *entry = NULL;
char *pkgname;
int r;
if (pkg_verify_signature(archive_name, archive, &entry, &pkgname))
return -1;
if (pkgname == NULL)
return 0;
/* XXX read PLIST and compare pkgname */
while ((r = archive_read_next_header(*archive, &entry)) == ARCHIVE_OK)
archive_read_data_skip(*archive);
free(pkgname);
return r == ARCHIVE_EOF ? 0 : -1;
}
static char *
extract_pkgname(int fd)
{
package_t plist;
plist_t *p;
struct archive *a;
struct archive_entry *entry;
char *buf;
ssize_t len;
int r;
a = archive_read_new();
archive_read_support_compression_all(a);
archive_read_support_format_all(a);
if (archive_read_open_fd(a, fd, 1024)) {
warnx("Cannot open binary package: %s",
archive_error_string(a));
archive_read_finish(a);
return NULL;
}
r = archive_read_next_header(a, &entry);
if (r != ARCHIVE_OK) {
warnx("Cannot extract package name: %s",
r == ARCHIVE_EOF ? "EOF" : archive_error_string(a));
archive_read_finish(a);
return NULL;
}
if (strcmp(archive_entry_pathname(entry), "+CONTENTS") != 0) {
warnx("Invalid binary package, doesn't start with +CONTENTS");
archive_read_finish(a);
return NULL;
}
if (archive_entry_size(entry) > SSIZE_MAX - 1) {
warnx("+CONTENTS too large to process");
archive_read_finish(a);
return NULL;
}
len = archive_entry_size(entry);
buf = xmalloc(len + 1);
if (archive_read_data(a, buf, len) != len) {
warnx("Short read when extracing +CONTENTS");
free(buf);
archive_read_finish(a);
return NULL;
}
buf[len] = '\0';
archive_read_finish(a);
parse_plist(&plist, buf);
free(buf);
p = find_plist(&plist, PLIST_NAME);
if (p != NULL) {
buf = xstrdup(p->name);
} else {
warnx("Invalid PLIST: missing @name");
buf = NULL;
}
free_plist(&plist);
if (lseek(fd, 0, SEEK_SET) != 0) {
warn("Cannot seek in archive");
free(buf);
return NULL;
}
return buf;
}
static const char hash_template[] =
"pkgsrc signature\n"
"\n"
"version: 1\n"
"pkgname: %s\n"
"algorithm: SHA512\n"
"block size: 65536\n"
"file size: %lld\n"
"\n";
static const char hash_trailer[] = "end pkgsrc signature\n";
#ifdef HAVE_SSL
void
pkg_sign_x509(const char *name, const char *output, const char *key_file, const char *cert_file)
{
struct archive *pkg;
struct archive_entry *entry, *hash_entry, *sign_entry;
int fd;
struct stat sb;
char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH];
unsigned char block[65536];
off_t i, size;
size_t block_len, signature_len;
if ((fd = open(name, O_RDONLY)) == -1)
err(EXIT_FAILURE, "Cannot open binary package %s", name);
if (fstat(fd, &sb) == -1)
err(EXIT_FAILURE, "Cannot stat %s", name);
entry = archive_entry_new();
archive_entry_copy_stat(entry, &sb);
pkgname = extract_pkgname(fd);
hash_file = xasprintf(hash_template, pkgname,
(long long)archive_entry_size(entry));
free(pkgname);
for (i = 0; i < archive_entry_size(entry); i += block_len) {
if (i + (off_t)sizeof(block) < archive_entry_size(entry))
block_len = sizeof(block);
else
block_len = archive_entry_size(entry) % sizeof(block);
if (read(fd, block, block_len) != (ssize_t)block_len)
err(2, "short read");
hash_block(block, block_len, hash);
tmp = xasprintf("%s%s\n", hash_file, hash);
free(hash_file);
hash_file = tmp;
}
tmp = xasprintf("%s%s", hash_file, hash_trailer);
free(hash_file);
hash_file = tmp;
if (easy_pkcs7_sign(hash_file, strlen(hash_file), &signature_file,
&signature_len, key_file, cert_file))
err(EXIT_FAILURE, "Cannot sign hash file");
lseek(fd, 0, SEEK_SET);
sign_entry = archive_entry_clone(entry);
hash_entry = archive_entry_clone(entry);
pkgname = strrchr(name, '/');
archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name);
archive_entry_set_pathname(hash_entry, HASH_FNAME);
archive_entry_set_pathname(sign_entry, SIGNATURE_FNAME);
archive_entry_set_size(hash_entry, strlen(hash_file));
archive_entry_set_size(sign_entry, signature_len);
pkg = archive_write_new();
archive_write_set_compression_none(pkg);
archive_write_set_format_ar_bsd(pkg);
archive_write_open_filename(pkg, output);
archive_write_header(pkg, hash_entry);
archive_write_data(pkg, hash_file, strlen(hash_file));
archive_write_finish_entry(pkg);
archive_entry_free(hash_entry);
archive_write_header(pkg, sign_entry);
archive_write_data(pkg, signature_file, signature_len);
archive_write_finish_entry(pkg);
archive_entry_free(sign_entry);
size = archive_entry_size(entry);
archive_write_header(pkg, entry);
for (i = 0; i < size; i += block_len) {
if (i + (off_t)sizeof(block) < size)
block_len = sizeof(block);
else
block_len = size % sizeof(block);
if (read(fd, block, block_len) != (ssize_t)block_len)
err(2, "short read");
archive_write_data(pkg, block, block_len);
}
archive_write_finish_entry(pkg);
archive_entry_free(entry);
archive_write_finish(pkg);
close(fd);
exit(0);
}
#endif
void
pkg_sign_gpg(const char *name, const char *output)
{
struct archive *pkg;
struct archive_entry *entry, *hash_entry, *sign_entry;
int fd;
struct stat sb;
char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH];
unsigned char block[65536];
off_t i, size;
size_t block_len, signature_len;
if ((fd = open(name, O_RDONLY)) == -1)
err(EXIT_FAILURE, "Cannot open binary package %s", name);
if (fstat(fd, &sb) == -1)
err(EXIT_FAILURE, "Cannot stat %s", name);
entry = archive_entry_new();
archive_entry_copy_stat(entry, &sb);
pkgname = extract_pkgname(fd);
hash_file = xasprintf(hash_template, pkgname,
(long long)archive_entry_size(entry));
free(pkgname);
for (i = 0; i < archive_entry_size(entry); i += block_len) {
if (i + (off_t)sizeof(block) < archive_entry_size(entry))
block_len = sizeof(block);
else
block_len = archive_entry_size(entry) % sizeof(block);
if (read(fd, block, block_len) != (ssize_t)block_len)
err(2, "short read");
hash_block(block, block_len, hash);
tmp = xasprintf("%s%s\n", hash_file, hash);
free(hash_file);
hash_file = tmp;
}
tmp = xasprintf("%s%s", hash_file, hash_trailer);
free(hash_file);
hash_file = tmp;
if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file,
&signature_len, gpg_keyring_sign, gpg_sign_as))
err(EXIT_FAILURE, "Cannot sign hash file");
lseek(fd, 0, SEEK_SET);
sign_entry = archive_entry_clone(entry);
hash_entry = archive_entry_clone(entry);
pkgname = strrchr(name, '/');
archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name);
archive_entry_set_pathname(hash_entry, HASH_FNAME);
archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME);
archive_entry_set_size(hash_entry, strlen(hash_file));
archive_entry_set_size(sign_entry, signature_len);
pkg = archive_write_new();
archive_write_set_compression_none(pkg);
archive_write_set_format_ar_bsd(pkg);
archive_write_open_filename(pkg, output);
archive_write_header(pkg, hash_entry);
archive_write_data(pkg, hash_file, strlen(hash_file));
archive_write_finish_entry(pkg);
archive_entry_free(hash_entry);
archive_write_header(pkg, sign_entry);
archive_write_data(pkg, signature_file, signature_len);
archive_write_finish_entry(pkg);
archive_entry_free(sign_entry);
size = archive_entry_size(entry);
archive_write_header(pkg, entry);
for (i = 0; i < size; i += block_len) {
if (i + (off_t)sizeof(block) < size)
block_len = sizeof(block);
else
block_len = size % sizeof(block);
if (read(fd, block, block_len) != (ssize_t)block_len)
err(2, "short read");
archive_write_data(pkg, block, block_len);
}
archive_write_finish_entry(pkg);
archive_entry_free(entry);
archive_write_finish(pkg);
close(fd);
exit(0);
}

View file

@ -0,0 +1,138 @@
.\" $NetBSD: pkg_summary.5,v 1.4 2012/02/19 17:49:09 tron Exp $
.\"
.\" Copyright (c) 2006 The NetBSD Foundation
.\"
.\" 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. 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 AND ITS 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 REGENTS 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.
.\"
.Dd April 11, 2009
.Dt PKG_SUMMARY 5
.Os
.Sh NAME
.Nm pkg_summary
.Nd summary of binary package repository
.Sh DESCRIPTION
The file
.Nm
contains information about each package in a binary package
repository as a list of variable-value pairs.
The variables describing different packages are separated by one empty
line.
Each line has the format
.Ev VARIABLE=VALUE .
If the value consists of more than one line, each line is prefixed with
.Ev VARIABLE= .
Multi-line variables are guaranteed to be in consecutive lines.
.Pp
The following variables are used:
.Bl -tag -width indent
.It Ev BUILD_DATE
(required) The date and time when the package was built.
.It Ev CATEGORIES
(required) A list of categories which this package fits in, separated by
space.
.It Ev COMMENT
(required) A one-line description of the package.
.It Ev CONFLICTS
(optional) A list of dewey patterns of packages the package conflicts
with, one per line.
If missing, this package has no conflicts.
.It Ev DEPENDS
(optional) A list of dewey patterns of packages the package depends
on, one per line.
If missing, this package has no dependencies.
.It Ev DESCRIPTION
(required) A more detailed description of the package.
.\" DIGEST
.It Ev FILE_CKSUM
(optional) A checksum type supported by
.Xr digest 1
and checksum separated by space character.
.It Ev FILE_NAME
(optional) The name of the binary package file.
If not given,
.Pa PKGNAME.tgz
can be assumed.
.It Ev FILE_SIZE
(optional) The size of the binary package file, in bytes.
.It Ev HOMEPAGE
(optional) A URL where more information about the package can be found.
.It Ev LICENSE
(optional) The type of license this package is distributed under.
If empty or missing, it is OSI-approved.
.It Ev MACHINE_ARCH
(required) The architecture on which the package was compiled.
.It Ev OPSYS
(required) The operating system on which the package was compiled.
.It Ev OS_VERSION
(required) The version of the operating system on which the package
was compiled.
.It Ev PKG_OPTIONS
(optional) Any options selected to compile this package.
If missing, the package does not support options.
.It Ev PKGNAME
(required) The name of the package.
.It Ev PKGPATH
(required) The path of the package directory within pkgsrc.
.It Ev PKGTOOLS_VERSION
(required) The version of the package tools used to create the package.
.It Ev PREV_PKGPATH
(optional) The previous path of the package directory within pkgsrc when
a package was moved.
(See
.Ev SUPERSEDES
below for a renamed package.)
.It Ev PROVIDES
(optional) A list of shared libraries provided by the package,
including major version number, one per line.
If missing, this package does not provide shared libraries.
.It Ev REQUIRES
(optional) A list of shared libraries needed by the package, including
major version number, one per line.
If missing, this package does not require shared libraries.
.It Ev SIZE_PKG
(required) The size of the package when installed, in bytes.
.It Ev SUPERSEDES
(optional) A list of dewey patterns of previous packages this
package replaces, one per line.
This is used for package renaming.
.El
.Pp
The
.Nm pkg_summary
file can be generated using the
.Xr pkg_info 1
.Fl X
option.
For example, the following will list this data for all installed packages:
.Pp
.Dl "pkg_info -X -a"
.Sh SEE ALSO
.Xr digest 1 ,
.Xr pkg_info 1
.Sh HISTORY
The
.Nm pkg_summary
format was first officially documented in April 2006.

View file

@ -0,0 +1,339 @@
/* $NetBSD: pkgdb.c,v 1.1.1.8 2010/04/23 20:54:11 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: pkgdb.c,v 1.1.1.8 2010/04/23 20:54:11 joerg Exp $");
/*-
* Copyright (c) 1999-2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Hubert Feyrer <hubert@feyrer.de>.
*
* 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.
*
* 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.
*/
#ifdef NETBSD
#include <db.h>
#else
#include <nbcompat/db.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_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#include "lib.h"
#define PKGDB_FILE "pkgdb.byfile.db" /* indexed by filename */
/*
* Where we put logging information by default if PKG_DBDIR is unset.
*/
#ifndef DEF_LOG_DIR
#define DEF_LOG_DIR "/var/db/pkg"
#endif
/* just in case we change the environment variable name */
#define PKG_DBDIR "PKG_DBDIR"
static DB *pkgdbp;
static char pkgdb_dir_default[] = DEF_LOG_DIR;
static char *pkgdb_dir = pkgdb_dir_default;
static int pkgdb_dir_prio = 0;
/*
* Return name of cache file in the buffer that was passed.
*/
char *
pkgdb_get_database(void)
{
return xasprintf("%s/%s", pkgdb_get_dir(), PKGDB_FILE);
}
/*
* Open the pkg-database
* Return value:
* 1: everything ok
* 0: error
*/
int
pkgdb_open(int mode)
{
BTREEINFO info;
char *cachename;
/* try our btree format first */
info.flags = 0;
info.cachesize = 2*1024*1024;
info.maxkeypage = 0;
info.minkeypage = 0;
info.psize = 4096;
info.compare = NULL;
info.prefix = NULL;
info.lorder = 0;
cachename = pkgdb_get_database();
pkgdbp = (DB *) dbopen(cachename,
(mode == ReadOnly) ? O_RDONLY : O_RDWR | O_CREAT,
0644, DB_BTREE, (void *) &info);
free(cachename);
return (pkgdbp != NULL);
}
/*
* Close the pkg database
*/
void
pkgdb_close(void)
{
if (pkgdbp != NULL) {
(void) (*pkgdbp->close) (pkgdbp);
pkgdbp = NULL;
}
}
/*
* Store value "val" with key "key" in database
* Return value is as from ypdb_store:
* 0: ok
* 1: key already present
* -1: some other error, see errno
*/
int
pkgdb_store(const char *key, const char *val)
{
DBT keyd, vald;
if (pkgdbp == NULL)
return -1;
keyd.data = __UNCONST(key);
keyd.size = strlen(key) + 1;
vald.data = __UNCONST(val);
vald.size = strlen(val) + 1;
if (keyd.size > MaxPathSize || vald.size > MaxPathSize)
return -1;
return (*pkgdbp->put) (pkgdbp, &keyd, &vald, R_NOOVERWRITE);
}
/*
* Recall value for given key
* Return value:
* NULL if some error occurred or value for key not found (check errno!)
* String for "value" else
*/
char *
pkgdb_retrieve(const char *key)
{
DBT keyd, vald;
int status;
char *eos;
static int corruption_warning;
if (pkgdbp == NULL)
return NULL;
keyd.data = __UNCONST(key);
keyd.size = strlen(key) + 1;
errno = 0; /* to be sure it's 0 if the key doesn't match anything */
vald.data = (void *)NULL;
vald.size = 0;
status = (*pkgdbp->get) (pkgdbp, &keyd, &vald, 0);
if (status)
return NULL;
eos = memchr(vald.data, 0, vald.size);
if (eos == NULL || eos + 1 != (char *)vald.data + vald.size) {
if (!corruption_warning) {
warnx("pkgdb corrupted, please run ``pkg_admin rebuild''");
corruption_warning = 1;
}
return NULL;
}
return vald.data;
}
/* dump contents of the database to stdout */
int
pkgdb_dump(void)
{
DBT key;
DBT val;
int type;
if (pkgdb_open(ReadOnly)) {
for (type = R_FIRST ; (*pkgdbp->seq)(pkgdbp, &key, &val, type) == 0 ; type = R_NEXT) {
printf("file: %.*s pkg: %.*s\n",
(int) key.size, (char *) key.data,
(int) val.size, (char *) val.data);
}
pkgdb_close();
return 0;
} else
return -1;
}
/*
* Remove data set from pkgdb
* Return value as ypdb_delete:
* 0: everything ok
* 1: key not present
* -1: some error occurred (see errno)
*/
int
pkgdb_remove(const char *key)
{
DBT keyd;
if (pkgdbp == NULL)
return -1;
keyd.data = __UNCONST(key);
keyd.size = strlen(key) + 1;
if (keyd.size > MaxPathSize)
return -1;
return (*pkgdbp->del) (pkgdbp, &keyd, 0);
}
/*
* Remove any entry from the cache which has a data field of `pkg'.
* Return value:
* 1: everything ok
* 0: error
*/
int
pkgdb_remove_pkg(const char *pkg)
{
DBT data;
DBT key;
int type;
int ret;
size_t cc;
char *cachename;
if (pkgdbp == NULL) {
return 0;
}
cachename = pkgdb_get_database();
cc = strlen(pkg);
for (ret = 1, type = R_FIRST; (*pkgdbp->seq)(pkgdbp, &key, &data, type) == 0 ; type = R_NEXT) {
if ((cc + 1) == data.size && strncmp(data.data, pkg, cc) == 0) {
if (Verbose) {
printf("Removing file `%s' from %s\n", (char *)key.data, cachename);
}
switch ((*pkgdbp->del)(pkgdbp, &key, 0)) {
case -1:
warn("Error removing `%s' from %s", (char *)key.data, cachename);
ret = 0;
break;
case 1:
warn("Key `%s' not present in %s", (char *)key.data, cachename);
ret = 0;
break;
}
}
}
free(cachename);
return ret;
}
/*
* Return the location of the package reference counts database directory.
*/
char *
pkgdb_refcount_dir(void)
{
static char buf[MaxPathSize];
char *tmp;
if ((tmp = getenv(PKG_REFCOUNT_DBDIR_VNAME)) != NULL)
strlcpy(buf, tmp, sizeof(buf));
else
snprintf(buf, sizeof(buf), "%s.refcount", pkgdb_get_dir());
return buf;
}
/*
* Return directory where pkgdb is stored
*/
const char *
pkgdb_get_dir(void)
{
return pkgdb_dir;
}
/*
* Set the first place we look for where pkgdb is stored.
*/
void
pkgdb_set_dir(const char *dir, int prio)
{
if (prio < pkgdb_dir_prio)
return;
pkgdb_dir_prio = prio;
if (dir == pkgdb_dir)
return;
if (pkgdb_dir != pkgdb_dir_default)
free(pkgdb_dir);
pkgdb_dir = xstrdup(dir);
}
char *
pkgdb_pkg_dir(const char *pkg)
{
return xasprintf("%s/%s", pkgdb_get_dir(), pkg);
}
char *
pkgdb_pkg_file(const char *pkg, const char *file)
{
return xasprintf("%s/%s/%s", pkgdb_get_dir(), pkg, file);
}

View file

@ -0,0 +1,54 @@
.\" $NetBSD: pkgsrc.7,v 1.1.1.1 2008/09/30 19:00:27 joerg Exp $
.\"
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by 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.
.\"
.\" 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.
.\"
.Dd March 2, 2007
.Dt PKGSRC 7
.Os
.Sh NAME
.Nm pkgsrc
.Nd NetBSD packages collection (framework for third-party software)
.Sh DESCRIPTION
The
.Nx
Packages Collection (pkgsrc) is a framework for building and
maintaining third-party software on
.Nx
and other
.Ux Ns -like
systems.
It is used to enable freely available software to be configured
and built easily on supported platforms.
.Pp
Tools are available to install ready-to-use packages and to perform
various administrative tasks for the package system.
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Pa http://www.netbsd.org/docs/pkgsrc/

View file

@ -0,0 +1,783 @@
/* $NetBSD: plist.c,v 1.1.1.5 2009/08/06 16:55:28 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: plist.c,v 1.1.1.5 2009/08/06 16:55:28 joerg Exp $");
/*
* 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
*
* General packing list routines.
*
*/
/*-
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "lib.h"
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#ifndef NETBSD
#include <nbcompat/md5.h>
#else
#include <md5.h>
#endif
static int delete_with_parents(const char *, Boolean, Boolean);
/* This struct defines a plist command type */
typedef struct cmd_t {
const char *c_s; /* string to recognise */
pl_ent_t c_type; /* type of command */
int c_argc; /* # of arguments */
int c_subst; /* can substitute real prefix */
} cmd_t;
/* Commands to recognise */
static const cmd_t cmdv[] = {
{"cwd", PLIST_CWD, 1, 1},
{"src", PLIST_SRC, 1, 1},
{"exec", PLIST_CMD, 1, 0},
{"unexec", PLIST_UNEXEC, 1, 0},
{"mode", PLIST_CHMOD, 1, 0},
{"owner", PLIST_CHOWN, 1, 0},
{"group", PLIST_CHGRP, 1, 0},
{"comment", PLIST_COMMENT, 1, 0},
{"ignore", PLIST_IGNORE, 0, 0},
{"name", PLIST_NAME, 1, 0},
{"display", PLIST_DISPLAY, 1, 0},
{"pkgdep", PLIST_PKGDEP, 1, 0},
{"pkgcfl", PLIST_PKGCFL, 1, 0},
{"pkgdir", PLIST_PKGDIR, 1, 0},
{"dirrm", PLIST_DIR_RM, 1, 0},
{"option", PLIST_OPTION, 1, 0},
{"blddep", PLIST_BLDDEP, 1, 0},
{NULL, FAIL, 0, 0}
};
/*
* Add an item to the end of a packing list
*/
void
add_plist(package_t *p, pl_ent_t type, const char *arg)
{
plist_t *tmp;
tmp = new_plist_entry();
tmp->name = (arg == NULL) ? NULL : xstrdup(arg);
tmp->type = type;
if (!p->head) {
p->head = p->tail = tmp;
} else {
tmp->prev = p->tail;
p->tail->next = tmp;
p->tail = tmp;
}
}
/*
* Add an item to the start of a packing list
*/
void
add_plist_top(package_t *p, pl_ent_t type, const char *arg)
{
plist_t *tmp;
tmp = new_plist_entry();
tmp->name = (arg == NULL) ? NULL : xstrdup(arg);
tmp->type = type;
if (!p->head) {
p->head = p->tail = tmp;
} else {
tmp->next = p->head;
p->head->prev = tmp;
p->head = tmp;
}
}
/*
* Return the last (most recent) entry in a packing list
*/
plist_t *
last_plist(package_t *p)
{
return p->tail;
}
/*
* Mark all items in a packing list to prevent iteration over them
*/
void
mark_plist(package_t *pkg)
{
plist_t *pp;
for (pp = pkg->head; pp; pp = pp->next) {
pp->marked = TRUE;
}
}
/*
* Find a given item in a packing list and, if so, return it (else NULL)
*/
plist_t *
find_plist(package_t *pkg, pl_ent_t type)
{
plist_t *pp;
for (pp = pkg->head; pp && pp->type != type; pp = pp->next) {
}
return pp;
}
/*
* Look for a specific boolean option argument in the list
*/
char *
find_plist_option(package_t *pkg, const char *name)
{
plist_t *p;
for (p = pkg->head; p; p = p->next) {
if (p->type == PLIST_OPTION
&& strcmp(p->name, name) == 0) {
return p->name;
}
}
return (char *) NULL;
}
/*
* Delete plist item 'type' in the list (if 'name' is non-null, match it
* too.) If 'all' is set, delete all items, not just the first occurance.
*/
void
delete_plist(package_t *pkg, Boolean all, pl_ent_t type, char *name)
{
plist_t *p = pkg->head;
while (p) {
plist_t *pnext = p->next;
if (p->type == type && (!name || !strcmp(name, p->name))) {
free(p->name);
if (p->prev)
p->prev->next = pnext;
else
pkg->head = pnext;
if (pnext)
pnext->prev = p->prev;
else
pkg->tail = p->prev;
free(p);
if (!all)
return;
p = pnext;
} else
p = p->next;
}
}
/*
* Allocate a new packing list entry, and return a pointer to it.
*/
plist_t *
new_plist_entry(void)
{
return xcalloc(1, sizeof(plist_t));
}
/*
* Free an entire packing list
*/
void
free_plist(package_t *pkg)
{
plist_t *p = pkg->head;
while (p) {
plist_t *p1 = p->next;
free(p->name);
free(p);
p = p1;
}
pkg->head = pkg->tail = NULL;
}
/*
* For an ASCII string denoting a plist command, return its code and
* optionally its argument(s)
*/
static int
plist_cmd(const char *s, char **arg)
{
const cmd_t *cmdp;
const char *cp, *sp;
char *sp2;
sp = NULL; /* Older GCC can't detect that the loop is executed */
for (cmdp = cmdv; cmdp->c_s; ++cmdp) {
for (sp = s, cp = cmdp->c_s; *sp && *cp; ++cp, ++sp)
if (*sp != *cp)
break;
if (*cp == '\0')
break;
}
if (cmdp->c_s == NULL || arg == NULL)
return cmdp->c_type;
while (isspace((unsigned char)*sp))
++sp;
*arg = xstrdup(sp);
if (*sp) {
sp2 = *arg + strlen(*arg) - 1;
/*
* The earlier loop ensured that at least one non-whitespace
* is in the string.
*/
while (isspace((unsigned char)*sp2))
--sp2;
sp2[1] = '\0';
}
return cmdp->c_type;
}
/*
* Parse a packaging list from a memory buffer.
*/
void
parse_plist(package_t *pkg, const char *buf)
{
int cmd;
char *line, *cp;
const char *eol, *next;
size_t len;
pkg->head = NULL;
pkg->tail = NULL;
for (; *buf; buf = next) {
/* Until add_plist can deal with trailing whitespace. */
if ((eol = strchr(buf, '\n')) != NULL) {
next = eol + 1;
len = eol - buf;
} else {
len = strlen(buf);
next = buf + len;
}
while (len && isspace((unsigned char)buf[len - 1]))
--len;
if (len == 0)
continue;
line = xmalloc(len + 1);
memcpy(line, buf, len);
line[len] = '\0';
if (*(cp = line) == CMD_CHAR) {
if ((cmd = plist_cmd(line + 1, &cp)) == FAIL) {
warnx("Unrecognised PLIST command `%s'", line);
continue;
}
if (*cp == '\0') {
free(cp);
cp = NULL;
}
} else {
cmd = PLIST_FILE;
}
add_plist(pkg, cmd, cp);
free(cp);
}
}
/*
* Read a packing list from a file
*/
void
append_plist(package_t *pkg, FILE * fp)
{
char pline[MaxPathSize];
char *cp;
int cmd;
int len;
int free_cp;
while (fgets(pline, MaxPathSize, fp) != (char *) NULL) {
for (len = strlen(pline); len &&
isspace((unsigned char) pline[len - 1]);) {
pline[--len] = '\0';
}
if (len == 0) {
continue;
}
free_cp = 0;
if (*(cp = pline) == CMD_CHAR) {
if ((cmd = plist_cmd(pline + 1, &cp)) == FAIL) {
warnx("Unrecognised PLIST command `%s'", pline);
continue;
}
if (*cp == '\0') {
free(cp);
cp = NULL;
}
free_cp = 1;
} else {
cmd = PLIST_FILE;
}
add_plist(pkg, cmd, cp);
if (free_cp)
free(cp);
}
}
void
read_plist(package_t *pkg, FILE * fp)
{
pkg->head = NULL;
pkg->tail = NULL;
append_plist(pkg, fp);
}
/*
* Write a packing list to a file, converting commands to ASCII equivs
*/
void
write_plist(package_t *pkg, FILE * fp, char *realprefix)
{
plist_t *p;
const cmd_t *cmdp;
for (p = pkg->head; p; p = p->next) {
if (p->type == PLIST_FILE) {
/* Fast-track files - these are the most common */
(void) fprintf(fp, "%s\n", p->name);
continue;
}
for (cmdp = cmdv; cmdp->c_type != FAIL && cmdp->c_type != p->type; cmdp++) {
}
if (cmdp->c_type == FAIL) {
warnx("Unknown PLIST command type %d (%s)", p->type, p->name);
} else if (cmdp->c_argc == 0) {
(void) fprintf(fp, "%c%s\n", CMD_CHAR, cmdp->c_s);
} else if (cmdp->c_subst && realprefix) {
(void) fprintf(fp, "%c%s %s\n", CMD_CHAR, cmdp->c_s, realprefix);
} else {
(void) fprintf(fp, "%c%s %s\n", CMD_CHAR, cmdp->c_s,
(p->name) ? p->name : "");
}
}
}
/*
* Like write_plist, but compute memory string.
*/
void
stringify_plist(package_t *pkg, char **real_buf, size_t *real_len,
const char *realprefix)
{
plist_t *p;
const cmd_t *cmdp;
char *buf;
size_t len;
int item_len;
/* Pass One: compute output size only. */
len = 0;
for (p = pkg->head; p; p = p->next) {
if (p->type == PLIST_FILE) {
len += strlen(p->name) + 1;
continue;
}
for (cmdp = cmdv; cmdp->c_type != FAIL && cmdp->c_type != p->type; cmdp++) {
}
if (cmdp->c_type == FAIL)
continue;
if (cmdp->c_argc == 0)
len += 1 + strlen(cmdp->c_s) + 1;
else if (cmdp->c_subst && realprefix)
len += 1 + strlen(cmdp->c_s) + 1 + strlen(realprefix) + 1;
else
len += 1 + strlen(cmdp->c_s) + 1 + strlen(p->name ? p->name : "") + 1;
}
/* Pass Two: build actual string. */
buf = xmalloc(len + 1);
*real_buf = buf;
*real_len = len;
++len;
#define UPDATE_LEN \
do { \
if (item_len < 0 || (size_t)item_len > len) \
errx(2, "Size computation failed, aborted."); \
buf += item_len; \
len -= item_len; \
} while (/* CONSTCOND */0)
for (p = pkg->head; p; p = p->next) {
if (p->type == PLIST_FILE) {
/* Fast-track files - these are the most common */
item_len = snprintf(buf, len, "%s\n", p->name);
UPDATE_LEN;
continue;
}
for (cmdp = cmdv; cmdp->c_type != FAIL && cmdp->c_type != p->type; cmdp++) {
}
if (cmdp->c_type == FAIL) {
warnx("Unknown PLIST command type %d (%s)", p->type, p->name);
} else if (cmdp->c_argc == 0) {
item_len = snprintf(buf, len, "%c%s\n", CMD_CHAR, cmdp->c_s);
UPDATE_LEN;
} else if (cmdp->c_subst && realprefix) {
item_len = snprintf(buf, len, "%c%s %s\n", CMD_CHAR, cmdp->c_s, realprefix);
UPDATE_LEN;
} else {
item_len = snprintf(buf, len, "%c%s %s\n", CMD_CHAR, cmdp->c_s,
(p->name) ? p->name : "");
UPDATE_LEN;
}
}
if (len != 1)
errx(2, "Size computation failed, aborted.");
}
/*
* Delete the results of a package installation.
*
* This is here rather than in the pkg_delete code because pkg_add needs to
* run it too in cases of failure.
*/
int
delete_package(Boolean ign_err, package_t *pkg, Boolean NoDeleteFiles,
const char *destdir)
{
plist_t *p;
const char *last_file = "";
int fail = SUCCESS;
Boolean preserve;
char tmp[MaxPathSize];
const char *prefix = NULL, *name = NULL;
if (!pkgdb_open(ReadWrite)) {
err(EXIT_FAILURE, "cannot open pkgdb");
}
preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
for (p = pkg->head; p; p = p->next) {
switch (p->type) {
case PLIST_NAME:
name = p->name;
break;
case PLIST_CWD:
if (prefix == NULL)
prefix = p->name;
break;
default:
break;
}
}
if (name == NULL || prefix == NULL)
errx(EXIT_FAILURE, "broken PLIST");
/*
* Remove database entries first, directory removal is done
* in the main loop below.
*/
for (p = pkg->head; p; p = p->next) {
if (p->type == PLIST_PKGDIR)
delete_pkgdir(name, prefix, p->name);
}
for (p = pkg->head; p; p = p->next) {
switch (p->type) {
case PLIST_NAME:
/* Handled already */
break;
case PLIST_PKGDIR:
case PLIST_DIR_RM:
(void) snprintf(tmp, sizeof(tmp), "%s/%s",
prefix, p->name);
if (has_pkgdir(tmp))
continue;
(void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s",
destdir ? destdir : "", destdir ? "/" : "",
prefix, p->name);
if (!fexists(tmp)) {
if (p->type == PLIST_PKGDIR)
warnx("Directory `%s' disappeared, skipping", tmp);
} else if (!isdir(tmp)) {
warnx("attempting to delete a file `%s' as a directory\n"
"this packing list is incorrect - ignoring delete request", tmp);
} else if (delete_with_parents(tmp, ign_err, TRUE))
fail = FAIL;
break;
case PLIST_IGNORE:
p = p->next;
break;
case PLIST_UNEXEC:
if (NoDeleteFiles)
break;
format_cmd(tmp, sizeof(tmp), p->name, prefix, last_file);
printf("Executing `%s'\n", tmp);
if (!Fake && system(tmp)) {
warnx("unexec command for `%s' failed", tmp);
fail = FAIL;
}
break;
case PLIST_FILE:
last_file = p->name;
(void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s",
destdir ? destdir : "", destdir ? "/" : "",
prefix, p->name);
if (isdir(tmp)) {
warnx("attempting to delete directory `%s' as a file\n"
"this packing list is incorrect - ignoring delete request", tmp);
} else {
int restored = 0; /* restored from preserve? */
if (p->next && p->next->type == PLIST_COMMENT) {
if (strncmp(p->next->name, CHECKSUM_HEADER, ChecksumHeaderLen) == 0) {
char *cp, buf[LegibleChecksumLen];
if ((cp = MD5File(tmp, buf)) != NULL) {
/* Mismatch? */
if (strcmp(cp, p->next->name + ChecksumHeaderLen) != 0) {
printf("original MD5 checksum failed, %s: %s\n",
Force ? "deleting anyway" : "not deleting", tmp);
if (!Force) {
fail = FAIL;
goto pkgdb_cleanup;
}
}
}
} else if (strncmp(p->next->name, SYMLINK_HEADER, SymlinkHeaderLen) == 0) {
char buf[MaxPathSize + SymlinkHeaderLen];
int cc;
(void) strlcpy(buf, SYMLINK_HEADER,
sizeof(buf));
if ((cc = readlink(tmp, &buf[SymlinkHeaderLen],
sizeof(buf) - SymlinkHeaderLen - 1)) < 0) {
warn("can't readlink `%s'", tmp);
goto pkgdb_cleanup;
}
buf[SymlinkHeaderLen + cc] = 0x0;
if (strcmp(buf, p->next->name) != 0) {
if ((cc = readlink(&buf[SymlinkHeaderLen], &buf[SymlinkHeaderLen],
sizeof(buf) - SymlinkHeaderLen)) < 0) {
printf("symlink %s is not same as recorded value, %s: %s\n",
buf, Force ? "deleting anyway" : "not deleting", tmp);
if (!Force) {
fail = FAIL;
goto pkgdb_cleanup;
}
}
buf[SymlinkHeaderLen + cc] = 0x0;
if (strcmp(buf, p->next->name) != 0) {
printf("symlink %s is not same as recorded value, %s: %s\n",
buf, Force ? "deleting anyway" : "not deleting", tmp);
if (!Force) {
fail = FAIL;
goto pkgdb_cleanup;
}
}
}
}
}
if (Verbose && !NoDeleteFiles)
printf("Delete file %s\n", tmp);
if (!Fake && !NoDeleteFiles) {
if (delete_with_parents(tmp, ign_err, FALSE))
fail = FAIL;
if (preserve && name) {
char tmp2[MaxPathSize];
if (make_preserve_name(tmp2, MaxPathSize, name, tmp)) {
if (fexists(tmp2)) {
if (rename(tmp2, tmp))
warn("preserve: unable to restore %s as %s",
tmp2, tmp);
else
restored = 1;
}
}
}
}
pkgdb_cleanup:
if (!Fake) {
if (!restored) {
errno = 0;
if (pkgdb_remove(tmp) && errno)
perror("pkgdb_remove");
}
}
}
break;
default:
break;
}
}
pkgdb_close();
return fail;
}
/*
* Selectively delete a hierarchy
* Returns 1 on error, 0 else.
*/
static int
delete_with_parents(const char *fname, Boolean ign_err, Boolean ign_nonempty)
{
char *cp, *cp2;
if (remove(fname)) {
if (!ign_err && (!ign_nonempty || errno != ENOTEMPTY))
warnx("Couldn't remove %s", fname);
return 0;
}
cp = xstrdup(fname);
while (*cp) {
if ((cp2 = strrchr(cp, '/')) != NULL)
*cp2 = '\0';
if (!isemptydir(cp))
break;
if (has_pkgdir(cp))
break;
if (rmdir(cp))
break;
}
free(cp);
return 0;
}
void
add_pkgdir(const char *pkg, const char *prefix, const char *path)
{
char *fullpath, *oldvalue, *newvalue;
fullpath = xasprintf("%s/%s", prefix, path);
oldvalue = pkgdb_retrieve(fullpath);
if (oldvalue) {
if (strncmp(oldvalue, "@pkgdir ", 8) != 0)
errx(EXIT_FAILURE, "Internal error while processing pkgdb, run pkg_admin rebuild");
newvalue = xasprintf("%s %s", oldvalue, pkg);
pkgdb_remove(fullpath);
} else {
newvalue = xasprintf("@pkgdir %s", pkg);
}
pkgdb_store(fullpath, newvalue);
free(fullpath);
free(newvalue);
}
void
delete_pkgdir(const char *pkg, const char *prefix, const char *path)
{
size_t pkg_len, len;
char *fullpath, *oldvalue, *newvalue, *iter;
fullpath = xasprintf("%s/%s", prefix, path);
oldvalue = pkgdb_retrieve(fullpath);
if (oldvalue && strncmp(oldvalue, "@pkgdir ", 8) == 0) {
newvalue = xstrdup(oldvalue);
iter = newvalue + 8;
pkg_len = strlen(pkg);
while (*iter) {
if (strncmp(iter, pkg, pkg_len) == 0 &&
(iter[pkg_len] == ' ' || iter[pkg_len] == '\0')) {
len = strlen(iter + pkg_len);
memmove(iter, iter + pkg_len + 1, len);
if (len == 0)
*iter = '\0';
} else {
iter += strcspn(iter, " ");
iter += strspn(iter, " ");
}
}
pkgdb_remove(fullpath);
if (iter != newvalue + 8)
pkgdb_store(fullpath, newvalue);
free(newvalue);
}
free(fullpath);
}
int
has_pkgdir(const char *path)
{
const char *value;
value = pkgdb_retrieve(path);
if (value && strncmp(value, "@pkgdir ", 8) == 0)
return 1;
else
return 0;
}

View file

@ -0,0 +1,195 @@
/* $NetBSD: remove.c,v 1.1.1.2 2009/08/06 16:55:29 joerg Exp $ */
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: remove.c,v 1.1.1.2 2009/08/06 16:55:29 joerg Exp $");
#if HAVE_DIRENT_H
#include <dirent.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#include <errno.h>
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lib.h"
static int
safe_fchdir(int cwd)
{
int tmp_errno, rv;
tmp_errno = errno;
rv = fchdir(cwd);
errno = tmp_errno;
return rv;
}
static int
long_remove(const char **path_ptr, int missing_ok, int *did_chdir)
{
char tmp_path[PATH_MAX + 1];
const char *path;
size_t i, len;
int rv;
path = *path_ptr;
len = strlen(path);
*did_chdir = 0;
while (len >= PATH_MAX) {
for (i = PATH_MAX - 1; i > 0; --i) {
if (path[i] == '/')
break;
}
if (i == 0) {
errno = ENAMETOOLONG;
return -1; /* Assumes PATH_MAX > NAME_MAX */
}
memcpy(tmp_path, path, i);
tmp_path[i] = '\0';
if (chdir(tmp_path))
return -1;
*did_chdir = 1;
path += i + 1;
len -= i + 1;
}
if (remove(path) == 0 || (errno == ENOENT && missing_ok))
rv = 0;
else
rv = -1;
*path_ptr = path;
return rv;
}
static int
recursive_remove_internal(const char *path, int missing_ok, int cwd)
{
DIR *dir;
struct dirent *de;
const char *sub_path;
char *subdir;
int did_chdir, rv;
/*
* If the argument is longer than PATH_MAX, long_remove
* will try to shorten it using chdir. So before returning,
* make sure to fchdir back to the original cwd.
*/
sub_path = path;
if (long_remove(&sub_path, missing_ok, &did_chdir) == 0)
rv = 0;
else if (errno != ENOTEMPTY) /* Other errors are terminal. */
rv = -1;
else
rv = 1;
if (rv != 1) {
if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
rv = -1;
return rv;
}
if ((dir = opendir(sub_path)) == NULL) {
if (errno == EMFILE)
warn("opendir failed");
return -1;
}
if (did_chdir && fchdir(cwd) == -1)
return -1;
rv = 0;
while ((de = readdir(dir)) != NULL) {
if (strcmp(de->d_name, ".") == 0)
continue;
if (strcmp(de->d_name, "..") == 0)
continue;
subdir = xasprintf("%s/%s", path, de->d_name);
rv = recursive_remove_internal(subdir, 1, cwd);
free(subdir);
}
closedir(dir);
safe_fchdir(cwd);
rv |= long_remove(&path, missing_ok, &did_chdir);
if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0)
rv = -1;
return rv;
}
int
recursive_remove(const char *path, int missing_ok)
{
int orig_cwd, rv;
/* First try the easy case of regular file or empty directory. */
if (remove(path) == 0 || (errno == ENOENT && missing_ok))
return 0;
/*
* If the path is too long, long_remove will use chdir to shorten it,
* so remember the current directory first.
*/
if ((orig_cwd = open(".", O_RDONLY)) == -1)
return -1;
rv = recursive_remove_internal(path, missing_ok, orig_cwd);
close(orig_cwd);
return rv;
}

102
external/bsd/pkg_install/dist/lib/str.c vendored Normal file
View file

@ -0,0 +1,102 @@
/* $NetBSD: str.c,v 1.1.1.2 2009/02/02 20:44:08 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: str.c,v 1.1.1.2 2009/02/02 20:44:08 joerg Exp $");
/*
* 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 string utilities.
*
*/
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
#include "lib.h"
#include "dewey.h"
/* pull in definitions and macros for resizing arrays as we go */
#include "defs.h"
/*
* Return the suffix portion of a path
*/
const char *
suffix_of(const char *str)
{
const char *dot;
return ((dot = strrchr(basename_of(str), '.')) == NULL) ? "" : dot + 1;
}
/*
* Return the filename portion of a path
*/
const char *
basename_of(const char *str)
{
const char *slash;
return ((slash = strrchr(str, '/')) == NULL) ? str : slash + 1;
}
/*
* Return the dirname portion of a path
*/
const char *
dirname_of(const char *path)
{
size_t cc;
char *s;
static char buf[MaxPathSize];
if ((s = strrchr(path, '/')) == NULL) {
return ".";
}
if (s == path) {
/* "/foo" -> return "/" */
return "/";
}
cc = (size_t) (s - path);
if (cc >= sizeof(buf))
errx(EXIT_FAILURE, "dirname_of: too long dirname: '%s'", path);
(void) memcpy(buf, path, cc);
buf[cc] = 0;
return buf;
}
/*
* Does the pkgname contain any of the special chars ("{[]?*<>")?
* If so, return 1, else 0
*/
int
ispkgpattern(const char *pkg)
{
return strpbrk(pkg, "<>[]?*{") != NULL;
}

345
external/bsd/pkg_install/dist/lib/var.c vendored Normal file
View file

@ -0,0 +1,345 @@
/* $NetBSD: var.c,v 1.2 2013/05/16 19:19:44 martin Exp $ */
/*-
* Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron, Thomas Klausner, Johnny Lam, and Joerg Sonnenberger.
*
* 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. 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_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: var.c,v 1.2 2013/05/16 19:19:44 martin Exp $");
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_ERR_H
#include <err.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#include "lib.h"
static const char *var_cmp(const char *, size_t, const char *, size_t);
static void var_print(FILE *, const char *, const char *);
/*
* Copy the specified varibales from the file fname to stdout.
*/
int
var_copy_list(const char *buf, const char **variables)
{
const char *eol, *next;
size_t len;
int i;
for (; *buf; buf = next) {
if ((eol = strchr(buf, '\n')) != NULL) {
next = eol + 1;
len = eol - buf;
} else {
next = eol;
len = strlen(buf);
}
for (i=0; variables[i]; i++) {
if (var_cmp(buf, len, variables[i],
strlen(variables[i])) != NULL) {
printf("%.*s\n", (int)len, buf);
break;
}
}
}
return 0;
}
/*
* Print the value of variable from the file fname to stdout.
*/
char *
var_get(const char *fname, const char *variable)
{
FILE *fp;
char *line;
size_t len;
size_t varlen;
char *value;
size_t valuelen;
size_t thislen;
const char *p;
varlen = strlen(variable);
if (varlen == 0)
return NULL;
fp = fopen(fname, "r");
if (!fp) {
if (errno != ENOENT)
warn("var_get: can't open '%s' for reading", fname);
return NULL;
}
value = NULL;
valuelen = 0;
while ((line = fgetln(fp, &len)) != (char *) NULL) {
if (line[len - 1] == '\n')
--len;
if ((p=var_cmp(line, len, variable, varlen)) == NULL)
continue;
thislen = line+len - p;
if (value) {
value = xrealloc(value, valuelen+thislen+2);
value[valuelen++] = '\n';
}
else {
value = xmalloc(thislen+1);
}
sprintf(value+valuelen, "%.*s", (int)thislen, p);
valuelen += thislen;
}
(void) fclose(fp);
return value;
}
/*
* Print the value of variable from the memory buffer to stdout.
*/
char *
var_get_memory(const char *buf, const char *variable)
{
const char *eol, *next, *data;
size_t len, varlen, thislen, valuelen;
char *value;
varlen = strlen(variable);
if (varlen == 0)
return NULL;
value = NULL;
valuelen = 0;
for (; buf && *buf; buf = next) {
if ((eol = strchr(buf, '\n')) != NULL) {
next = eol + 1;
len = eol - buf;
} else {
next = eol;
len = strlen(buf);
}
if ((data = var_cmp(buf, len, variable, varlen)) == NULL)
continue;
thislen = buf + len - data;
if (value) {
value = xrealloc(value, valuelen+thislen+2);
value[valuelen++] = '\n';
}
else {
value = xmalloc(thislen+1);
}
sprintf(value + valuelen, "%.*s", (int)thislen, data);
valuelen += thislen;
}
return value;
}
/*
* Add given variable with given value to file, overwriting any
* previous occurrence.
*/
int
var_set(const char *fname, const char *variable, const char *value)
{
FILE *fp;
FILE *fout;
char *tmpname;
int fd;
char *line;
size_t len;
size_t varlen;
Boolean done;
struct stat st;
varlen = strlen(variable);
if (varlen == 0)
return 0;
fp = fopen(fname, "r");
if (fp == NULL) {
if (errno != ENOENT) {
warn("var_set: can't open '%s' for reading", fname);
return -1;
}
if (value == NULL)
return 0; /* Nothing to do */
}
tmpname = xasprintf("%s.XXXXXX", fname);
if ((fd = mkstemp(tmpname)) < 0) {
free(tmpname);
if (fp != NULL)
fclose(fp);
warn("var_set: can't open temp file for '%s' for writing",
fname);
return -1;
}
if (chmod(tmpname, 0644) < 0) {
close(fd);
if (fp != NULL)
fclose(fp);
free(tmpname);
warn("var_set: can't set permissions for temp file for '%s'",
fname);
return -1;
}
if ((fout=fdopen(fd, "w")) == NULL) {
close(fd);
remove(tmpname);
free(tmpname);
if (fp != NULL)
fclose(fp);
warn("var_set: can't open temp file for '%s' for writing",
fname);
return -1;
}
done = FALSE;
if (fp) {
while ((line = fgetln(fp, &len)) != (char *) NULL) {
if (var_cmp(line, len, variable, varlen) == NULL)
fprintf(fout, "%.*s", (int)len, line);
else {
if (!done && value) {
var_print(fout, variable, value);
done = TRUE;
}
}
}
(void) fclose(fp);
}
if (!done && value)
var_print(fout, variable, value);
if (fclose(fout) < 0) {
free(tmpname);
warn("var_set: write error for '%s'", fname);
return -1;
}
if (stat(tmpname, &st) < 0) {
free(tmpname);
warn("var_set: cannot stat tempfile for '%s'", fname);
return -1;
}
if (st.st_size == 0) {
if (remove(tmpname) < 0) {
free(tmpname);
warn("var_set: cannot remove tempfile for '%s'",
fname);
return -1;
}
free(tmpname);
if (remove(fname) < 0) {
warn("var_set: cannot remove '%s'", fname);
return -1;
}
return 0;
}
if (rename(tmpname, fname) < 0) {
free(tmpname);
warn("var_set: cannot move tempfile to '%s'", fname);
return -1;
}
free(tmpname);
return 0;
}
/*
* Check if line contains variable var, return pointer to its value or NULL.
*/
static const char *
var_cmp(const char *line, size_t linelen, const char *var, size_t varlen)
{
/*
* We expect lines to look like one of the following
* forms:
* VAR=value
* VAR= value
* We print out the value of VAR, or nothing if it
* doesn't exist.
*/
if (linelen < varlen+1)
return NULL;
if (strncmp(var, line, varlen) != 0)
return NULL;
line += varlen;
if (*line != '=')
return NULL;
++line;
linelen -= varlen+1;
if (linelen > 0 && *line == ' ')
++line;
return line;
}
/*
* Print given variable with value to file f.
*/
static void
var_print(FILE *f, const char *variable, const char *value)
{
const char *p;
while ((p=strchr(value, '\n')) != NULL) {
if (p != value)
fprintf(f, "%s=%.*s\n", variable, (int)(p-value), value);
value = p+1;
}
if (*value)
fprintf(f, "%s=%s\n", variable, value);
}

View file

@ -0,0 +1,49 @@
/* $NetBSD: version.c,v 1.1.1.3 2010/02/03 14:24:00 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: version.c,v 1.1.1.3 2010/02/03 14:24:00 joerg Exp $");
/*
* Copyright (c) 2001 Thomas Klausner. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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_STDIO_H
#include <stdio.h>
#endif
#include "lib.h"
#include "version.h"
void
show_version(void)
{
printf("%d\n", PKGTOOLS_VERSION);
exit (0);
}

View file

@ -0,0 +1,32 @@
/* $NetBSD: version.h,v 1.10 2013/04/20 15:29:23 wiz Exp $ */
/*
* Copyright (c) 2001 Thomas Klausner. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _INST_LIB_VERSION_H_
#define _INST_LIB_VERSION_H_
#define PKGTOOLS_VERSION 20130131
#endif /* _INST_LIB_VERSION_H_ */

View file

@ -0,0 +1,652 @@
/* $NetBSD: vulnerabilities-file.c,v 1.1.1.5 2010/06/26 00:14:33 joerg Exp $ */
/*-
* Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: vulnerabilities-file.c,v 1.1.1.5 2010/06/26 00:14:33 joerg Exp $");
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifndef BOOTSTRAP
#include <archive.h>
#endif
#include <ctype.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifndef NETBSD
#include <nbcompat/sha1.h>
#include <nbcompat/sha2.h>
#else
#include <sha1.h>
#include <sha2.h>
#endif
#include <unistd.h>
#include "lib.h"
static struct pkg_vulnerabilities *read_pkg_vulnerabilities_archive(struct archive *, int);
static struct pkg_vulnerabilities *parse_pkg_vuln(const char *, size_t, int);
static const char pgp_msg_start[] = "-----BEGIN PGP SIGNED MESSAGE-----\n";
static const char pgp_msg_end[] = "-----BEGIN PGP SIGNATURE-----\n";
static const char pkcs7_begin[] = "-----BEGIN PKCS7-----\n";
static const char pkcs7_end[] = "-----END PKCS7-----\n";
static void
verify_signature_pkcs7(const char *input)
{
#ifdef HAVE_SSL
const char *begin_pkgvul, *end_pkgvul, *begin_sig, *end_sig;
if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
begin_pkgvul = input + strlen(pgp_msg_start);
if ((end_pkgvul = strstr(begin_pkgvul, pgp_msg_end)) == NULL)
errx(EXIT_FAILURE, "Invalid PGP signature");
if ((begin_sig = strstr(end_pkgvul, pkcs7_begin)) == NULL)
errx(EXIT_FAILURE, "No PKCS7 signature");
} else {
begin_pkgvul = input;
if ((begin_sig = strstr(begin_pkgvul, pkcs7_begin)) == NULL)
errx(EXIT_FAILURE, "No PKCS7 signature");
end_pkgvul = begin_sig;
}
if ((end_sig = strstr(begin_sig, pkcs7_end)) == NULL)
errx(EXIT_FAILURE, "Invalid PKCS7 signature");
end_sig += strlen(pkcs7_end);
if (easy_pkcs7_verify(begin_pkgvul, end_pkgvul - begin_pkgvul,
begin_sig, end_sig - begin_sig, certs_pkg_vulnerabilities, 0))
errx(EXIT_FAILURE, "Unable to verify PKCS7 signature");
#else
errx(EXIT_FAILURE, "OpenSSL support is not compiled in");
#endif
}
static void
verify_signature(const char *input, size_t input_len)
{
if (gpg_cmd == NULL && certs_pkg_vulnerabilities == NULL)
errx(EXIT_FAILURE,
"At least GPG or CERTIFICATE_ANCHOR_PKGVULN "
"must be configured");
if (gpg_cmd != NULL)
inline_gpg_verify(input, input_len, gpg_keyring_pkgvuln);
if (certs_pkg_vulnerabilities != NULL)
verify_signature_pkcs7(input);
}
static void *
sha512_hash_init(void)
{
static SHA512_CTX hash_ctx;
SHA512_Init(&hash_ctx);
return &hash_ctx;
}
static void
sha512_hash_update(void *ctx, const void *data, size_t len)
{
SHA512_CTX *hash_ctx = ctx;
SHA512_Update(hash_ctx, data, len);
}
static const char *
sha512_hash_finish(void *ctx)
{
static char hash[SHA512_DIGEST_STRING_LENGTH];
unsigned char digest[SHA512_DIGEST_LENGTH];
SHA512_CTX *hash_ctx = ctx;
int i;
SHA512_Final(digest, hash_ctx);
for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
unsigned char c;
c = digest[i] / 16;
if (c < 10)
hash[2 * i] = '0' + c;
else
hash[2 * i] = 'a' - 10 + c;
c = digest[i] % 16;
if (c < 10)
hash[2 * i + 1] = '0' + c;
else
hash[2 * i + 1] = 'a' - 10 + c;
}
hash[2 * i] = '\0';
return hash;
}
static void *
sha1_hash_init(void)
{
static SHA1_CTX hash_ctx;
SHA1Init(&hash_ctx);
return &hash_ctx;
}
static void
sha1_hash_update(void *ctx, const void *data, size_t len)
{
SHA1_CTX *hash_ctx = ctx;
SHA1Update(hash_ctx, data, len);
}
static const char *
sha1_hash_finish(void *ctx)
{
static char hash[SHA1_DIGEST_STRING_LENGTH];
SHA1_CTX *hash_ctx = ctx;
SHA1End(hash_ctx, hash);
return hash;
}
static const struct hash_algorithm {
const char *name;
size_t name_len;
void * (*init)(void);
void (*update)(void *, const void *, size_t);
const char * (* finish)(void *);
} hash_algorithms[] = {
{ "SHA512", 6, sha512_hash_init, sha512_hash_update,
sha512_hash_finish },
{ "SHA1", 4, sha1_hash_init, sha1_hash_update,
sha1_hash_finish },
{ NULL, 0, NULL, NULL, NULL }
};
static void
verify_hash(const char *input, const char *hash_line)
{
const struct hash_algorithm *hash;
void *ctx;
const char *last_start, *next, *hash_value;
int in_pgp_msg;
for (hash = hash_algorithms; hash->name != NULL; ++hash) {
if (strncmp(hash_line, hash->name, hash->name_len))
continue;
if (isspace((unsigned char)hash_line[hash->name_len]))
break;
}
if (hash->name == NULL) {
const char *end_name;
for (end_name = hash_line; *end_name != '\0'; ++end_name) {
if (!isalnum((unsigned char)*end_name))
break;
}
warnx("Unsupported hash algorithm: %.*s",
(int)(end_name - hash_line), hash_line);
return;
}
hash_line += hash->name_len;
if (!isspace((unsigned char)*hash_line))
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
++hash_line;
if (*hash_line == '\n')
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
ctx = (*hash->init)();
if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
input += strlen(pgp_msg_start);
in_pgp_msg = 1;
} else {
in_pgp_msg = 0;
}
for (last_start = input; *input != '\0'; input = next) {
if ((next = strchr(input, '\n')) == NULL)
errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
++next;
if (in_pgp_msg && strncmp(input, pgp_msg_end, strlen(pgp_msg_end)) == 0)
break;
if (!in_pgp_msg && strncmp(input, pkcs7_begin, strlen(pkcs7_begin)) == 0)
break;
if (*input == '\n' ||
strncmp(input, "Hash:", 5) == 0 ||
strncmp(input, "# $NetBSD", 9) == 0 ||
strncmp(input, "#CHECKSUM", 9) == 0) {
(*hash->update)(ctx, last_start, input - last_start);
last_start = next;
}
}
(*hash->update)(ctx, last_start, input - last_start);
hash_value = (*hash->finish)(ctx);
if (strncmp(hash_line, hash_value, strlen(hash_value)))
errx(EXIT_FAILURE, "%s hash doesn't match", hash->name);
hash_line += strlen(hash_value);
while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
++hash_line;
if (!isspace((unsigned char)*hash_line))
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
}
static void
add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *line)
{
size_t len_pattern, len_class, len_url;
const char *start_pattern, *start_class, *start_url;
start_pattern = line;
start_class = line;
while (*start_class != '\0' && !isspace((unsigned char)*start_class))
++start_class;
len_pattern = start_class - line;
while (*start_class != '\n' && isspace((unsigned char)*start_class))
++start_class;
if (*start_class == '0' || *start_class == '\n')
errx(EXIT_FAILURE, "Input error: missing classification");
start_url = start_class;
while (*start_url != '\0' && !isspace((unsigned char)*start_url))
++start_url;
len_class = start_url - start_class;
while (*start_url != '\n' && isspace((unsigned char)*start_url))
++start_url;
if (*start_url == '0' || *start_url == '\n')
errx(EXIT_FAILURE, "Input error: missing URL");
line = start_url;
while (*line != '\0' && !isspace((unsigned char)*line))
++line;
len_url = line - start_url;
if (pv->entries == *allocated) {
if (*allocated == 0)
*allocated = 16;
else if (*allocated <= SSIZE_MAX / 2)
*allocated *= 2;
else
errx(EXIT_FAILURE, "Too many vulnerabilities");
pv->vulnerability = xrealloc(pv->vulnerability,
sizeof(char *) * *allocated);
pv->classification = xrealloc(pv->classification,
sizeof(char *) * *allocated);
pv->advisory = xrealloc(pv->advisory,
sizeof(char *) * *allocated);
}
pv->vulnerability[pv->entries] = xmalloc(len_pattern + 1);
memcpy(pv->vulnerability[pv->entries], start_pattern, len_pattern);
pv->vulnerability[pv->entries][len_pattern] = '\0';
pv->classification[pv->entries] = xmalloc(len_class + 1);
memcpy(pv->classification[pv->entries], start_class, len_class);
pv->classification[pv->entries][len_class] = '\0';
pv->advisory[pv->entries] = xmalloc(len_url + 1);
memcpy(pv->advisory[pv->entries], start_url, len_url);
pv->advisory[pv->entries][len_url] = '\0';
++pv->entries;
}
struct pkg_vulnerabilities *
read_pkg_vulnerabilities_memory(void *buf, size_t len, int check_sum)
{
#ifdef BOOTSTRAP
errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap");
#else
struct archive *a;
struct pkg_vulnerabilities *pv;
if ((a = archive_read_new()) == NULL)
errx(EXIT_FAILURE, "memory allocation failed");
if (archive_read_support_compression_all(a) != ARCHIVE_OK ||
archive_read_support_format_raw(a) != ARCHIVE_OK ||
archive_read_open_memory(a, buf, len) != ARCHIVE_OK)
errx(EXIT_FAILURE, "Cannot open pkg_vulnerabilies buffer: %s",
archive_error_string(a));
pv = read_pkg_vulnerabilities_archive(a, check_sum);
return pv;
#endif
}
struct pkg_vulnerabilities *
read_pkg_vulnerabilities_file(const char *path, int ignore_missing, int check_sum)
{
#ifdef BOOTSTRAP
errx(EXIT_FAILURE, "Audit functions are unsupported during bootstrap");
#else
struct archive *a;
struct pkg_vulnerabilities *pv;
int fd;
if ((fd = open(path, O_RDONLY)) == -1) {
if (errno == ENOENT && ignore_missing)
return NULL;
err(EXIT_FAILURE, "Cannot open %s", path);
}
if ((a = archive_read_new()) == NULL)
errx(EXIT_FAILURE, "memory allocation failed");
if (archive_read_support_compression_all(a) != ARCHIVE_OK ||
archive_read_support_format_raw(a) != ARCHIVE_OK ||
archive_read_open_fd(a, fd, 65536) != ARCHIVE_OK)
errx(EXIT_FAILURE, "Cannot open ``%s'': %s", path,
archive_error_string(a));
pv = read_pkg_vulnerabilities_archive(a, check_sum);
close(fd);
return pv;
#endif
}
#ifndef BOOTSTRAP
static struct pkg_vulnerabilities *
read_pkg_vulnerabilities_archive(struct archive *a, int check_sum)
{
struct archive_entry *ae;
struct pkg_vulnerabilities *pv;
char *buf;
size_t buf_len, off;
ssize_t r;
if (archive_read_next_header(a, &ae) != ARCHIVE_OK)
errx(EXIT_FAILURE, "Cannot read pkg_vulnerabilities: %s",
archive_error_string(a));
off = 0;
buf_len = 65536;
buf = xmalloc(buf_len + 1);
for (;;) {
r = archive_read_data(a, buf + off, buf_len - off);
if (r <= 0)
break;
off += r;
if (off == buf_len) {
buf_len *= 2;
if (buf_len < off)
errx(EXIT_FAILURE, "pkg_vulnerabilties too large");
buf = xrealloc(buf, buf_len + 1);
}
}
if (r != ARCHIVE_OK)
errx(EXIT_FAILURE, "Cannot read pkg_vulnerabilities: %s",
archive_error_string(a));
archive_read_close(a);
buf[off] = '\0';
pv = parse_pkg_vuln(buf, off, check_sum);
free(buf);
return pv;
}
static struct pkg_vulnerabilities *
parse_pkg_vuln(const char *input, size_t input_len, int check_sum)
{
struct pkg_vulnerabilities *pv;
long version;
char *end;
const char *iter, *next;
size_t allocated_vulns;
int in_pgp_msg;
pv = xmalloc(sizeof(*pv));
allocated_vulns = pv->entries = 0;
pv->vulnerability = NULL;
pv->classification = NULL;
pv->advisory = NULL;
if (strlen(input) != input_len)
errx(1, "Invalid input (NUL character found)");
if (check_sum)
verify_signature(input, input_len);
if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) {
iter = input + strlen(pgp_msg_start);
in_pgp_msg = 1;
} else {
iter = input;
in_pgp_msg = 0;
}
for (; *iter; iter = next) {
if ((next = strchr(iter, '\n')) == NULL)
errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
++next;
if (*iter == '\0' || *iter == '\n')
continue;
if (strncmp(iter, "Hash:", 5) == 0)
continue;
if (strncmp(iter, "# $NetBSD", 9) == 0)
continue;
if (*iter == '#' && isspace((unsigned char)iter[1])) {
for (++iter; iter != next; ++iter) {
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Invalid header");
}
continue;
}
if (strncmp(iter, "#FORMAT", 7) != 0)
errx(EXIT_FAILURE, "Input header is malformed");
iter += 7;
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Invalid #FORMAT");
++iter;
version = strtol(iter, &end, 10);
if (iter == end || version != 1 || *end != '.')
errx(EXIT_FAILURE, "Input #FORMAT");
iter = end + 1;
version = strtol(iter, &end, 10);
if (iter == end || version != 1 || *end != '.')
errx(EXIT_FAILURE, "Input #FORMAT");
iter = end + 1;
version = strtol(iter, &end, 10);
if (iter == end || version != 0)
errx(EXIT_FAILURE, "Input #FORMAT");
for (iter = end; iter != next; ++iter) {
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Input #FORMAT");
}
break;
}
if (*iter == '\0')
errx(EXIT_FAILURE, "Missing #CHECKSUM or content");
for (iter = next; *iter; iter = next) {
if ((next = strchr(iter, '\n')) == NULL)
errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
++next;
if (*iter == '\0' || *iter == '\n')
continue;
if (in_pgp_msg && strncmp(iter, pgp_msg_end, strlen(pgp_msg_end)) == 0)
break;
if (!in_pgp_msg && strncmp(iter, pkcs7_begin, strlen(pkcs7_begin)) == 0)
break;
if (*iter == '#' &&
(iter[1] == '\0' || iter[1] == '\n' || isspace((unsigned char)iter[1])))
continue;
if (strncmp(iter, "#CHECKSUM", 9) == 0) {
iter += 9;
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
while (isspace((unsigned char)*iter))
++iter;
verify_hash(input, iter);
continue;
}
if (*iter == '#') {
/*
* This should really be an error,
* but it is still used.
*/
/* errx(EXIT_FAILURE, "Invalid data line starting with #"); */
continue;
}
add_vulnerability(pv, &allocated_vulns, iter);
}
if (pv->entries != allocated_vulns) {
pv->vulnerability = xrealloc(pv->vulnerability,
sizeof(char *) * pv->entries);
pv->classification = xrealloc(pv->classification,
sizeof(char *) * pv->entries);
pv->advisory = xrealloc(pv->advisory,
sizeof(char *) * pv->entries);
}
return pv;
}
#endif
void
free_pkg_vulnerabilities(struct pkg_vulnerabilities *pv)
{
size_t i;
for (i = 0; i < pv->entries; ++i) {
free(pv->vulnerability[i]);
free(pv->classification[i]);
free(pv->advisory[i]);
}
free(pv->vulnerability);
free(pv->classification);
free(pv->advisory);
free(pv);
}
static int
check_ignored_entry(struct pkg_vulnerabilities *pv, size_t i)
{
const char *iter, *next;
size_t entry_len, url_len;
if (ignore_advisories == NULL)
return 0;
url_len = strlen(pv->advisory[i]);
for (iter = ignore_advisories; *iter; iter = next) {
if ((next = strchr(iter, '\n')) == NULL) {
entry_len = strlen(iter);
next = iter + entry_len;
} else {
entry_len = next - iter;
++next;
}
if (url_len != entry_len)
continue;
if (strncmp(pv->advisory[i], iter, entry_len) == 0)
return 1;
}
return 0;
}
int
audit_package(struct pkg_vulnerabilities *pv, const char *pkgname,
const char *limit_vul_types, int output_type)
{
FILE *output = output_type == 1 ? stdout : stderr;
size_t i;
int retval, do_eol;
retval = 0;
do_eol = (strcasecmp(check_eol, "yes") == 0);
for (i = 0; i < pv->entries; ++i) {
if (check_ignored_entry(pv, i))
continue;
if (limit_vul_types != NULL &&
strcmp(limit_vul_types, pv->classification[i]))
continue;
if (!pkg_match(pv->vulnerability[i], pkgname))
continue;
if (strcmp("eol", pv->classification[i]) == 0) {
if (!do_eol)
continue;
retval = 1;
if (output_type == 0) {
puts(pkgname);
continue;
}
fprintf(output,
"Package %s has reached end-of-life (eol), "
"see %s/eol-packages\n", pkgname,
tnf_vulnerability_base);
continue;
}
retval = 1;
if (output_type == 0) {
puts(pkgname);
} else {
fprintf(output,
"Package %s has a %s vulnerability, see %s\n",
pkgname, pv->classification[i], pv->advisory[i]);
}
}
return retval;
}

View file

@ -0,0 +1,102 @@
/* $NetBSD: xwrapper.c,v 1.1.1.1 2009/02/02 20:44:09 joerg Exp $ */
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: xwrapper.c,v 1.1.1.1 2009/02/02 20:44:09 joerg Exp $");
#if HAVE_ERR_H
#include <err.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib.h"
char *
xasprintf(const char *fmt, ...)
{
va_list ap;
char *buf;
va_start(ap, fmt);
if (vasprintf(&buf, fmt, ap) == -1)
err(1, "asprintf failed");
va_end(ap);
return buf;
}
void *
xmalloc(size_t len)
{
void *ptr;
if ((ptr = malloc(len)) == NULL)
err(1, "malloc failed");
return ptr;
}
void *
xcalloc(size_t len, size_t n)
{
void *ptr;
if ((ptr = calloc(len, n)) == NULL)
err(1, "calloc failed");
return ptr;
}
void *
xrealloc(void *buf, size_t len)
{
void *ptr;
if ((ptr = realloc(buf, len)) == NULL)
err(1, "realloc failed");
return ptr;
}
char *
xstrdup(const char *str)
{
char *buf;
if ((buf = strdup(str)) == NULL)
err(1, "strdup failed");
return buf;
}

View file

@ -0,0 +1,136 @@
# $NetBSD: pkgsrc.cnf,v 1.1.1.1 2009/02/02 20:44:09 joerg Exp $
#
# OpenSSL sample configuration file for use by pkgsrc.sh
#
# This definition stops the following lines choking if HOME isn't
# defined.
HOME = .
RANDFILE = $ENV::HOME/.rnd
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ./pkgsrc # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
# Extension copying option: use with caution.
# copy_extensions = copy
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = default # use public key default MD
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
default_md = sha1
distinguished_name = req_distinguished_name
x509_extensions = v3_ca # The extentions to add to the self signed cert
string_mask = utf8only
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = AU
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Some-State
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Internet Widgits Pty Ltd
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName = Common Name (eg, YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ pkgkey ]
nsComment = "Certificate for binary pkgsrc packages"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName=email:move
extendedKeyUsage = codeSigning, emailProtection
[ pkgsec ]
nsComment = "Certificate for pkg-vulnerabilities"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName=email:move
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = critical,CA:true

View file

@ -0,0 +1,63 @@
#!/bin/sh
#
# $NetBSD: pkgsrc.sh,v 1.1.1.1 2009/02/02 20:44:09 joerg Exp $
#
CA="openssl ca -config pkgsrc.cnf"
REQ="openssl req -config pkgsrc.cnf"
set -e
new_ca() {
if [ -f $1/serial ]; then
echo "CA already exists, exiting" >& 2
exit 1
fi
mkdir -p $1/certs $1/crl $1/newcerts $1/private
echo "00" > $1/serial
touch $1/index.txt
echo "Making CA certificate ..."
$REQ -new -keyout $1/private/cakey.pem \
-out $1/careq.pem
$CA -out $1/cacert.pem -batch \
-keyfile $1/private/cakey.pem -selfsign \
-infiles $1/careq.pem
}
new_pkgkey() {
$REQ -new -keyout pkgkey_key.pem -out pkgkey_req.pem
$CA -extensions pkgkey -policy policy_match -out pkgkey_cert.pem -infiles pkgkey_req.pem
rm pkgkey_req.pem
echo "Signed certificate is in pkgkey_cert.pem, key in pkgkey_key.pem"
}
new_pkgsec() {
$REQ -new -keyout pkgsec_key.pem -out pkgsec_req.pem
$CA -extensions pkgsec -policy policy_match -out pkgsec_cert.pem -infiles pkgsec_req.pem
rm pkgsec_req.pem
echo "Signed certificate is in pkgsec_cert.pem, key in pkgsec_key.pem"
}
usage() {
echo "$0:"
echo "setup - create new CA in ./pkgsrc for use by pkg_install"
echo "pkgkey - create and sign a certificate for binary packages"
echo "pkgsec - create and sign a certificate for pkg-vulnerabilities"
}
case "$1" in
setup)
new_ca ./pkgsrc
;;
pkgkey)
new_pkgkey
;;
pkgsec)
new_pkgsec
;;
*)
usage
;;
esac

View file

@ -0,0 +1,59 @@
Use of digital signatures in pkg_install
----------------------------------------
(1) pkg_vulnerabilities: list of known vulnerabilities, provided by
the pkgsrc security team and updated regulary
(2) binary packages: check who provided binary packages
For (1) gpg is currently the only choice. After pkgsrcCon (?) a PKCS7
signature will be added as well. With the pkg_install-renovation branch,
PKCS7 is the only supported verification mechanism for (2) and preferred
for (1) once the infrastructure exists.
PKCS7 is a format to use RSA public key cryptography with X509
certificates. Those are commonly used for SSL. X509 implements a
hierachical trust model. For this purpose it means that one or more
certificates are installed and marked as trusted. A certificate used for
signing a binary package or pkg_vulnerabilities will have to be included
in the list to be trusted OR it must be itself signed by a trusted
certificate. The original list is called the TRUST ANCHOR.
Optionally, a second list of certificates can be provided to fill gaps.
Let's assume A is a trust anchor and C is used to sign a package. C
itself is not signed by A, so it won't be trusted. Instead, there's a
third certificate B; and C includes a signature with B. The certificate
chain file can now provide B signed by A. This gives a certificate chain
of C -> B (included in the package) -> A (with the chain file) and the
signature is valid and trusted.
Practical implications for pkgsrc users:
- get the pkgsrc-security certificate and point CERTIFICATE_ANCHOR_PKGVULN to it
- get the certificate used by your bulk builder and point
CERTIFICATE_ANCHOR_PKGS to it
- at some later point a CA for pkgsrc might be created, in that case it
will serve as certificate for both purposes; a list of all certificates
will be provided in that case to point CERTIFICATE_CHAIN to.
How to create your own keys:
The pkgsrc.sh script and the corresponding pkgsrc.cnf file provide a working
wrapper around the OpenSSL command line tool.
The root certificate can be created by running "sh pkgsrc.sh setup",
the output can found in the pkgsrc subdirectory of the current directory.
The meta data is for human beings and displayed e.g. by pkg_add, but not
relevant for cryptographic purposes. pkgsrc/newcerts/00.pem is the
public key and can be used as trust anchor.
A certificate for signing packages can be created by running
"sh pkgsrc.sh pkgkey". The private key can be found in pkgkey_key.pem
and the certificate in pkgkey_cert.pem.
Similary, "sh pkgsrc.sh pkgsec" will create a certificate/key pair for
signing pkg-vulnerabilities.
How to verify a certificate:
- decode the data with "openssl x509 -text -noout -in newcert.pem"
- "Issuer" is vouching for the identity (and reliability) of "Subject"
- "X509v3 Basic Constraints" should list "CA:FALSE" for all keys that are not allowed
to sign further keys.

28
external/bsd/pkg_install/lib/Makefile vendored Normal file
View file

@ -0,0 +1,28 @@
# $NetBSD: Makefile,v 1.9 2010/04/23 20:56:01 joerg Exp $
# Original from FreeBSD, no rcs id.
LIBISPRIVATE= yes
LIB= install
SRCS= automatic.c conflicts.c dewey.c \
fexec.c file.c global.c gpgsig.c iterate.c license.c lpkg.c \
opattern.c parse-config.c pkcs7.c pkg_signature.c \
pkgdb.c pkg_io.c plist.c remove.c \
str.c version.c var.c vulnerabilities-file.c xwrapper.c
MAN= pkg_install.conf.5 pkg_summary.5
version.o: version.h version.c
.include <bsd.init.mk>
pkg_install.conf.5: ${DIST}/lib/pkg_install.conf.5.in
${TOOL_SED} -e 's,@SYSCONFDIR@,/etc,' \
${DIST}/lib/pkg_install.conf.5.in > ${.TARGET}
.PATH: ${DIST}/lib
CLEANFILES+= pkg_install.conf.5
CPPFLAGS+= -DNETBSD
.include <bsd.lib.mk>

197
external/bsd/pkg_install/lib/config.h vendored Normal file
View file

@ -0,0 +1,197 @@
/* lib/config.h. Generated from config.h.in by configure. */
/* lib/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the <assert.h> header file. */
#define HAVE_ASSERT_H 1
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H 1
/* Define to 1 if you have the <dirent.h> header file. */
#define HAVE_DIRENT_H 1
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <err.h> header file. */
#define HAVE_ERR_H 1
/* Define to 1 if you have the <fnctl.h> header file. */
/* #undef HAVE_FNCTL_H */
/* Define to 1 if you have the <fnmatch.h> header file. */
#define HAVE_FNMATCH_H 1
/* Define to 1 if you have the <glob.h> header file. */
#define HAVE_GLOB_H 1
/* Define to 1 if you have the <grp.h> header file. */
#define HAVE_GRP_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `db' library (-ldb). */
/* #undef HAVE_LIBDB */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#define HAVE_SYS_CDEFS_H 1
/* Define to 1 if you have the <sys/file.h> header file. */
#define HAVE_SYS_FILE_H 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/queue.h> header file. */
#define HAVE_SYS_QUEUE_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/utsname.h> header file. */
#define HAVE_SYS_UTSNAME_H 1
/* Define to 1 if you have the <sys/wait.h> header file. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vfork' function. */
#define HAVE_VFORK 1
/* Define to 1 if you have the <vis.h> header file. */
#define HAVE_VIS_H 1
/* Define to 1 if the `z' modifider for printf is missing. */
/* #undef MISSING_SIZE_T_SUPPORT */
/* Defined when PRIu64 is missing or broken */
/* #undef NEED_PRI_MACRO */
/* Defined when to retain only the numeric OS version */
/* #undef NUMERIC_VERSION_ONLY */
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "joerg@NetBSD.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "pkg_install"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "pkg_install 20090911"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pkg_install"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "20090911"
/* The size of `int', as computed by sizeof. */
#define SIZEOF_INT 4
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG 8
/* The size of `long long', as computed by sizeof. */
#define SIZEOF_LONG_LONG 8
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 8
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
/* #undef _UINT32_T */
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
/* #undef _UINT64_T */
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
/* #undef _UINT8_T */
/* Define to the type of an unsigned integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint16_t */
/* Define to the type of an unsigned integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint32_t */
/* Define to the type of an unsigned integer type of width exactly 64 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint64_t */
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint8_t */
#if !HAVE_VFORK
# define vfork fork
#endif
#ifndef MISSING_SIZE_T_SUPPORT
# define PRIzu "zu"
#elif SIZEOF_SIZE_T == SIZEOF_INT
# define PRIzu "u"
#elif SIZEOF_SIZE_T == SIZEOF_LONG
# define PRIzu "lu"
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
# define PRIzu "llu"
#else
# errror "Unknown size_t size"
#endif

View file

@ -0,0 +1,8 @@
/* $NetBSD: nbcompat.h,v 1.1 2008/09/30 19:19:56 joerg Exp $ */
/*
* In pkgsrc, libnbcompat is used to provide compatibility functions.
* This is not needed on native NetBSD, so provide an empty header.
*/
#include <sys/statvfs.h>

View file

@ -0,0 +1,13 @@
#!/bin/sh
# $NetBSD: prepare-import.sh,v 1.4 2013/04/20 15:30:34 wiz Exp $
#
# Copy new pkgsrc/pkgtools/pkg_install/files to dist.
# Run this script and check for additional files and
# directories to prune, only relevant content is included.
set -e
cd dist
rm -f Makefile.in README config* install-sh tkpkg
rm -f */Makefile.in */*.cat*
rm -rf CVS */CVS view

View file

@ -0,0 +1,6 @@
# $NetBSD: Makefile,v 1.3 2009/02/02 20:47:21 joerg Exp $
SUBDIR= bpm pkg_add pkg_admin pkg_create \
pkg_delete pkg_info
.include <bsd.subdir.mk>

View file

@ -0,0 +1,25 @@
# $NetBSD: Makefile.inc,v 1.3 2010/11/05 09:09:01 he Exp $
.include <bsd.own.mk>
.include "${.PARSEDIR}/../Makefile.inc"
LIBINSTALL != cd ${.PARSEDIR}/../lib && ${PRINTOBJDIR}
BINDIR?= /usr/sbin
CPPFLAGS+= -DBINDIR='"${BINDIR}"'
DPADD+= ${LIBINSTALL}/libinstall.a
LDADD+= -L${LIBINSTALL} -linstall -ltermcap
DPADD+= ${LIBFETCH} ${LIBSSL} ${LIBCRYPTO}
LDADD+= -lfetch -lssl -lcrypto
DPADD+= ${LIBARCHIVE}
LDADD+= -larchive
DPADD+= ${LIBZ} ${LIBBZ2}
LDADD+= -lz -lbz2
DPADD+= ${LIBLZMA}
LDADD+= -llzma

View file

@ -0,0 +1,15 @@
# $NetBSD: Makefile,v 1.1 2008/09/30 19:19:56 joerg Exp $
SCRIPTS= bpm.sh
MAN= bpm.1
.include <bsd.init.mk>
.PATH: ${DIST}/bpm
CLEANFILES+= bpm.sh
bpm.sh: ${DIST}/bpm/bpm.sh.in
${TOOL_CAT} ${DIST}/bpm/bpm.sh.in > ${.TARGET}
.include <bsd.prog.mk>

View file

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.2 2009/02/02 20:47:21 joerg Exp $
# Original from FreeBSD, no rcs id.
PROG= pkg_add
SRCS= main.c perform.c
.include <bsd.init.mk>
.PATH: ${DIST}/add
CPPFLAGS+= -DMACHINE_ARCH=\"${MACHINE_ARCH}\"
.include <bsd.prog.mk>

View file

@ -0,0 +1,22 @@
# $NetBSD: Makefile,v 1.2 2009/02/02 20:47:21 joerg Exp $
PROG= pkg_admin
SRCS= audit.c check.c main.c
SCRIPTS= audit-packages.sh download-vulnerability-list.sh
CLEANFILES= audit-packages.sh download-vulnerability-list.sh
audit-packages.sh: audit-packages.sh.in
sed -e 's|@PKG_ADMIN@|/usr/sbin/pkg_admin|' \
${DIST}/admin/audit-packages.sh.in > $@
download-vulnerability-list.sh: download-vulnerability-list.sh.in
sed -e 's|@PKG_ADMIN@|/usr/sbin/pkg_admin|' \
${DIST}/admin/download-vulnerability-list.sh.in > $@
LINK_PKGVUL= yes
.include <bsd.init.mk>
.PATH: ${DIST}/admin
.include <bsd.prog.mk>

View file

@ -0,0 +1,11 @@
# $NetBSD: Makefile,v 1.2 2009/02/02 20:47:21 joerg Exp $
# Original from FreeBSD, no rcs id.
PROG= pkg_create
SRCS= main.c perform.c pl.c util.c build.c
.include <bsd.init.mk>
.PATH: ${DIST}/create
.include <bsd.prog.mk>

View file

@ -0,0 +1,10 @@
# $NetBSD: Makefile,v 1.2 2009/02/25 21:23:17 joerg Exp $
# Original from FreeBSD, no rcs id.
PROG= pkg_delete
.include <bsd.init.mk>
.PATH: ${DIST}/delete
.include <bsd.prog.mk>

View file

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.3 2011/05/26 12:56:26 joerg Exp $
# Original from FreeBSD, no rcs id
PROG= pkg_info
SRCS= main.c perform.c show.c
.include <bsd.init.mk>
.PATH: ${DIST}/info
CWARNFLAGS.clang+= -Wno-format-security
.include <bsd.prog.mk>