After around 20 years of duty it is time for pkg_install to retire

This commit is contained in:
Baptiste Daroussin 2013-10-31 13:00:35 +00:00
parent 8cf0e32801
commit c92d635ad3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=257444
65 changed files with 20 additions and 11728 deletions

View File

@ -38,6 +38,23 @@
# xargs -n1 | sort | uniq -d;
# done
# 20131031: pkg_install has been removed
OLD_FILES+=etc/periodic/daily/220.backup-pkgdb
OLD_FILES+=etc/periodic/daily/490.status-pkg-changes
OLD_FILES+=etc/periodic/security/460.chkportsum
OLD_FILES+=etc/periodic/weekly/400.status-pkg
OLD_FILES+=usr/sbin/pkg_add
OLD_FILES+=usr/sbin/pkg_create
OLD_FILES+=usr/sbin/pkg_delete
OLD_FILES+=usr/sbin/pkg_info
OLD_FILES+=usr/sbin/pkg_updating
OLD_FILES+=usr/sbin/pkg_version
OLD_FILES+=usr/share/man/man1/pkg_add.1.gz
OLD_FILES+=usr/share/man/man1/pkg_create.1.gz
OLD_FILES+=usr/share/man/man1/pkg_delete.1.gz
OLD_FILES+=usr/share/man/man1/pkg_info.1.gz
OLD_FILES+=usr/share/man/man1/pkg_updating.1.gz
OLD_FILES+=usr/share/man/man1/pkg_version.1.gz
# 20131030: /etc/keys moved to /usr/share/keys
OLD_DIRS+=etc/keys
OLD_DIRS+=etc/keys/pkg

View File

@ -1,51 +0,0 @@
#!/bin/sh
#
# $FreeBSD$
#
# If there is a global system configuration file, suck it in.
#
if [ -r /etc/defaults/periodic.conf ]
then
. /etc/defaults/periodic.conf
source_periodic_confs
fi
rc=0
case "$daily_backup_pkgdb_enable" in
[Yy][Ee][Ss])
bak="${daily_backup_pkgdb_dir:-/var/backups}"
bak_file="${bak}/pkgdb.bak.tbz"
pkg_dbdir=`make -f/usr/share/mk/bsd.port.mk -V PKG_DBDIR 2>/dev/null` ||
pkg_dbdir=/var/db/pkg
if [ ! -d "$bak" ]
then
install -d -o root -g wheel -m 750 $bak || {
echo '$daily_backup_pkgdb_enable is enabled but' \
"$daily_backup_pkgdb_dir doesn't exist" ;
exit 2 ; }
fi
echo ''
echo 'Backing up package db directory:'
new_bak_file=`mktemp ${bak_file}-XXXXX`
if tar -cjHf "${new_bak_file}" "$pkg_dbdir" 2>/dev/null; then
chmod 644 "${new_bak_file}"
if [ -e "${bak_file}.2" -a -e "${bak_file}" ]; then
unlink "${bak_file}.2"
mv "${bak_file}" "${bak_file}.2"
fi
[ -e "${bak_file}" ] && mv "${bak_file}" "${bak_file}.2"
mv "${new_bak_file}" "${bak_file}"
else
rc=3
fi ;;
esac
exit $rc

View File

@ -1,43 +0,0 @@
#!/bin/sh
#
# $FreeBSD$
#
# If there is a global system configuration file, suck it in.
#
if [ -r /etc/defaults/periodic.conf ]; then
. /etc/defaults/periodic.conf
source_periodic_confs
fi
case "$daily_status_pkg_changes_enable" in
[Yy][Ee][Ss])
if [ ! -f /usr/sbin/pkg_info ]; then
echo '$daily_status_pkg_changes_enable is enabled but' \
"/usr/sbin/pkg_info doesn't exist"
rc=2
else
bak=/var/backups
rc=0
if [ -f $bak/pkg_info.bak ]; then
mv -f $bak/pkg_info.bak $bak/pkg_info.bak2
fi
${pkg_info:-/usr/sbin/pkg_info} > $bak/pkg_info.bak
cmp -sz $bak/pkg_info.bak $bak/pkg_info.bak2
if [ $? -eq 1 ]; then
echo ""
echo "Changes in installed packages:"
diff -U 0 $bak/pkg_info.bak2 $bak/pkg_info.bak \
| grep '^[-+][^-+]' | sort -k 1.2
fi
fi
;;
*)
rc=0
;;
esac
exit $rc

View File

@ -36,11 +36,6 @@ FILES+= 130.clean-msgs
FILES+= 480.status-ntpd
.endif
.if ${MK_PKGTOOLS} != "no"
FILES+= 220.backup-pkgdb \
490.status-pkg-changes
.endif
.if ${MK_RCMDS} != "no"
FILES+= 140.clean-rwho \
430.status-rwho

View File

@ -1,66 +0,0 @@
#!/bin/sh -
#
# Copyright (c) 2010 The FreeBSD Project
# 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 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 AUTHOR 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$
#
if [ -r /etc/defaults/periodic.conf ]
then
. /etc/defaults/periodic.conf
source_periodic_confs
fi
. /etc/periodic/security/security.functions
security_daily_compat_var security_status_chkportsum_enable
rc=0
echo ""
echo 'Checking for ports with mismatched checksums:'
if check_yesno_period security_status_chkportsum_enable
then
set -f
pkg_info -ga 2>/dev/null | \
while IFS= read -r line; do
set -- $line
case $1 in
Information)
case $2 in
for) name="${3%%:}" ;;
*) name='??' ;;
esac
;;
Mismatched|'') ;;
*) [ -n "${name}" ] &&
echo "${name}: ${line%% fails the original MD5 checksum}"
;;
esac
done
fi
exit $rc

View File

@ -29,8 +29,4 @@ FILES+= 500.ipfwdenied \
FILES+= 520.pfdenied
.endif
.if ${MK_PKGTOOLS} != "no"
FILES+= 460.chkportsum
.endif
.include <bsd.prog.mk>

View File

@ -1,33 +0,0 @@
#!/bin/sh -
#
# $FreeBSD$
#
# If there is a global system configuration file, suck it in.
#
if [ -r /etc/defaults/periodic.conf ]
then
. /etc/defaults/periodic.conf
source_periodic_confs
fi
case "$weekly_status_pkg_enable" in
[Yy][Ee][Ss])
echo ""
echo "Check for out of date packages:"
rc=$(${pkg_version:-pkg_version} -v ${pkg_version_index} |
sed -n -e 's/^\([^ ]*\) *< */ \1 /p' \
-e '/^[^ ]*-\([^ ]*\) *\* *multiple versions.*[ ,]\1[,)].*/d' \
-e 's/^\([^ ]*\) *\* *multiple versions.*\((.*\)/ \1 needs updating \2/p' \
-e 's/^\(bsdpan-[^ ]*\) *? *unknown in index/ \1 may be outdated - check CPAN version manually/p' \
-e 's/^\([^ ]*-[^ ]*\) *? *unknown in index/ \1 is obsolete/p' \
-e 's/^\([^ ]*-[^ ]*\) *? *\(orphaned:.*\)$/ \1 was \2/p' |
tee /dev/stderr |
wc -l)
[ $rc -gt 1 ] && rc=1;;
*) rc=0;;
esac
exit $rc

View File

@ -16,8 +16,4 @@ FILES+= 310.locate
FILES+= 320.whatis 330.catman
.endif
.if ${MK_PKGTOOLS} != "no"
FILES+= 400.status-pkg
.endif
.include <bsd.prog.mk>

View File

@ -1,7 +1,7 @@
.\" DO NOT EDIT-- this file is automatically generated.
.\" from FreeBSD: head/tools/build/options/makeman 255964 2013-10-01 07:22:04Z des
.\" $FreeBSD$
.Dd October 25, 2013
.Dd October 31, 2013
.Dt SRC.CONF 5
.Os
.Sh NAME
@ -860,15 +860,10 @@ When set, it also enforces the following options:
.Va WITHOUT_AUTHPF
.El
.It Va WITHOUT_PKGBOOTSTRAP
.\" from FreeBSD: head/tools/build/options/WITHOUT_PKGBOOTSTRAP 238023 2012-07-02 20:26:11Z marcel
.\" $FreeBSD: head/tools/build/options/WITHOUT_PKGBOOTSTRAP 257440 2013-10-31 12:05:37Z bapt
Set to not build
.Xr pkg 1
.Xr pkg 7
bootstrap tool
.It Va WITH_PKGTOOLS
.\" from FreeBSD: head/tools/build/options/WITH_PKGTOOLS 253305 2013-07-12 23:11:17Z bapt
Set to build
.Xr pkg_add 8
and related programs.
.It Va WITHOUT_PMC
.\" from FreeBSD: head/tools/build/options/WITHOUT_PMC 183242 2008-09-21 22:02:26Z sam
Set to not build

View File

@ -3613,29 +3613,6 @@ OLD_FILES+=usr/sbin/pkg
OLD_FILES+=usr/share/man/man7/pkg.7.gz
.endif
.if ${MK_PKGTOOLS} == no
OLD_FILES+=etc/periodic/daily/220.backup-pkgdb
OLD_FILES+=etc/periodic/daily/490.status-pkg-changes
OLD_FILES+=etc/periodic/security/460.chkportsum
OLD_FILES+=etc/periodic/weekly/400.status-pkg
OLD_FILES+=usr/include/pkg.h
OLD_FILES+=usr/lib/libpkg.a
OLD_FILES+=usr/lib/libpkg.so
OLD_LIBS+=usr/lib/libpkg.so.0
OLD_FILES+=usr/sbin/pkg_add
OLD_FILES+=usr/sbin/pkg_create
OLD_FILES+=usr/sbin/pkg_delete
OLD_FILES+=usr/sbin/pkg_info
OLD_FILES+=usr/sbin/pkg_updating
OLD_FILES+=usr/sbin/pkg_version
OLD_FILES+=usr/share/man/man1/pkg_add.1.gz
OLD_FILES+=usr/share/man/man1/pkg_create.1.gz
OLD_FILES+=usr/share/man/man1/pkg_delete.1.gz
OLD_FILES+=usr/share/man/man1/pkg_info.1.gz
OLD_FILES+=usr/share/man/man1/pkg_updating.1.gz
OLD_FILES+=usr/share/man/man1/pkg_version.1.gz
.endif
.if ${MK_PORTSNAP} == no
OLD_FILES+=etc/portsnap.conf
OLD_FILES+=usr/libexec/make_index

View File

@ -1,4 +0,0 @@
.\" $FreeBSD$
Set to build
.Xr pkg_add 8
and related programs.

View File

@ -251,10 +251,6 @@ SUBDIR+= ftp-proxy
SUBDIR+= pkg
.endif
.if ${MK_PKGTOOLS} != "no"
SUBDIR+= pkg_install
.endif
# XXX MK_TOOLCHAIN?
.if ${MK_PMC} != "no"
SUBDIR+= pmcannotate

View File

@ -1,20 +0,0 @@
# $FreeBSD$
.include <bsd.own.mk>
SUBDIR= lib add create delete info updating version
.include <bsd.subdir.mk>
DATE!= grep PKG_INSTALL_VERSION ${.CURDIR}/lib/lib.h | sed 's|.*[ ]||'
distfile: clean
@(cd ${.CURDIR}/..; \
cp -r pkg_install pkg_install-${DATE}; \
tar -czf pkg_install/pkg_install-${DATE}.tar.gz \
--exclude .#* --exclude *~ --exclude CVS \
--exclude .svn --exclude pkg_install-*.tar.gz \
pkg_install-${DATE}; \
rm -rf pkg_install-${DATE})

View File

@ -1,17 +0,0 @@
# $FreeBSD$
.include <bsd.own.mk>
LIBINSTALL= ${.OBJDIR}/../lib/libinstall.a
DPADD+= ${LIBUTIL}
LDADD+= -lutil
.if ${MK_OPENSSL} != "no" && \
defined(LDADD) && ${LDADD:M-lfetch} != ""
DPADD+= ${LIBSSL} ${LIBCRYPTO}
LDADD+= -lssl -lcrypto
.endif
# Inherit BINDIR from one level up.
.include "../Makefile.inc"

View File

@ -1,10 +0,0 @@
$FreeBSD$
This is the pkg_install suite of tools for doing maintenance of
software "packages". More documentation is available in the man pages
for each individual command.
This code was written by Jordan Hubbard for FreeBSD, snatched and
mildly reshaped by John Kohl in NetBSD and the changes taken back into
FreeBSD again by Jordan, who then proceeded to add another couple
of dozen features on top. Whee! :-)

View File

@ -1,14 +0,0 @@
# $FreeBSD$
PROG= pkg_add
SRCS= main.c perform.c futil.c extract.c
CFLAGS+= -I${.CURDIR}/../lib
WARNS?= 3
WFORMAT?= 1
DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD}
LDADD= ${LIBINSTALL} -lfetch -lmd
.include <bsd.prog.mk>

View File

@ -1,48 +0,0 @@
/* $FreeBSD$ */
/*
* 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
* 18 July 1993
*
* Include and define various things wanted by the add command.
*
*/
#ifndef _INST_ADD_H_INCLUDE
#define _INST_ADD_H_INCLUDE
typedef enum { NORMAL, MASTER, SLAVE } add_mode_t;
extern char *Prefix;
extern Boolean PrefixRecursive;
extern Boolean NoInstall;
extern Boolean NoRecord;
extern Boolean FailOnAlreadyInstalled;
extern Boolean KeepPackage;
extern Boolean IgnoreDeps;
extern char *Mode;
extern char *Owner;
extern char *Group;
extern char *Directory;
extern char *PkgName;
extern char *PkgAddCmd;
extern char FirstPen[];
extern add_mode_t AddMode;
int make_hierarchy(char *, Boolean);
void extract_plist(const char *, Package *);
void apply_perms(const char *, const char *);
#endif /* _INST_ADD_H_INCLUDE */

View File

@ -1,288 +0,0 @@
/*
* 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
* 18 July 1993
*
* This is the package extraction code for the add module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <ctype.h>
#include <err.h>
#include "lib.h"
#include "add.h"
#define STARTSTRING "/usr/bin/tar cf -"
#define TOOBIG(str) \
(((int)strlen(str) + FILENAME_MAX + where_count > maxargs) ||\
((int)strlen(str) + FILENAME_MAX + perm_count > maxargs))
#define PUSHOUT(todir) /* push out string */ \
if (where_count > (int)sizeof(STARTSTRING)-1) { \
strcat(where_args, "|/usr/bin/tar --unlink -xpPf - -C "); \
strcat(where_args, todir); \
if (system(where_args)) { \
cleanup(0); \
errx(2, "%s: can not invoke %ld byte tar pipeline: %s", \
__func__, (long)strlen(where_args), where_args); \
} \
strcpy(where_args, STARTSTRING); \
where_count = sizeof(STARTSTRING)-1; \
} \
if (perm_count) { \
apply_perms(todir, perm_args); \
perm_args[0] = 0;\
perm_count = 0; \
}
static void
rollback(const char *name, const char *home, PackingList start, PackingList stop)
{
PackingList q;
char try[FILENAME_MAX], bup[FILENAME_MAX];
const char *dir;
char *prefix = NULL;
dir = home;
for (q = start; q != stop; q = q->next) {
if (q->type == PLIST_FILE) {
snprintf(try, FILENAME_MAX, "%s/%s", dir, q->name);
if (make_preserve_name(bup, FILENAME_MAX, name, try) && fexists(bup)) {
(void)chflags(try, 0);
(void)unlink(try);
if (rename(bup, try))
warnx("rollback: unable to rename %s back to %s", bup, try);
}
}
else if (q->type == PLIST_CWD) {
if (!prefix)
prefix = q->name;
if (q->name == NULL)
q->name = prefix;
else if (strcmp(q->name, "."))
dir = q->name;
else
dir = home;
}
}
}
#define add_char(buf, len, pos, ch) do {\
if ((pos) < (len)) { \
buf[(pos)] = (ch); \
buf[(pos) + 1] = '\0'; \
} \
++(pos); \
} while (0)
static int
add_arg(char *buf, int len, const char *str)
{
int i = 0;
add_char(buf, len, i, ' ');
for (; *str != '\0'; ++str) {
if (!isalnum(*str) && *str != '/' && *str != '.' && *str != '-')
add_char(buf, len, i, '\\');
add_char(buf, len, i, *str);
}
return (i);
}
void
extract_plist(const char *home, Package *pkg)
{
PackingList p = pkg->head;
char *last_file, *prefix = NULL;
char *where_args, *perm_args, *last_chdir;
long maxargs;
int where_count = 0, perm_count = 0, add_count;
Boolean preserve;
maxargs = sysconf(_SC_ARG_MAX) / 2; /* Just use half the argument space */
where_args = alloca(maxargs);
if (!where_args) {
cleanup(0);
errx(2, "%s: can't get argument list space", __func__);
}
perm_args = alloca(maxargs);
if (!perm_args) {
cleanup(0);
errx(2, "%s: can't get argument list space", __func__);
}
strcpy(where_args, STARTSTRING);
where_count = sizeof(STARTSTRING)-1;
perm_args[0] = 0;
last_chdir = 0;
preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE;
/* Reset the world */
Owner = NULL;
Group = NULL;
Mode = NULL;
last_file = NULL;
Directory = (char *)home;
/* Do it */
while (p) {
char cmd[FILENAME_MAX];
switch(p->type) {
case PLIST_NAME:
PkgName = p->name;
if (Verbose)
printf("extract: Package name is %s\n", p->name);
break;
case PLIST_FILE:
last_file = p->name;
if (Verbose)
printf("extract: %s/%s\n", Directory, p->name);
if (!Fake) {
char try[FILENAME_MAX];
/* first try to rename it into place */
snprintf(try, FILENAME_MAX, "%s/%s", Directory, p->name);
if (fexists(try)) {
(void)chflags(try, 0); /* XXX hack - if truly immutable, rename fails */
if (preserve && PkgName) {
char pf[FILENAME_MAX];
if (make_preserve_name(pf, FILENAME_MAX, PkgName, try)) {
if (rename(try, pf)) {
warnx(
"unable to back up %s to %s, aborting pkg_add",
try, pf);
rollback(PkgName, home, pkg->head, p);
return;
}
}
}
}
if (rename(p->name, try) == 0) {
/* try to add to list of perms to be changed and run in bulk. */
if (p->name[0] == '/' || TOOBIG(p->name)) {
PUSHOUT(Directory);
}
add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name);
if (add_count < 0 || add_count >= maxargs - perm_count) {
cleanup(0);
errx(2, "%s: oops, miscounted strings!", __func__);
}
perm_count += add_count;
}
else {
/* rename failed, try copying with a big tar command */
if (last_chdir != Directory) {
if (last_chdir == NULL) {
PUSHOUT(Directory);
} else {
PUSHOUT(last_chdir);
}
last_chdir = Directory;
}
else if (p->name[0] == '/' || TOOBIG(p->name)) {
PUSHOUT(Directory);
}
add_count = add_arg(&where_args[where_count], maxargs - where_count, p->name);
if (add_count < 0 || add_count >= maxargs - where_count) {
cleanup(0);
errx(2, "%s: oops, miscounted strings!", __func__);
}
where_count += add_count;
add_count = add_arg(&perm_args[perm_count], maxargs - perm_count, p->name);
if (add_count < 0 || add_count >= maxargs - perm_count) {
cleanup(0);
errx(2, "%s: oops, miscounted strings!", __func__);
}
perm_count += add_count;
}
}
break;
case PLIST_CWD:
if (!prefix)
prefix = p->name;
if (p->name == NULL)
p->name = strdup(prefix);
if (Verbose)
printf("extract: CWD to %s\n", p->name);
PUSHOUT(Directory);
if (strcmp(p->name, ".")) {
if (!Fake && make_hierarchy(p->name, TRUE) == FAIL) {
cleanup(0);
errx(2, "%s: unable to cwd to '%s'", __func__, p->name);
}
Directory = p->name;
}
else
Directory = (char *)home;
break;
case PLIST_CMD:
if ((strstr(p->name, "%B") || strstr(p->name, "%F") ||
strstr(p->name, "%f")) && last_file == NULL) {
cleanup(0);
errx(2, "%s: no last file specified for '%s' command",
__func__, p->name);
}
if (strstr(p->name, "%D") && Directory == NULL) {
cleanup(0);
errx(2, "%s: no directory specified for '%s' command",
__func__, p->name);
}
format_cmd(cmd, FILENAME_MAX, p->name, Directory, last_file);
PUSHOUT(Directory);
if (Verbose)
printf("extract: execute '%s'\n", cmd);
if (!Fake && system(cmd))
warnx("command '%s' failed", cmd);
break;
case PLIST_CHMOD:
PUSHOUT(Directory);
Mode = p->name;
break;
case PLIST_CHOWN:
PUSHOUT(Directory);
Owner = p->name;
break;
case PLIST_CHGRP:
PUSHOUT(Directory);
Group = p->name;
break;
case PLIST_COMMENT: /* FALLTHROUGH */
case PLIST_NOINST:
break;
case PLIST_IGNORE:
p = p->next;
break;
default:
break;
}
p = p->next;
}
PUSHOUT(Directory);
}

View File

@ -1,98 +0,0 @@
/*
* 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
* 18 July 1993
*
* Miscellaneous file access utilities.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include "lib.h"
#include "add.h"
/*
* Assuming dir is a desired directory name, make it and all intervening
* directories necessary.
*/
int
make_hierarchy(char *dir, Boolean set_perm)
{
char *cp1, *cp2;
if (dir[0] == '/')
cp1 = cp2 = dir + 1;
else
cp1 = cp2 = dir;
while (cp2) {
if ((cp2 = strchr(cp1, '/')) !=NULL )
*cp2 = '\0';
if (fexists(dir)) {
if (!isdir(dir)) {
if (cp2)
*cp2 = '/';
return FAIL;
}
}
else {
if (mkdir(dir, 0777) < 0) {
if (cp2)
*cp2 = '/';
return FAIL;
}
if (set_perm)
apply_perms(NULL, dir);
}
/* Put it back */
if (cp2) {
*cp2 = '/';
cp1 = cp2 + 1;
}
}
return SUCCESS;
}
/* Using permission defaults, apply them as necessary */
void
apply_perms(const char *dir, const char *arg)
{
const char *cd_to;
if (!dir || *arg == '/') /* absolute path? */
cd_to = "/";
else
cd_to = dir;
if (Mode)
if (vsystem("cd %s && /bin/chmod -R %s %s", cd_to, Mode, arg))
warnx("couldn't change modes of '%s' to '%s'", arg, Mode);
if (Owner && Group) {
if (vsystem("cd %s && /usr/sbin/chown -R %s:%s %s", cd_to, Owner, Group, arg))
warnx("couldn't change owner/group of '%s' to '%s:%s'",
arg, Owner, Group);
return;
}
if (Owner) {
if (vsystem("cd %s && /usr/sbin/chown -R %s %s", cd_to, Owner, arg))
warnx("couldn't change owner of '%s' to '%s'", arg, Owner);
return;
} else if (Group)
if (vsystem("cd %s && /usr/bin/chgrp -R %s %s", cd_to, Group, arg))
warnx("couldn't change group of '%s' to '%s'", arg, Group);
}

View File

@ -1,376 +0,0 @@
/*
*
* 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
* 18 July 1993
*
* This is the add module.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/sysctl.h>
#include <err.h>
#include <getopt.h>
#include "lib.h"
#include "add.h"
char *Prefix = NULL;
Boolean PrefixRecursive = FALSE;
char *Chroot = NULL;
Boolean NoInstall = FALSE;
Boolean NoRecord = FALSE;
Boolean Remote = FALSE;
Boolean KeepPackage = FALSE;
Boolean FailOnAlreadyInstalled = TRUE;
Boolean IgnoreDeps = FALSE;
char *Mode = NULL;
char *Owner = NULL;
char *Group = NULL;
char *PkgName = NULL;
char *PkgAddCmd = NULL;
char *Directory = NULL;
char FirstPen[FILENAME_MAX];
add_mode_t AddMode = NORMAL;
char **pkgs;
struct {
int lowver; /* Lowest version number to match */
int hiver; /* Highest version number to match */
const char *directory; /* Directory it lives in */
} releases[] = {
{ 410000, 410000, "/packages-4.1-release" },
{ 420000, 420000, "/packages-4.2-release" },
{ 430000, 430000, "/packages-4.3-release" },
{ 440000, 440000, "/packages-4.4-release" },
{ 450000, 450000, "/packages-4.5-release" },
{ 460000, 460001, "/packages-4.6-release" },
{ 460002, 460099, "/packages-4.6.2-release" },
{ 470000, 470099, "/packages-4.7-release" },
{ 480000, 480099, "/packages-4.8-release" },
{ 490000, 490099, "/packages-4.9-release" },
{ 491000, 491099, "/packages-4.10-release" },
{ 492000, 492099, "/packages-4.11-release" },
{ 500000, 500099, "/packages-5.0-release" },
{ 501000, 501099, "/packages-5.1-release" },
{ 502000, 502009, "/packages-5.2-release" },
{ 502010, 502099, "/packages-5.2.1-release" },
{ 503000, 503099, "/packages-5.3-release" },
{ 504000, 504099, "/packages-5.4-release" },
{ 505000, 505099, "/packages-5.5-release" },
{ 600000, 600099, "/packages-6.0-release" },
{ 601000, 601099, "/packages-6.1-release" },
{ 602000, 602099, "/packages-6.2-release" },
{ 603000, 603099, "/packages-6.3-release" },
{ 604000, 604099, "/packages-6.4-release" },
{ 700000, 700099, "/packages-7.0-release" },
{ 701000, 701099, "/packages-7.1-release" },
{ 702000, 702099, "/packages-7.2-release" },
{ 703000, 703099, "/packages-7.3-release" },
{ 704000, 704099, "/packages-7.4-release" },
{ 800000, 800499, "/packages-8.0-release" },
{ 801000, 801499, "/packages-8.1-release" },
{ 802000, 802499, "/packages-8.2-release" },
{ 803000, 803499, "/packages-8.3-release" },
{ 900000, 900499, "/packages-9.0-release" },
{ 901000, 901499, "/packages-9.1-release" },
{ 902000, 902499, "/packages-9.2-release" },
{ 300000, 399000, "/packages-3-stable" },
{ 400000, 499000, "/packages-4-stable" },
{ 502100, 502128, "/packages-5-current" },
{ 503100, 599000, "/packages-5-stable" },
{ 600100, 699000, "/packages-6-stable" },
{ 700100, 799000, "/packages-7-stable" },
{ 800500, 899000, "/packages-8-stable" },
{ 900500, 999000, "/packages-9-stable" },
{ 1000000, 1099000, "/packages-10-current" },
{ 0, 9999999, "/packages-current" },
{ 0, 0, NULL }
};
static char *getpackagesite(void);
int getosreldate(void);
static void usage(void);
static char opts[] = "hviIRfFnrp:P:SMt:C:K";
static struct option longopts[] = {
{ "chroot", required_argument, NULL, 'C' },
{ "dry-run", no_argument, NULL, 'n' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "keep", no_argument, NULL, 'K' },
{ "master", no_argument, NULL, 'M' },
{ "no-deps", no_argument, NULL, 'i' },
{ "no-record", no_argument, NULL, 'R' },
{ "no-script", no_argument, NULL, 'I' },
{ "prefix", required_argument, NULL, 'p' },
{ "remote", no_argument, NULL, 'r' },
{ "template", required_argument, NULL, 't' },
{ "slave", no_argument, NULL, 'S' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
int
main(int argc, char **argv)
{
int ch, error;
char **start;
char *cp, *packagesite = NULL, *remotepkg = NULL, *ptr;
static char temppackageroot[MAXPATHLEN];
static char pkgaddpath[MAXPATHLEN];
if (*argv[0] != '/' && strchr(argv[0], '/') != NULL)
PkgAddCmd = realpath(argv[0], pkgaddpath);
else
PkgAddCmd = argv[0];
start = argv;
while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
switch(ch) {
case 'v':
Verbose++;
break;
case 'p':
Prefix = optarg;
PrefixRecursive = FALSE;
break;
case 'P':
Prefix = optarg;
PrefixRecursive = TRUE;
break;
case 'I':
NoInstall = TRUE;
break;
case 'R':
NoRecord = TRUE;
break;
case 'f':
Force = TRUE;
break;
case 'F':
FailOnAlreadyInstalled = FALSE;
break;
case 'K':
KeepPackage = TRUE;
break;
case 'n':
Fake = TRUE;
break;
case 'r':
Remote = TRUE;
break;
case 't':
if (strlcpy(FirstPen, optarg, sizeof(FirstPen)) >= sizeof(FirstPen))
errx(1, "-t Argument too long.");
break;
case 'S':
AddMode = SLAVE;
break;
case 'M':
AddMode = MASTER;
break;
case 'C':
Chroot = optarg;
break;
case 'i':
IgnoreDeps = TRUE;
break;
case 'h':
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (AddMode != SLAVE) {
pkgs = (char **)malloc((argc+1) * sizeof(char *));
for (ch = 0; ch <= argc; pkgs[ch++] = NULL) ;
/* Get all the remaining package names, if any */
for (ch = 0; *argv; ch++, argv++) {
char temp[MAXPATHLEN];
if (Remote) {
if ((packagesite = getpackagesite()) == NULL)
errx(1, "package name too long");
if (strlcpy(temppackageroot, packagesite,
sizeof(temppackageroot)) >= sizeof(temppackageroot))
errx(1, "package name too long");
if (strlcat(temppackageroot, *argv, sizeof(temppackageroot))
>= sizeof(temppackageroot))
errx(1, "package name too long");
remotepkg = temppackageroot;
if (!((ptr = strrchr(remotepkg, '.')) && ptr[1] == 't' &&
(ptr[2] == 'b' || ptr[2] == 'g' || ptr[2] == 'x') &&
ptr[3] == 'z' && !ptr[4])) {
if (getenv("PACKAGESUFFIX")) {
if (strlcat(remotepkg, getenv("PACKAGESUFFIX"),
sizeof(temppackageroot)) >= sizeof(temppackageroot))
errx(1, "package name too long");
} else {
if (strlcat(remotepkg, ".tbz",
sizeof(temppackageroot)) >= sizeof(temppackageroot))
errx(1, "package name too long");
}
}
}
if (!strcmp(*argv, "-")) /* stdin? */
pkgs[ch] = (char *)"-";
else if (isURL(*argv)) { /* preserve URLs */
if (strlcpy(temp, *argv, sizeof(temp)) >= sizeof(temp))
errx(1, "package name too long");
pkgs[ch] = strdup(temp);
}
else if ((Remote) && isURL(remotepkg)) {
if (strlcpy(temp, remotepkg, sizeof(temp)) >= sizeof(temp))
errx(1, "package name too long");
pkgs[ch] = strdup(temp);
} else { /* expand all pathnames to fullnames */
if (fexists(*argv)) /* refers to a file directly */
pkgs[ch] = strdup(realpath(*argv, temp));
else { /* look for the file in the expected places */
if (!(cp = fileFindByPath(NULL, *argv))) {
/* let pkg_do() fail later, so that error is reported */
if (strlcpy(temp, *argv, sizeof(temp)) >= sizeof(temp))
errx(1, "package name too long");
pkgs[ch] = strdup(temp);
} else {
if (strlcpy(temp, cp, sizeof(temp)) >= sizeof(temp))
errx(1, "package name too long");
pkgs[ch] = strdup(temp);
}
}
}
if (packagesite != NULL)
packagesite[0] = '\0';
}
}
/* If no packages, yelp */
if (!ch) {
warnx("missing package name(s)");
usage();
}
else if (ch > 1 && AddMode == MASTER) {
warnx("only one package name may be specified with master mode");
usage();
}
/* Perform chroot if requested */
if (Chroot != NULL) {
if (chdir(Chroot))
errx(1, "chdir to %s failed", Chroot);
if (chroot("."))
errx(1, "chroot to %s failed", Chroot);
}
warnpkgng();
/* Make sure the sub-execs we invoke get found */
setenv("PATH",
"/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
1);
/* Set a reasonable umask */
umask(022);
if ((error = pkg_perform(pkgs)) != 0) {
if (Verbose)
warnx("%d package addition(s) failed", error);
return error;
}
else
return 0;
}
static char *
getpackagesite(void)
{
int reldate, i;
static char sitepath[MAXPATHLEN];
int archmib[] = { CTL_HW, HW_MACHINE_ARCH };
char arch[64];
size_t archlen = sizeof(arch);
if (getenv("PACKAGESITE")) {
if (strlcpy(sitepath, getenv("PACKAGESITE"), sizeof(sitepath))
>= sizeof(sitepath))
return NULL;
return sitepath;
}
if (getenv("PACKAGEROOT")) {
if (strlcpy(sitepath, getenv("PACKAGEROOT"), sizeof(sitepath))
>= sizeof(sitepath))
return NULL;
} else {
if (strlcat(sitepath, "ftp://ftp.freebsd.org", sizeof(sitepath))
>= sizeof(sitepath))
return NULL;
}
if (strlcat(sitepath, "/pub/FreeBSD/ports/", sizeof(sitepath))
>= sizeof(sitepath))
return NULL;
if (sysctl(archmib, 2, arch, &archlen, NULL, 0) == -1)
return NULL;
arch[archlen-1] = 0;
if (strlcat(sitepath, arch, sizeof(sitepath)) >= sizeof(sitepath))
return NULL;
reldate = getosreldate();
for(i = 0; releases[i].directory != NULL; i++) {
if (reldate >= releases[i].lowver && reldate <= releases[i].hiver) {
if (strlcat(sitepath, releases[i].directory, sizeof(sitepath))
>= sizeof(sitepath))
return NULL;
break;
}
}
if (strlcat(sitepath, "/Latest/", sizeof(sitepath)) >= sizeof(sitepath))
return NULL;
return sitepath;
}
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n",
"usage: pkg_add [-viInfFrRMSK] [-t template] [-p prefix] [-P prefix] [-C chrootdir]",
" pkg-name [pkg-name ...]");
exit(1);
}

View File

@ -1,709 +0,0 @@
/*
* 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
* 18 July 1993
*
* This is the main body of the add module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include <paths.h>
#include "lib.h"
#include "add.h"
#include <libgen.h>
#include <signal.h>
#include <sys/wait.h>
static int pkg_do(char *);
static int sanity_check(char *);
static char LogDir[FILENAME_MAX];
static int zapLogDir; /* Should we delete LogDir? */
int
pkg_perform(char **pkgs)
{
int i, err_cnt = 0;
signal(SIGINT, cleanup);
signal(SIGHUP, cleanup);
if (AddMode == SLAVE)
err_cnt = pkg_do(NULL);
else {
for (i = 0; pkgs[i]; i++)
err_cnt += pkg_do(pkgs[i]);
}
return err_cnt;
}
/*
* This is seriously ugly code following. Written very fast!
* [And subsequently made even worse.. Sigh! This code was just born
* to be hacked, I guess.. :) -jkh]
*/
static int
pkg_do(char *pkg)
{
Package Plist;
char pkg_fullname[FILENAME_MAX];
char playpen[FILENAME_MAX];
char extract_contents[FILENAME_MAX];
char *extract;
const char *where_to;
FILE *cfile;
int code;
PackingList p;
struct stat sb;
int inPlace, conflictsfound, errcode;
/* support for separate pre/post install scripts */
int new_m = 0;
char pre_script[FILENAME_MAX] = INSTALL_FNAME;
char post_script[FILENAME_MAX];
char pre_arg[FILENAME_MAX], post_arg[FILENAME_MAX];
char *conflict[2];
char **matched;
int fd;
conflictsfound = 0;
code = 0;
zapLogDir = 0;
LogDir[0] = '\0';
strcpy(playpen, FirstPen);
inPlace = 0;
memset(&Plist, '\0', sizeof(Plist));
/* Are we coming in for a second pass, everything already extracted? */
if (!pkg) {
fgets(playpen, FILENAME_MAX, stdin);
playpen[strlen(playpen) - 1] = '\0'; /* pesky newline! */
if (chdir(playpen) == FAIL) {
warnx("pkg_add in SLAVE mode can't chdir to %s", playpen);
return 1;
}
read_plist(&Plist, stdin);
where_to = playpen;
}
/* Nope - do it now */
else {
/* Is it an ftp://foo.bar.baz/file.t[bg]z specification? */
if (isURL(pkg)) {
if (!(where_to = fileGetURL(NULL, pkg, KeepPackage))) {
warnx("unable to fetch '%s' by URL", pkg);
return 1;
}
strcpy(pkg_fullname, pkg);
cfile = fopen(CONTENTS_FNAME, "r");
if (!cfile) {
warnx(
"unable to open table of contents file '%s' - not a package?",
CONTENTS_FNAME);
goto bomb;
}
read_plist(&Plist, cfile);
fclose(cfile);
}
else {
strcpy(pkg_fullname, pkg); /*
* Copy for sanity's sake,
* could remove pkg_fullname
*/
if (strcmp(pkg, "-")) {
if (stat(pkg_fullname, &sb) == FAIL) {
warnx("can't stat package file '%s'", pkg_fullname);
goto bomb;
}
sprintf(extract_contents, "--fast-read %s", CONTENTS_FNAME);
extract = extract_contents;
}
else {
extract = NULL;
sb.st_size = 100000; /* Make up a plausible average size */
}
if (!(where_to = make_playpen(playpen, sb.st_size * 4)))
errx(1, "unable to make playpen for %lld bytes", (long long)sb.st_size * 4);
/* Since we can call ourselves recursively, keep notes on where we came from */
if (!getenv("_TOP"))
setenv("_TOP", where_to, 1);
if (unpack(pkg_fullname, extract)) {
warnx(
"unable to extract table of contents file from '%s' - not a package?",
pkg_fullname);
goto bomb;
}
cfile = fopen(CONTENTS_FNAME, "r");
if (!cfile) {
warnx(
"unable to open table of contents file '%s' - not a package?",
CONTENTS_FNAME);
goto bomb;
}
read_plist(&Plist, cfile);
fclose(cfile);
/* Extract directly rather than moving? Oh goodie! */
if (find_plist_option(&Plist, "extract-in-place")) {
if (Verbose)
printf("Doing in-place extraction for %s\n", pkg_fullname);
p = find_plist(&Plist, PLIST_CWD);
if (p) {
if (!isdir(p->name) && !Fake) {
if (Verbose)
printf("Desired prefix of %s does not exist, creating..\n", p->name);
vsystem("/bin/mkdir -p %s", p->name);
if (chdir(p->name) == -1) {
warn("unable to change directory to '%s'", p->name);
goto bomb;
}
}
where_to = p->name;
inPlace = 1;
}
else {
warnx(
"no prefix specified in '%s' - this is a bad package!",
pkg_fullname);
goto bomb;
}
}
/*
* Apply a crude heuristic to see how much space the package will
* take up once it's unpacked. I've noticed that most packages
* compress an average of 75%, so multiply by 4 for good measure.
*/
if (!extract && !inPlace && min_free(playpen) < sb.st_size * 4) {
warnx("projected size of %lld exceeds available free space.\n"
"Please set your PKG_TMPDIR variable to point to a location with more\n"
"free space and try again", (long long)sb.st_size * 4);
warnx("not extracting %s\ninto %s, sorry!",
pkg_fullname, where_to);
goto bomb;
}
/* If this is a direct extract and we didn't want it, stop now */
if (inPlace && Fake)
goto success;
/* Finally unpack the whole mess. If extract is null we
already + did so so don't bother doing it again. */
if (extract && unpack(pkg_fullname, NULL)) {
warnx("unable to extract '%s'!", pkg_fullname);
goto bomb;
}
}
/* Check for sanity and dependencies */
if (sanity_check(pkg))
goto bomb;
/* If we're running in MASTER mode, just output the plist and return */
if (AddMode == MASTER) {
printf("%s\n", where_playpen());
write_plist(&Plist, stdout);
return 0;
}
}
/*
* If we have a prefix, delete the first one we see and add this
* one in place of it.
*/
if (Prefix) {
delete_plist(&Plist, FALSE, PLIST_CWD, NULL);
add_plist_top(&Plist, PLIST_CWD, Prefix);
}
setenv(PKG_PREFIX_VNAME, (p = find_plist(&Plist, PLIST_CWD)) ? p->name : ".", 1);
/* Protect against old packages with bogus @name and origin fields */
if (Plist.name == NULL)
Plist.name = "anonymous";
if (Plist.origin == NULL)
Plist.origin = "anonymous/anonymous";
/*
* See if we're already registered either with the same name (the same
* version) or some other version with the same origin.
*/
if ((isinstalledpkg(Plist.name) > 0 ||
matchbyorigin(Plist.origin, NULL) != NULL) && !Force) {
warnx("package '%s' or its older version already installed%s",
Plist.name, FailOnAlreadyInstalled ? "" : " (ignored)");
code = FailOnAlreadyInstalled != FALSE;
goto success; /* close enough for government work */
}
/* Now check the packing list for conflicts */
if (!IgnoreDeps){
for (p = Plist.head; p != NULL; p = p->next) {
if (p->type == PLIST_CONFLICTS) {
int i;
conflict[0] = strdup(p->name);
conflict[1] = NULL;
matched = matchinstalled(MATCH_GLOB, conflict, &errcode);
free(conflict[0]);
if (errcode == 0 && matched != NULL)
for (i = 0; matched[i] != NULL; i++)
if (isinstalledpkg(matched[i]) > 0) {
warnx("package '%s' conflicts with %s", Plist.name,
matched[i]);
conflictsfound = 1;
}
continue;
}
}
if(conflictsfound) {
if(!Force) {
warnx("please use pkg_delete first to remove conflicting package(s) or -f to force installation");
code = 1;
goto bomb;
} else
warnx("-f specified; proceeding anyway");
}
#if ENSURE_THAT_ALL_REQUIREMENTS_ARE_MET
/*
* Before attempting to do the slave mode bit, ensure that we've
* downloaded & processed everything we need.
* It's possible that we haven't already installed all of our
* dependencies if the dependency list was misgenerated due to
* other dynamic dependencies or if a dependency was added to a
* package without all REQUIRED_BY packages being regenerated.
*/
for (p = pkg ? Plist.head : NULL; p; p = p->next) {
const char *ext;
char *deporigin;
if (p->type != PLIST_PKGDEP)
continue;
deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL;
if (isinstalledpkg(p->name) <= 0 &&
!(deporigin != NULL && matchbyorigin(deporigin, NULL) != NULL)) {
char subpkg[FILENAME_MAX], *sep;
strlcpy(subpkg, pkg, sizeof subpkg);
if ((sep = strrchr(subpkg, '/')) != NULL) {
*sep = '\0';
if ((sep = strrchr(subpkg, '/')) != NULL) {
*sep = '\0';
strlcat(subpkg, "/All/", sizeof subpkg);
strlcat(subpkg, p->name, sizeof subpkg);
if ((ext = strrchr(pkg, '.')) == NULL) {
if (getenv("PACKAGESUFFIX"))
ext = getenv("PACKAGESUFFIX");
else
ext = ".tbz";
}
strlcat(subpkg, ext, sizeof subpkg);
pkg_do(subpkg);
}
}
}
}
#endif
/* Now check the packing list for dependencies */
for (p = Plist.head; p ; p = p->next) {
char *deporigin;
if (p->type != PLIST_PKGDEP)
continue;
deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL;
if (Verbose) {
printf("Package '%s' depends on '%s'", Plist.name, p->name);
if (deporigin != NULL)
printf(" with '%s' origin", deporigin);
printf(".\n");
}
if (isinstalledpkg(p->name) <= 0 &&
!(deporigin != NULL && matchbyorigin(deporigin, NULL) != NULL)) {
char path[FILENAME_MAX];
const char *cp = NULL;
if (!Fake) {
char prefixArg[2 + MAXPATHLEN]; /* "-P" + Prefix */
if (PrefixRecursive) {
strlcpy(prefixArg, "-P", sizeof(prefixArg));
strlcat(prefixArg, Prefix, sizeof(prefixArg));
}
if (!isURL(pkg) && !getenv("PKG_ADD_BASE")) {
const char *ext;
ext = strrchr(pkg_fullname, '.');
if (ext == NULL) {
if (getenv("PACKAGESUFFIX")) {
ext = getenv("PACKAGESUFFIX");
} else {
ext = ".tbz";
}
}
snprintf(path, FILENAME_MAX, "%s/%s%s", getenv("_TOP"), p->name, ext);
if (fexists(path))
cp = path;
else
cp = fileFindByPath(pkg, p->name);
if (cp) {
if (Verbose)
printf("Loading it from %s.\n", cp);
if (vsystem("%s %s %s '%s'", PkgAddCmd, Verbose ? "-v " : "", PrefixRecursive ? prefixArg : "", cp)) {
warnx("autoload of dependency '%s' failed%s",
cp, Force ? " (proceeding anyway)" : "!");
if (!Force)
++code;
}
}
else {
warnx("could not find package %s %s",
p->name, Force ? " (proceeding anyway)" : "!");
if (!Force)
++code;
}
}
else if ((cp = fileGetURL(pkg, p->name, KeepPackage)) != NULL) {
if (Verbose)
printf("Finished loading %s via a URL\n", p->name);
if (!fexists("+CONTENTS")) {
warnx("autoloaded package %s has no +CONTENTS file?",
p->name);
if (!Force)
++code;
}
else if (vsystem("(pwd; /bin/cat +CONTENTS) | %s %s %s %s -S", PkgAddCmd, Verbose ? "-v" : "", PrefixRecursive ? prefixArg : "", KeepPackage ? "-K" : "")) {
warnx("pkg_add of dependency '%s' failed%s",
p->name, Force ? " (proceeding anyway)" : "!");
if (!Force)
++code;
}
else if (Verbose)
printf("\t'%s' loaded successfully.\n", p->name);
/* Nuke the temporary playpen */
leave_playpen();
}
}
else {
if (Verbose)
printf("and was not found%s.\n", Force ? " (proceeding anyway)" : "");
else
printf("Package dependency %s for %s not found%s\n", p->name, pkg,
Force ? " (proceeding anyway)" : "!");
if (!Force)
++code;
}
}
else if (Verbose)
printf(" - already installed.\n");
}
} /* if (!IgnoreDeps) */
if (code != 0)
goto bomb;
/* Look for the requirements file */
if ((fd = open(REQUIRE_FNAME, O_RDWR)) != -1) {
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IXALL); /* be sure, chmod a+x */
close(fd);
if (Verbose)
printf("Running requirements file first for %s..\n", Plist.name);
if (!Fake && vsystem("./%s %s INSTALL", REQUIRE_FNAME, Plist.name)) {
warnx("package %s fails requirements %s", pkg_fullname,
Force ? "installing anyway" : "- not installed");
if (!Force) {
code = 1;
goto success; /* close enough for government work */
}
}
}
/*
* Test whether to use the old method of passing tokens to installation
* scripts, and set appropriate variables..
*/
if (fexists(POST_INSTALL_FNAME)) {
new_m = 1;
sprintf(post_script, "%s", POST_INSTALL_FNAME);
pre_arg[0] = '\0';
post_arg[0] = '\0';
} else {
if (fexists(INSTALL_FNAME)) {
sprintf(post_script, "%s", INSTALL_FNAME);
sprintf(pre_arg, "PRE-INSTALL");
sprintf(post_arg, "POST-INSTALL");
}
}
/* If we're really installing, and have an installation file, run it */
if (!NoInstall && (fd = open(pre_script, O_RDWR)) != -1) {
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IXALL); /* be sure, chmod a+x */
close(fd);
if (Verbose)
printf("Running pre-install for %s..\n", Plist.name);
if (!Fake && vsystem("./%s %s %s", pre_script, Plist.name, pre_arg)) {
warnx("install script returned error status");
unlink(pre_script);
code = 1;
goto success; /* nothing to uninstall yet */
}
}
/* Now finally extract the entire show if we're not going direct */
if (!inPlace && !Fake)
extract_plist(".", &Plist);
if (!Fake && fexists(MTREE_FNAME)) {
if (Verbose)
printf("Running mtree for %s..\n", Plist.name);
p = find_plist(&Plist, PLIST_CWD);
if (Verbose)
printf("mtree -U -f %s -d -e -p %s >%s\n", MTREE_FNAME, p ? p->name : "/", _PATH_DEVNULL);
if (!Fake) {
if (vsystem("/usr/sbin/mtree -U -f %s -d -e -p %s >%s", MTREE_FNAME, p ? p->name : "/", _PATH_DEVNULL))
warnx("mtree returned a non-zero status - continuing");
}
}
/* Run the installation script one last time? */
if (!NoInstall && (fd = open(post_script, O_RDWR)) != -1) {
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IXALL); /* be sure, chmod a+x */
close(fd);
if (Verbose)
printf("Running post-install for %s..\n", Plist.name);
if (!Fake && vsystem("./%s %s %s", post_script, Plist.name, post_arg)) {
warnx("install script returned error status");
unlink(post_script);
code = 1;
goto fail;
}
}
/* Time to record the deed? */
if (!NoRecord && !Fake) {
char contents[FILENAME_MAX];
char **depnames = NULL, **deporigins = NULL, ***depmatches;
int i, dep_count = 0;
FILE *contfile;
if (getuid() != 0)
warnx("not running as root - trying to record install anyway");
sprintf(LogDir, "%s/%s", LOG_DIR, Plist.name);
zapLogDir = 1;
if (Verbose)
printf("Attempting to record package into %s..\n", LogDir);
if (make_hierarchy(LogDir, FALSE)) {
warnx("can't record package into '%s', you're on your own!",
LogDir);
bzero(LogDir, FILENAME_MAX);
code = 1;
goto success; /* close enough for government work */
}
/* Make sure pkg_info can read the entry */
fd = open(LogDir, O_RDWR);
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IRALL | S_IXALL); /* be sure, chmod a+rx */
close(fd);
move_file(".", DESC_FNAME, LogDir);
move_file(".", COMMENT_FNAME, LogDir);
if (fexists(INSTALL_FNAME))
move_file(".", INSTALL_FNAME, LogDir);
if (fexists(POST_INSTALL_FNAME))
move_file(".", POST_INSTALL_FNAME, LogDir);
if (fexists(DEINSTALL_FNAME))
move_file(".", DEINSTALL_FNAME, LogDir);
if (fexists(POST_DEINSTALL_FNAME))
move_file(".", POST_DEINSTALL_FNAME, LogDir);
if (fexists(REQUIRE_FNAME))
move_file(".", REQUIRE_FNAME, LogDir);
if (fexists(DISPLAY_FNAME))
move_file(".", DISPLAY_FNAME, LogDir);
if (fexists(MTREE_FNAME))
move_file(".", MTREE_FNAME, LogDir);
sprintf(contents, "%s/%s", LogDir, CONTENTS_FNAME);
contfile = fopen(contents, "w");
if (!contfile) {
warnx("can't open new contents file '%s'! can't register pkg",
contents);
goto success; /* can't log, but still keep pkg */
}
write_plist(&Plist, contfile);
fclose(contfile);
for (p = Plist.head; p ; p = p->next) {
char *deporigin;
if (p->type != PLIST_PKGDEP)
continue;
deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name :
NULL;
if (Verbose) {
printf("Trying to record dependency on package '%s'", p->name);
if (deporigin != NULL)
printf(" with '%s' origin", deporigin);
printf(".\n");
}
if (deporigin) {
/* Defer to origin lookup */
depnames = realloc(depnames, (dep_count + 1) * sizeof(*depnames));
depnames[dep_count] = p->name;
deporigins = realloc(deporigins, (dep_count + 2) * sizeof(*deporigins));
deporigins[dep_count] = deporigin;
deporigins[dep_count + 1] = NULL;
dep_count++;
} else {
/* No origin recorded, try to register on literal package name */
sprintf(contents, "%s/%s/%s", LOG_DIR, p->name,
REQUIRED_BY_FNAME);
contfile = fopen(contents, "a");
if (!contfile) {
warnx("can't open dependency file '%s'!\n"
"dependency registration is incomplete", contents);
} else {
fprintf(contfile, "%s\n", Plist.name);
if (fclose(contfile) == EOF) {
warnx("cannot properly close file %s", contents);
}
}
}
}
if (dep_count > 0) {
depmatches = matchallbyorigin((const char **)deporigins, NULL);
free(deporigins);
if (!IgnoreDeps && depmatches) {
for (i = 0; i < dep_count; i++) {
if (depmatches[i]) {
int j;
char **tmp = depmatches[i];
for (j = 0; tmp[j] != NULL; j++) {
/* Origin looked up */
sprintf(contents, "%s/%s/%s", LOG_DIR, tmp[j],
REQUIRED_BY_FNAME);
if (depnames[i] && strcmp(depnames[i], tmp[j]) != 0)
warnx("warning: package '%s' requires '%s', but '%s' "
"is installed", Plist.name, depnames[i], tmp[j]);
contfile = fopen(contents, "a");
if (!contfile) {
warnx("can't open dependency file '%s'!\n"
"dependency registration is incomplete", contents);
} else {
fprintf(contfile, "%s\n", Plist.name);
if (fclose(contfile) == EOF)
warnx("cannot properly close file %s", contents);
}
}
} else if (depnames[i]) {
/* No package present with this origin, try literal package name */
sprintf(contents, "%s/%s/%s", LOG_DIR, depnames[i],
REQUIRED_BY_FNAME);
contfile = fopen(contents, "a");
if (!contfile) {
warnx("can't open dependency file '%s'!\n"
"dependency registration is incomplete", contents);
} else {
fprintf(contfile, "%s\n", Plist.name);
if (fclose(contfile) == EOF) {
warnx("cannot properly close file %s", contents);
}
}
}
}
}
}
if (Verbose)
printf("Package %s registered in %s\n", Plist.name, LogDir);
}
if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) {
FILE *fp;
char buf[BUFSIZ];
snprintf(buf, sizeof buf, "%s/%s", LogDir, p->name);
fp = fopen(buf, "r");
if (fp) {
putc('\n', stdout);
while (fgets(buf, sizeof(buf), fp))
fputs(buf, stdout);
putc('\n', stdout);
(void) fclose(fp);
} else {
if (!Fake) {
warnx("cannot open %s as display file", buf);
}
}
}
goto success;
bomb:
code = 1;
goto success;
fail:
/* Nuke the whole (installed) show, XXX but don't clean directories */
if (!Fake)
delete_package(FALSE, FALSE, &Plist);
success:
/* delete the packing list contents */
free_plist(&Plist);
leave_playpen();
return code;
}
static int
sanity_check(char *pkg)
{
int code = 0;
if (!fexists(CONTENTS_FNAME)) {
warnx("package %s has no CONTENTS file!", pkg);
code = 1;
}
else if (!fexists(COMMENT_FNAME)) {
warnx("package %s has no COMMENT file!", pkg);
code = 1;
}
else if (!fexists(DESC_FNAME)) {
warnx("package %s has no DESC file!", pkg);
code = 1;
}
return code;
}
void
cleanup(int sig)
{
static int in_cleanup = 0;
if (!in_cleanup) {
in_cleanup = 1;
if (sig)
printf("Signal %d received, cleaning up..\n", sig);
if (!Fake && zapLogDir && LogDir[0])
vsystem("%s -rf %s", REMOVE_CMD, LogDir);
while (leave_playpen())
;
}
if (sig)
exit(1);
}

View File

@ -1,612 +0,0 @@
.\"
.\" 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
.\"
.\" $FreeBSD$
.\"
.Dd November 9, 2012
.Dt PKG_ADD 1
.Os
.Sh NAME
.Nm pkg_add
.Nd a utility for installing software package distributions
.Sh SYNOPSIS
.Nm
.Op Fl viInfFrRMSK
.Op Fl t Ar template
.Op Fl p Ar prefix
.Op Fl P Ar prefix
.Op Fl C Ar chrootdir
.Ar pkg-name Op Ar pkg-name ...
.Sh DESCRIPTION
The
.Nm
command is used to extract packages that have been previously created
with the
.Xr pkg_create 1
command.
.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 Em 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
.Fl M
flag 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 +INSTALL, +POST-INSTALL, +DEINSTALL, +POST-DEINSTALL,
+REQUIRE or +MTREE_DIRS files, and inspect the +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 Op Ar pkg-name ...
The named packages are installed.
A package name of
.Fl
will cause
.Nm
to read from stdin.
If the packages are not found in the current
working directory,
.Nm
will search them in each directory named by
.Ev PKG_PATH .
.It Fl v , -verbose
Turn on verbose output.
.It Fl K , -keep
Keep any downloaded package in
.Ev PKGDIR
if it is defined or in current directory by default.
.It Fl i , -no-deps
Install the package without fetching and installing
dependencies.
.It Fl I , -no-script
If any installation scripts (pre-install or post-install) exist for a given
package, do not execute them.
.It Fl n , -dry-run
Do not actually install a package, just report the steps that
would be taken if it was.
.It Fl R , -no-record
Do not record the installation of a package.
This means
that you cannot deinstall it later, so only use this option if
you know what you are doing!
.It Fl r , -remote
Use the remote fetching feature.
This will determine the appropriate
objformat and release and then fetch and install the package.
.It Fl f , -force
Force installation to proceed even if prerequisite packages are not
installed or the requirements script fails.
Although
.Nm
will still try to find and auto-install missing prerequisite packages,
a failure to find one will not be fatal.
.It Fl F
Already installed packages are not an error.
.It Fl p , -prefix Ar prefix
Set
.Ar prefix
as the directory in which to extract files from a package.
If a package has set its default directory, it will be overridden
by this flag.
Note that only the first
.Cm @cwd
directive will be replaced, since
.Nm
has no way of knowing which directory settings are relative and
which are absolute.
It is rare in any case to see more than one
directory transition made, but when such does happen and you wish
to have control over *all* directory transitions, then you
may then wish to look into the use of
.Cm MASTER
and
.Cm SLAVE
modes (see the
.Fl M
and
.Fl S
options).
If the
.Fl p
flag appears after any
.Fl P
flag on the command line, it overrides its effect, causing
.Nm
not to use the given
.Ar prefix
recursively.
.It Fl P Ar prefix
Does the same as the
.Fl p
option, except that the given
.Ar prefix
is also used recursively for the dependency packages, if any.
If the
.Fl P
flag appears after any
.Fl p
flag on the command line, it overrides its effect, causing
.Nm
to use the given
.Ar prefix
recursively.
.It Fl t , -template Ar template
Use
.Ar template
as the input to
.Xr mktemp 3
when creating a
.Dq staging area .
By default, this is the string
.Pa /var/tmp/instmp.XXXXXX ,
but it may be necessary to override it in the situation where
space in your
.Pa /var/tmp
directory is limited.
Be sure to leave some number of `X' characters
for
.Xr mktemp 3
to fill in with a unique ID.
.Pp
You can get a performance boost by setting the staging area
.Ar template
to reside on the same disk partition as target directories for package
file installation; often this is
.Pa /usr .
.It Fl M , -master
Run in
.Cm MASTER
mode.
This is a very specialized mode for running
.Nm
and is meant to be run in conjunction with
.Cm SLAVE
mode.
When run in this mode,
.Nm
does no work beyond extracting the package into a temporary staging
area (see the
.Fl t
option), reading in the packing list, and then dumping it (prefaced by
the current staging area) to stdout where it may be filtered by a
program such as
.Xr sed 1 .
When used in conjunction with
.Cm SLAVE
mode, it allows you to make radical changes to the package structure
before acting on its contents.
.It Fl S , -slave
Run in
.Cm SLAVE
mode.
This is a very specialized mode for running
.Nm
and is meant to be run in conjunction with
.Cm MASTER
mode.
When run in this mode,
.Nm
expects the release contents to be already extracted and waiting
in the staging area, the location of which is read as a string
from stdin.
The complete packing list is also read from stdin,
and the contents then acted on as normal.
.It Fl C , -chroot Ar chrootdir
Before doing any operations,
.Xr chroot 2
to the
.Ar chrootdir
directory so that all package files, and the package database, are
installed to
.Ar chrootdir .
Note that
.Ar chrootdir
needs to be a fairly complete file system, including everything normally
needed by
.Nm
to run.
This flag was added to help support operations done by
.Xr sysinstall 8
and is not expected to be useful for much else.
Be careful that
.Ar chrootdir
is properly configured and cannot be modified by normal users,
versions of commands like
.Xr fetch 1
may be run inside
.Ar chrootdir
as a side effect.
.El
.Pp
One or more
.Ar pkg-name
arguments may be specified, each being either a file containing the
package (these usually end with a
.Dq .tbz
suffix) or a
URL pointing at a file available on an ftp site.
Thus you may
extract files directly from their anonymous ftp locations (e.g.\&
.Nm
.Li ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/packages/shells/bash-1.14.7.tbz ) .
Note: 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
The
.Nm
utility extracts each package's
.Dq "packing list"
into a special staging directory (see
.Sx ENVIRONMENT ) ,
parses it, and then runs
through the following sequence to fully extract the contents of the package:
.Bl -enum
.It
A check is made to determine if the package is already recorded as installed.
If it is, installation is terminated.
.It
A check is made to determine if the package conflicts (from
.Ic @conflicts
directives, see
.Xr pkg_create 1 )
with an already installed package.
If it is, installation is terminated.
.It
Scan all the package dependencies (from
.Ic @pkgdep
directives, see
.Xr pkg_create 1 )
are read from the packing list.
If any of these required packages is 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
Search for any
.Ic @option
directives which control how the package is added to the system.
At the time of this writing, the only currently implemented option is
.Ic @option Cm extract-in-place
which will cause the package to be extracted directly into its
prefix directory without moving through a staging area.
.It
If
.Ic @option Cm extract-in-place
is enabled, the package is now extracted directly into its
final location, otherwise it is extracted into the staging area.
.It
If a requirements script
.Pa +REQUIRE
exists for the package (see the
.Fl r
flag of
.Xr pkg_create 1 ) ,
then execute it with the following arguments:
.Pp
.D1 Ar pkg-name Li INSTALL
.Pp
where
.Ar pkg-name
is the name of the package in question and the
.Dq Li INSTALL
keyword denotes this as an installation requirements check (useful if
you want to have one script serving multiple functions).
.It
If a pre-install script
.Pa +INSTALL
exists for the package,
it is then executed with the following arguments:
.Pp
.D1 Ar pkg-name Li PRE-INSTALL
.Pp
where
.Ar pkg-name
is the name of the package in question and
.Dq Li PRE-INSTALL
is a keyword denoting this as the preinstallation phase.
.Pp
.Sy Note :
The
.Dq Li PRE-INSTALL
keyword will not appear if separate scripts for pre-install and post-install
are given during package creation time (using the
.Fl i
and
.Fl I
flags to
.Xr pkg_create 1 ) .
.It
If
.Cm @option Cm extract-in-place
is not used, then the packing list (this is the
.Pa +CONTENTS
file) is now used as a guide for moving (or copying, as necessary) files from
the staging area into their final locations.
.It
If an mtree file
.Pa +MTREE_DIRS
exists for the package (see the
.Fl m
flag of
.Xr pkg_create 1 ) ,
then
.Xr mtree 8
is invoked as:
.Pp
.D1 Nm mtree Fl U f Pa +MTREE_DIRS Fl d e p Ar prefix
.Pp
where
.Ar prefix
is either the prefix specified with the
.Fl p
or
.Fl P
flag or,
if neither flag was specified, the name of the first directory named by a
.Ic @cwd
directive within this package.
.It
If a post-install script
.Pa +POST-INSTALL
exists for the package,
it is then executed with the following arguments:
.Pp
.D1 Ar pkg-name Li POST-INSTALL
.Pp
where
.Ar pkg-name
is the name of the package in question and
.Dq Li POST-INSTALL
is a keyword denoting this as the post-installation phase.
.Pp
.Sy Note :
The
.Dq Li POST-INSTALL
keyword will not appear if separate scripts for pre-install and post-install
are given during package creation time (using the
.Fl i
and
.Fl I
flags to
.Xr pkg_create 1 ) .
.Pp
Reasoning behind passing keywords such as
.Dq Li POST-INSTALL
and
.Dq Li PRE-INSTALL
is that this allows you to write a single
install
script that does both
.Dq before
and
.Dq after
actions.
But, separating the
functionality is more advantageous and easier from a maintenance viewpoint.
.It
After installation is complete, a copy of the
description
.Pq Pa +DESC ,
comment
.Pq Pa +COMMENT ,
pre-install script
.Pq Pa +INSTALL ,
post-install script
.Pq Pa +POST-INSTALL ,
deinstall script
.Pq Pa +DEINSTALL ,
post-deinstall script
.Pq Pa +POST-DEINSTALL ,
requirements script
.Pq Pa +REQUIRE ,
display
.Pq Pa +DISPLAY ,
mtree
.Pq Pa +MTREE_DIRS ,
and packing list
.Pq Pa +CONTENTS
files are copied into
.Pa /var/db/pkg/ Ns Aq Ar pkg-name
for subsequent possible use by
.Xr pkg_delete 1 .
Any package dependencies are recorded in the other packages'
.Pa /var/db/pkg/ Ns Ao Ar other-pkg Ac Ns Pa /+REQUIRED_BY
file
(if the environment variable
.Ev PKG_DBDIR
is set, this overrides the
.Pa /var/db/pkg/
path shown above).
.It
Finally, the staging area is deleted and the program terminates.
.El
.Pp
All the scripts are called with the environment variable
.Ev PKG_PREFIX
set to the installation prefix (see the
.Fl p
and
.Fl P
options 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
or
.Fl P
flags to
.Nm .
.Sh ENVIRONMENT
The value of the
.Ev PKG_PATH
is used if a given package cannot be found.
The environment variable
should be a series of entries separated by colons.
Each entry
consists of a directory name.
The current directory may be indicated
implicitly by an empty directory name, or explicitly by a single
period.
.Pp
The environment variable
.Ev PKG_DBDIR
specifies an alternative location for the installed package database,
default location is
.Pa /var/db/pkg .
.Pp
The environment variables
.Ev PKG_TMPDIR
and
.Ev TMPDIR ,
in that order, are taken to name temporary directories where
.Nm
will attempt to create its staging area in.
If these variables are not present or if the directories named lack
sufficient space, then
.Nm
will use the first of
.Pa /var/tmp ,
.Pa /tmp
or
.Pa /usr/tmp
with sufficient space.
.Pp
The environment variable
.Ev PACKAGEROOT
specifies an alternate location for
.Nm
to fetch from.
The fetch URL is built using this environment variable and the automatic
directory logic that
.Nm
uses when the
.Fl r
option is invoked.
An example setting would be
.Qq Li ftp://ftp3.FreeBSD.org .
.Pp
The environment variable
.Ev PACKAGESITE
specifies an alternate location for
.Nm
to fetch from.
This variable subverts the automatic directory logic
that
.Nm
uses when the
.Fl r
option is invoked.
Thus it should be a complete URL to the remote package file(s).
.Pp
The environment variable
.Ev PKGDIR
specifies an alternative location to save downloaded packages to when
.Fl K
option is used.
.Pp
The environment variable
.Ev PACKAGESUFFIX
specifies an alternative file extension to use when fetching remote
packages. Default is .tbz
.Sh FILES
.Bl -tag -width /var/db/pkg -compact
.It Pa /var/tmp
Temporary directory for creating the staging area, if environmental variables
.Ev PKG_TMPDIR
or
.Ev TMPDIR
do not point to a suitable directory.
.It Pa /tmp
Next choice if
.Pa /var/tmp
does not exist or has insufficient space.
.It Pa /usr/tmp
Last choice if
.Pa /var/tmp
and
.Pa /tmp
are not suitable for creating the staging area.
.It Pa /var/db/pkg
Default location of the installed package database.
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh SEE ALSO
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Xr pkg_version 1 ,
.Xr mktemp 3 ,
.Xr sysconf 3 ,
.Xr mtree 8
.Sh AUTHORS
.An Jordan Hubbard
.Sh CONTRIBUTORS
.An John Kohl Aq jtk@rational.com
.Sh BUGS
Hard links between files in a distribution are only preserved if either
(1) the staging area is on the same file system as the target directory of
all the links to the file, or (2) all the links to the file are bracketed by
.Cm @cwd
directives in the contents file,
.Em and
the link names are extracted with a single
.Cm tar
command (not split between
invocations due to exec argument-space limitations--this depends on the
value returned by
.Fn sysconf _SC_ARG_MAX ) .
.Pp
Sure to be others.

View File

@ -1,14 +0,0 @@
# $FreeBSD$
PROG= pkg_create
SRCS= main.c perform.c pl.c
CFLAGS+= -I${.CURDIR}/../lib
WARNS?= 3
WFORMAT?= 1
DPADD= ${LIBINSTALL} ${LIBMD}
LDADD= ${LIBINSTALL} -lmd
.include <bsd.prog.mk>

View File

@ -1,58 +0,0 @@
/* $FreeBSD$ */
/*
* 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
* 18 July 1993
*
* Include and define various things wanted by the create command.
*
*/
#ifndef _INST_CREATE_H_INCLUDE
#define _INST_CREATE_H_INCLUDE
extern match_t MatchType;
extern char *Prefix;
extern char *Comment;
extern char *Desc;
extern char *Display;
extern char *Install;
extern char *PostInstall;
extern char *DeInstall;
extern char *PostDeInstall;
extern char *Contents;
extern char *Require;
extern char *SrcDir;
extern char *BaseDir;
extern char *ExcludeFrom;
extern char *Mtree;
extern char *Pkgdeps;
extern char *Conflicts;
extern char *Origin;
extern char *InstalledPkg;
extern char PlayPen[];
extern int Dereference;
extern int PlistOnly;
extern int Recursive;
extern int Regenerate;
enum zipper {NONE, GZIP, BZIP, BZIP2, XZ };
extern enum zipper Zipper;
void add_cksum(Package *, PackingList, const char *);
void check_list(const char *, Package *);
void copy_plist(const char *, Package *);
#endif /* _INST_CREATE_H_INCLUDE */

View File

@ -1,268 +0,0 @@
/*
* FreeBSD install - a package for the installation and maintenance
* of non-core utilities.
*
* Jordan K. Hubbard
* 18 July 1993
*
* This is the create module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <getopt.h>
#include <err.h>
#include "lib.h"
#include "create.h"
match_t MatchType = MATCH_GLOB;
char *Prefix = NULL;
char *Comment = NULL;
char *Desc = NULL;
char *SrcDir = NULL;
char *BaseDir = NULL;
char *Display = NULL;
char *Install = NULL;
char *PostInstall = NULL;
char *DeInstall = NULL;
char *PostDeInstall = NULL;
char *Contents = NULL;
char *Require = NULL;
char *ExcludeFrom = NULL;
char *Mtree = NULL;
char *Pkgdeps = NULL;
char *Conflicts = NULL;
char *Origin = NULL;
char *InstalledPkg = NULL;
char PlayPen[FILENAME_MAX];
int Dereference = FALSE;
int PlistOnly = FALSE;
int Recursive = FALSE;
int Regenerate = TRUE;
int Help = FALSE;
enum zipper Zipper = BZIP2;
static void usage(void);
static char opts[] = "EGYNnORhjJvxyzf:p:P:C:c:d:i:I:k:K:r:t:X:D:m:s:S:o:b:";
static struct option longopts[] = {
{ "backup", required_argument, NULL, 'b' },
{ "extended", no_argument, NULL, 'E' },
{ "help", no_argument, &Help, TRUE },
{ "no", no_argument, NULL, 'N' },
{ "no-glob", no_argument, NULL, 'G' },
{ "origin", required_argument, NULL, 'o' },
{ "plist-only", no_argument, NULL, 'O' },
{ "prefix", required_argument, NULL, 'p' },
{ "recursive", no_argument, NULL, 'R' },
{ "regex", no_argument, NULL, 'x' },
{ "template", required_argument, NULL, 't' },
{ "verbose", no_argument, NULL, 'v' },
{ "yes", no_argument, NULL, 'Y' },
{ NULL, 0, NULL, 0 },
};
int
main(int argc, char **argv)
{
int ch;
char **pkgs, **start, *tmp;
warnpkgng();
pkgs = start = argv;
while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1)
switch(ch) {
case 'v':
Verbose++;
break;
case 'x':
MatchType = MATCH_REGEX;
break;
case 'E':
MatchType = MATCH_EREGEX;
break;
case 'G':
MatchType = MATCH_EXACT;
break;
case 'N':
AutoAnswer = NO;
break;
case 'Y':
AutoAnswer = YES;
break;
case 'O':
PlistOnly = TRUE;
break;
case 'p':
Prefix = optarg;
break;
case 's':
SrcDir = optarg;
break;
case 'S':
BaseDir = optarg;
break;
case 'f':
Contents = optarg;
break;
case 'C':
Conflicts = optarg;
break;
case 'c':
Comment = optarg;
break;
case 'd':
Desc = optarg;
break;
case 'i':
Install = optarg;
break;
case 'I':
PostInstall = optarg;
break;
case 'k':
DeInstall = optarg;
break;
case 'K':
PostDeInstall = optarg;
break;
case 'r':
Require = optarg;
break;
case 't':
strlcpy(PlayPen, optarg, sizeof(PlayPen));
break;
case 'X':
ExcludeFrom = optarg;
break;
case 'h':
Dereference = TRUE;
break;
case 'D':
Display = optarg;
break;
case 'm':
Mtree = optarg;
break;
case 'P':
Pkgdeps = optarg;
break;
case 'o':
Origin = optarg;
break;
case 'y':
case 'j':
Zipper = BZIP2;
break;
case 'z':
Zipper = GZIP;
break;
case 'J':
Zipper = XZ;
break;
case 'b':
InstalledPkg = optarg;
while ((tmp = strrchr(optarg, (int)'/')) != NULL) {
*tmp++ = '\0';
/*
* If character after the '/' is alphanumeric, then we've
* found the package name. Otherwise we've come across
* a trailing '/' and need to continue our quest.
*/
if (isalpha(*tmp)) {
InstalledPkg = tmp;
break;
}
}
break;
case 'R':
Recursive = TRUE;
break;
case 'n':
Regenerate = FALSE;
break;
case 0:
if (Help)
usage();
break;
default:
usage();
break;
}
argc -= optind;
argv += optind;
/* Get all the remaining package names, if any */
while (*argv)
*pkgs++ = *argv++;
/* If no packages, yelp */
if ((pkgs == start) && (InstalledPkg == NULL))
warnx("missing package name"), usage();
*pkgs = NULL;
if ((start[0] != NULL) && (start[1] != NULL)) {
warnx("only one package name allowed ('%s' extraneous)", start[1]);
usage();
}
if (start[0] == NULL)
start[0] = InstalledPkg;
if (!pkg_perform(start)) {
if (Verbose)
warnx("package creation failed");
return 1;
}
else
return 0;
}
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
"usage: pkg_create [-YNOhjnvyz] [-C conflicts] [-P pkgs] [-p prefix]",
" [-i iscript] [-I piscript] [-k dscript] [-K pdscript]",
" [-r rscript] [-s srcdir] [-S basedir]",
" [-t template] [-X excludefile]",
" [-D displayfile] [-m mtreefile] [-o originpath]",
" -c comment -d description -f packlist pkg-filename",
" pkg_create [-EGYNRhnvxy] -b pkg-name [pkg-filename]");
exit(1);
}

View File

@ -1,607 +0,0 @@
/*
* 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
* 18 July 1993
*
* This is the main body of the create module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include "create.h"
#include <err.h>
#include <libgen.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syslimits.h>
#include <sys/wait.h>
#include <unistd.h>
static void sanity_check(void);
static void make_dist(const char *, const char *, const char *, Package *);
static int create_from_installed_recursive(const char *, const char *);
static int create_from_installed(const char *, const char *, const char *);
int
pkg_perform(char **pkgs)
{
static const char *home;
char *pkg = *pkgs; /* Only one arg to create */
char *cp;
FILE *pkg_in, *fp;
Package plist;
int len;
const char *suf;
/* Preliminary setup */
if (InstalledPkg == NULL)
sanity_check();
if (Verbose && !PlistOnly)
printf("Creating package %s\n", pkg);
/* chop suffix off if already specified, remembering if we want to compress */
len = strlen(pkg);
if (len > 4) {
if (!strcmp(&pkg[len - 4], ".tbz")) {
Zipper = BZIP2;
pkg[len - 4] = '\0';
}
else if (!strcmp(&pkg[len - 4], ".tgz")) {
Zipper = GZIP;
pkg[len - 4] = '\0';
}
else if (!strcmp(&pkg[len - 4], ".txz")) {
Zipper = XZ;
pkg[len - 4] = '\0';
}
else if (!strcmp(&pkg[len - 4], ".tar")) {
Zipper = NONE;
pkg[len - 4] = '\0';
}
}
if (Zipper == BZIP2) {
suf = "tbz";
setenv("BZIP2", "--best", 0);
} else if (Zipper == GZIP) {
suf = "tgz";
setenv("GZIP", "-9", 0);
} else if (Zipper == XZ) {
suf = "txz";
} else
suf = "tar";
if (InstalledPkg != NULL) {
char *pkgglob[] = { InstalledPkg, NULL };
char **matched, **pkgs;
int i, error;
pkgs = pkgglob;
if (MatchType != MATCH_EXACT) {
matched = matchinstalled(MatchType, pkgs, &error);
if (!error && matched != NULL)
pkgs = matched;
else if (MatchType != MATCH_GLOB)
errx(1, "no packages match pattern");
}
/*
* Is there is only one installed package matching the pattern,
* we need to respect the optional pkg-filename parameter. If,
* however, the pattern matches several packages, this parameter
* makes no sense and is ignored.
*/
if (pkgs[1] == NULL) {
if (pkg == InstalledPkg)
pkg = *pkgs;
InstalledPkg = *pkgs;
if (!Recursive)
return (create_from_installed(InstalledPkg, pkg, suf));
return (create_from_installed_recursive(pkg, suf));
}
for (i = 0; pkgs[i] != NULL; i++) {
InstalledPkg = pkg = pkgs[i];
if (!Recursive)
create_from_installed(pkg, pkg, suf);
else
create_from_installed_recursive(pkg, suf);
}
return TRUE;
}
get_dash_string(&Comment);
get_dash_string(&Desc);
if (!strcmp(Contents, "-"))
pkg_in = stdin;
else {
pkg_in = fopen(Contents, "r");
if (!pkg_in) {
cleanup(0);
errx(2, "%s: unable to open contents file '%s' for input",
__func__, Contents);
}
}
plist.head = plist.tail = NULL;
/* Stick the dependencies, if any, at the top */
if (Pkgdeps) {
char **deps, *deporigin;
int i;
int ndeps = 0;
if (Verbose && !PlistOnly)
printf("Registering depends:");
/* Count number of dependencies */
for (cp = Pkgdeps; cp != NULL && *cp != '\0';
cp = strpbrk(++cp, " \t\n")) {
ndeps++;
}
if (ndeps != 0) {
/* Create easy to use NULL-terminated list */
deps = alloca(sizeof(*deps) * ndeps + 1);
if (deps == NULL) {
errx(2, "%s: alloca() failed", __func__);
/* Not reached */
}
for (i = 0; Pkgdeps;) {
cp = strsep(&Pkgdeps, " \t\n");
if (*cp) {
deps[i] = cp;
i++;
}
}
ndeps = i;
deps[ndeps] = NULL;
sortdeps(deps);
for (i = 0; i < ndeps; i++) {
deporigin = strchr(deps[i], ':');
if (deporigin != NULL) {
*deporigin = '\0';
add_plist_top(&plist, PLIST_DEPORIGIN, ++deporigin);
}
add_plist_top(&plist, PLIST_PKGDEP, deps[i]);
if (Verbose && !PlistOnly)
printf(" %s", deps[i]);
}
}
if (Verbose && !PlistOnly)
printf(".\n");
}
/* Put the conflicts directly after the dependencies, if any */
if (Conflicts) {
if (Verbose && !PlistOnly)
printf("Registering conflicts:");
while (Conflicts) {
cp = strsep(&Conflicts, " \t\n");
if (*cp) {
add_plist(&plist, PLIST_CONFLICTS, cp);
if (Verbose && !PlistOnly)
printf(" %s", cp);
}
}
if (Verbose && !PlistOnly)
printf(".\n");
}
/* If a SrcDir override is set, add it now */
if (SrcDir) {
if (Verbose && !PlistOnly)
printf("Using SrcDir value of %s\n", SrcDir);
add_plist(&plist, PLIST_SRC, SrcDir);
}
/* Slurp in the packing list */
read_plist(&plist, pkg_in);
/* Prefix should add an @cwd to the packing list */
if (Prefix) {
if (Prefix[0] != '/') {
char resolved_prefix[PATH_MAX];
if (realpath(Prefix, resolved_prefix) == NULL)
err(EXIT_FAILURE, "couldn't resolve path for prefix: %s", Prefix);
add_plist_top(&plist, PLIST_CWD, resolved_prefix);
} else {
add_plist_top(&plist, PLIST_CWD, Prefix);
}
}
/* Add the origin if asked, at the top */
if (Origin)
add_plist_top(&plist, PLIST_ORIGIN, Origin);
/*
* 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(pkg));
if (asprintf(&cp, "PKG_FORMAT_REVISION:%d.%d", PLIST_FMT_VER_MAJOR,
PLIST_FMT_VER_MINOR) == -1) {
errx(2, "%s: asprintf() failed", __func__);
}
add_plist_top(&plist, PLIST_COMMENT, cp);
free(cp);
/*
* We're just here for to dump out a revised plist for the FreeBSD ports
* hack. It's not a real create in progress.
*/
if (PlistOnly) {
check_list(home, &plist);
write_plist(&plist, stdout);
exit(0);
}
/* Make a directory to stomp around in */
home = make_playpen(PlayPen, 0);
signal(SIGINT, cleanup);
signal(SIGHUP, cleanup);
/* Make first "real contents" pass over it */
check_list(home, &plist);
(void) umask(022); /*
* Make sure gen'ed directories, files don't have
* group or other write bits.
*/
/* copy_plist(home, &plist); */
/* mark_plist(&plist); */
/* Now put the release specific items in */
if (!Prefix) {
add_plist(&plist, PLIST_CWD, ".");
}
write_file(COMMENT_FNAME, Comment);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
add_cksum(&plist, plist.tail, COMMENT_FNAME);
write_file(DESC_FNAME, Desc);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, DESC_FNAME);
add_cksum(&plist, plist.tail, DESC_FNAME);
if (Install) {
copy_file(home, Install, INSTALL_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
add_cksum(&plist, plist.tail, INSTALL_FNAME);
}
if (PostInstall) {
copy_file(home, PostInstall, POST_INSTALL_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, POST_INSTALL_FNAME);
add_cksum(&plist, plist.tail, POST_INSTALL_FNAME);
}
if (DeInstall) {
copy_file(home, DeInstall, DEINSTALL_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
add_cksum(&plist, plist.tail, DEINSTALL_FNAME);
}
if (PostDeInstall) {
copy_file(home, PostDeInstall, POST_DEINSTALL_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, POST_DEINSTALL_FNAME);
add_cksum(&plist, plist.tail, POST_DEINSTALL_FNAME);
}
if (Require) {
copy_file(home, Require, REQUIRE_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
add_cksum(&plist, plist.tail, REQUIRE_FNAME);
}
if (Display) {
copy_file(home, Display, DISPLAY_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
add_cksum(&plist, plist.tail, DISPLAY_FNAME);
add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
}
if (Mtree) {
copy_file(home, Mtree, MTREE_FNAME);
add_plist(&plist, PLIST_IGNORE, NULL);
add_plist(&plist, PLIST_FILE, MTREE_FNAME);
add_cksum(&plist, plist.tail, MTREE_FNAME);
add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
}
/* Finally, write out the packing list */
fp = fopen(CONTENTS_FNAME, "w");
if (!fp) {
cleanup(0);
errx(2, "%s: can't open file %s for writing",
__func__, CONTENTS_FNAME);
}
write_plist(&plist, fp);
if (fclose(fp)) {
cleanup(0);
errx(2, "%s: error while closing %s",
__func__, CONTENTS_FNAME);
}
/* And stick it into a tar ball */
make_dist(home, pkg, suf, &plist);
/* Cleanup */
free(Comment);
free(Desc);
free_plist(&plist);
leave_playpen();
return TRUE; /* Success */
}
static void
make_dist(const char *homedir, const char *pkg, const char *suff, Package *plist)
{
struct stat sb;
char tball[FILENAME_MAX];
PackingList p;
int ret;
const char *args[50]; /* Much more than enough. */
int nargs = 0;
int pipefds[2];
FILE *totar;
pid_t pid;
const char *cname;
char *prefix = NULL;
args[nargs++] = "tar"; /* argv[0] */
if (*pkg == '/')
snprintf(tball, FILENAME_MAX, "%s.%s", pkg, suff);
else
snprintf(tball, FILENAME_MAX, "%s/%s.%s", homedir, pkg, suff);
/*
* If the package tarball exists already, and we are running in `no
* clobber' mode, skip this package.
*/
if (stat(tball, &sb) == 0 && Regenerate == FALSE) {
if (Verbose)
printf("Skipping package '%s'. It already exists.\n", tball);
return;
}
args[nargs++] = "-c";
args[nargs++] = "-f";
args[nargs++] = tball;
if (strchr(suff, 'z')) { /* Compress/gzip/bzip2? */
if (Zipper == BZIP2) {
args[nargs++] = "-j";
cname = "bzip'd ";
}
else if (Zipper == XZ) {
args[nargs++] = "-J";
cname = "xz'd ";
}
else {
args[nargs++] = "-z";
cname = "gzip'd ";
}
} else {
cname = "";
}
if (Dereference)
args[nargs++] = "-h";
if (ExcludeFrom) {
args[nargs++] = "-X";
args[nargs++] = ExcludeFrom;
}
args[nargs++] = "-T"; /* Take filenames from file instead of args. */
args[nargs++] = "-"; /* Use stdin for the file. */
args[nargs] = NULL;
if (Verbose)
printf("Creating %star ball in '%s'\n", cname, tball);
/* Set up a pipe for passing the filenames, and fork off a tar process. */
if (pipe(pipefds) == -1) {
cleanup(0);
errx(2, "%s: cannot create pipe", __func__);
}
if ((pid = fork()) == -1) {
cleanup(0);
errx(2, "%s: cannot fork process for tar", __func__);
}
if (pid == 0) { /* The child */
dup2(pipefds[0], 0);
close(pipefds[0]);
close(pipefds[1]);
execv("/usr/bin/tar", (char * const *)(uintptr_t)args);
cleanup(0);
errx(2, "%s: failed to execute tar command", __func__);
}
/* Meanwhile, back in the parent process ... */
close(pipefds[0]);
if ((totar = fdopen(pipefds[1], "w")) == NULL) {
cleanup(0);
errx(2, "%s: fdopen failed", __func__);
}
fprintf(totar, "%s\n", CONTENTS_FNAME);
fprintf(totar, "%s\n", COMMENT_FNAME);
fprintf(totar, "%s\n", DESC_FNAME);
if (Install)
fprintf(totar, "%s\n", INSTALL_FNAME);
if (PostInstall)
fprintf(totar, "%s\n", POST_INSTALL_FNAME);
if (DeInstall)
fprintf(totar, "%s\n", DEINSTALL_FNAME);
if (PostDeInstall)
fprintf(totar, "%s\n", POST_DEINSTALL_FNAME);
if (Require)
fprintf(totar, "%s\n", REQUIRE_FNAME);
if (Display)
fprintf(totar, "%s\n", DISPLAY_FNAME);
if (Mtree)
fprintf(totar, "%s\n", MTREE_FNAME);
for (p = plist->head; p; p = p->next) {
if (p->type == PLIST_FILE)
fprintf(totar, "%s\n", p->name);
else if (p->type == PLIST_CWD && p->name == NULL)
fprintf(totar, "-C\n%s\n", prefix);
else if (p->type == PLIST_CWD && BaseDir && p->name && p->name[0] == '/')
fprintf(totar, "-C\n%s%s\n", BaseDir, p->name);
else if (p->type == PLIST_CWD || p->type == PLIST_SRC)
fprintf(totar, "-C\n%s\n", p->name);
else if (p->type == PLIST_IGNORE)
p = p->next;
if (p->type == PLIST_CWD && !prefix)
prefix = p->name;
}
fclose(totar);
wait(&ret);
/* assume either signal or bad exit is enough for us */
if (ret) {
cleanup(0);
errx(2, "%s: tar command failed with code %d", __func__, ret);
}
}
static void
sanity_check()
{
if (!Comment) {
cleanup(0);
errx(2, "%s: required package comment string is missing (-c comment)",
__func__);
}
if (!Desc) {
cleanup(0);
errx(2, "%s: required package description string is missing (-d desc)",
__func__);
}
if (!Contents) {
cleanup(0);
errx(2, "%s: required package contents list is missing (-f [-]file)",
__func__);
}
}
/* Clean up those things that would otherwise hang around */
void
cleanup(int sig)
{
int in_cleanup = 0;
if (!in_cleanup) {
in_cleanup = 1;
leave_playpen();
}
if (sig)
exit(1);
}
static int
create_from_installed_recursive(const char *pkg, const char *suf)
{
FILE *fp;
Package plist;
PackingList p;
char tmp[PATH_MAX];
int rval;
if (!create_from_installed(InstalledPkg, pkg, suf))
return FALSE;
snprintf(tmp, sizeof(tmp), "%s/%s/%s", LOG_DIR, InstalledPkg, CONTENTS_FNAME);
if (!fexists(tmp)) {
warnx("can't find package '%s' installed!", InstalledPkg);
return FALSE;
}
/* Suck in the contents list */
plist.head = plist.tail = NULL;
fp = fopen(tmp, "r");
if (!fp) {
warnx("unable to open %s file", tmp);
return FALSE;
}
read_plist(&plist, fp);
fclose(fp);
rval = TRUE;
for (p = plist.head; p ; p = p->next) {
if (p->type != PLIST_PKGDEP)
continue;
if (Verbose)
printf("Creating package %s\n", p->name);
if (!create_from_installed(p->name, p->name, suf)) {
rval = FALSE;
break;
}
}
free_plist(&plist);
return rval;
}
static int
create_from_installed(const char *ipkg, const char *pkg, const char *suf)
{
FILE *fp;
Package plist;
char homedir[MAXPATHLEN], log_dir[FILENAME_MAX];
snprintf(log_dir, sizeof(log_dir), "%s/%s", LOG_DIR, ipkg);
if (!fexists(log_dir)) {
warnx("can't find package '%s' installed!", ipkg);
return FALSE;
}
getcwd(homedir, sizeof(homedir));
if (chdir(log_dir) == FAIL) {
warnx("can't change directory to '%s'!", log_dir);
return FALSE;
}
/* Suck in the contents list */
plist.head = plist.tail = NULL;
fp = fopen(CONTENTS_FNAME, "r");
if (!fp) {
warnx("unable to open %s file", CONTENTS_FNAME);
return FALSE;
}
read_plist(&plist, fp);
fclose(fp);
Install = isfile(INSTALL_FNAME) ? (char *)INSTALL_FNAME : NULL;
PostInstall = isfile(POST_INSTALL_FNAME) ?
(char *)POST_INSTALL_FNAME : NULL;
DeInstall = isfile(DEINSTALL_FNAME) ? (char *)DEINSTALL_FNAME : NULL;
PostDeInstall = isfile(POST_DEINSTALL_FNAME) ?
(char *)POST_DEINSTALL_FNAME : NULL;
Require = isfile(REQUIRE_FNAME) ? (char *)REQUIRE_FNAME : NULL;
Display = isfile(DISPLAY_FNAME) ? (char *)DISPLAY_FNAME : NULL;
Mtree = isfile(MTREE_FNAME) ? (char *)MTREE_FNAME : NULL;
make_dist(homedir, pkg, suf, &plist);
free_plist(&plist);
if (chdir(homedir) == FAIL) {
warnx("can't change directory to '%s'!", homedir);
return FALSE;
}
return TRUE;
}

View File

@ -1,670 +0,0 @@
.\"
.\" 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
.\" $FreeBSD$
.\"
.\" 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 November 9, 2012
.Dt PKG_CREATE 1
.Os
.Sh NAME
.Nm pkg_create
.Nd a utility for creating software package distributions
.Sh SYNOPSIS
.Nm
.Op Fl YNOhjnvyz
.Op Fl C Ar conflicts
.Op Fl P Ar pkgs
.Op Fl p Ar prefix
.Op Fl i Ar iscript
.Op Fl I Ar piscript
.Op Fl k Ar dscript
.Op Fl K Ar pdscript
.Op Fl r Ar rscript
.Op Fl s Ar srcdir
.Op Fl S Ar basedir
.Op Fl t Ar template
.Op Fl X Ar excludefile
.Op Fl D Ar displayfile
.Op Fl m Ar mtreefile
.Op Fl o Ar originpath
.Fl c Ar comment
.Fl d Ar description
.Fl f Ar packlist
.Ar pkg-filename
.Nm
.Op Fl EGYNRhnvxy
.Fl b Ar pkg-name
.Op Ar pkg-filename
.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
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 f Ar packinglist
Fetch
.Dq packing list
for package from the file
.Ar packinglist
or
.Cm stdin
if
.Ar packinglist
is a
.Cm -
(dash).
.It Fl c Xo
.Oo Fl Oc Ns Ar desc
.Xc
Fetch package
.Dq 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 Xo
.Oo Fl Oc Ns Ar desc
.Xc
Fetch long description for package from file
.Ar desc
or, if preceded by
.Cm - ,
the argument itself.
.It Fl Y , -yes
Assume a default answer of `Yes' for any questions asked.
.It Fl N , -no
Assume a default answer of `No' for any questions asked.
.It Fl O , -plist-only
Go into a `packing list Only' mode.
This is a custom hack for the
.Fx
.Em "Ports Collection"
and is used to do `fake pkg_add' operations when a port is installed.
In such cases, it is necessary to know what the final, adjusted packing
list will look like.
.It Fl v , -verbose
Turn on verbose output.
.It Fl h
Force tar to follow symbolic links, so that the files they point to
are dumped, rather than the links themselves.
.It Fl i Ar iscript
Set
.Ar iscript
to be the pre-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 will be passed the package's name as the
first argument.
.Pp
.Sy Note :
if the
.Fl I
option is not given, this script will serve as both the pre-install and the
post-install script for the package, differentiating between the
functionality by passing the keywords
.Ar PRE-INSTALL
and
.Ar POST-INSTALL
respectively, after the package's name.
.It Fl I Ar piscript
Set
.Ar piscript
to be the post-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 will be passed the package's name as
the first argument.
.It Fl C Ar conflicts
Set the initial package conflict list to
.Ar conflicts .
This is assumed to be a whitespace separated list of package names
and is meant as a convenient shorthand for specifying multiple
.Cm @conflicts
directives in the packing list (see PACKING LIST DETAILS section below).
.It Fl P Ar pkgs
Set the initial package dependency list to
.Ar pkgs .
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
.Sx "PACKING LIST DETAILS"
section below).
Each argument from the
.Ar pkgs
list could be in the form
.Ar pkgname Ns Op : Ns Ar pkgorigin ,
where optional
.Ar pkgorigin
element denotes origin of each dependency from the list and it is
recorded into the packing list along with the
.Ar pkgname
using
.Cm @comment
directive.
.It Fl p , -prefix Ar prefix
Set
.Ar prefix
as the initial directory
.Dq base
to start from in selecting files for
the package.
.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 will be passed the package's
name as the first argument.
.Pp
.Sy Note :
if the
.Fl K
option is not given, this script will serve as both the de-install and the
post-deinstall script for the package, differentiating between the
functionality by passing the keywords
.Ar DEINSTALL
and
.Ar POST-DEINSTALL
respectively, along with the package's name.
.It Fl K Ar pdscript
Set
.Ar pdscript
to be the post-deinstall procedure for the package.
This can be any
executable program (or shell script).
It will be invoked automatically when
the package is later de-installed.
It will be passed the package's name as
the first argument.
.It Fl r Ar rscript
Set
.Ar rscript
to be the
.Dq requirements
procedure for the package.
This can be any
executable program (or shell script).
It will be invoked automatically
at installation/deinstallation time to determine whether or not
installation/deinstallation should proceed.
To differentiate between installation and deinstallation, the keywords
.Ar INSTALL
and
.Ar DEINSTALL
are passed respectively, along with the package's name.
.It Fl s Ar srcdir
.Ar srcdir
will override the value of
.Cm @cwd
during package creation.
.It Fl S Ar basedir
.Ar basedir
will be prefixed to all
.Cm @cwd
during package creation.
.It Fl t , -template 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 `X' characters
for
.Xr mktemp 3
to fill in with a unique ID.
.It Fl X Ar excludefile
Pass
.Ar excludefile
as a
.Fl exclude-from
argument to
.Cm tar
when creating final package.
See
.Cm tar
man page (or run
.Cm tar
with
.Fl -help
flag) for further information on using this flag.
.It Fl D Ar displayfile
Display the file (by concatenating it to stdout)
after installing the package.
Useful for things like
legal notices on almost-free software, etc.
.It Fl m Ar mtreefile
Run
.Xr mtree 8
with input from mtreefile before the package is installed.
Mtree is invoked as
.Cm mtree
.Fl u
.Fl f
.Ar mtreefile
.Fl d
.Fl e
.Fl p
.Pa prefix ,
where
.Pa prefix
is the name of the first directory named by a
.Cm @cwd
directive.
.It Fl o , -origin Ar originpath
Record an
.Ar originpath ,
as location of the port from which package has been created in the
.Fx
.Em "Ports Collection" .
It should be in the form
.Pa MASTERCATEGORY/PORTDIR .
.It Fl j
Use
.Xr bzip2 1
utility to compress package tarball instead of
.Xr gzip 1 .
Please note that this option is a NO-OP if the format of the resulting
archive is explicitly specified by the recognizable suffix of
.Ar pkg-filename .
Currently
.Nm
recognizes the following suffixes:
.Pa .tbz , .tgz, .txz
and
.Pa .tar .
.It Fl y
Compatibility synonym for
.Fl j .
.It Fl z
Use
.Xr gzip 1
utility to compress package tarball.
.It Fl J
Use
.Xr xz 1
utility to compress package tarball instead of
.Xr gzip 1 .
Please note that this option is a NO-OP if the format of the resulting
archive is explicitly specified by the recognizable suffix of
.Ar pkg-filename .
Currently
.Nm
recognizes the following suffixes:
.Pa .tbz , .tgz, .txz
and
.Pa .tar .
.It Fl b , -backup Ar pkg-name
Create package file from a locally installed package named
.Ar pkg-name .
If the
.Ar pkg-filename
is not specified, then resulting archive will be created in the
current directory and named
.Ar pkg-name
with an appropriate extraction suffix applied.
.It Fl R , -recursive
When creating package file from a locally installed package
also create package files for all packages required by
.Ar pkg-name .
Resulting archive(s) will be created in the current directory
and named using name of the respective package with appropriate
extraction suffix applied.
.It Fl x , -regex
Use basic regular expressions for
.Ar pkg-name .
.It Fl E , -extended
Use extended (modern) regular expressions for
.Ar pkg-name .
.It Fl G , -no-glob
Use exact matching for
.Ar pkg-name .
.It Fl n
Run in
.Dq no clobber
mode.
If a package tarball exists, the
.Nm
utility will not overwrite it.
This is useful, for example, when multiple packages are saved with
several consecutive runs of
.Nm
with the
.Fl Rb
options.
Saving common dependencies multiple times would do a lot of duplicate
work in this case.
The
.Fl n
option avoids repackaging common dependencies multiple times.
.El
.Sh PACKING LIST DETAILS
The
.Dq 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 Op Ar directory
Set the internal directory pointer to point to
.Ar directory .
All subsequent filenames will be assumed relative to this directory.
If no
.Ar directory
argument is given, it will set the internal directory pointer to the
first prefix value.
Note:
.Cm @cd
is also an alias for this command.
.It Cm @srcdir Ar directory
Set the internal directory pointer for _creation only_ to
.Ar directory .
That is to say that it overrides
.Cm @cwd
for package creation but not extraction.
.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
.Dq 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
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
.Dq special sequence expansion
to get at files regardless of where they have
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 is later handed off to it, that is
no surprise).
Use without an arg to set back to default (extraction)
permissions.
.It Cm @option Ar option
Set internal package options, the only two currently supported ones
being
.Ar extract-in-place ,
which tells the pkg_add command not to extract the package's tarball
into a staging area but rather directly into the target
hierarchy (this is typically meant to be used only by distributions
or other special package types), and
.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
Imbed a comment in the packing list.
Useful in
trying to document some particularly hairy sequence that
may trip someone up later.
.It Cm @noinst Ar option Ar file
Specify that the package would have installed
.Pa file
if
.Pa option
had been specified at build time.
The action of
.Cm @noinst
is the same that
.Cm @comment
(which is doing nothing, it is just additional information).
.It Cm @ignore
Used internally to tell extraction to ignore the next file (do not
copy it anywhere), as it is used for some special purpose.
.It Cm @ignore_inst
Similar to
.Cm @ignore ,
but the ignoring of the next file is delayed one evaluation cycle.
This
makes it possible to use this directive in the
.Ar packinglist
file, so you can pack a
specialized datafile in with a distribution for your install script (or
something) yet have the installer ignore it.
.It Cm @name Ar name
Set the name of the package.
This is mandatory and is usually
put at the top.
This name is potentially different from 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 package name and add it automatically
if none is given.
.It Cm @dirrm Ar name
Declare directory
.Pa name
to be deleted at deinstall time.
By default, directories created by a
package installation are not deleted when the package is deinstalled;
this provides an explicit directory cleanup method.
This directive
should appear at the end of the package list.
If more than one
.Cm @dirrm
directives are used, the directories are removed in the order specified.
The
.Pa name
directory will not be removed unless it is empty.
.It Cm @mtree Ar name
Declare
.Pa name
as an
.Xr mtree 8
input file to be used at install time (see
.Fl m
above).
Only the first
.Cm @mtree
directive is honored.
.It Cm @display Ar name
Declare
.Pa name
as the file to be displayed at install time (see
.Fl D
above).
.It Cm @pkgdep Ar pkgname
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 @conflicts 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
The environment variable
.Ev PKG_TMPDIR
names the directory where
.Nm
will attempt to create its temporary files.
If
.Ev PKG_TMPDIR
is not set,
the directory named by the contents of
.Ev TMPDIR
will be used.
If neither of
.Ev PKG_TMPDIR
and
.Ev TMPDIR
are set, the builtin defaults are used.
.Sh FILES
.Bl -tag -width /usr/tmp -compact
.It Pa /var/tmp
Temporary directory if environmental variables
.Ev PKG_TMPDIR
and
.Ev TMPDIR
are not set.
.It Pa /tmp
The next choice if
.Pa /var/tmp
does not exist.
.It Pa /usr/tmp
The last choice if
.Pa /tmp
is unsuitable.
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Xr pkg_version 1 ,
.Xr sysconf 3
.Sh HISTORY
The
.Nm
command first appeared in
.Fx .
.Sh AUTHORS
.An Jordan Hubbard
.Sh CONTRIBUTORS
.An John Kohl Aq jtk@rational.com ,
.An Oliver Eikemeier Aq eik@FreeBSD.org
.Sh BUGS
Hard links between files in a distribution must be bracketed by
.Cm @cwd
directives in order to be preserved as hard links when the package is
extracted.
They additionally must not end up being split between
.Cm tar
invocations due to exec argument-space limitations (this depends on the
value returned by
.Fn sysconf _SC_ARG_MAX ) .
.Pp
Sure to be others.

View File

@ -1,281 +0,0 @@
/*
* 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
* 18 July 1993
*
* Routines for dealing with the packing list.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include "create.h"
#include <errno.h>
#include <err.h>
#include <md5.h>
/* Add an MD5 checksum entry for a file or link */
void
add_cksum(Package *pkg, PackingList p, const char *fname)
{
char *cp = NULL, buf[33];
if (issymlink(fname)) {
int len;
char lnk[FILENAME_MAX];
if ((len = readlink(fname, lnk, FILENAME_MAX)) > 0)
cp = MD5Data((unsigned char *)lnk, len, buf);
} else if (isfile(fname)) {
/* Don't record MD5 checksum for device nodes and such */
cp = MD5File(fname, buf);
}
if (cp != NULL) {
PackingList tmp = new_plist_entry();
tmp->name = copy_string(strconcat("MD5:", cp));
tmp->type = PLIST_COMMENT;
tmp->next = p->next;
tmp->prev = p;
p->next = tmp;
if (pkg->tail == p)
pkg->tail = tmp;
}
}
/* Check a list for files that require preconversion */
void
check_list(const char *home, Package *pkg)
{
const char *where = home;
const char *there = NULL;
char name[FILENAME_MAX];
char *prefix = NULL;
PackingList p;
for (p = pkg->head; p != NULL; p = p->next)
switch (p->type) {
case PLIST_CWD:
if (!prefix)
prefix = p->name;
where = (p->name == NULL) ? prefix : p->name;
break;
case PLIST_IGNORE:
p = p->next;
break;
case PLIST_SRC:
there = p->name;
break;
case PLIST_FILE:
if (there)
snprintf(name, sizeof(name), "%s/%s", there, p->name);
else
snprintf(name, sizeof(name), "%s%s/%s",
BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name);
add_cksum(pkg, p, name);
break;
default:
break;
}
}
static int
trylink(const char *from, const char *to)
{
if (link(from, to) == 0)
return 0;
if (errno == ENOENT) {
/* try making the container directory */
char *cp = strrchr(to, '/');
if (cp)
vsystem("/bin/mkdir -p %.*s", cp - to,
to);
return link(from, to);
}
return -1;
}
#define STARTSTRING "/usr/bin/tar cf -"
#define TOOBIG(str) (int)strlen(str) + 6 + (int)strlen(home) + where_count > maxargs
#define PUSHOUT() /* push out string */ \
if (where_count > (int)sizeof(STARTSTRING)-1) { \
strcat(where_args, "|/usr/bin/tar xpf -"); \
if (system(where_args)) { \
cleanup(0); \
errx(2, "%s: can't invoke tar pipeline", __func__); \
} \
memset(where_args, 0, maxargs); \
last_chdir = NULL; \
strcpy(where_args, STARTSTRING); \
where_count = sizeof(STARTSTRING)-1; \
}
/*
* Copy unmarked files in packing list to playpen - marked files
* have already been copied in an earlier pass through the list.
*/
void
copy_plist(const char *home, Package *plist)
{
PackingList p = plist->head;
const char *where = home;
const char *there = NULL, *mythere;
char *where_args, *prefix = NULL;
const char *last_chdir, *root = "/";
long maxargs;
int where_count = 0, add_count;
struct stat stb;
dev_t curdir;
maxargs = sysconf(_SC_ARG_MAX);
maxargs -= 64; /*
* Some slop for the tar cmd text,
* and sh -c
*/
where_args = malloc(maxargs);
if (!where_args) {
cleanup(0);
errx(2, "%s: can't get argument list space", __func__);
}
memset(where_args, 0, maxargs);
strcpy(where_args, STARTSTRING);
where_count = sizeof(STARTSTRING)-1;
last_chdir = 0;
if (stat(".", &stb) == 0)
curdir = stb.st_dev;
else
curdir = (dev_t) -1; /*
* It's ok if this is a valid dev_t;
* this is just a hint for an
* optimization.
*/
while (p) {
if (p->type == PLIST_CWD)
{
if (!prefix)
prefix = p->name;
where = p->name == NULL ? prefix : p->name;
}
else if (p->type == PLIST_SRC)
there = p->name;
else if (p->type == PLIST_IGNORE)
p = p->next;
else if (p->type == PLIST_FILE && !p->marked) {
char fn[FILENAME_MAX];
/* First, look for it in the "home" dir */
sprintf(fn, "%s/%s", home, p->name);
if (fexists(fn)) {
if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
S_ISREG(stb.st_mode)) {
/*
* If we can link it to the playpen, that avoids a copy
* and saves time.
*/
if (p->name[0] != '/') {
/*
* Don't link abspn stuff--it doesn't come from
* local dir!
*/
if (trylink(fn, p->name) == 0) {
p = p->next;
continue;
}
}
}
if (TOOBIG(fn)) {
PUSHOUT();
}
if (p->name[0] == '/') {
add_count = snprintf(&where_args[where_count],
maxargs - where_count,
" %s %s",
last_chdir == root ? "" : "-C /",
p->name);
last_chdir = root;
} else {
add_count = snprintf(&where_args[where_count],
maxargs - where_count,
" %s%s %s",
last_chdir == home ? "" : "-C ",
last_chdir == home ? "" : home,
p->name);
last_chdir = home;
}
if (add_count < 0 || add_count >= maxargs - where_count) {
cleanup(0);
errx(2, "%s: oops, miscounted strings!", __func__);
}
where_count += add_count;
}
/*
* Otherwise, try along the actual extraction path..
*/
else {
if (p->name[0] == '/')
mythere = root;
else mythere = there;
if (mythere)
snprintf(fn, sizeof(fn), "%s/%s", mythere, p->name);
else
snprintf(fn, sizeof(fn), "%s%s/%s",
BaseDir && where && where[0] == '/' ? BaseDir : "", where, p->name);
if (lstat(fn, &stb) == 0 && stb.st_dev == curdir &&
S_ISREG(stb.st_mode)) {
/*
* If we can link it to the playpen, that avoids a copy
* and saves time.
*/
if (trylink(fn, p->name) == 0) {
p = p->next;
continue;
}
}
if (TOOBIG(p->name)) {
PUSHOUT();
}
if (last_chdir == (mythere ? mythere : where))
add_count = snprintf(&where_args[where_count],
maxargs - where_count,
" %s", p->name);
else
add_count = snprintf(&where_args[where_count],
maxargs - where_count,
" -C %s %s",
mythere ? mythere : where,
p->name);
if (add_count < 0 || add_count >= maxargs - where_count) {
cleanup(0);
errx(2, "%s: oops, miscounted strings!", __func__);
}
where_count += add_count;
last_chdir = (mythere ? mythere : where);
}
}
p = p->next;
}
PUSHOUT();
free(where_args);
}

View File

@ -1,13 +0,0 @@
# $FreeBSD$
PROG= pkg_delete
SRCS= main.c perform.c
CFLAGS+= -I${.CURDIR}/../lib
WFORMAT?= 1
DPADD= ${LIBINSTALL} ${LIBMD}
LDADD= ${LIBINSTALL} -lmd
.include <bsd.prog.mk>

View File

@ -1,35 +0,0 @@
/* $FreeBSD$ */
/*
* 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
* 18 July 1993
*
* Include and define various things wanted by the delete command.
*
*/
#ifndef _INST_DELETE_H_INCLUDE
#define _INST_DELETE_H_INCLUDE
extern char *Prefix;
extern Boolean CleanDirs;
extern Boolean Interactive;
extern Boolean NoDeInstall;
extern Boolean Recursive;
extern char *Directory;
extern char *PkgName;
extern match_t MatchType;
#endif /* _INST_DELETE_H_INCLUDE */

View File

@ -1,180 +0,0 @@
/*
*
* 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
* 18 July 1993
*
* This is the delete module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <err.h>
#include "lib.h"
#include "delete.h"
char *Prefix = NULL;
Boolean CleanDirs = FALSE;
Boolean Interactive = FALSE;
Boolean NoDeInstall = FALSE;
Boolean Recursive = FALSE;
match_t MatchType = MATCH_GLOB;
static void usage(void);
static char opts[] = "adDfGhinp:rvxX";
static struct option longopts[] = {
{ "all", no_argument, NULL, 'a' },
{ "clean-dirs", no_argument, NULL, 'd' },
{ "dry-run", no_argument, NULL, 'n' },
{ "extended", no_argument, NULL, 'X' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "interactive",no_argument, NULL, 'i' },
{ "prefix", required_argument, NULL, 'p' },
{ "recursive", no_argument, NULL, 'r' },
{ "regex", no_argument, NULL, 'x' },
{ "no-glob", no_argument, NULL, 'G' },
{ "no-script", no_argument, NULL, 'D' },
{ "no-scripts", no_argument, NULL, 'D' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 },
};
int
main(int argc, char **argv)
{
int ch, error;
char **pkgs, **start;
char *pkgs_split;
const char *tmp;
struct stat stat_s;
warnpkgng();
pkgs = start = argv;
while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1)
switch(ch) {
case 'v':
Verbose++;
break;
case 'f':
Force = TRUE;
break;
case 'p':
Prefix = optarg;
break;
case 'D':
NoDeInstall = TRUE;
break;
case 'd':
CleanDirs = TRUE;
break;
case 'n':
Fake = TRUE;
Verbose = TRUE;
break;
case 'a':
MatchType = MATCH_ALL;
break;
case 'G':
MatchType = MATCH_EXACT;
break;
case 'x':
MatchType = MATCH_REGEX;
break;
case 'X':
MatchType = MATCH_EREGEX;
break;
case 'i':
Interactive = TRUE;
break;
case 'r':
Recursive = TRUE;
break;
case 'h':
default:
usage();
break;
}
argc -= optind;
argv += optind;
/* Get all the remaining package names, if any */
while (*argv) {
/* Don't try to apply heuristics if arguments are regexs */
if (MatchType != MATCH_REGEX)
while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
*pkgs_split++ = '\0';
/*
* If character after the '/' is alphanumeric, then we've found the
* package name. Otherwise we've come across a trailing '/' and
* need to continue our quest.
*/
if (isalnum(*pkgs_split) || ((MatchType == MATCH_GLOB) && \
strpbrk(pkgs_split, "*?[]") != NULL)) {
*argv = pkgs_split;
break;
}
}
*pkgs++ = *argv++;
}
/* If no packages, yelp */
if (pkgs == start && MatchType != MATCH_ALL)
warnx("missing package name(s)"), usage();
*pkgs = NULL;
tmp = LOG_DIR;
(void) stat(tmp, &stat_s);
if (!Fake && getuid() && geteuid() != stat_s.st_uid) {
if (!Force)
errx(1, "you do not own %s, use -f to force", tmp);
else
warnx("you do not own %s (proceeding anyways)", tmp);
}
if ((error = pkg_perform(start)) != 0) {
if (Verbose)
warnx("%d package deletion(s) failed", error);
return error;
}
else
return 0;
}
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n",
"usage: pkg_delete [-dDfGinrvxX] [-p prefix] pkg-name ...",
" pkg_delete -a [flags]");
exit(1);
}

View File

@ -1,425 +0,0 @@
/*
* 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
* 18 July 1993
*
* This is the main body of the delete module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include "lib.h"
#include "delete.h"
static int pkg_do(char *);
static void sanity_check(char *);
static void undepend(char *, char *);
static char LogDir[FILENAME_MAX];
int
pkg_perform(char **pkgs)
{
char **matched, **rb, **rbtmp;
int errcode, i, j;
int err_cnt = 0;
struct reqr_by_entry *rb_entry;
struct reqr_by_head *rb_list;
if (MatchType != MATCH_EXACT) {
matched = matchinstalled(MatchType, pkgs, &errcode);
if (errcode != 0)
return 1;
/* Not reached */
/*
* Copy matched[] into pkgs[], because we'll need to use
* matchinstalled() later on.
*/
if (matched != NULL) {
pkgs = NULL;
for (i = 0; matched[i] != NULL; i++) {
pkgs = realloc(pkgs, sizeof(*pkgs) * (i + 2));
pkgs[i] = strdup(matched[i]);
}
pkgs[i] = NULL;
}
else switch (MatchType) {
case MATCH_GLOB:
break;
case MATCH_ALL:
warnx("no packages installed");
return 0;
case MATCH_EREGEX:
case MATCH_REGEX:
warnx("no packages match pattern(s)");
return 1;
default:
break;
}
}
err_cnt += sortdeps(pkgs);
for (i = 0; pkgs[i]; i++) {
if (Recursive == TRUE) {
errcode = requiredby(pkgs[i], &rb_list, FALSE, TRUE);
if (errcode < 0) {
err_cnt++;
} else if (errcode > 0) {
/*
* Copy values from the rb_list queue into argv-like NULL
* terminated list because requiredby() uses some static
* storage, while pkg_do() below will call this function,
* thus blowing our rb_list away.
*/
rbtmp = rb = alloca((errcode + 1) * sizeof(*rb));
if (rb == NULL) {
warnx("%s(): alloca() failed", __func__);
err_cnt++;
continue;
}
STAILQ_FOREACH(rb_entry, rb_list, link) {
*rbtmp = alloca(strlen(rb_entry->pkgname) + 1);
if (*rbtmp == NULL) {
warnx("%s(): alloca() failed", __func__);
err_cnt++;
continue;
}
strcpy(*rbtmp, rb_entry->pkgname);
rbtmp++;
}
*rbtmp = NULL;
err_cnt += sortdeps(rb);
for (j = 0; rb[j]; j++)
err_cnt += pkg_do(rb[j]);
}
}
err_cnt += pkg_do(pkgs[i]);
}
return err_cnt;
}
static Package Plist;
/* This is seriously ugly code following. Written very fast! */
static int
pkg_do(char *pkg)
{
FILE *cfile;
char *deporigin, **deporigins = NULL, **depnames = NULL, ***depmatches, home[FILENAME_MAX];
PackingList p;
int i, len;
int isinstalled;
/* support for separate pre/post install scripts */
int new_m = 0, dep_count = 0;
const char *pre_script = DEINSTALL_FNAME;
const char *post_script, *pre_arg, *post_arg;
struct reqr_by_entry *rb_entry;
struct reqr_by_head *rb_list;
int fd;
struct stat sb;
if (!pkg || !(len = strlen(pkg)))
return 1;
if (pkg[len - 1] == '/')
pkg[len - 1] = '\0';
/* Reset some state */
if (Plist.head)
free_plist(&Plist);
sprintf(LogDir, "%s/%s", LOG_DIR, pkg);
isinstalled = isinstalledpkg(pkg);
if (isinstalled == 0) {
warnx("no such package '%s' installed", pkg);
return 1;
} else if (isinstalled < 0) {
warnx("the package info for package '%s' is corrupt%s",
pkg, Force ? " (but I'll delete it anyway)" : " (use -f to force removal)");
if (!Force)
return 1;
if (!Fake) {
if (vsystem("%s -rf %s", REMOVE_CMD, LogDir)) {
warnx("couldn't remove log entry in %s, deinstall failed", LogDir);
} else {
warnx("couldn't completely deinstall package '%s',\n"
"only the log entry in %s was removed", pkg, LogDir);
}
}
return 0;
}
if (!getcwd(home, FILENAME_MAX)) {
cleanup(0);
errx(2, "%s: unable to get current working directory!", __func__);
}
if (chdir(LogDir) == FAIL) {
warnx("unable to change directory to %s! deinstall failed", LogDir);
return 1;
}
if (Interactive == TRUE) {
int first, ch;
(void)fprintf(stderr, "delete %s? ", pkg);
(void)fflush(stderr);
first = ch = getchar();
while (ch != '\n' && ch != EOF)
ch = getchar();
if (first != 'y' && first != 'Y')
return 0;
/* Not reached */
}
if (requiredby(pkg, &rb_list, FALSE, TRUE) < 0)
return 1;
if (!STAILQ_EMPTY(rb_list)) {
warnx("package '%s' is required by these other packages\n"
"and may not be deinstalled%s:",
pkg, Force ? " (but I'll delete it anyway)" : "");
STAILQ_FOREACH(rb_entry, rb_list, link)
fprintf(stderr, "%s\n", rb_entry->pkgname);
if (!Force)
return 1;
}
sanity_check(LogDir);
cfile = fopen(CONTENTS_FNAME, "r");
if (!cfile) {
warnx("unable to open '%s' file", CONTENTS_FNAME);
return 1;
}
/* If we have a prefix, add it now */
if (Prefix)
add_plist(&Plist, PLIST_CWD, Prefix);
read_plist(&Plist, cfile);
fclose(cfile);
p = find_plist(&Plist, PLIST_CWD);
if (!p) {
warnx("package '%s' doesn't have a prefix", pkg);
return 1;
}
setenv(PKG_PREFIX_VNAME, p->name, 1);
if ((fd = open(REQUIRE_FNAME, O_RDWR)) != -1) {
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IXALL); /* be sure, chmod a+x */
close(fd);
if (Verbose)
printf("Executing 'require' script.\n");
if (vsystem("./%s %s DEINSTALL", REQUIRE_FNAME, pkg)) {
warnx("package %s fails requirements %s", pkg,
Force ? "" : "- not deleted");
if (!Force)
return 1;
}
}
/*
* Test whether to use the old method of passing tokens to deinstallation
* scripts, and set appropriate variables..
*/
if (fexists(POST_DEINSTALL_FNAME)) {
new_m = 1;
post_script = POST_DEINSTALL_FNAME;
pre_arg = post_arg = "";
} else if (fexists(DEINSTALL_FNAME)) {
post_script = DEINSTALL_FNAME;
pre_arg = "DEINSTALL";
post_arg = "POST-DEINSTALL";
} else {
post_script = pre_arg = post_arg = NULL;
}
if (!NoDeInstall && pre_script != NULL && (fd = open(pre_script, O_RDWR)) != -1) {
if (Fake)
printf("Would execute de-install script at this point.\n");
else {
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IXALL); /* be sure, chmod a+x */
close(fd);
if (vsystem("./%s %s %s", pre_script, pkg, pre_arg)) {
warnx("deinstall script returned error status");
if (!Force)
return 1;
}
}
}
for (p = Plist.head; p ; p = p->next) {
if (p->type != PLIST_PKGDEP)
continue;
deporigin = (p->next != NULL && p->next->type == PLIST_DEPORIGIN) ? p->next->name :
NULL;
if (Verbose) {
printf("Trying to remove dependency on package '%s'", p->name);
if (deporigin != NULL)
printf(" with '%s' origin", deporigin);
printf(".\n");
}
if (!Fake) {
if (deporigin) {
deporigins = realloc(deporigins, (dep_count + 2) * sizeof(*deporigins));
depnames = realloc(depnames, (dep_count + 1) * sizeof(*depnames));
deporigins[dep_count] = deporigin;
deporigins[dep_count + 1] = NULL;
depnames[dep_count] = p->name;
dep_count++;
} else {
undepend(p->name, pkg);
}
}
}
if (dep_count > 0) {
/* Undepend all the dependencies at once */
depmatches = matchallbyorigin((const char **)deporigins, NULL);
free(deporigins);
if (depmatches) {
for (i = 0; i < dep_count; i++) {
if (depmatches[i]) {
char **tmp = depmatches[i];
int j;
for (j = 0; tmp[j] != NULL; j++)
undepend(tmp[j], pkg);
} else if (depnames[i]) {
undepend(depnames[i], pkg);
}
}
}
}
if (chdir(home) == FAIL) {
cleanup(0);
errx(2, "%s: unable to return to working directory %s!", __func__,
home);
}
/*
* Some packages aren't packed right, so we need to just ignore
* delete_package()'s status. Ugh! :-(
*/
if (delete_package(FALSE, CleanDirs, &Plist) == FAIL)
warnx(
"couldn't entirely delete package `%s'\n"
"(perhaps the packing list is incorrectly specified?)", pkg);
if (chdir(LogDir) == FAIL) {
warnx("unable to change directory to %s! deinstall failed", LogDir);
return 1;
}
if (!NoDeInstall && post_script != NULL && (fd = open(post_script, O_RDWR)) != -1) {
if (Fake)
printf("Would execute post-deinstall script at this point.\n");
else {
fstat(fd, &sb);
fchmod(fd, sb.st_mode | S_IXALL); /* be sure, chmod a+x */
close(fd);
if (vsystem("./%s %s %s", post_script, pkg, post_arg)) {
warnx("post-deinstall script returned error status");
if (!Force)
return 1;
}
}
}
if (chdir(home) == FAIL) {
cleanup(0);
errx(2, "%s: unable to return to working directory %s!", __func__,
home);
}
if (!Fake) {
if (vsystem("%s -r%c %s", REMOVE_CMD, Force ? 'f' : ' ', LogDir)) {
warnx("couldn't remove log entry in %s, deinstall failed", LogDir);
if (!Force)
return 1;
}
}
return 0;
}
static void
sanity_check(char *pkg)
{
if (!fexists(CONTENTS_FNAME)) {
cleanup(0);
errx(2, "%s: installed package %s has no %s file!", __func__,
pkg, CONTENTS_FNAME);
}
}
void
cleanup(int sig)
{
if (sig)
exit(1);
}
static void
undepend(char *p, char *pkgname)
{
char fname[FILENAME_MAX], ftmp[FILENAME_MAX];
FILE *fpwr;
int s;
struct reqr_by_entry *rb_entry;
struct reqr_by_head *rb_list;
if (requiredby(p, &rb_list, Verbose, FALSE) <= 0)
return;
snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, p, REQUIRED_BY_FNAME);
snprintf(ftmp, sizeof(ftmp), "%s.XXXXXX", fname);
s = mkstemp(ftmp);
if (s == -1) {
warnx("couldn't open temp file '%s'", ftmp);
return;
}
fpwr = fdopen(s, "w");
if (fpwr == NULL) {
close(s);
warnx("couldn't fdopen temp file '%s'", ftmp);
goto cleanexit;
}
STAILQ_FOREACH(rb_entry, rb_list, link)
if (strcmp(rb_entry->pkgname, pkgname)) /* no match */
fputs(rb_entry->pkgname, fpwr), putc('\n', fpwr);
if (fchmod(s, 0644) == FAIL) {
warnx("error changing permission of temp file '%s'", ftmp);
fclose(fpwr);
goto cleanexit;
}
if (fclose(fpwr) == EOF) {
warnx("error closing temp file '%s'", ftmp);
goto cleanexit;
}
if (rename(ftmp, fname) == -1)
warnx("error renaming '%s' to '%s'", ftmp, fname);
cleanexit:
remove(ftmp);
return;
}

View File

@ -1,297 +0,0 @@
.\"
.\" 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_delete.1
.\" $FreeBSD$
.\"
.Dd November 9, 2012
.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 dDfGinrvxX
.Op Fl p Ar prefix
.Ar pkg-name ...
.Nm
.Fl a
.Op Ar flags
.Sh DESCRIPTION
The
.Nm
command is used to delete packages that have been previously installed
with the
.Xr pkg_add 1
command.
.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 Em 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 ( /var/db/pkg/<pkg-name>/ ) .
Pay particular attention to any +INSTALL, +POST-INSTALL, +DEINSTALL,
+POST-DEINSTALL, +REQUIRE or +MTREE_DIRS files, and inspect the +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.
.It Fl a , -all
Unconditionally delete all currently installed packages.
.It Fl i , -interactive
Request confirmation before attempting to delete each package,
regardless whether or not the standard input device is a
terminal.
.It Fl v , -verbose
Turn on verbose output.
.It Fl D , -no-script , -no-scripts
If a deinstallation script exists for a given package, do not execute it.
.It Fl n , -dry-run
Do not actually deinstall a package, just report the steps that
would be taken if it were.
.It Fl p , -prefix 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 d , -clean-dirs
Remove empty directories created by file cleanup.
By default, only
files/directories explicitly listed in a package's contents (either as
normal files/directories or with the
.Cm @dirrm
directive) will be removed at deinstallation time.
This option tells
.Nm
to also remove any directories that were emptied as a result of removing
the package.
.It Fl f , -force
Force removal of the package, even if a dependency is recorded or the
deinstall or require script fails.
.It Fl G , -no-glob
Do not try to expand shell glob patterns in the
.Ar pkg-name
when selecting packages to be deleted (by default
.Nm
automatically expands shell glob patterns in the
.Ar pkg-name ) .
.It Fl x , -regex
Treat the
.Ar pkg-name
as a regular expression and delete all packages whose names match
that regular expression.
Multiple regular expressions could be
provided, in that case
.Nm
deletes all packages that match at least one
regular expression from the list.
.It Fl X , -extended
Like
.Fl x ,
but treats the
.Ar pkg-name
as an extended regular expression.
.It Fl r , -recursive
Recursive removal.
In addition to specified packages, delete all
packages that depend on those packages as well.
.El
.Sh TECHNICAL DETAILS
The
.Nm
utility
does pretty much what it says.
It examines installed package records in
.Pa /var/db/pkg/<pkg-name> ,
deletes the package contents, and finally removes the package records.
If the environment variable
.Ev PKG_DBDIR
is set, this overrides the
.Pa /var/db/pkg/
path shown above.
.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 the package contains a
.Ar require
file (see
.Xr pkg_create 1 ) ,
then this is executed first as
.Bd -ragged -offset indent -compact
.Cm require
.Ar <pkg-name>
.Ar DEINSTALL
.Ed
(where
.Ar pkg-name
is the name of the package in question and
.Ar DEINSTALL
is a keyword denoting that this is a deinstallation)
to see whether or not deinstallation should continue.
A non-zero exit
status means no, unless the
.Fl f
option is specified.
.Pp
If a
.Cm deinstall
script exists for the package, it is executed before 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
.Nm deinstall
script is called as:
.Bd -ragged -offset indent -compact
.Cm script
.Ar <pkg-name>
.Ar DEINSTALL
.Ed
where
.Ar pkg-name
is the name of the package in question and
.Ar DEINSTALL
is a keyword denoting this as the pre-deinstallation phase.
.Pp
.Sy Note :
The
.Ar DEINSTALL
keyword will not appear if separate scripts for deinstall and post-deinstall
are given during package creation time (using the
.Fl k
and
.Fl K
flags to
.Xr pkg_create 1 ) .
.Pp
If a
.Cm post-deinstall
script exists for the package, it is executed
.Cm after
all files are removed.
It is this script's responsibility to clean up any
additional messy details around the package's installation, and leave the
system (hopefully) in the same state that it was prior to the installation
of the package.
.Pp
The
.Nm post-deinstall
script is called as:
.Bd -ragged -offset indent -compact
.Cm script
.Ar <pkg-name>
.Ar POST-DEINSTALL
.Ed
where
.Ar pkg-name
is the name of the package in question and
.Ar POST-DEINSTALL
is a keyword denoting this as the post-deinstallation phase.
.Pp
.Sy Note :
The
.Ar POST-DEINSTALL
keyword will not appear if separate scripts for deinstall and post-deinstall
are given during package creation time (using the
.Fl k
and
.Fl K
flags to
.Xr pkg_create 1 ) .
.Pp
Reasoning behind passing keywords such as
.Ar DEINSTALL
and
.Ar POST-DEINSTALL
is that it lets you potentially write only one program/script that handles
all aspects of installation and deletion.
.Pp
But experience has proved that this is a lot more difficult to maintain and
is not as advantageous as having separate scripts that handle each aspect of
installation and deinstallation.
.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
.Cm pkg_add .
.Sh ENVIRONMENT
The environment variable
.Ev PKG_DBDIR
specifies an alternative location for the installed package database.
.Sh FILES
.Bl -tag -width /var/db/pkg -compact
.It Pa /var/db/pkg
Default location of the installed package database.
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_create 1 ,
.Xr pkg_info 1 ,
.Xr pkg_version 1 ,
.Xr mktemp 3 ,
.Xr mtree 8
.Sh AUTHORS
.An Jordan Hubbard
.Sh CONTRIBUTORS
.An John Kohl Aq jtk@rational.com ,
.An Oliver Eikemeier Aq eik@FreeBSD.org
.Sh BUGS
Sure to be some.

View File

@ -1,13 +0,0 @@
# $FreeBSD$
PROG= pkg_info
SRCS= main.c perform.c show.c
CFLAGS+= -I${.CURDIR}/../lib
WFORMAT?= 1
DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD}
LDADD= ${LIBINSTALL} -lfetch -lmd
.include <bsd.prog.mk>

View File

@ -1,84 +0,0 @@
/* $FreeBSD$ */
/*
* 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
* 23 August 1993
*
* Include and define various things wanted by the info command.
*
*/
#ifndef _INST_INFO_H_INCLUDE
#define _INST_INFO_H_INCLUDE
#include <sys/queue.h>
#ifndef MAXINDEXSIZE
#define MAXINDEXSIZE 59
#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_REQUIRE 0x00020
#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_SIZE 0x01000
#define SHOW_ORIGIN 0x02000
#define SHOW_CKSUM 0x04000
#define SHOW_FMTREV 0x08000
#define SHOW_PTREV 0x10000
#define SHOW_DEPEND 0x20000
#define SHOW_PKGNAME 0x40000
struct which_entry {
TAILQ_ENTRY(which_entry) next;
char file[PATH_MAX];
char package[PATH_MAX];
Boolean skip;
};
TAILQ_HEAD(which_head, which_entry);
extern int Flags;
extern Boolean QUIET;
extern Boolean UseBlkSz;
extern Boolean KeepPackage;
extern char *InfoPrefix;
extern char PlayPen[];
extern char *CheckPkg;
extern char *LookUpOrigin;
extern match_t MatchType;
extern struct which_head *whead;
extern void show_file(const char *, const char *);
extern void show_plist(const char *, Package *, plist_t, Boolean);
extern void show_files(const char *, Package *);
extern void show_index(const char *, const char *);
extern void show_size(const char *, Package *);
extern int show_cksum(const char *, Package *);
extern void show_origin(const char *, Package *);
extern void show_fmtrev(const char *, Package *);
#endif /* _INST_INFO_H_INCLUDE */

View File

@ -1,295 +0,0 @@
/*
*
* 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
* 18 July 1993
*
* This is the info module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <getopt.h>
#include <err.h>
#include "lib.h"
#include "info.h"
int Flags = 0;
match_t MatchType = MATCH_GLOB;
Boolean QUIET = FALSE;
Boolean UseBlkSz = FALSE;
char *InfoPrefix = (char *)(uintptr_t)"";
char PlayPen[FILENAME_MAX];
char *CheckPkg = NULL;
char *LookUpOrigin = NULL;
Boolean KeepPackage = FALSE;
struct which_head *whead;
static void usage(void);
static char opts[] = "abcdDe:EfgGhiIjkKl:LmoO:pPqQrRst:vVW:xX";
static struct option longopts[] = {
{ "all", no_argument, NULL, 'a' },
{ "blocksize", no_argument, NULL, 'b' },
{ "exist", required_argument, NULL, 'X' },
{ "exists", required_argument, NULL, 'X' },
{ "extended", no_argument, NULL, 'e' },
{ "help", no_argument, NULL, 'h' },
{ "keep", no_argument, NULL, 'K' },
{ "no-glob", no_argument, NULL, 'G' },
{ "origin", required_argument, NULL, 'O' },
{ "quiet", no_argument, NULL, 'q' },
{ "regex", no_argument, NULL, 'x' },
{ "template", required_argument, NULL, 't' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'P' },
{ "which", required_argument, NULL, 'W' },
{ NULL, 0, NULL, 0 }
};
int
main(int argc, char **argv)
{
int ch;
char **pkgs, **start;
char *pkgs_split;
warnpkgng();
whead = malloc(sizeof(struct which_head));
if (whead == NULL)
err(2, NULL);
TAILQ_INIT(whead);
pkgs = start = argv;
if (argc == 1) {
MatchType = MATCH_ALL;
Flags = SHOW_INDEX;
}
else while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
switch(ch) {
case 'a':
MatchType = MATCH_ALL;
break;
case 'b':
UseBlkSz = TRUE;
break;
case 'v':
Verbose++;
/* Reasonable definition of 'everything' */
Flags = SHOW_COMMENT | SHOW_DESC | SHOW_PLIST | SHOW_INSTALL |
SHOW_DEINSTALL | SHOW_REQUIRE | SHOW_DISPLAY | SHOW_MTREE;
break;
case 'E':
Flags |= SHOW_PKGNAME;
break;
case 'I':
Flags |= SHOW_INDEX;
break;
case 'p':
Flags |= SHOW_PREFIX;
break;
case 'c':
Flags |= SHOW_COMMENT;
break;
case 'd':
Flags |= SHOW_DESC;
break;
case 'D':
Flags |= SHOW_DISPLAY;
break;
case 'f':
Flags |= SHOW_PLIST;
break;
case 'g':
Flags |= SHOW_CKSUM;
break;
case 'G':
MatchType = MATCH_EXACT;
break;
case 'i':
Flags |= SHOW_INSTALL;
break;
case 'j':
Flags |= SHOW_REQUIRE;
break;
case 'k':
Flags |= SHOW_DEINSTALL;
break;
case 'K':
KeepPackage = TRUE;
break;
case 'r':
Flags |= SHOW_DEPEND;
break;
case 'R':
Flags |= SHOW_REQBY;
break;
case 'L':
Flags |= SHOW_FILES;
break;
case 'm':
Flags |= SHOW_MTREE;
break;
case 's':
Flags |= SHOW_SIZE;
break;
case 'o':
Flags |= SHOW_ORIGIN;
break;
case 'O':
LookUpOrigin = strdup(optarg);
if (LookUpOrigin == NULL)
err(2, NULL);
break;
case 'V':
Flags |= SHOW_FMTREV;
break;
case 'l':
InfoPrefix = optarg;
break;
case 'q':
Quiet = TRUE;
break;
case 'Q':
Quiet = TRUE;
QUIET = TRUE;
break;
case 't':
strlcpy(PlayPen, optarg, sizeof(PlayPen));
break;
case 'x':
MatchType = MATCH_REGEX;
break;
case 'X':
MatchType = MATCH_EREGEX;
break;
case 'e':
CheckPkg = optarg;
break;
case 'W':
{
struct which_entry *entp;
entp = calloc(1, sizeof(struct which_entry));
if (entp == NULL)
err(2, NULL);
strlcpy(entp->file, optarg, PATH_MAX);
entp->skip = FALSE;
TAILQ_INSERT_TAIL(whead, entp, next);
break;
}
case 'P':
Flags = SHOW_PTREV;
break;
case 'h':
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (Flags & SHOW_PTREV) {
if (!Quiet)
printf("Package tools revision: ");
printf("%d\n", PKG_INSTALL_VERSION);
exit(0);
}
/* Set some reasonable defaults */
if (!Flags)
Flags = SHOW_COMMENT | SHOW_DESC | SHOW_REQBY;
/* Get all the remaining package names, if any */
while (*argv) {
/*
* Don't try to apply heuristics if arguments are regexs or if
* the argument refers to an existing file.
*/
if (MatchType != MATCH_REGEX && MatchType != MATCH_EREGEX && !isfile(*argv) && !isURL(*argv))
while ((pkgs_split = strrchr(*argv, (int)'/')) != NULL) {
*pkgs_split++ = '\0';
/*
* If character after the '/' is alphanumeric or shell
* metachar, then we've found the package name. Otherwise
* we've come across a trailing '/' and need to continue our
* quest.
*/
if (isalnum(*pkgs_split) || ((MatchType == MATCH_GLOB) && \
strpbrk(pkgs_split, "*?[]") != NULL)) {
*argv = pkgs_split;
break;
}
}
*pkgs++ = *argv++;
}
/* If no packages, yelp */
if (pkgs == start && MatchType != MATCH_ALL && !CheckPkg &&
TAILQ_EMPTY(whead) && LookUpOrigin == NULL)
warnx("missing package name(s)"), usage();
*pkgs = NULL;
return pkg_perform(start);
}
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
"usage: pkg_info [-bcdDEfgGiIjkKLmopPqQrRsvVxX] [-e package] [-l prefix]",
" [-t template] -a | pkg-name ...",
" pkg_info [-qQ] -W filename",
" pkg_info [-qQ] -O origin",
" pkg_info");
exit(1);
}

View File

@ -1,476 +0,0 @@
/*
* 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
* 23 Aug 1993
*
* This is the main body of the info module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include "info.h"
#include <err.h>
#include <signal.h>
static int pkg_do(char *);
static int find_pkg(struct which_head *);
static int cmp_path(const char *, const char *, const char *);
static char *abspath(const char *);
static int find_pkgs_by_origin(const char *);
static int matched_packages(char **pkgs);
int
pkg_perform(char **pkgs)
{
char **matched;
int err_cnt = 0;
int i, errcode;
signal(SIGINT, cleanup);
/* Overriding action? */
if (Flags & SHOW_PKGNAME) {
return matched_packages(pkgs);
} else if (CheckPkg) {
return isinstalledpkg(CheckPkg) > 0 ? 0 : 1;
/* Not reached */
} else if (!TAILQ_EMPTY(whead)) {
return find_pkg(whead);
} else if (LookUpOrigin != NULL) {
return find_pkgs_by_origin(LookUpOrigin);
}
if (MatchType != MATCH_EXACT) {
matched = matchinstalled(MatchType, pkgs, &errcode);
if (errcode != 0)
return 1;
/* Not reached */
if (matched != NULL)
pkgs = matched;
else switch (MatchType) {
case MATCH_GLOB:
break;
case MATCH_ALL:
warnx("no packages installed");
return 0;
/* Not reached */
case MATCH_REGEX:
case MATCH_EREGEX:
warnx("no packages match pattern(s)");
return 1;
/* Not reached */
default:
break;
}
}
for (i = 0; pkgs[i]; i++)
err_cnt += pkg_do(pkgs[i]);
return err_cnt;
}
static int
pkg_do(char *pkg)
{
Boolean installed = FALSE, isTMP = FALSE;
char log_dir[FILENAME_MAX];
char fname[FILENAME_MAX];
Package plist;
FILE *fp;
struct stat sb;
const char *cp = NULL;
int code = 0;
if (isURL(pkg)) {
if ((cp = fileGetURL(NULL, pkg, KeepPackage)) != NULL) {
if (!getcwd(fname, FILENAME_MAX))
upchuck("getcwd");
isTMP = TRUE;
} else {
goto bail;
}
}
else if (fexists(pkg) && isfile(pkg)) {
int len;
if (*pkg != '/') {
if (!getcwd(fname, FILENAME_MAX))
upchuck("getcwd");
len = strlen(fname);
snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
}
else
strcpy(fname, pkg);
cp = fname;
}
else {
if ((cp = fileFindByPath(NULL, pkg)) != NULL)
strncpy(fname, cp, FILENAME_MAX);
}
if (cp) {
if (!isURL(pkg)) {
/*
* Apply a crude heuristic to see how much space the package will
* take up once it's unpacked. I've noticed that most packages
* compress an average of 75%, but we're only unpacking the + files so
* be very optimistic.
*/
if (stat(fname, &sb) == FAIL) {
warnx("can't stat package file '%s'", fname);
code = 1;
goto bail;
}
make_playpen(PlayPen, sb.st_size / 2);
if (unpack(fname, "'+*'")) {
warnx("error during unpacking, no info for '%s' available", pkg);
code = 1;
goto bail;
}
}
}
/* It's not an uninstalled package, try and find it among the installed */
else {
int isinstalled = isinstalledpkg(pkg);
if (isinstalled < 0) {
warnx("the package info for package '%s' is corrupt", pkg);
return 1;
} else if (isinstalled == 0) {
warnx("can't find package '%s' installed or in a file!", pkg);
return 1;
}
sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
if (chdir(log_dir) == FAIL) {
warnx("can't change directory to '%s'!", log_dir);
return 1;
}
installed = TRUE;
}
/* Suck in the contents list */
plist.head = plist.tail = NULL;
fp = fopen(CONTENTS_FNAME, "r");
if (!fp) {
warnx("unable to open %s file", CONTENTS_FNAME);
code = 1;
goto bail;
}
/* If we have a prefix, add it now */
read_plist(&plist, fp);
fclose(fp);
/*
* Index is special info type that has to override all others to make
* any sense.
*/
if (Flags & SHOW_INDEX) {
char tmp[FILENAME_MAX];
snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
show_index(tmp, COMMENT_FNAME);
}
else {
/* Start showing the package contents */
if (!Quiet)
printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
else if (QUIET)
printf("%s%s:", InfoPrefix, pkg);
if (Flags & SHOW_COMMENT)
show_file("Comment:\n", COMMENT_FNAME);
if (Flags & SHOW_DEPEND)
show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
show_file("Required by:\n", REQUIRED_BY_FNAME);
if (Flags & SHOW_DESC)
show_file("Description:\n", DESC_FNAME);
if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
show_file("Install notice:\n", DISPLAY_FNAME);
if (Flags & SHOW_PLIST)
show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
if (Flags & SHOW_REQUIRE && fexists(REQUIRE_FNAME))
show_file("Requirements script:\n", REQUIRE_FNAME);
if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
show_file("Install script:\n", INSTALL_FNAME);
if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
show_file("Post-Install script:\n", POST_INSTALL_FNAME);
if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
show_file("De-Install script:\n", DEINSTALL_FNAME);
if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
show_file("mtree file:\n", MTREE_FNAME);
if (Flags & SHOW_PREFIX)
show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
if (Flags & SHOW_FILES)
show_files("Files:\n", &plist);
if ((Flags & SHOW_SIZE) && installed)
show_size("Package Size:\n", &plist);
if ((Flags & SHOW_CKSUM) && installed)
code += show_cksum("Mismatched Checksums:\n", &plist);
if (Flags & SHOW_ORIGIN)
show_origin("Origin:\n", &plist);
if (Flags & SHOW_FMTREV)
show_fmtrev("Packing list format revision:\n", &plist);
if (!Quiet)
puts(InfoPrefix);
}
free_plist(&plist);
bail:
leave_playpen();
if (isTMP)
unlink(fname);
return (code ? 1 : 0);
}
void
cleanup(int sig)
{
static int in_cleanup = 0;
if (!in_cleanup) {
in_cleanup = 1;
leave_playpen();
}
if (sig)
exit(1);
}
/*
* Return an absolute path, additionally removing all .'s, ..'s, and extraneous
* /'s, as realpath() would, but without resolving symlinks, because that can
* potentially screw up our comparisons later.
*/
static char *
abspath(const char *pathname)
{
char *tmp, *tmp1, *resolved_path;
char *cwd = NULL;
int len;
if (pathname[0] != '/') {
cwd = getcwd(NULL, MAXPATHLEN);
asprintf(&resolved_path, "%s/%s/", cwd, pathname);
} else
asprintf(&resolved_path, "%s/", pathname);
if (resolved_path == NULL)
errx(2, NULL);
if (cwd != NULL)
free(cwd);
while ((tmp = strstr(resolved_path, "//")) != NULL)
strcpy(tmp, tmp + 1);
while ((tmp = strstr(resolved_path, "/./")) != NULL)
strcpy(tmp, tmp + 2);
while ((tmp = strstr(resolved_path, "/../")) != NULL) {
*tmp = '\0';
if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
tmp1 = resolved_path;
strcpy(tmp1, tmp + 3);
}
len = strlen(resolved_path);
if (len > 1 && resolved_path[len - 1] == '/')
resolved_path[len - 1] = '\0';
return resolved_path;
}
/*
* Comparison to see if the path we're on matches the
* one we are looking for.
*/
static int
cmp_path(const char *target, const char *current, const char *cwd)
{
char *resolved, *temp;
int rval;
asprintf(&temp, "%s/%s", cwd, current);
if (temp == NULL)
errx(2, NULL);
/*
* Make sure there's no multiple /'s or other weird things in the PLIST,
* since some plists seem to have them and it could screw up our strncmp.
*/
resolved = abspath(temp);
if (strcmp(target, resolved) == 0)
rval = 1;
else
rval = 0;
free(temp);
free(resolved);
return rval;
}
/*
* Look through package dbs in LOG_DIR and find which
* packages installed the files in which_list.
*/
static int
find_pkg(struct which_head *which_list)
{
char **installed;
int errcode, i;
struct which_entry *wp;
TAILQ_FOREACH(wp, which_list, next) {
const char *msg = "file cannot be found";
char *tmp;
wp->skip = TRUE;
/* If it's not a file, we'll see if it's an executable. */
if (isfile(wp->file) == FALSE) {
if (strchr(wp->file, '/') == NULL) {
tmp = vpipe("/usr/bin/which %s", wp->file);
if (tmp != NULL) {
strlcpy(wp->file, tmp, PATH_MAX);
wp->skip = FALSE;
free(tmp);
} else
msg = "file is not in PATH";
}
} else {
tmp = abspath(wp->file);
if (isfile(tmp)) {
strlcpy(wp->file, tmp, PATH_MAX);
wp->skip = FALSE;
}
free(tmp);
}
if (wp->skip == TRUE)
warnx("%s: %s", wp->file, msg);
}
installed = matchinstalled(MATCH_ALL, NULL, &errcode);
if (installed == NULL)
return errcode;
for (i = 0; installed[i] != NULL; i++) {
FILE *fp;
Package pkg;
PackingList itr;
char *cwd = NULL;
char tmp[PATH_MAX];
snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, installed[i],
CONTENTS_FNAME);
fp = fopen(tmp, "r");
if (fp == NULL) {
warn("%s", tmp);
return 1;
}
pkg.head = pkg.tail = NULL;
read_plist(&pkg, fp);
fclose(fp);
for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
if (itr->type == PLIST_CWD) {
cwd = itr->name;
} else if (itr->type == PLIST_FILE) {
TAILQ_FOREACH(wp, which_list, next) {
if (wp->skip == TRUE)
continue;
if (!cmp_path(wp->file, itr->name, cwd))
continue;
if (wp->package[0] != '\0') {
warnx("both %s and %s claim to have installed %s\n",
wp->package, installed[i], wp->file);
} else {
strlcpy(wp->package, installed[i], PATH_MAX);
}
}
}
}
free_plist(&pkg);
}
TAILQ_FOREACH(wp, which_list, next) {
if (wp->package[0] != '\0') {
if (Quiet)
puts(wp->package);
else
printf("%s was installed by package %s\n", \
wp->file, wp->package);
}
}
while (!TAILQ_EMPTY(which_list)) {
wp = TAILQ_FIRST(which_list);
TAILQ_REMOVE(which_list, wp, next);
free(wp);
}
free(which_list);
return 0;
}
/*
* Look through package dbs in LOG_DIR and find which
* packages have the given origin. Don't use read_plist()
* because this increases time necessary for lookup by 40
* times, as we don't really have to parse all plist to
* get origin.
*/
static int
find_pkgs_by_origin(const char *origin)
{
char **matched;
int errcode, i;
if (!Quiet)
printf("The following installed package(s) has %s origin:\n", origin);
matched = matchbyorigin(origin, &errcode);
if (matched == NULL)
return errcode;
for (i = 0; matched[i] != NULL; i++)
puts(matched[i]);
return 0;
}
/*
* List only the matching package names.
* Mainly intended for scripts.
*/
static int
matched_packages(char **pkgs)
{
char **matched;
int i, errcode;
matched = matchinstalled(MatchType == MATCH_GLOB ? MATCH_NGLOB : MatchType, pkgs, &errcode);
if (errcode != 0 || matched == NULL)
return 1;
for (i = 0; matched[i]; i++)
if (!Quiet)
printf("%s\n", matched[i]);
else if (QUIET)
printf("%s%s\n", InfoPrefix, matched[i]);
return 0;
}

View File

@ -1,302 +0,0 @@
.\"
.\" 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
.\" $FreeBSD$
.\"
.Dd November 9, 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 bcdDEfghGiIjkKLmopPqQrRsvVxX
.Op Fl e Ar package
.Op Fl l Ar prefix
.Op Fl t Ar template
.Fl a | Ar pkg-name ...
.Nm
.Op Fl qQ
.Fl W Ar filename
.Nm
.Op Fl qQ
.Fl O Ar origin
.Nm
.Sh DESCRIPTION
The
.Nm
command is used to dump out information for packages, either packed up in
files with the
.Xr pkg_create 1
command or already installed on the system
with the
.Xr pkg_add 1
command.
.Sh OPTIONS
The following command line options are supported:
.Bl -tag -width indent
.It Ar pkg-name ...
The named packages are described.
A package name may either be the name of
an installed package, the pathname to a package distribution file or a
URL to an FTP available package.
Package version numbers can also be matched in a relational manner using the
.Pa >= , <= , >
and
.Pa <
operators.
For example,
.Pp
.Dl "pkg_info 'portupgrade>=20030723'"
.Pp
will match versions 20030723 and later of the
.Pa portupgrade
package.
.It Fl a , -all
Show all currently installed packages.
.It Fl b , -blocksize
Use the
.Ev BLOCKSIZE
environment variable for output even when the
.Fl q
or
.Fl Q
flag is present.
.It Fl h , -help
Print help message.
.It Fl v , -verbose
Turn on verbose output.
.It Fl p
Show the installation prefix for each package.
.It Fl q , -quiet
Be
.Dq quiet
in emitting report headers and such, just dump the
raw info (basically, assume a non-human reading).
.It Fl Q
Be
.Dq quiet
as above but print preface output with the package name.
.It Fl c
Show the (one line) comment field for each package.
.It Fl d
Show the long description field for each package.
.It Fl D
Show the install-message file for each package.
.It Fl f
Show the packing list instructions for each package.
.It Fl g
Show files that do not match the recorded checksum.
.It Fl i
Show the install script (if any) for each package.
.It Fl I
Show an index line for each package.
This option takes
precedence over all other package formatting options.
.It Fl j
Show the requirements script (if any) for each package.
.It Fl k
Show the de-install script (if any) for each package.
.It Fl K , -keep
Keep any downloaded package in
.Ev PKGDIR
if it is defined or in current directory by default.
.It Fl r
For each of the specified packages,
show the list of packages on which it depends.
.It Fl R
For each of the specified packages,
show the list of installed packages which require it.
.It Fl m
Show the
.Xr mtree 8
file (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.
.It Fl s
Show the total size occupied by files installed within each package.
.It Fl o
Show the
.Dq origin
path recorded on package generation.
This path is the directory name in the
.Fx
.Em "Ports Collection"
of the underlying port from which the package was generated.
.It Fl G , -no-glob
Do not try to expand shell glob patterns in the
.Ar pkg-name
when selecting packages to be displayed (by default
.Nm
automatically expands shell glob patterns in the
.Ar pkg-name ) .
.It Fl W , -which Ar filename
For the specified
.Ar filename
argument show which package it belongs to.
If the file is not in the
current directory, and does not have an absolute path, then the
directories specified in the environment variable
.Ev PATH
are searched using
.Xr which 1 .
.It Fl O , -origin Ar origin
List all packages having the specified
.Ar origin .
.It Fl x , -regex
Treat the
.Ar pkg-name
as a regular expression and display information only for packages
whose names match that regular expression.
Multiple regular
expressions could be provided, in that case
.Nm
displays information about all packages that match at least one
regular expression from the list.
.It Fl X , -extended
Like
.Fl x ,
but treats the
.Ar pkg-name
as an extended regular expression.
.It Fl e , -exists Ar package
If the package identified by
.Ar package
is currently installed, return 0, otherwise return 1.
This option
allows you to easily test for the presence of another (perhaps
prerequisite) package from a script.
.It Fl E
Show only matching package names.
This option takes
precedence over all other package formatting options.
If any packages match, return 0, otherwise return 1.
.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 do not
necessarily want the output intermingled in such a way that they cannot
organize it.
This lets you add a special token to the start of
each field.
.It Fl t , -template Ar template
Use
.Ar template
as the argument to
.Xr mktemp 3
when creating a
.Dq staging area .
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
.Ql X
characters for
.Xr mktemp 3
to fill in with a unique ID.
.Bd -ragged -offset indent -compact
Note: This should really not be necessary with
.Nm ,
since very little information is extracted from each package
and one would have to have a very small
.Pa /tmp
indeed to overflow it.
.Ed
.It Fl V
Show revision number of the packing list format.
.It Fl P , -version
Show revision number of package tools.
.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 /var/db/pkg/ Ns Aq Ar pkg-name .
.Sh ENVIRONMENT
.Bl -tag -width ".Ev PKG_TMPDIR"
.It Ev BLOCKSIZE
If the environment variable
.Ev BLOCKSIZE
is set the block counts will be displayed in units of that
size block.
.It Ev PKG_TMPDIR
Points to the directory where
.Nm
creates its temporary files.
If this variable is not set,
.Ev TMPDIR
is used.
If both are unset, the builtin defaults are used.
.It Ev PKG_DBDIR
Specifies an alternative location for the installed package database.
.It Ev PKG_PATH
Specifies an alternative package location, if a given package cannot be
found.
.It Ev PKGDIR
Specifies an alternative location to save downloaded packages to.
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh FILES
.Bl -tag -width ".Pa /var/db/pkg" -compact
.It Pa /var/tmp
Used if the environment variables
.Ev PKG_TMPDIR
and
.Ev TMPDIR
are not set, or if the directories named have insufficient space.
.It Pa /tmp
The next choice if
.Pa /var/tmp
does not exist or has insufficient space.
.It Pa /usr/tmp
The last choice if
.Pa /tmp
is unsuitable.
.It Pa /var/db/pkg
Default location of the installed package database.
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_version 1 ,
.Xr mktemp 3 ,
.Xr mtree 8
.Sh AUTHORS
.An Jordan Hubbard
.Sh CONTRIBUTORS
.An John Kohl Aq jtk@rational.com ,
.An Oliver Eikemeier Aq eik@FreeBSD.org
.Sh BUGS
Sure to be some.

View File

@ -1,404 +0,0 @@
/*
* 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
* 23 Aug 1993
*
* Various display routines for the info module.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include "info.h"
#include <err.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <md5.h>
void
show_file(const char *title, const char *fname)
{
FILE *fp;
char line[1024];
int n;
if (!Quiet)
printf("%s%s", InfoPrefix, title);
fp = fopen(fname, "r");
if (fp == (FILE *) NULL)
printf("ERROR: show_file: Can't open '%s' for reading!\n", fname);
else {
int append_nl = 0;
while ((n = fread(line, 1, 1024, fp)) != 0)
fwrite(line, 1, n, stdout);
fclose(fp);
append_nl = (line[n - 1] != '\n'); /* Do we have a trailing \n ? */
if (append_nl)
printf("\n");
}
printf("\n"); /* just in case */
}
void
show_index(const char *title, const char *fname)
{
FILE *fp;
char line[MAXINDEXSIZE+2];
strlcpy(line, "???\n", sizeof(line));
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
fflush(stdout);
}
fp = fopen(fname, "r");
if (fp == (FILE *) NULL) {
warnx("show_file: can't open '%s' for reading", fname);
} else {
if(fgets(line, MAXINDEXSIZE + 1, fp)) {
size_t line_length = strlen(line);
if (line[line_length - 1] != '\n') { /* Do we have a trailing \n ? */
line[line_length] = '\n'; /* Add a trailing \n */
line[line_length + 1] = '\0'; /* Terminate string */
}
}
fclose(fp);
}
fputs(line, stdout);
}
/* Show a packing list item type. If showall is TRUE, show all */
void
show_plist(const char *title, Package *plist, plist_t type, Boolean showall)
{
PackingList p;
Boolean ign = FALSE;
char *prefix = NULL;
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
fflush(stdout);
}
p = plist->head;
while (p) {
if (p->type != type && showall != TRUE) {
p = p->next;
continue;
}
switch(p->type) {
case PLIST_FILE:
if (ign) {
printf(Quiet ? "%s\n" : "File: %s (ignored)\n", p->name);
ign = FALSE;
}
else
printf(Quiet ? "%s\n" : "File: %s\n", p->name);
break;
case PLIST_CWD:
if (!prefix)
prefix = p->name;
printf(Quiet ? "@cwd %s\n" : "\tCWD to %s\n", (p->name == NULL) ? prefix : p->name);
break;
case PLIST_SRC:
printf(Quiet ? "@srcdir %s\n" : "\tSRCDIR to %s\n", p->name);
break;
case PLIST_CMD:
printf(Quiet ? "@exec %s\n" : "\tEXEC '%s'\n", p->name);
break;
case PLIST_UNEXEC:
printf(Quiet ? "@unexec %s\n" : "\tUNEXEC '%s'\n", p->name);
break;
case PLIST_CHMOD:
printf(Quiet ? "@chmod %s\n" : "\tCHMOD to %s\n",
p->name ? p->name : "(clear default)");
break;
case PLIST_CHOWN:
printf(Quiet ? "@chown %s\n" : "\tCHOWN to %s\n",
p->name ? p->name : "(clear default)");
break;
case PLIST_CHGRP:
printf(Quiet ? "@chgrp %s\n" : "\tCHGRP to %s\n",
p->name ? p->name : "(clear default)");
break;
case PLIST_COMMENT:
printf(Quiet ? "@comment %s\n" : "\tComment: %s\n", p->name);
break;
case PLIST_NOINST:
printf(Quiet ? "@noinst %s\n" : "\tNot installed: %s\n", p->name);
break;
case PLIST_IGNORE:
ign = TRUE;
break;
case PLIST_IGNORE_INST:
printf(Quiet ? "@ignore_inst ??? doesn't belong here.\n" :
"\tIgnore next file installation directive (doesn't belong)\n");
ign = TRUE;
break;
case PLIST_NAME:
printf(Quiet ? "@name %s\n" : "\tPackage name: %s\n", p->name);
break;
case PLIST_DISPLAY:
printf(Quiet ? "@display %s\n" : "\tInstall message file: %s\n", p->name);
break;
case PLIST_PKGDEP:
printf(Quiet ? "@pkgdep %s\n" : "Dependency: %s\n", p->name);
break;
case PLIST_DEPORIGIN:
printf(Quiet ? "@comment DEPORIGIN:%s\n" :
"\tdependency origin: %s\n", p->name);
break;
case PLIST_CONFLICTS:
printf(Quiet ? "@conflicts %s\n" : "Conflicts: %s\n", p->name);
break;
case PLIST_MTREE:
printf(Quiet ? "@mtree %s\n" : "\tPackage mtree file: %s\n", p->name);
break;
case PLIST_DIR_RM:
printf(Quiet ? "@dirrm %s\n" : "\tDeinstall directory remove: %s\n", p->name);
break;
case PLIST_OPTION:
printf(Quiet ? "@option %s\n" :
"\tOption \"%s\" controlling package installation behaviour\n",
p->name);
break;
case PLIST_ORIGIN:
printf(Quiet ? "@comment ORIGIN:%s\n" :
"\tPackage origin: %s\n", p->name);
break;
default:
cleanup(0);
errx(2, "%s: unknown command type %d (%s)",
__func__, p->type, p->name);
break;
}
p = p->next;
}
}
static const char *
elide_root(const char *dir)
{
if (strcmp(dir, "/") == 0)
return "";
return dir;
}
/* Show all files in the packing list (except ignored ones) */
void
show_files(const char *title, Package *plist)
{
PackingList p;
Boolean ign = FALSE;
char *prefix = NULL;
const char *dir = ".";
if (!Quiet)
printf("%s%s", InfoPrefix, title);
p = plist->head;
while (p) {
switch(p->type) {
case PLIST_FILE:
if (!ign)
printf("%s/%s\n", elide_root(dir), p->name);
ign = FALSE;
break;
case PLIST_CWD:
if (!prefix)
prefix = p->name;
if (p->name == NULL)
dir = prefix;
else
dir = p->name;
break;
case PLIST_IGNORE:
ign = TRUE;
break;
/* Silence GCC in the -Wall mode */
default:
break;
}
p = p->next;
}
}
/* Calculate and show size of all installed package files (except ignored ones) */
void
show_size(const char *title, Package *plist)
{
PackingList p;
Boolean ign = FALSE;
const char *dir = ".";
struct stat sb;
char tmp[FILENAME_MAX];
unsigned long size = 0;
long blksize;
int headerlen;
char *descr;
char *prefix = NULL;
descr = getbsize(&headerlen, &blksize);
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
fflush(stdout);
}
for (p = plist->head; p != NULL; p = p->next) {
switch (p->type) {
case PLIST_FILE:
if (!ign) {
snprintf(tmp, FILENAME_MAX, "%s/%s", elide_root(dir), p->name);
if (!lstat(tmp, &sb)) {
size += sb.st_size;
if (Verbose)
printf("%lu\t%s\n", (unsigned long) howmany(sb.st_size, blksize), tmp);
}
}
ign = FALSE;
break;
case PLIST_CWD:
if (!prefix)
prefix = p->name;
if (p->name == NULL)
dir = prefix;
else
dir = p->name;
break;
case PLIST_IGNORE:
ign = TRUE;
break;
/* Silence GCC in the -Wall mode */
default:
break;
}
}
if (!Quiet)
printf("%lu\t(%s)\n", howmany(size, blksize), descr);
else
if (UseBlkSz)
printf("%lu\n", howmany(size, blksize));
else
printf("%lu\n", size);
}
/* Show files that don't match the recorded checksum */
int
show_cksum(const char *title, Package *plist)
{
PackingList p;
const char *dir = ".";
char *prefix = NULL;
char tmp[FILENAME_MAX];
int errcode = 0;
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
fflush(stdout);
}
for (p = plist->head; p != NULL; p = p->next)
if (p->type == PLIST_CWD) {
if (!prefix)
prefix = p->name;
if (p->name == NULL)
dir = prefix;
else
dir = p->name;
} else if (p->type == PLIST_FILE) {
snprintf(tmp, FILENAME_MAX, "%s/%s", elide_root(dir), p->name);
if (!fexists(tmp)) {
warnx("%s doesn't exist", tmp);
errcode = 1;
} else if (p->next && p->next->type == PLIST_COMMENT &&
(strncmp(p->next->name, "MD5:", 4) == 0)) {
char *cp = NULL, buf[33];
/*
* For packing lists whose version is 1.1 or greater, the md5
* hash for a symlink is calculated on the string returned
* by readlink().
*/
if (issymlink(tmp) && verscmp(plist, 1, 0) > 0) {
int len;
char linkbuf[FILENAME_MAX];
if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
cp = MD5Data((unsigned char *)linkbuf, len, buf);
} else if (isfile(tmp) || verscmp(plist, 1, 1) < 0)
cp = MD5File(tmp, buf);
if (cp != NULL) {
/* Mismatch? */
if (strcmp(cp, p->next->name + 4))
printf("%s fails the original MD5 checksum\n", tmp);
else if (Verbose)
printf("%s matched the original MD5 checksum\n", tmp);
}
}
}
return (errcode);
}
/* Show an "origin" path (usually category/portname) */
void
show_origin(const char *title, Package *plist)
{
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
fflush(stdout);
}
printf("%s\n", plist->origin != NULL ? plist->origin : "");
}
/* Show revision number of the packing list */
void
show_fmtrev(const char *title, Package *plist)
{
if (!Quiet) {
printf("%s%s", InfoPrefix, title);
fflush(stdout);
}
printf("%d.%d\n", plist->fmtver_maj, plist->fmtver_mnr);
}

View File

@ -1,11 +0,0 @@
# $FreeBSD$
LIB= install
INTERNALLIB=
SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c match.c \
deps.c version.c pkgwrap.c url.c pkgng.c
WARNS?= 3
WFORMAT?= 1
.include <bsd.lib.mk>

View File

@ -1,241 +0,0 @@
/*
* 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.
*
* Maxim Sobolev
* 14 March 2001
*
* Routines used to do various operations with dependencies
* among installed packages.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <stdio.h>
void list_deps(const char *pkgname, char **pkgs, char *listed,
char *check_loop, char **newpkgs, int *nrnewpkgs,
int *err_cnt);
/*
* Sort given NULL-terminated list of installed packages (pkgs) in
* such a way that if package A depends on package B then after
* sorting A will be listed before B no matter how they were
* originally positioned in the list.
*
* Works by performing a recursive depth-first search on the
* required-by lists.
*/
int
sortdeps(char **pkgs)
{
int i, err_cnt=0;
int nrpkgs, nrnewpkgs;
char *listed, *check_loop, **newpkgs;
char *cp;
if (pkgs[0] == NULL || pkgs[1] == NULL)
return (0);
nrpkgs = 0;
while (pkgs[nrpkgs]) nrpkgs++;
listed = alloca(nrpkgs);
if (listed == NULL) {
warnx("%s(): alloca() failed", __func__);
return 1;
}
bzero(listed,nrpkgs);
check_loop = alloca(nrpkgs);
if (check_loop == NULL) {
warnx("%s(): alloca() failed", __func__);
return 1;
}
bzero(check_loop,nrpkgs);
newpkgs = alloca(nrpkgs*sizeof(char*));
if (newpkgs == NULL) {
warnx("%s(): alloca() failed", __func__);
return 1;
}
nrnewpkgs = 0;
for (i = 0; pkgs[i]; i++) if (!listed[i]) {
check_loop[i] = 1;
cp = strchr(pkgs[i], ':');
if (cp != NULL)
*cp = '\0';
list_deps(pkgs[i],pkgs,listed,check_loop,newpkgs,&nrnewpkgs,&err_cnt);
if (cp != NULL)
*cp = ':';
listed[i] = 1;
newpkgs[nrnewpkgs] = pkgs[i];
nrnewpkgs++;
}
if (nrnewpkgs != nrpkgs) {
fprintf(stderr,"This shouldn't happen, and indicates a huge error in the code.\n");
exit(1);
}
for (i = 0; i < nrnewpkgs; i++) pkgs[i] = newpkgs[i];
return err_cnt;
}
/*
* This recursive function lists the dependencies (that is, the
* "required-by"s) for pkgname, putting them into newpkgs.
*/
void list_deps(const char *pkgname, char **pkgs, char *listed,
char *check_loop, char **newpkgs, int *nrnewpkgs,
int *err_cnt) {
char **rb, **rbtmp;
char *cp;
int errcode, i, j;
struct reqr_by_entry *rb_entry;
struct reqr_by_head *rb_list;
if (isinstalledpkg(pkgname) <= 0)
return;
errcode = requiredby(pkgname, &rb_list, FALSE, TRUE);
if (errcode < 0)
return;
/*
* We put rb_list into an argv style NULL terminated list,
* because requiredby uses some static storage, and list_deps
* is a recursive function.
*/
rbtmp = rb = alloca((errcode + 1) * sizeof(*rb));
if (rb == NULL) {
warnx("%s(): alloca() failed", __func__);
(*err_cnt)++;
return;
}
STAILQ_FOREACH(rb_entry, rb_list, link) {
*rbtmp = alloca(strlen(rb_entry->pkgname) + 1);
if (*rbtmp == NULL) {
warnx("%s(): alloca() failed", __func__);
(*err_cnt)++;
return;
}
strcpy(*rbtmp, rb_entry->pkgname);
rbtmp++;
}
*rbtmp = NULL;
for (i = 0; rb[i]; i++)
for (j = 0; pkgs[j]; j++) if (!listed[j]) {
cp = strchr(pkgs[j], ':');
if (cp != NULL)
*cp = '\0';
if (strcmp(rb[i], pkgs[j]) == 0) { /*match */
/*
* Try to avoid deadlock if package A depends on B which in
* turn depends on C and C due to an error depends on A.
* It Should Never Happen[tm] in real life.
*/
if (check_loop[j]) {
warnx("dependency loop detected for package %s", pkgs[j]);
(*err_cnt)++;
}
else {
check_loop[j] = 1;
list_deps(pkgs[j],pkgs,listed,check_loop,newpkgs,nrnewpkgs,err_cnt);
listed[j] = 1;
newpkgs[*nrnewpkgs] = pkgs[j];
(*nrnewpkgs)++;
}
}
if (cp != NULL)
*cp = ':';
}
}
/*
* Load +REQUIRED_BY file and return a list with names of
* packages that require package referred to by `pkgname'.
*
* Optionally check that packages listed there are actually
* installed and filter out those that don't (filter == TRUE).
*
* strict argument controls whether the caller want warnings
* to be emitted when there are some non-fatal conditions,
* i.e. package doesn't have +REQUIRED_BY file or some packages
* listed in +REQUIRED_BY don't exist.
*
* Result returned in the **list, while return value is equal
* to the number of entries in the resulting list. Print error
* message and return -1 on error.
*/
int
requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter)
{
FILE *fp;
char fbuf[FILENAME_MAX], fname[FILENAME_MAX];
int retval;
struct reqr_by_entry *rb_entry;
static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list);
*list = &rb_list;
/* Deallocate any previously allocated space */
while (!STAILQ_EMPTY(&rb_list)) {
rb_entry = STAILQ_FIRST(&rb_list);
STAILQ_REMOVE_HEAD(&rb_list, link);
free(rb_entry);
}
if (isinstalledpkg(pkgname) <= 0) {
if (strict == TRUE)
warnx("no such package '%s' installed", pkgname);
return -1;
}
snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, pkgname,
REQUIRED_BY_FNAME);
fp = fopen(fname, "r");
if (fp == NULL) {
/* Probably pkgname doesn't have any packages that depend on it */
if (strict == TRUE)
warnx("couldn't open dependency file '%s'", fname);
return 0;
}
retval = 0;
while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
if (fbuf[strlen(fbuf) - 1] == '\n')
fbuf[strlen(fbuf) - 1] = '\0';
if (filter == TRUE && isinstalledpkg(fbuf) <= 0) {
if (strict == TRUE)
warnx("package '%s' is recorded in the '%s' but isn't "
"actually installed", fbuf, fname);
continue;
}
retval++;
rb_entry = malloc(sizeof(*rb_entry));
if (rb_entry == NULL) {
warnx("%s(): malloc() failed", __func__);
retval = -1;
break;
}
strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname));
STAILQ_INSERT_TAIL(&rb_list, rb_entry, link);
}
fclose(fp);
return retval;
}

View File

@ -1,110 +0,0 @@
/*
* 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
* 18 July 1993
*
* Miscellaneous system routines.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
/*
* Unusual system() substitute. Accepts format string and args,
* builds and executes command. Returns exit code.
*/
int
vsystem(const char *fmt, ...)
{
va_list args;
char *cmd;
long maxargs;
int ret;
maxargs = sysconf(_SC_ARG_MAX);
maxargs -= 32; /* some slop for the sh -c */
cmd = malloc(maxargs);
if (!cmd) {
warnx("vsystem can't alloc arg space");
return 1;
}
va_start(args, fmt);
if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) {
warnx("vsystem args are too long");
va_end(args);
return 1;
}
#ifdef DEBUG
printf("Executing %s\n", cmd);
#endif
ret = system(cmd);
va_end(args);
free(cmd);
return ret;
}
char *
vpipe(const char *fmt, ...)
{
FILE *fp;
char *cmd, *rp;
long maxargs;
va_list args;
rp = malloc(MAXPATHLEN);
if (!rp) {
warnx("vpipe can't alloc buffer space");
return NULL;
}
maxargs = sysconf(_SC_ARG_MAX);
maxargs -= 32; /* some slop for the sh -c */
cmd = alloca(maxargs);
if (!cmd) {
warnx("vpipe can't alloc arg space");
return NULL;
}
va_start(args, fmt);
if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) {
warnx("vsystem args are too long");
va_end(args);
return NULL;
}
#ifdef DEBUG
fprintf(stderr, "Executing %s\n", cmd);
#endif
fflush(NULL);
fp = popen(cmd, "r");
if (fp == NULL) {
warnx("popen() failed");
va_end(args);
return NULL;
}
get_string(rp, MAXPATHLEN, fp);
#ifdef DEBUG
fprintf(stderr, "Returned %s\n", rp);
#endif
va_end(args);
if (pclose(fp) || (strlen(rp) == 0)) {
free(rp);
return NULL;
}
return rp;
}

View File

@ -1,436 +0,0 @@
/*
* 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
* 18 July 1993
*
* Miscellaneous file access utilities.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <pwd.h>
#include <time.h>
#include <sys/wait.h>
/* Quick check to see if a file exists */
Boolean
fexists(const char *fname)
{
int fd;
if ((fd = open(fname, O_RDONLY)) == -1)
return FALSE;
close(fd);
return TRUE;
}
/* Quick check to see if something is a directory or symlink to a directory */
Boolean
isdir(const char *fname)
{
struct stat sb;
if (lstat(fname, &sb) != FAIL && S_ISDIR(sb.st_mode))
return TRUE;
else if (lstat(strconcat(fname, "/."), &sb) != FAIL && S_ISDIR(sb.st_mode))
return TRUE;
else
return FALSE;
}
/* Check to see if file is a dir or symlink to a dir, and is empty */
Boolean
isemptydir(const char *fname)
{
if (isdir(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;
}
/*
* Returns TRUE if file is a regular file or symlink pointing to 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 or symlink pointing to 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;
}
/* Returns TRUE if file is a symbolic link. */
Boolean
issymlink(const char *fname)
{
struct stat sb;
if (lstat(fname, &sb) != FAIL && S_ISLNK(sb.st_mode))
return TRUE;
return FALSE;
}
/* Returns TRUE if file is a URL specification */
Boolean
isURL(const char *fname)
{
/*
* I'm sure there are other types of URL specifications that I could
* also be looking for here, but for now I'll just be happy to get ftp
* and http working.
*/
if (!fname)
return FALSE;
while (isspace(*fname))
++fname;
if (!strncmp(fname, "ftp://", 6) || !strncmp(fname, "http://", 7) ||
!strncmp(fname, "https://", 8) || !strncmp(fname, "file://", 7))
return TRUE;
return FALSE;
}
char *
fileFindByPath(const char *base, const char *fname)
{
static char tmp[FILENAME_MAX];
char *cp;
const char *suffixes[] = {".tbz", ".tgz", ".tar", ".txz", NULL};
int i;
if (fexists(fname) && isfile(fname)) {
strcpy(tmp, fname);
return tmp;
}
if (base) {
strcpy(tmp, base);
cp = strrchr(tmp, '/');
if (cp) {
*cp = '\0'; /* chop name */
cp = strrchr(tmp, '/');
}
if (cp)
for (i = 0; suffixes[i] != NULL; i++) {
*(cp + 1) = '\0';
strcat(cp, "All/");
strcat(cp, fname);
strcat(cp, suffixes[i]);
if (fexists(tmp))
return tmp;
}
}
cp = getenv("PKG_PATH");
while (cp) {
char *cp2 = strsep(&cp, ":");
for (i = 0; suffixes[i] != NULL; i++) {
snprintf(tmp, FILENAME_MAX, "%s/%s%s", cp2 ? cp2 : cp, fname, suffixes[i]);
if (fexists(tmp) && isfile(tmp))
return tmp;
}
}
return NULL;
}
char *
fileGetContents(const char *fname)
{
char *contents;
struct stat sb;
int fd;
if (stat(fname, &sb) == FAIL) {
cleanup(0);
errx(2, "%s: can't stat '%s'", __func__, fname);
}
contents = (char *)malloc(sb.st_size + 1);
fd = open(fname, O_RDONLY, 0);
if (fd == FAIL) {
cleanup(0);
errx(2, "%s: unable to open '%s' for reading", __func__, fname);
}
if (read(fd, contents, sb.st_size) != sb.st_size) {
cleanup(0);
errx(2, "%s: short read on '%s' - did not get %lld bytes", __func__,
fname, (long long)sb.st_size);
}
close(fd);
contents[sb.st_size] = '\0';
return contents;
}
/*
* Takes a filename and package name, returning (in "try") the
* canonical "preserve" name for it.
*/
Boolean
make_preserve_name(char *try, int max, const char *name, const char *file)
{
int len, i;
if ((len = strlen(file)) == 0)
return FALSE;
else
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;
}
/* Write the contents of "str" to a file */
void
write_file(const char *name, const char *str)
{
FILE *fp;
size_t len;
fp = fopen(name, "w");
if (!fp) {
cleanup(0);
errx(2, "%s: cannot fopen '%s' for writing", __func__, name);
}
len = strlen(str);
if (fwrite(str, 1, len, fp) != len) {
cleanup(0);
errx(2, "%s: short fwrite on '%s', tried to write %ld bytes",
__func__, name, (long)len);
}
if (fclose(fp)) {
cleanup(0);
errx(2, "%s: failure to fclose '%s'", __func__, name);
}
}
void
copy_file(const char *dir, const char *fname, const char *to)
{
char cmd[FILENAME_MAX];
if (fname[0] == '/')
snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s %s", fname, to);
else
snprintf(cmd, FILENAME_MAX, "/bin/cp -r %s/%s %s", dir, fname, to);
if (vsystem(cmd)) {
cleanup(0);
errx(2, "%s: could not perform '%s'", __func__, cmd);
}
}
void
move_file(const char *dir, const char *fname, const char *tdir)
{
char from[FILENAME_MAX];
char to[FILENAME_MAX];
if (fname[0] == '/')
strncpy(from, fname, FILENAME_MAX);
else
snprintf(from, FILENAME_MAX, "%s/%s", dir, fname);
snprintf(to, FILENAME_MAX, "%s/%s", tdir, fname);
if (rename(from, to) == -1) {
if (vsystem("/bin/mv %s %s", from, to)) {
cleanup(0);
errx(2, "%s: could not move '%s' to '%s'", __func__, from, to);
}
}
}
/*
* Copy a hierarchy (possibly from dir) to the current directory, or
* if "to" is TRUE, from the current directory to a location someplace
* else.
*
* Though slower, using tar to copy preserves symlinks and everything
* without me having to write some big hairy routine to do it.
*/
void
copy_hierarchy(const char *dir, const char *fname, Boolean to)
{
char cmd[FILENAME_MAX * 3];
if (!to) {
/* If absolute path, use it */
if (*fname == '/')
dir = "/";
snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - -C %s %s | /usr/bin/tar xpf -",
dir, fname);
}
else
snprintf(cmd, FILENAME_MAX * 3, "/usr/bin/tar cf - %s | /usr/bin/tar xpf - -C %s",
fname, dir);
#ifdef DEBUG
printf("Using '%s' to copy trees.\n", cmd);
#endif
if (system(cmd)) {
cleanup(0);
errx(2, "%s: could not perform '%s'", __func__, cmd);
}
}
/* Unpack a tar file */
int
unpack(const char *pkg, const char *flist)
{
const char *comp, *cp;
char suff[80];
comp = "";
/*
* Figure out by a crude heuristic whether this or not this is probably
* compressed and whichever compression utility was used (gzip or bzip2).
*/
if (strcmp(pkg, "-")) {
cp = strrchr(pkg, '.');
if (cp) {
strcpy(suff, cp + 1);
if (strchr(suff, 'z') || strchr(suff, 'Z')) {
if (strchr(suff, 'b'))
comp = "-j";
else
comp = "-z";
}
}
}
else
comp = "-j";
if (vsystem("/usr/bin/tar -xp %s -f '%s' %s", comp, pkg, flist ? flist : "")) {
warnx("tar extract of %s failed!", pkg);
return 1;
}
return 0;
}
/*
* 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
*
* Does not check for overflow - caution!
*
*/
void
format_cmd(char *buf, int max, const char *fmt, const char *dir, const char *name)
{
char *cp, scratch[FILENAME_MAX * 2];
int l;
while (*fmt && max > 0) {
if (*fmt == '%') {
switch (*++fmt) {
case 'F':
strncpy(buf, name, max);
l = strlen(name);
buf += l, max -= l;
break;
case 'D':
strncpy(buf, dir, max);
l = strlen(dir);
buf += l, max -= l;
break;
case 'B':
snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name);
cp = &scratch[strlen(scratch) - 1];
while (cp != scratch && *cp != '/')
--cp;
*cp = '\0';
strncpy(buf, scratch, max);
l = strlen(scratch);
buf += l, max -= l;
break;
case 'f':
snprintf(scratch, FILENAME_MAX * 2, "%s/%s", dir, name);
cp = &scratch[strlen(scratch) - 1];
while (cp != scratch && *(cp - 1) != '/')
--cp;
strncpy(buf, cp, max);
l = strlen(cp);
buf += l, max -= l;
break;
default:
*buf++ = *fmt;
--max;
break;
}
++fmt;
}
else {
*buf++ = *fmt++;
--max;
}
}
*buf = '\0';
}

View File

@ -1,32 +0,0 @@
/*
* 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
* 18 July 1993
*
* Semi-convenient place to stick some needed globals.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
/* These are global for all utils */
Boolean Quiet = FALSE;
Boolean Fake = FALSE;
Boolean Force = FALSE;
int AutoAnswer = FALSE;
int Verbose = 0; /* Allow multiple levels of verbose. */

View File

@ -1,243 +0,0 @@
/* $FreeBSD$ */
/*
* 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
* 18 July 1993
*
* Include and define various things wanted by the library routines.
*
*/
#ifndef _INST_LIB_LIB_H_
#define _INST_LIB_LIB_H_
/* Includes */
#include <sys/param.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/queue.h>
#include <sys/utsname.h>
#include <ctype.h>
#include <dirent.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Macros */
#define SUCCESS (0)
#define FAIL (-1)
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#define YES 2
#define NO 1
/* Some more stat macros. */
#define S_IRALL 0000444
#define S_IWALL 0000222
#define S_IXALL 0000111
/* Usually "rm", but often "echo" during debugging! */
#define REMOVE_CMD "/bin/rm"
/* Usually "rm", but often "echo" during debugging! */
#define RMDIR_CMD "/bin/rmdir"
/* Where the ports lives by default */
#define DEF_PORTS_DIR "/usr/ports"
/* just in case we change the environment variable name */
#define PORTSDIR "PORTSDIR"
/* macro to get name of directory where the ports lives */
#define PORTS_DIR (getenv(PORTSDIR) ? getenv(PORTSDIR) : DEF_PORTS_DIR)
/* Where we put logging information by default, else ${PKG_DBDIR} if set */
#define DEF_LOG_DIR "/var/db/pkg"
/* just in case we change the environment variable name */
#define PKG_DBDIR "PKG_DBDIR"
/* macro to get name of directory where we put logging information */
#define LOG_DIR (getenv(PKG_DBDIR) ? getenv(PKG_DBDIR) : DEF_LOG_DIR)
/* The names of our "special" files */
#define CONTENTS_FNAME "+CONTENTS"
#define COMMENT_FNAME "+COMMENT"
#define DESC_FNAME "+DESC"
#define INSTALL_FNAME "+INSTALL"
#define POST_INSTALL_FNAME "+POST-INSTALL"
#define DEINSTALL_FNAME "+DEINSTALL"
#define POST_DEINSTALL_FNAME "+POST-DEINSTALL"
#define REQUIRE_FNAME "+REQUIRE"
#define REQUIRED_BY_FNAME "+REQUIRED_BY"
#define DISPLAY_FNAME "+DISPLAY"
#define MTREE_FNAME "+MTREE_DIRS"
#define CMD_CHAR '@' /* prefix for extended PLIST cmd */
/* The name of the "prefix" environment variable given to scripts */
#define PKG_PREFIX_VNAME "PKG_PREFIX"
/*
* Version of the package tools - increase whenever you make a change
* in the code that is not cosmetic only.
*/
#define PKG_INSTALL_VERSION 20130122
#define PKG_WRAPCONF_FNAME "/var/db/pkg_install.conf"
#define main(argc, argv) real_main(argc, argv)
/* Version numbers to assist with changes in package file format */
#define PLIST_FMT_VER_MAJOR 1
#define PLIST_FMT_VER_MINOR 1
enum _plist_t {
PLIST_FILE, PLIST_CWD, PLIST_CMD, PLIST_CHMOD,
PLIST_CHOWN, PLIST_CHGRP, PLIST_COMMENT, PLIST_IGNORE,
PLIST_NAME, PLIST_UNEXEC, PLIST_SRC, PLIST_DISPLAY,
PLIST_PKGDEP, PLIST_CONFLICTS, PLIST_MTREE, PLIST_DIR_RM,
PLIST_IGNORE_INST, PLIST_OPTION, PLIST_ORIGIN, PLIST_DEPORIGIN,
PLIST_NOINST
};
typedef enum _plist_t plist_t;
enum _match_t {
MATCH_ALL, MATCH_EXACT, MATCH_GLOB, MATCH_NGLOB, MATCH_EREGEX, MATCH_REGEX
};
typedef enum _match_t match_t;
/* Types */
typedef unsigned int Boolean;
struct _plist {
struct _plist *prev, *next;
char *name;
Boolean marked;
plist_t type;
};
typedef struct _plist *PackingList;
struct _pack {
struct _plist *head, *tail;
const char *name;
const char *origin;
int fmtver_maj, fmtver_mnr;
};
typedef struct _pack Package;
struct reqr_by_entry {
STAILQ_ENTRY(reqr_by_entry) link;
char pkgname[PATH_MAX];
};
STAILQ_HEAD(reqr_by_head, reqr_by_entry);
/* Prototypes */
/* Misc */
int vsystem(const char *, ...);
char *vpipe(const char *, ...);
void cleanup(int);
const char *make_playpen(char *, off_t);
char *where_playpen(void);
int leave_playpen(void);
off_t min_free(const char *);
void warnpkgng(void);
/* String */
char *get_dash_string(char **);
char *copy_string(const char *);
char *copy_string_adds_newline(const char *);
Boolean suffix(const char *, const char *);
void nuke_suffix(char *);
void str_lowercase(char *);
char *strconcat(const char *, const char *);
char *get_string(char *, int, FILE *);
/* File */
Boolean fexists(const char *);
Boolean isdir(const char *);
Boolean isemptydir(const char *fname);
Boolean isemptyfile(const char *fname);
Boolean isfile(const char *);
Boolean isempty(const char *);
Boolean issymlink(const char *);
Boolean isURL(const char *);
const char *fileGetURL(const char *, const char *, int);
char *fileFindByPath(const char *, const char *);
char *fileGetContents(const char *);
void write_file(const char *, const char *);
void copy_file(const char *, const char *, const char *);
void move_file(const char *, const char *, const char *);
void copy_hierarchy(const char *, const char *, Boolean);
int delete_hierarchy(const char *, Boolean, Boolean);
int unpack(const char *, const char *);
void format_cmd(char *, int, const char *, const char *, const char *);
/* Msg */
void upchuck(const char *);
void barf(const char *, ...);
void whinge(const char *, ...);
Boolean y_or_n(Boolean, const char *, ...);
/* Packing list */
PackingList new_plist_entry(void);
PackingList last_plist(Package *);
PackingList find_plist(Package *, plist_t);
char *find_plist_option(Package *, const char *name);
void plist_delete(Package *, Boolean, plist_t, const char *);
void free_plist(Package *);
void mark_plist(Package *);
void csum_plist_entry(char *, PackingList);
void add_plist(Package *, plist_t, const char *);
void add_plist_top(Package *, plist_t, const char *);
void delete_plist(Package *pkg, Boolean all, plist_t type, const char *name);
void write_plist(Package *, FILE *);
void read_plist(Package *, FILE *);
int plist_cmd(const char *, char **);
int delete_package(Boolean, Boolean, Package *);
Boolean make_preserve_name(char *, int, const char *, const char *);
/* For all */
int pkg_perform(char **);
int real_main(int, char **);
/* Query installed packages */
char **matchinstalled(match_t, char **, int *);
char **matchbyorigin(const char *, int *);
char ***matchallbyorigin(const char **, int *);
int isinstalledpkg(const char *name);
int pattern_match(match_t MatchType, char *pattern, const char *pkgname);
/* Dependencies */
int sortdeps(char **);
int chkifdepends(const char *, const char *);
int requiredby(const char *, struct reqr_by_head **, Boolean, Boolean);
/* Version */
int verscmp(Package *, int, int);
int version_cmp(const char *, const char *);
/* Externs */
extern Boolean Quiet;
extern Boolean Fake;
extern Boolean Force;
extern int AutoAnswer;
extern int Verbose;
#endif /* _INST_LIB_LIB_H_ */

View File

@ -1,603 +0,0 @@
/*
* 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.
*
* Maxim Sobolev
* 24 February 2001
*
* Routines used to query installed packages.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <fnmatch.h>
#include <fts.h>
#include <regex.h>
/*
* Simple structure representing argv-like
* NULL-terminated list.
*/
struct store {
int currlen;
int used;
char **store;
};
static int rex_match(const char *, const char *, int);
static int csh_match(const char *, const char *, int);
struct store *storecreate(struct store *);
static int storeappend(struct store *, const char *);
static int fname_cmp(const FTSENT * const *, const FTSENT * const *);
/*
* Function to query names of installed packages.
* MatchType - one of MATCH_ALL, MATCH_EREGEX, MATCH_REGEX, MATCH_GLOB, MATCH_NGLOB;
* patterns - NULL-terminated list of glob or regex patterns
* (could be NULL for MATCH_ALL);
* retval - return value (could be NULL if you don't want/need
* return value).
* Returns NULL-terminated list with matching names.
* Names in list returned are dynamically allocated and should
* not be altered by the caller.
*/
char **
matchinstalled(match_t MatchType, char **patterns, int *retval)
{
int i, errcode, len;
char *matched;
const char *paths[2] = {LOG_DIR, NULL};
static struct store *store = NULL;
FTS *ftsp;
FTSENT *f;
Boolean *lmatched = NULL;
store = storecreate(store);
if (store == NULL) {
if (retval != NULL)
*retval = 1;
return NULL;
}
if (retval != NULL)
*retval = 0;
if (!isdir(paths[0])) {
if (retval != NULL)
*retval = 1;
return NULL;
/* Not reached */
}
/* Count number of patterns */
if (patterns != NULL) {
for (len = 0; patterns[len]; len++) {}
lmatched = alloca(sizeof(*lmatched) * len);
if (lmatched == NULL) {
warnx("%s(): alloca() failed", __func__);
if (retval != NULL)
*retval = 1;
return NULL;
}
} else
len = 0;
for (i = 0; i < len; i++)
lmatched[i] = FALSE;
ftsp = fts_open((char * const *)(uintptr_t)paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
if (ftsp != NULL) {
while ((f = fts_read(ftsp)) != NULL) {
if (f->fts_info == FTS_D && f->fts_level == 1) {
fts_set(ftsp, f, FTS_SKIP);
matched = NULL;
errcode = 0;
if (MatchType == MATCH_ALL)
matched = f->fts_name;
else
for (i = 0; patterns[i]; i++) {
errcode = pattern_match(MatchType, patterns[i], f->fts_name);
if (errcode == 1) {
matched = f->fts_name;
lmatched[i] = TRUE;
errcode = 0;
}
if (matched != NULL || errcode != 0)
break;
}
if (errcode == 0 && matched != NULL)
errcode = storeappend(store, matched);
if (errcode != 0) {
if (retval != NULL)
*retval = 1;
return NULL;
/* Not reached */
}
}
}
fts_close(ftsp);
}
if (MatchType == MATCH_GLOB) {
for (i = 0; i < len; i++)
if (lmatched[i] == FALSE)
storeappend(store, patterns[i]);
}
if (store->used == 0)
return NULL;
else
return store->store;
}
int
pattern_match(match_t MatchType, char *pattern, const char *pkgname)
{
int errcode = 0;
const char *fname = pkgname;
char basefname[PATH_MAX];
char condchar = '\0';
char *condition;
/* do we have an appended condition? */
condition = strpbrk(pattern, "<>=");
if (condition) {
const char *ch;
/* yes, isolate the pattern from the condition ... */
if (condition > pattern && condition[-1] == '!')
condition--;
condchar = *condition;
*condition = '\0';
/* ... and compare the name without version */
ch = strrchr(fname, '-');
if (ch && ch - fname < PATH_MAX) {
strlcpy(basefname, fname, ch - fname + 1);
fname = basefname;
}
}
switch (MatchType) {
case MATCH_EREGEX:
case MATCH_REGEX:
errcode = rex_match(pattern, fname, MatchType == MATCH_EREGEX ? 1 : 0);
break;
case MATCH_NGLOB:
case MATCH_GLOB:
errcode = (csh_match(pattern, fname, 0) == 0) ? 1 : 0;
break;
case MATCH_EXACT:
errcode = (strcmp(pattern, fname) == 0) ? 1 : 0;
break;
case MATCH_ALL:
errcode = 1;
break;
default:
break;
}
/* loop over all appended conditions */
while (condition) {
/* restore the pattern */
*condition = condchar;
/* parse the condition (fun with bits) */
if (errcode == 1) {
char *nextcondition;
/* compare version numbers */
int match = 0;
if (*++condition == '=') {
match = 2;
condition++;
}
switch(condchar) {
case '<':
match |= 1;
break;
case '>':
match |= 4;
break;
case '=':
match |= 2;
break;
case '!':
match = 5;
break;
}
/* isolate the version number from the next condition ... */
nextcondition = strpbrk(condition, "<>=!");
if (nextcondition) {
condchar = *nextcondition;
*nextcondition = '\0';
}
/* and compare the versions (version_cmp removes the filename for us) */
if ((match & (1 << (version_cmp(pkgname, condition) + 1))) == 0)
errcode = 0;
condition = nextcondition;
} else {
break;
}
}
return errcode;
}
/*
* Synopsis is similar to matchinstalled(), but use origin
* as a key for matching packages.
*/
char ***
matchallbyorigin(const char **origins, int *retval)
{
char **installed, **allorigins = NULL;
char ***matches = NULL;
int i, j;
if (retval != NULL)
*retval = 0;
installed = matchinstalled(MATCH_ALL, NULL, retval);
if (installed == NULL)
return NULL;
/* Gather origins for all installed packages */
for (i = 0; installed[i] != NULL; i++) {
FILE *fp;
char *buf, *cp, tmp[PATH_MAX];
int cmd;
allorigins = realloc(allorigins, (i + 1) * sizeof(*allorigins));
allorigins[i] = NULL;
snprintf(tmp, PATH_MAX, "%s/%s", LOG_DIR, installed[i]);
/*
* SPECIAL CASE: ignore empty dirs, since we can can see them
* during port installation.
*/
if (isemptydir(tmp))
continue;
strncat(tmp, "/" CONTENTS_FNAME, PATH_MAX);
fp = fopen(tmp, "r");
if (fp == NULL) {
warnx("the package info for package '%s' is corrupt", installed[i]);
continue;
}
cmd = -1;
while (fgets(tmp, sizeof(tmp), fp)) {
int len = strlen(tmp);
while (len && isspace(tmp[len - 1]))
tmp[--len] = '\0';
if (!len)
continue;
cp = tmp;
if (tmp[0] != CMD_CHAR)
continue;
cmd = plist_cmd(tmp + 1, &cp);
if (cmd == PLIST_ORIGIN) {
asprintf(&buf, "%s", cp);
allorigins[i] = buf;
break;
}
}
if (cmd != PLIST_ORIGIN && ( Verbose || 0 != strncmp("bsdpan-", installed[i], 7 ) ) )
warnx("package %s has no origin recorded", installed[i]);
fclose(fp);
}
/* Resolve origins into package names, retaining the sequence */
for (i = 0; origins[i] != NULL; i++) {
matches = realloc(matches, (i + 1) * sizeof(*matches));
struct store *store = NULL;
store = storecreate(store);
for (j = 0; installed[j] != NULL; j++) {
if (allorigins[j]) {
if (csh_match(origins[i], allorigins[j], FNM_PATHNAME) == 0) {
storeappend(store, installed[j]);
}
}
}
if (store->used == 0)
matches[i] = NULL;
else
matches[i] = store->store;
}
if (allorigins) {
for (i = 0; installed[i] != NULL; i++)
if (allorigins[i])
free(allorigins[i]);
free(allorigins);
}
return matches;
}
/*
* Synopsis is similar to matchinstalled(), but use origin
* as a key for matching packages.
*/
char **
matchbyorigin(const char *origin, int *retval)
{
const char *origins[2];
char ***tmp;
origins[0] = origin;
origins[1] = NULL;
tmp = matchallbyorigin(origins, retval);
if (tmp && tmp[0]) {
return tmp[0];
} else {
return NULL;
}
}
/*
* Small linked list to memoize results of isinstalledpkg(). A hash table
* would be faster but for n ~= 1000 may be overkill.
*/
struct iip_memo {
LIST_ENTRY(iip_memo) iip_link;
char *iip_name;
int iip_result;
};
LIST_HEAD(, iip_memo) iip_memo = LIST_HEAD_INITIALIZER(iip_memo);
/*
*
* Return 1 if the specified package is installed,
* 0 if not, and -1 if an error occurred.
*/
int
isinstalledpkg(const char *name)
{
int result;
char *buf, *buf2;
struct iip_memo *memo;
LIST_FOREACH(memo, &iip_memo, iip_link) {
if (strcmp(memo->iip_name, name) == 0)
return memo->iip_result;
}
buf2 = NULL;
asprintf(&buf, "%s/%s", LOG_DIR, name);
if (buf == NULL)
goto errout;
if (!isdir(buf) || access(buf, R_OK) == FAIL) {
result = 0;
} else {
asprintf(&buf2, "%s/%s", buf, CONTENTS_FNAME);
if (buf2 == NULL)
goto errout;
if (!isfile(buf2) || access(buf2, R_OK) == FAIL)
result = -1;
else
result = 1;
}
free(buf);
buf = strdup(name);
if (buf == NULL)
goto errout;
free(buf2);
buf2 = NULL;
memo = malloc(sizeof *memo);
if (memo == NULL)
goto errout;
memo->iip_name = buf;
memo->iip_result = result;
LIST_INSERT_HEAD(&iip_memo, memo, iip_link);
return result;
errout:
if (buf != NULL)
free(buf);
if (buf2 != NULL)
free(buf2);
return -1;
}
/*
* Returns 1 if specified pkgname matches RE pattern.
* Otherwise returns 0 if doesn't match or -1 if RE
* engine reported an error (usually invalid syntax).
*/
static int
rex_match(const char *pattern, const char *pkgname, int extended)
{
char errbuf[128];
int errcode;
int retval;
regex_t rex;
retval = 0;
errcode = regcomp(&rex, pattern, (extended ? REG_EXTENDED : REG_BASIC) | REG_NOSUB);
if (errcode == 0)
errcode = regexec(&rex, pkgname, 0, NULL, 0);
if (errcode == 0) {
retval = 1;
} else if (errcode != REG_NOMATCH) {
regerror(errcode, &rex, errbuf, sizeof(errbuf));
warnx("%s: %s", pattern, errbuf);
retval = -1;
}
regfree(&rex);
return retval;
}
/*
* Match string by a csh-style glob pattern. Returns 0 on
* match and FNM_NOMATCH otherwise, to be compatible with
* fnmatch(3).
*/
static int
csh_match(const char *pattern, const char *string, int flags)
{
int ret = FNM_NOMATCH;
const char *nextchoice = pattern;
const char *current = NULL;
int prefixlen = -1;
int currentlen = 0;
int level = 0;
do {
const char *pos = nextchoice;
const char *postfix = NULL;
Boolean quoted = FALSE;
nextchoice = NULL;
do {
const char *eb;
if (!*pos) {
postfix = pos;
} else if (quoted) {
quoted = FALSE;
} else {
switch (*pos) {
case '{':
++level;
if (level == 1) {
current = pos+1;
prefixlen = pos-pattern;
}
break;
case ',':
if (level == 1 && !nextchoice) {
nextchoice = pos+1;
currentlen = pos-current;
}
break;
case '}':
if (level == 1) {
postfix = pos+1;
if (!nextchoice)
currentlen = pos-current;
}
level--;
break;
case '[':
eb = pos+1;
if (*eb == '!' || *eb == '^')
eb++;
if (*eb == ']')
eb++;
while(*eb && *eb != ']')
eb++;
if (*eb)
pos=eb;
break;
case '\\':
quoted = TRUE;
break;
default:
;
}
}
pos++;
} while (!postfix);
if (current) {
char buf[FILENAME_MAX];
snprintf(buf, sizeof(buf), "%.*s%.*s%s", prefixlen, pattern, currentlen, current, postfix);
ret = csh_match(buf, string, flags);
if (ret) {
current = nextchoice;
level = 1;
} else
current = NULL;
} else
ret = fnmatch(pattern, string, flags);
} while (current);
return ret;
}
/*
* Create an empty store, optionally deallocating
* any previously allocated space if store != NULL.
*/
struct store *
storecreate(struct store *store)
{
int i;
if (store == NULL) {
store = malloc(sizeof *store);
if (store == NULL) {
warnx("%s(): malloc() failed", __func__);
return NULL;
}
store->currlen = 0;
store->store = NULL;
} else if (store->store != NULL) {
/* Free previously allocated memory */
for (i = 0; store->store[i] != NULL; i++)
free(store->store[i]);
store->store[0] = NULL;
}
store->used = 0;
return store;
}
/*
* Append specified element to the provided store.
*/
static int
storeappend(struct store *store, const char *item)
{
if (store->used + 2 > store->currlen) {
store->currlen += 16;
store->store = reallocf(store->store,
store->currlen * sizeof(*(store->store)));
if (store->store == NULL) {
store->currlen = 0;
warnx("%s(): reallocf() failed", __func__);
return 1;
}
}
asprintf(&(store->store[store->used]), "%s", item);
if (store->store[store->used] == NULL) {
warnx("%s(): malloc() failed", __func__);
return 1;
}
store->used++;
store->store[store->used] = NULL;
return 0;
}
static int
fname_cmp(const FTSENT * const *a, const FTSENT * const *b)
{
return strcmp((*a)->fts_name, (*b)->fts_name);
}

View File

@ -1,76 +0,0 @@
/*
* 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
* 18 July 1993
*
* Miscellaneous message routines.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <paths.h>
/* Die a relatively simple death */
void
upchuck(const char *message)
{
cleanup(0);
errx(1, "fatal error during execution: %s", message);
}
/*
* As a yes/no question, prompting from the varargs string and using
* default if user just hits return.
*/
Boolean
y_or_n(Boolean def, const char *msg, ...)
{
va_list args;
int ch = 0;
FILE *tty;
va_start(args, msg);
/*
* Need to open /dev/tty because file collection may have been
* collected on stdin
*/
tty = fopen(_PATH_TTY, "r");
if (!tty) {
cleanup(0);
errx(2, "can't open %s!", _PATH_TTY);
}
while (ch != 'Y' && ch != 'N') {
vfprintf(stderr, msg, args);
if (def)
fprintf(stderr, " [yes]? ");
else
fprintf(stderr, " [no]? ");
fflush(stderr);
if (AutoAnswer) {
ch = (AutoAnswer == YES) ? 'Y' : 'N';
fprintf(stderr, "%c\n", ch);
}
else
ch = toupper(fgetc(tty));
if (ch == '\n')
ch = (def) ? 'Y' : 'N';
}
fclose(tty) ;
va_end(args);
return (ch == 'Y') ? TRUE : FALSE;
}

View File

@ -1,186 +0,0 @@
/*
* 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
* 18 July 1993
*
* Routines for managing the "play pen".
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <libutil.h>
#include <libgen.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <sys/mount.h>
/* For keeping track of where we are */
static char PenLocation[FILENAME_MAX];
char *
where_playpen(void)
{
return PenLocation;
}
/* Find a good place to play. */
static char *
find_play_pen(char *pen, off_t sz)
{
char *cp;
struct stat sb;
char humbuf[6];
if (pen[0] && isdir(dirname(pen)) == TRUE && (min_free(dirname(pen)) >= sz))
return pen;
else if ((cp = getenv("PKG_TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz))
sprintf(pen, "%s/instmp.XXXXXX", cp);
else if ((cp = getenv("TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz))
sprintf(pen, "%s/instmp.XXXXXX", cp);
else if (stat("/var/tmp", &sb) != FAIL && min_free("/var/tmp") >= sz)
strcpy(pen, "/var/tmp/instmp.XXXXXX");
else if (stat("/tmp", &sb) != FAIL && min_free("/tmp") >= sz)
strcpy(pen, "/tmp/instmp.XXXXXX");
else if ((stat("/usr/tmp", &sb) == SUCCESS || mkdir("/usr/tmp", 01777) == SUCCESS) && min_free("/usr/tmp") >= sz)
strcpy(pen, "/usr/tmp/instmp.XXXXXX");
else {
cleanup(0);
humanize_number(humbuf, sizeof humbuf, sz, "", HN_AUTOSCALE,
HN_NOSPACE);
errx(2,
"%s: can't find enough temporary space to extract the files, please set your\n"
"PKG_TMPDIR environment variable to a location with at least %s bytes\n"
"free", __func__, humbuf);
return NULL;
}
return pen;
}
#define MAX_STACK 20
static char *pstack[MAX_STACK];
static int pdepth = -1;
static const char *
pushPen(const char *pen)
{
if (++pdepth == MAX_STACK)
errx(2, "%s: stack overflow.\n", __func__);
pstack[pdepth] = strdup(pen);
return pstack[pdepth];
}
static void
popPen(char *pen)
{
if (pdepth == -1) {
pen[0] = '\0';
return;
}
strcpy(pen, pstack[pdepth]);
free(pstack[pdepth--]);
}
/*
* Make a temporary directory to play in and chdir() to it, returning
* pathname of previous working directory.
*/
const char *
make_playpen(char *pen, off_t sz)
{
char humbuf1[6], humbuf2[6];
char cwd[FILENAME_MAX];
if (!find_play_pen(pen, sz))
return NULL;
if (!mkdtemp(pen)) {
cleanup(0);
errx(2, "%s: can't mktemp '%s'", __func__, pen);
}
if (Verbose) {
if (sz) {
humanize_number(humbuf1, sizeof humbuf1, sz, "", HN_AUTOSCALE,
HN_NOSPACE);
humanize_number(humbuf2, sizeof humbuf2, min_free(pen),
"", HN_AUTOSCALE, HN_NOSPACE);
fprintf(stderr, "Requested space: %s bytes, free space: %s bytes in %s\n", humbuf1, humbuf2, pen);
}
}
if (min_free(pen) < sz) {
rmdir(pen);
cleanup(0);
errx(2, "%s: not enough free space to create '%s'.\n"
"Please set your PKG_TMPDIR environment variable to a location\n"
"with more space and\ntry the command again", __func__, pen);
}
if (!getcwd(cwd, FILENAME_MAX)) {
upchuck("getcwd");
return NULL;
}
if (chdir(pen) == FAIL) {
cleanup(0);
errx(2, "%s: can't chdir to '%s'", __func__, pen);
}
strcpy(PenLocation, pen);
return pushPen(cwd);
}
/* Convenience routine for getting out of playpen */
int
leave_playpen()
{
static char left[FILENAME_MAX];
void (*oldsig)(int);
if (!PenLocation[0])
return 0;
/* Don't interrupt while we're cleaning up */
oldsig = signal(SIGINT, SIG_IGN);
strcpy(left, PenLocation);
popPen(PenLocation);
if (chdir(PenLocation) == FAIL) {
cleanup(0);
errx(2, "%s: can't chdir back to '%s'", __func__, PenLocation);
}
if (left[0] == '/' && vsystem("/bin/rm -rf %s", left))
warnx("couldn't remove temporary dir '%s'", left);
signal(SIGINT, oldsig);
return 1;
}
off_t
min_free(const char *tmpdir)
{
struct statfs buf;
if (statfs(tmpdir, &buf) != 0) {
warn("statfs");
return -1;
}
return (off_t)buf.f_bavail * (off_t)buf.f_bsize;
}

View File

@ -1,61 +0,0 @@
/*-
* Copyright (c) 2012 Eitan Adler
* 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 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 AUTHOR 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$
*/
#include <sys/cdefs.h>
#include "lib.h"
#include <err.h>
static const char message[] = "You appear to be using the newer pkg(1) tool on \
this system for package management, rather than the legacy package \
management tools (pkg_*). The legacy tools should no longer be used on \
this system.";
void warnpkgng(void)
{
char pkgngpath[MAXPATHLEN + 1];
char *pkgngdir;
char *dontwarn;
int rc;
dontwarn = getenv("PKG_OLD_NOWARN");
if (dontwarn != NULL)
return;
pkgngdir = getenv("PKG_DBDIR");
if (pkgngdir == NULL)
pkgngdir = "/var/db/pkg";
rc = snprintf(pkgngpath, sizeof(pkgngpath), "%s/local.sqlite", pkgngdir);
if ((size_t)rc >= sizeof(pkgngpath)) {
warnx("path too long: %s/local.sqlite", pkgngdir);
return;
}
if (access(pkgngpath, F_OK) == 0)
warnx(message);
}

View File

@ -1,89 +0,0 @@
/*
* 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.
*
* Maxim Sobolev
* 8 September 2002
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#undef main
#define SEPARATORS " \t"
extern char **environ;
int
main(int argc, char **argv)
{
FILE *f;
char buffer[FILENAME_MAX], *cp, *verstr;
int len;
if (getenv("PKG_NOWRAP") != NULL)
goto nowrap;
f = fopen(PKG_WRAPCONF_FNAME, "r");
if (f == NULL)
goto nowrap;
cp = fgets(buffer, 256, f);
fclose(f);
if (cp == NULL)
goto nowrap;
len = strlen(cp);
if (cp[len - 1] == '\n')
cp[len - 1] = '\0';
while (strchr(SEPARATORS, *cp) != NULL)
cp++;
verstr = cp;
cp = strpbrk(cp, SEPARATORS);
if (cp == NULL)
goto nowrap;
*cp = '\0';
for (cp = verstr; *cp != '\0'; cp++)
if (isdigit(*cp) == 0)
goto nowrap;
if (atoi(verstr) < PKG_INSTALL_VERSION)
goto nowrap;
cp++;
while (*cp != '\0' && strchr(SEPARATORS, *cp) != NULL)
cp++;
if (*cp == '\0')
goto nowrap;
bcopy(cp, buffer, strlen(cp) + 1);
cp = strpbrk(buffer, SEPARATORS);
if (cp != NULL)
*cp = '\0';
if (!isdir(buffer))
goto nowrap;
cp = strrchr(argv[0], '/');
if (cp == NULL)
cp = argv[0];
else
cp++;
strlcat(buffer, "/", sizeof(buffer));
strlcat(buffer, cp, sizeof(buffer));
setenv("PKG_NOWRAP", "1", 1);
execve(buffer, argv, environ);
nowrap:
unsetenv("PKG_NOWRAP");
return(real_main(argc, argv));
}

View File

@ -1,596 +0,0 @@
/*
* 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
* 18 July 1993
*
* General packing list routines.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <md5.h>
/* Add an item to a packing list */
void
add_plist(Package *p, plist_t type, const char *arg)
{
PackingList tmp;
tmp = new_plist_entry();
tmp->name = copy_string(arg);
tmp->type = type;
if (!p->head)
p->head = p->tail = tmp;
else {
tmp->prev = p->tail;
p->tail->next = tmp;
p->tail = tmp;
}
switch (type) {
case PLIST_NAME:
p->name = tmp->name;
break;
case PLIST_ORIGIN:
p->origin = tmp->name;
break;
default:
break;
}
}
void
add_plist_top(Package *p, plist_t type, const char *arg)
{
PackingList tmp;
tmp = new_plist_entry();
tmp->name = copy_string(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 */
PackingList
last_plist(Package *p)
{
return p->tail;
}
/* Mark all items in a packing list to prevent iteration over them */
void
mark_plist(Package *pkg)
{
PackingList p = pkg->head;
while (p) {
p->marked = TRUE;
p = p->next;
}
}
/* Find a given item in a packing list and, if so, return it (else NULL) */
PackingList
find_plist(Package *pkg, plist_t type)
{
PackingList p = pkg->head;
while (p) {
if (p->type == type)
return p;
p = p->next;
}
return NULL;
}
/* Look for a specific boolean option argument in the list */
char *
find_plist_option(Package *pkg, const char *name)
{
PackingList p = pkg->head;
while (p) {
if (p->type == PLIST_OPTION && !strcmp(p->name, name))
return p->name;
p = p->next;
}
return 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 occurrence.
*/
void
delete_plist(Package *pkg, Boolean all, plist_t type, const char *name)
{
PackingList p = pkg->head;
while (p) {
PackingList 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 */
PackingList
new_plist_entry(void)
{
PackingList ret;
ret = (PackingList)malloc(sizeof(struct _plist));
bzero(ret, sizeof(struct _plist));
return ret;
}
/* Free an entire packing list */
void
free_plist(Package *pkg)
{
PackingList p = pkg->head;
while (p) {
PackingList 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)
*/
int
plist_cmd(const char *s, char **arg)
{
char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */
char *cp;
const char *sp;
strcpy(cmd, s);
str_lowercase(cmd);
cp = cmd;
sp = s;
while (*cp) {
if (isspace(*cp)) {
*cp = '\0';
while (isspace(*sp)) /* Never sure if macro, increment later */
++sp;
break;
}
++cp, ++sp;
}
if (arg)
*arg = (char *)sp;
if (!strcmp(cmd, "cwd"))
return PLIST_CWD;
else if (!strcmp(cmd, "srcdir"))
return PLIST_SRC;
else if (!strcmp(cmd, "cd"))
return PLIST_CWD;
else if (!strcmp(cmd, "exec"))
return PLIST_CMD;
else if (!strcmp(cmd, "unexec"))
return PLIST_UNEXEC;
else if (!strcmp(cmd, "mode"))
return PLIST_CHMOD;
else if (!strcmp(cmd, "owner"))
return PLIST_CHOWN;
else if (!strcmp(cmd, "group"))
return PLIST_CHGRP;
else if (!strcmp(cmd, "noinst"))
return PLIST_NOINST;
else if (!strcmp(cmd, "comment")) {
if (!strncmp(*arg, "ORIGIN:", 7)) {
*arg += 7;
return PLIST_ORIGIN;
} else if (!strncmp(*arg, "DEPORIGIN:", 10)) {
*arg += 10;
return PLIST_DEPORIGIN;
}
return PLIST_COMMENT;
} else if (!strcmp(cmd, "ignore"))
return PLIST_IGNORE;
else if (!strcmp(cmd, "ignore_inst"))
return PLIST_IGNORE_INST;
else if (!strcmp(cmd, "name"))
return PLIST_NAME;
else if (!strcmp(cmd, "display"))
return PLIST_DISPLAY;
else if (!strcmp(cmd, "pkgdep"))
return PLIST_PKGDEP;
else if (!strcmp(cmd, "conflicts"))
return PLIST_CONFLICTS;
else if (!strcmp(cmd, "mtree"))
return PLIST_MTREE;
else if (!strcmp(cmd, "dirrm"))
return PLIST_DIR_RM;
else if (!strcmp(cmd, "option"))
return PLIST_OPTION;
else
return FAIL;
}
/* Read a packing list from a file */
void
read_plist(Package *pkg, FILE *fp)
{
char *cp, pline[FILENAME_MAX];
int cmd, major, minor;
pkg->fmtver_maj = 1;
pkg->fmtver_mnr = 0;
pkg->origin = NULL;
while (fgets(pline, FILENAME_MAX, fp)) {
int len = strlen(pline);
while (len && isspace(pline[len - 1]))
pline[--len] = '\0';
if (!len)
continue;
cp = pline;
if (pline[0] != CMD_CHAR) {
cmd = PLIST_FILE;
goto bottom;
}
cmd = plist_cmd(pline + 1, &cp);
if (cmd == FAIL) {
warnx("%s: unknown command '%s' (package tools out of date?)",
__func__, pline);
goto bottom;
}
if (*cp == '\0') {
cp = NULL;
if (cmd == PLIST_PKGDEP) {
warnx("corrupted record for package %s (pkgdep line without "
"argument), ignoring", pkg->name);
cmd = FAIL;
}
goto bottom;
}
if (cmd == PLIST_COMMENT && sscanf(cp, "PKG_FORMAT_REVISION:%d.%d\n",
&major, &minor) == 2) {
pkg->fmtver_maj = major;
pkg->fmtver_mnr = minor;
if (verscmp(pkg, PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR) <= 0)
goto bottom;
warnx("plist format revision (%d.%d) is higher than supported"
"(%d.%d)", pkg->fmtver_maj, pkg->fmtver_mnr,
PLIST_FMT_VER_MAJOR, PLIST_FMT_VER_MINOR);
if (pkg->fmtver_maj > PLIST_FMT_VER_MAJOR) {
cleanup(0);
exit(2);
}
}
bottom:
add_plist(pkg, cmd, cp);
}
}
/* Write a packing list to a file, converting commands to ascii equivs */
void
write_plist(Package *pkg, FILE *fp)
{
PackingList plist = pkg->head;
while (plist) {
switch(plist->type) {
case PLIST_FILE:
fprintf(fp, "%s\n", plist->name);
break;
case PLIST_CWD:
fprintf(fp, "%ccwd %s\n", CMD_CHAR, (plist->name == NULL) ? "" : plist->name);
break;
case PLIST_SRC:
fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
break;
case PLIST_CMD:
fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
break;
case PLIST_UNEXEC:
fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
break;
case PLIST_CHMOD:
fprintf(fp, "%cmode %s\n", CMD_CHAR, plist->name ? plist->name : "");
break;
case PLIST_CHOWN:
fprintf(fp, "%cowner %s\n", CMD_CHAR, plist->name ? plist->name : "");
break;
case PLIST_CHGRP:
fprintf(fp, "%cgroup %s\n", CMD_CHAR, plist->name ? plist->name : "");
break;
case PLIST_COMMENT:
fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
break;
case PLIST_NOINST:
fprintf(fp, "%cnoinst %s\n", CMD_CHAR, plist->name);
break;
case PLIST_IGNORE:
case PLIST_IGNORE_INST: /* a one-time non-ignored file */
fprintf(fp, "%cignore\n", CMD_CHAR);
break;
case PLIST_NAME:
fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
break;
case PLIST_DISPLAY:
fprintf(fp, "%cdisplay %s\n", CMD_CHAR, plist->name);
break;
case PLIST_PKGDEP:
fprintf(fp, "%cpkgdep %s\n", CMD_CHAR, plist->name);
break;
case PLIST_CONFLICTS:
fprintf(fp, "%cconflicts %s\n", CMD_CHAR, plist->name);
break;
case PLIST_MTREE:
fprintf(fp, "%cmtree %s\n", CMD_CHAR, plist->name);
break;
case PLIST_DIR_RM:
fprintf(fp, "%cdirrm %s\n", CMD_CHAR, plist->name);
break;
case PLIST_OPTION:
fprintf(fp, "%coption %s\n", CMD_CHAR, plist->name);
break;
case PLIST_ORIGIN:
fprintf(fp, "%ccomment ORIGIN:%s\n", CMD_CHAR, plist->name);
break;
case PLIST_DEPORIGIN:
fprintf(fp, "%ccomment DEPORIGIN:%s\n", CMD_CHAR, plist->name);
break;
default:
cleanup(0);
errx(2, "%s: unknown command type %d (%s)", __func__,
plist->type, plist->name);
break;
}
plist = plist->next;
}
}
/*
* 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, Boolean nukedirs, Package *pkg)
{
PackingList p;
const char *Where = ".", *last_file = "";
Boolean fail = SUCCESS;
Boolean preserve;
char tmp[FILENAME_MAX], *name = NULL;
char *prefix = NULL;
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_IGNORE:
p = p->next;
break;
case PLIST_CWD:
if (!prefix)
prefix = p->name;
Where = (p->name == NULL) ? prefix : p->name;
if (Verbose)
printf("Change working directory to %s\n", Where);
break;
case PLIST_UNEXEC:
format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file);
if (Verbose)
printf("Execute '%s'\n", tmp);
if (!Fake && system(tmp)) {
warnx("unexec command for '%s' failed", tmp);
fail = FAIL;
}
break;
case PLIST_FILE:
last_file = p->name;
if (*p->name == '/')
strlcpy(tmp, p->name, FILENAME_MAX);
else
sprintf(tmp, "%s/%s", Where, p->name);
if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) {
warnx("cannot delete specified file '%s' - it is a directory!\n"
"this packing list is incorrect - ignoring delete request", tmp);
}
else {
if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) {
char *cp = NULL, buf[33];
/*
* For packing lists whose version is 1.1 or greater, the md5
* hash for a symlink is calculated on the string returned
* by readlink().
*/
if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) {
int len;
char linkbuf[FILENAME_MAX];
if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0)
cp = MD5Data((unsigned char *)linkbuf, len, buf);
} else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0)
cp = MD5File(tmp, buf);
if (cp != NULL) {
/* Mismatch? */
if (strcmp(cp, p->next->name + 4)) {
warnx("'%s' fails original MD5 checksum - %s",
tmp, Force ? "deleted anyway." : "not deleted.");
if (!Force) {
fail = FAIL;
continue;
}
}
}
}
if (Verbose)
printf("Delete file %s\n", tmp);
if (!Fake) {
if (delete_hierarchy(tmp, ign_err, nukedirs))
fail = FAIL;
if (preserve && name) {
char tmp2[FILENAME_MAX];
if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) {
if (fexists(tmp2)) {
if (rename(tmp2, tmp))
warn("preserve: unable to restore %s as %s",
tmp2, tmp);
}
}
}
}
}
break;
case PLIST_DIR_RM:
sprintf(tmp, "%s/%s", Where, p->name);
if (!isdir(tmp) && fexists(tmp)) {
warnx("cannot delete specified directory '%s' - it is a file!\n"
"this packing list is incorrect - ignoring delete request", tmp);
}
else {
if (Verbose)
printf("Delete directory %s\n", tmp);
if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) {
warnx("unable to completely remove directory '%s'", tmp);
fail = FAIL;
}
}
last_file = p->name;
break;
default:
break;
}
}
return fail;
}
#ifdef DEBUG
#define RMDIR(dir) vsystem("%s %s", RMDIR_CMD, dir)
#define REMOVE(dir,ie) vsystem("%s %s%s", REMOVE_CMD, (ie ? "-f " : ""), dir)
#else
#define RMDIR rmdir
#define REMOVE(file,ie) (remove(file) && !(ie))
#endif
/* Selectively delete a hierarchy */
int
delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
{
char *cp1, *cp2;
cp1 = cp2 = strdup(dir);
if (!fexists(dir) && !issymlink(dir)) {
if (!ign_err)
warnx("%s '%s' doesn't exist",
isdir(dir) ? "directory" : "file", dir);
return !ign_err;
}
else if (nukedirs) {
if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
return 1;
}
else if (isdir(dir) && !issymlink(dir)) {
if (RMDIR(dir) && !ign_err)
return 1;
}
else {
if (REMOVE(dir, ign_err))
return 1;
}
if (!nukedirs)
return 0;
while (cp2) {
if ((cp2 = strrchr(cp1, '/')) != NULL)
*cp2 = '\0';
if (!isemptydir(dir))
return 0;
if (RMDIR(dir) && !ign_err) {
if (!fexists(dir))
warnx("directory '%s' doesn't exist", dir);
else
return 1;
}
/* back up the pathname one component */
if (cp2) {
cp1 = strdup(dir);
}
}
return 0;
}

View File

@ -1,129 +0,0 @@
/*
* 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
* 18 July 1993
*
* Miscellaneous string utilities.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
char *
strconcat(const char *s1, const char *s2)
{
static char tmp[FILENAME_MAX];
tmp[0] = '\0';
strncpy(tmp, s1 ? s1 : s2, FILENAME_MAX); /* XXX: what if both are NULL? */
if (s1 && s2)
strncat(tmp, s2, FILENAME_MAX - strlen(tmp));
return tmp;
}
/* Get a string parameter as a file spec or as a "contents follow -" spec */
char *
get_dash_string(char **str)
{
char *s = *str;
if (*s == '-')
*str = copy_string_adds_newline(s + 1);
else
*str = fileGetContents(s);
return *str;
}
/* Rather Obvious */
char *
copy_string(const char *str)
{
return (str ? strdup(str) : NULL);
}
/* Rather Obvious but adds a trailing \n newline */
char *
copy_string_adds_newline(const char *str)
{
if (str == NULL) {
return (NULL);
} else {
char *copy;
size_t line_length;
line_length = strlen(str) + 2;
if ((copy = malloc(line_length)) == NULL)
return (NULL);
memcpy(copy, str, line_length - 2);
copy[line_length - 2] = '\n'; /* Adds trailing \n */
copy[line_length - 1] = '\0';
return (copy);
}
}
/* Return TRUE if 'str' ends in suffix 'suff' */
Boolean
suffix(const char *str, const char *suff)
{
char *idx;
Boolean ret = FALSE;
idx = strrchr(str, '.');
if (idx && !strcmp(idx + 1, suff))
ret = TRUE;
return ret;
}
/* Assuming str has a suffix, brutally murder it! */
void
nuke_suffix(char *str)
{
char *idx;
idx = strrchr(str, '.');
if (idx)
*idx = '\0'; /* Yow! Don't try this on a const! */
}
/* Lowercase a whole string */
void
str_lowercase(char *str)
{
while (*str) {
*str = tolower(*str);
++str;
}
}
char *
get_string(char *str, int max, FILE *fp)
{
int len;
if (!str)
return NULL;
str[0] = '\0';
while (fgets(str, max, fp)) {
len = strlen(str);
while (len && isspace(str[len - 1]))
str[--len] = '\0';
if (len)
return str;
}
return NULL;
}

View File

@ -1,177 +0,0 @@
/*
* 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
* 18 July 1993
*
* URL file access utilities.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
#include <fetch.h>
#include <libgen.h>
#include <sys/wait.h>
#include <stdio.h>
/*
* Try and fetch a file by URL, returning the directory name for where
* it's unpacked, if successful.
*/
const char *
fileGetURL(const char *base, const char *spec, int keep_package)
{
const char *rp;
char *cp, *tmp;
char fname[FILENAME_MAX];
char pen[FILENAME_MAX];
char pkg[FILENAME_MAX];
char buf[8192];
FILE *ftp;
pid_t tpid;
int pfd[2], pstat, r, w = 0;
char *hint;
int fd, pkgfd = 0;
rp = NULL;
/* Special tip that sysinstall left for us */
hint = getenv("PKG_ADD_BASE");
if (!isURL(spec)) {
if (!base && !hint)
return NULL;
/*
* We've been given an existing URL (that's known-good) and now we need
* to construct a composite one out of that and the basename we were
* handed as a dependency.
*/
if (base) {
strcpy(fname, base);
/*
* Advance back two slashes to get to the root of the package
* hierarchy
*/
cp = strrchr(fname, '/');
if (cp) {
*cp = '\0'; /* chop name */
cp = strrchr(fname, '/');
}
if (cp) {
*(cp + 1) = '\0';
strcat(cp, "All/");
strcat(cp, spec);
if (getenv("PACKAGESUFFIX"))
strcat(cp, getenv("PACKAGESUFFIX"));
else
strcat(cp, ".tbz");
}
else
return NULL;
}
else {
/*
* Otherwise, we've been given an environment variable hinting
* at the right location from sysinstall
*/
strcpy(fname, hint);
strcat(fname, spec);
if (getenv("PACKAGESUFFIX"))
strcat(fname, getenv("PACKAGESUFFIX"));
else
strcat(fname, ".tbz");
}
}
else
strcpy(fname, spec);
if (keep_package) {
tmp = getenv("PKGDIR");
strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg));
tmp = basename(fname);
strlcat(pkg, "/", sizeof(pkg));
strlcat(pkg, tmp, sizeof(pkg));
if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
printf("Error: Unable to open %s\n", pkg);
perror("open");
return NULL;
}
}
fetchDebug = (Verbose > 0);
if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) {
printf("Error: Unable to get %s: %s\n",
fname, fetchLastErrString);
/* If the fetch fails, yank the package. */
if (keep_package && unlink(pkg) < 0 && Verbose) {
warnx("failed to remove partially fetched package: %s", pkg);
}
return NULL;
}
if (isatty(0) || Verbose)
printf("Fetching %s...", fname), fflush(stdout);
pen[0] = '\0';
if ((rp = make_playpen(pen, 0)) == NULL) {
printf("Error: Unable to construct a new playpen for FTP!\n");
fclose(ftp);
return NULL;
}
if (pipe(pfd) == -1) {
warn("pipe()");
cleanup(0);
exit(2);
}
if ((tpid = fork()) == -1) {
warn("pipe()");
cleanup(0);
exit(2);
}
if (!tpid) {
dup2(pfd[0], 0);
for (fd = getdtablesize() - 1; fd >= 3; --fd)
close(fd);
execl("/usr/bin/tar", "tar",
Verbose ? "-xpjvf" : "-xpjf",
"-", (char *)0);
_exit(2);
}
close(pfd[0]);
for (;;) {
if ((r = fread(buf, 1, sizeof buf, ftp)) < 1)
break;
if ((w = write(pfd[1], buf, r)) != r)
break;
if (keep_package) {
if ((w = write(pkgfd, buf, r)) != r)
break;
}
}
if (ferror(ftp))
warn("warning: error reading from server");
fclose(ftp);
if (keep_package) {
close(pkgfd);
}
close(pfd[1]);
if (w == -1)
warn("warning: error writing to tar");
tpid = waitpid(tpid, &pstat, 0);
if (Verbose)
printf("tar command returns %d status\n", WEXITSTATUS(pstat));
if (rp && (isatty(0) || Verbose))
printf(" Done.\n");
return rp;
}

View File

@ -1,328 +0,0 @@
/*
* 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.
*
* Maxim Sobolev
* 31 July 2001
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include <err.h>
/*
* Routines to assist with PLIST_FMT_VER numbers in the packing
* lists.
*
* Following is the PLIST_FMT_VER history:
* 1.0 - Initial revision;
* 1.1 - When recording/checking checksum of symlink use hash of readlink()
* value instead of the hash of an object this links points to.
*
*/
int
verscmp(Package *pkg, int major, int minor)
{
int rval = 0;
if ((pkg->fmtver_maj < major) || (pkg->fmtver_maj == major &&
pkg->fmtver_mnr < minor))
rval = -1;
else if ((pkg->fmtver_maj > major) || (pkg->fmtver_maj == major &&
pkg->fmtver_mnr > minor))
rval = 1;
return rval;
}
/*
* split_version(pkgname, endname, epoch, revision) returns a pointer to
* the version portion of a package name and the two special components.
*
* Syntax is: ${PORTNAME}-${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
*
* Written by Oliver Eikemeier
* Based on work of Jeremy D. Lea.
*/
static const char *
split_version(const char *pkgname, const char **endname, unsigned long *epoch, unsigned long *revision)
{
char *ch;
const char *versionstr;
const char *endversionstr;
if (pkgname == NULL)
errx(2, "%s: Passed NULL pkgname.", __func__);
/* Look for the last '-' in the pkgname */
ch = strrchr(pkgname, '-');
/* Cheat if we are just passed a version, not a valid package name */
versionstr = ch ? ch + 1 : pkgname;
/* Look for the last '_' in the version string, advancing the end pointer */
ch = strrchr(versionstr, '_');
if (revision != NULL) {
*revision = ch ? strtoul(ch + 1, NULL, 10) : 0;
}
endversionstr = ch;
/* Look for the last ',' in the remaining version string */
ch = strrchr(endversionstr ? endversionstr + 1 : versionstr, ',');
if (epoch != NULL) {
*epoch = ch ? strtoul(ch + 1, NULL, 10) : 0;
}
if (ch && !endversionstr)
endversionstr = ch;
/* set the pointer behind the last character of the version without revision or epoch */
if (endname)
*endname = endversionstr ? endversionstr : strrchr(versionstr, '\0');
return versionstr;
}
/*
* PORTVERSIONs are composed of components separated by dots. A component
* consists of a version number, a letter and a patchlevel number. This does
* not conform to the porter's handbook, but let us formulate rules that
* fit the current practice and are far simpler than to make decisions
* based on the order of netters and lumbers. Besides, people use versions
* like 10b2 in the ports...
*/
typedef struct {
#ifdef __LONG_LONG_SUPPORTED
long long n;
long long pl;
#else
long n;
long pl;
#endif
int a;
} version_component;
/*
* get_component(position, component) gets the value of the next component
* (number - letter - number triple) and returns a pointer to the next character
* after any leading separators
*
* - components are separated by dots
* - characters !~ [a-zA-Z0-9.+*] are treated as separators
* (1.0:2003.09.16 = 1.0.2003.09.16), this may not be what you expect:
* 1.0.1:2003.09.16 < 1.0:2003.09.16
* - consecutive separators are collapsed (10..1 = 10.1)
* - missing separators are inserted, essentially
* letter number letter => letter number . letter (10a1b2 = 10a1.b2)
* - missing components are assumed to be equal to 0 (10 = 10.0 = 10.0.0)
* - the letter sort order is: [none], a, b, ..., z; numbers without letters
* sort first (10 < 10a < 10b)
* - missing version numbers (in components starting with a letter) sort as -1
* (a < 0, 10.a < 10)
* - a separator is inserted before the special strings "pl", "alpha", "beta",
* "pre" and "rc".
* - "pl" sorts before every other letter, "alpha", "beta", "pre" and "rc"
* sort as a, b, p and r. (10alpha = 10.a < 10, but 10 < 10a; pl11 < alpha3
* < 0.1beta2 = 0.1.b2 < 0.1)
* - other strings use only the first letter for sorting, case is ignored
* (1.d2 = 1.dev2 = 1.Development2)
* - The special component `*' is guaranteed to be the smallest possible
* component (2.* < 2pl1 < 2alpha3 < 2.9f7 < 3.*)
* - components separated by `+' are handled by version_cmp below
*
* Oliver Eikemeier
*/
static const struct {
const char *name;
size_t namelen;
int value;
} stage[] = {
{ "pl", 2, 0 },
{ "alpha", 5, 'a'-'a'+1 },
{ "beta", 4, 'b'-'a'+1 },
{ "pre", 3, 'p'-'a'+1 },
{ "rc", 2, 'r'-'a'+1 },
{ NULL, 0, -1 }
};
static const char *
get_component(const char *position, version_component *component)
{
const char *pos = position;
int hasstage = 0, haspatchlevel = 0;
if (!pos)
errx(2, "%s: Passed NULL position.", __func__);
/* handle version number */
if (isdigit(*pos)) {
char *endptr;
#ifdef __LONG_LONG_SUPPORTED
component->n = strtoll(pos, &endptr, 10);
#else
component->n = strtol(pos, &endptr, 10);
#endif
/* should we test for errno == ERANGE? */
pos = endptr;
} else if (*pos == '*') {
component->n = -2;
do {
pos++;
} while(*pos && *pos != '+');
} else {
component->n = -1;
hasstage = 1;
}
/* handle letter */
if (isalpha(*pos)) {
int c = tolower(*pos);
haspatchlevel = 1;
/* handle special suffixes */
if (isalpha(pos[1])) {
int i;
for (i = 0; stage[i].name; i++) {
if (strncasecmp(pos, stage[i].name, stage[i].namelen) == 0
&& !isalpha(pos[stage[i].namelen])) {
if (hasstage) {
/* stage to value */
component->a = stage[i].value;
pos += stage[i].namelen;
} else {
/* insert dot */
component->a = 0;
haspatchlevel = 0;
}
c = 0;
break;
}
}
}
/* unhandled above */
if (c) {
/* use the first letter and skip following */
component->a = c - 'a' + 1;
do {
++pos;
} while (isalpha(*pos));
}
} else {
component->a = 0;
haspatchlevel = 0;
}
if (haspatchlevel) {
/* handle patch number */
if (isdigit(*pos)) {
char *endptr;
#ifdef __LONG_LONG_SUPPORTED
component->pl = strtoll(pos, &endptr, 10);
#else
component->pl = strtol(pos, &endptr, 10);
#endif
/* should we test for errno == ERANGE? */
pos = endptr;
} else {
component->pl = -1;
}
} else {
component->pl = 0;
}
/* skip trailing separators */
while (*pos && !isdigit(*pos) && !isalpha(*pos) && *pos != '+' && *pos != '*') {
pos++;
}
return pos;
}
/*
* version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version
* components of pkg1 is less than, equal to or greater than pkg2. No
* comparison of the basenames is done.
*
* The port version is defined by:
* ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
* ${PORTEPOCH} supersedes ${PORTVERSION} supersedes ${PORTREVISION}.
* See the commit log for revision 1.349 of ports/Mk/bsd.port.mk
* for more information.
*
* The epoch and revision are defined to be a single number, while the rest
* of the version should conform to the porting guidelines. It can contain
* multiple components, separated by a period, including letters.
*
* The tests allow for significantly more latitude in the version numbers
* than is allowed in the guidelines. No point in enforcing them here.
* That's what portlint is for.
*
* Jeremy D. Lea.
* reimplemented by Oliver Eikemeier
*/
int
version_cmp(const char *pkg1, const char *pkg2)
{
const char *v1, *v2, *ve1, *ve2;
unsigned long e1, e2, r1, r2;
int result = 0;
v1 = split_version(pkg1, &ve1, &e1, &r1);
v2 = split_version(pkg2, &ve2, &e2, &r2);
/* Check epoch, port version, and port revision, in that order. */
if (e1 != e2) {
result = (e1 < e2 ? -1 : 1);
}
/* Shortcut check for equality before invoking the parsing routines. */
if (result == 0 && (ve1 - v1 != ve2 - v2 || strncasecmp(v1, v2, ve1 - v1) != 0)) {
/* Loop over different components (the parts separated by dots).
* If any component differs, we have the basis for an inequality. */
while(result == 0 && (v1 < ve1 || v2 < ve2)) {
int block_v1 = 0;
int block_v2 = 0;
version_component vc1 = {0, 0, 0};
version_component vc2 = {0, 0, 0};
if (v1 < ve1 && *v1 != '+') {
v1 = get_component(v1, &vc1);
} else {
block_v1 = 1;
}
if (v2 < ve2 && *v2 != '+') {
v2 = get_component(v2, &vc2);
} else {
block_v2 = 1;
}
if (block_v1 && block_v2) {
if (v1 < ve1)
v1++;
if (v2 < ve2)
v2++;
} else if (vc1.n != vc2.n) {
result = (vc1.n < vc2.n ? -1 : 1);
} else if (vc1.a != vc2.a) {
result = (vc1.a < vc2.a ? -1 : 1);
} else if (vc1.pl != vc2.pl) {
result = (vc1.pl < vc2.pl ? -1 : 1);
}
}
}
/* Compare FreeBSD revision numbers. */
if (result == 0 && r1 != r2) {
result = (r1 < r2 ? -1 : 1);
}
return result;
}

View File

@ -1,152 +0,0 @@
#!/usr/local/bin/wish -f
#$FreeBSD$
#
set pkgname ""
wm title . "Package Installation"
#--------------------------------------------------------------
# The top level main window, consisting of a bar of buttons and a list
# of packages and a description of the current package.
#--------------------------------------------------------------
frame .menu -relief raised -borderwidth 1
frame .frame -borderwidth 4
scrollbar .frame.scroll -relief sunken -command ".frame.list yview"
listbox .frame.list -yscroll ".frame.scroll set" -relief sunken -setgrid 1
pack append .frame .frame.scroll {right filly} \
.frame.list {left expand fill}
# build the lower window shoing the complete description of a pacage
frame .f -borderwidth 4
text .f.t -width 80 -height 20 -yscrollcommand ".f.s set" -relief sunken
# Initially display instructions in this window. Erase the
# instructions and show the package description when the user clicks
# on a package.
#
.f.t insert end "Double click on a package above to see its
complete description here."
scrollbar .f.s -relief sunken -command ".f.t yview"
pack append .f .f.s {right filly} .f.t {left expand fill}
bind .frame.list <Double-Button-1> \
{foreach i [selection get] {do_description $i}}
pack append . .menu {top fill} \
.f {bottom expand fill} \
.frame {bottom expand fill}
#----------------------------------------------------------------
# Make menu bar:
#----------------------------------------------------------------
button .menu.inst -text "Install" \
-command "apply_to_pkg \"pkg_add -v\""
button .menu.dein -text "Deinstall" \
-command "apply_to_pkg \"pkg_delete -v\""
button .menu.installed -text "What is Installed?" \
-command "list_pkgs \"pkg_info -I -a |tr ' ' ' '\""
button .menu.available -text "What can I install?" \
-command "list_pkgs \"pkg_info -I -c [glob -nocomplain *.{tgz,tar.z,tar.gz,tar.Z}] |tr ' ' ' '\""
button .menu.cont -text "Contents?" \
-command "apply_to_pkg \"pkg_info -d -v\""
button .menu.quit -text "Quit" -command "destroy ."
button .menu.help -text "Help" -command "do_help"
pack append .menu \
.menu.inst left \
.menu.dein left \
.menu.installed left \
.menu.available left \
.menu.cont left \
.menu.quit left \
.menu.help right
#-------------------------------------------------------
# Display the package description.
#-------------------------------------------------------
proc list_pkgs {s} {
set line ""
set f [eval "open {| sh -c \"$s\" } r"]
.frame.list delete 0 end
while {[gets $f line] > 0} {
.frame.list insert end $line
}
close $f
}
# display the list of available packages
set archives [glob -nocomplain *.{tgz,tar.z,tar.gz,tar.Z}]
if {$archives == ""} {
.frame.list delete 0 end
.frame.list insert end "Warning: no compressed tar archives files found."
} else {
list_pkgs "pkg_info -I -c $archives |tr ' ' ' '"
}
#-------------------------------------------------------
# Display the package description.
#-------------------------------------------------------
proc do_description {s} {
global pkgname
regexp {[^ ]*} $s filename
set pkgname $filename
.f.t delete 0.0 end
set cmd "pkg_info -d $filename |tr -d ' '"
set f [eval "open {| csh -c \"$cmd\" } r"]
while {![eof $f]} {
.f.t insert end [read $f]
}
}
#-------------------------------------------------------
# package install window.
#-------------------------------------------------------
proc do_help {{w .help}} {
catch {destroy $w}
toplevel $w
wm title $w "Help"
wm iconname $w "Help"
button $w.ok -text OK -command "destroy $w"
message $w.t -relief raised -bd 2 \
-text "You can install, deinstall and list info on the available packages. To select a package and see its complete description, press mouse button 1 over the package name. To install a selected package, press the Install button. To exit, press the \"Quit\" button."
pack append $w $w.ok {bottom fillx} $w.t {expand fill}
}
#-------------------------------------------------------
# Apply a command to a package.
#-------------------------------------------------------
proc apply_to_pkg {s} {
apply_to_pkg_err $s ""
}
#-------------------------------------------------------
# Apply a command to a package, with error stream redirection instructions.
#-------------------------------------------------------
proc apply_to_pkg_err {s errredir} {
global pkgname
.f.t delete 0.0 end
if {$pkgname == ""} {
.f.t insert end "You must double click on a package name first!"
} else {
apply_to_pkg_int "$s $pkgname" "2>&1"
}
}
proc apply_to_pkg_int {s errredir} {
.f.t delete 0.0 end
.f.t insert end "Running: $s\n"
set f [eval "open {| sh -c \"$s $errredir\" } r"]
while {![eof $f]} {
.f.t insert end [read $f 64]
}
}
#-------------------------------------------------------
# Invoke an arbitrary command.
#-------------------------------------------------------
proc do_command {s} {
.f.t delete 0.0 end
.f.t insert end "Running: $s\n"
set f [eval "open {| $s} r"]
while {![eof $f]} {
.f.t insert end [read $f 64]
}
}
# local variables:
# mode: csh
# compile-command: ""
# comment-start: "# "
# comment-start-skip: "# "
# end:

View File

@ -1,13 +0,0 @@
# $FreeBSD$
PROG= pkg_updating
SRCS= main.c
CFLAGS+= -I${.CURDIR}/../lib
WFORMAT?= 1
DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD}
LDADD= ${LIBINSTALL} -lfetch -lmd
.include <bsd.prog.mk>

View File

@ -1,284 +0,0 @@
/*-
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Beat Gätzi
* ----------------------------------------------------------------------------
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <stdio.h>
#include <errno.h>
#include <fetch.h>
#include <limits.h>
#include <sysexits.h>
#include <getopt.h>
#include "lib.h"
#include "pathnames.h"
typedef struct installedport {
struct installedport *next; /* List of installed ports. */
char name[LINE_MAX]; /* Name of the installed port. */
} INSTALLEDPORT;
int usage(void);
static char opts[] = "d:f:h";
static struct option longopts[] = {
{ "date", required_argument, NULL, 'd' },
{ "file", required_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
/*
* Parse /usr/port/UPDATING for corresponding entries. If no argument is
* passed to pkg_updating all entries for all installed ports are displayed.
* If a list of portnames is passed to pkg_updating only entries for the
* given portnames are displayed. Use the -d option to define that only newer
* entries as this date are shown.
*/
int
main(int argc, char *argv[])
{
/* Keyword for searching portname in UPDATING. */
const char *affects = "AFFECTS";
/* Indicate a date -> end of a entry. Will fail on 2100-01-01... */
const char *end = "20";
/* Keyword for searching origin portname of installed port. */
const char *origin = "@comment ORIGIN:";
const char *pkgdbpath = LOG_DIR; /* Location of pkgdb */
const char *updatingfile = UPDATING; /* Location of UPDATING */
char *date = NULL; /* Passed -d argument */
char *dateline = NULL; /* Saved date of an entry */
/* Tmp lines for parsing file */
char *tmpline1 = NULL;
char *tmpline2 = NULL;
char originline[LINE_MAX]; /* Line of +CONTENTS */
/* Temporary variable to create path to +CONTENTS for installed ports. */
char tmp_file[MAXPATHLEN];
char updatingline[LINE_MAX]; /* Line of UPDATING */
int ch; /* Char used by getopt */
int found = 0; /* Found an entry */
int linelength; /* Length of parsed line */
int maxcharperline = LINE_MAX; /* Max chars per line */
int dflag = 0; /* -d option set */
/* If pflag = 0 UPDATING will be checked for all installed ports. */
int pflag = 0;
size_t n; /* Offset to create path */
struct dirent *pkgdbdir; /* pkgdb directory */
struct stat attribute; /* attribute of pkgdb element */
/* Needed nodes for linked list with installed ports. */
INSTALLEDPORT *head = (INSTALLEDPORT *) NULL;
INSTALLEDPORT *curr = (INSTALLEDPORT *) NULL;
DIR *dir;
FILE *fd;
warnpkgng();
while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
switch (ch) {
case 'd':
dflag = 1;
date = optarg;
break;
case 'f':
updatingfile = optarg;
break;
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
/* Check if passed date has a correct format. */
if (dflag == 1) {
linelength = strlen(date);
if (linelength != 8)
exit(EX_DATAERR);
if (strspn(date, "0123456789") != 8) {
fprintf(stderr, "unknown date format: %s\n", date);
exit(EX_DATAERR);
}
}
/* Save the list of passed portnames. */
if (argc != 0) {
pflag = 1;
while (*argv) {
if ((curr = (INSTALLEDPORT *)
malloc(sizeof(INSTALLEDPORT))) == NULL)
(void)exit(EXIT_FAILURE);
strlcpy(curr->name, *argv, strlen(*argv) + 1);
curr->next = head;
head = curr;
(void)*argv++;
}
}
/*
* UPDATING will be parsed for all installed ports
* if no portname is passed.
*/
if (pflag == 0) {
/* Open /var/db/pkg and search for all installed ports. */
if ((dir = opendir(pkgdbpath)) != NULL) {
while ((pkgdbdir = readdir(dir)) != NULL) {
if (strcmp(pkgdbdir->d_name, ".") != 0 &&
strcmp(pkgdbdir->d_name, "..") != 0) {
/* Create path to +CONTENTS file for each installed port */
n = strlcpy(tmp_file, pkgdbpath, sizeof(tmp_file));
n = strlcpy(tmp_file + n, "/", sizeof(tmp_file) - n);
n = strlcat(tmp_file + n, pkgdbdir->d_name,
sizeof(tmp_file) - n);
if (stat(tmp_file, &attribute) == -1) {
fprintf(stderr, "can't open %s: %s\n",
tmp_file, strerror(errno));
return EXIT_FAILURE;
}
if (attribute.st_mode & S_IFREG)
continue;
(void)strlcat(tmp_file + n, "/",
sizeof(tmp_file) - n);
(void)strlcat(tmp_file + n, CONTENTS_FNAME,
sizeof(tmp_file) - n);
/* Open +CONTENT file */
fd = fopen(tmp_file, "r");
if (fd == NULL) {
fprintf(stderr, "warning: can't open %s: %s\n",
tmp_file, strerror(errno));
continue;
}
/*
* Parses +CONTENT for ORIGIN line and
* put element into linked list.
*/
while (fgets(originline, maxcharperline, fd) != NULL) {
tmpline1 = strstr(originline, origin);
if (tmpline1 != NULL) {
/* Tmp variable to store port name. */
char *pname;
pname = strrchr(originline, (int)':');
pname++;
if ((curr = (INSTALLEDPORT *)
malloc(sizeof(INSTALLEDPORT))) == NULL)
(void)exit(EXIT_FAILURE);
if (pname[strlen(pname) - 1] == '\n')
pname[strlen(pname) - 1] = '\0';
strlcpy (curr->name, pname, sizeof(curr->name));
curr->next = head;
head = curr;
}
}
if (ferror(fd)) {
fprintf(stderr, "error reading input\n");
exit(EX_IOERR);
}
(void)fclose(fd);
}
}
closedir(dir);
}
}
/* Fetch UPDATING file if needed and open file */
if (isURL(updatingfile)) {
if ((fd = fetchGetURL(updatingfile, "")) == NULL) {
fprintf(stderr, "Error: Unable to get %s: %s\n",
updatingfile, fetchLastErrString);
exit(EX_UNAVAILABLE);
}
}
else {
fd = fopen(updatingfile, "r");
}
if (fd == NULL) {
fprintf(stderr, "can't open %s: %s\n",
updatingfile, strerror(errno));
exit(EX_UNAVAILABLE);
}
/* Parse opened UPDATING file. */
while (fgets(updatingline, maxcharperline, fd) != NULL) {
/* No entry is found so far */
if (found == 0) {
/* Search for AFFECTS line to parse the portname. */
tmpline1 = strstr(updatingline, affects);
if (tmpline1 != NULL) {
curr = head;
while (curr != NULL) {
tmpline2 = strstr(updatingline, curr->name);
if (tmpline2 != NULL)
break;
curr = curr->next;
}
if (tmpline2 != NULL) {
/* If -d is set, check if entry is newer than the date. */
if ((dflag == 1) && (strncmp(dateline, date, 8) < 0))
continue;
printf("%s", dateline);
printf("%s", updatingline);
found = 1;
}
}
}
/* Search for the end of an entry, if not found print the line. */
else {
tmpline1 = strstr(updatingline, end);
if (tmpline1 == NULL)
printf("%s", updatingline);
else {
linelength = strlen(updatingline);
if (linelength == 10)
found = 0;
else
printf("%s", updatingline);
}
}
/* Save the actual line, it could be a date. */
dateline = strdup(updatingline);
}
if (ferror(fd)) {
fprintf(stderr, "error reading input\n");
exit(EX_IOERR);
}
(void)fclose(fd);
exit(EX_OK);
}
int
usage(void)
{
fprintf(stderr,
"usage: pkg_updating [-h] [-d YYYYMMDD] [-f file] [portname ...]\n");
exit(EX_USAGE);
}
void
cleanup(int sig)
{
if (sig)
exit(1);
}

View File

@ -1,17 +0,0 @@
/*-
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Beat Gätzi
* ----------------------------------------------------------------------------
*
* $FreeBSD$
*
*/
/* Where the updating file lives by default */
#define DEF_UPDATING "/usr/ports/UPDATING"
/* macro to define location of the UPDATING file */
#define UPDATING (getenv(PORTSDIR) ? strcat(getenv(PORTSDIR), \
"/UPDATING") : DEF_UPDATING)

View File

@ -1,97 +0,0 @@
.\"
.\" FreeBSD updating - Scan the installed ports and show all UPDATING entries
.\" that affect one of the installed ports. Alternative a list of portnames
.\" could be passed to pkg_updating
.\"
.\" "THE BEER-WARE LICENSE" (Revision 42):
.\" <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
.\" can do whatever you want with this stuff. If we meet some day, and you think
.\" this stuff is worth it, you can buy me a beer in return. Beat Gätzi
.\"
.\" $FreeBSD$
.\"
.Dd November 9, 2012
.Dt PKG_UPDATING 1
.Os
.Sh NAME
.Nm pkg_updating
.Nd a utility for displaying UPDATING entries of software packages
.Sh SYNOPSIS
.Nm
.Op Fl h
.Op Fl d Ar date
.Op Fl f Ar file
.Op Ar pkg-name ...
.Nm
.Sh DESCRIPTION
The
.Nm
command scans the installed ports and show all UPDATING entries that affect one
of the installed ports. Alternative a list of pkg-names could be passed.
.Sh OPTIONS
The following command line options are supported:
.Bl -tag -width indent
.It Ar pkg-name ...
UPDATING entries for the named packages are displayed.
.It Fl d , -date Ar date
Only entries newer than
.Ar date
are shown. Use a YYYYMMDD date format.
.It Fl f , -file Ar file
Defines a alternative location of the UPDATING
.Ar file .
.It Fl h , -help
Print help message.
.El
.Sh ENVIRONMENT
.Bl -tag -width PKG_DBDIR
.It Ev PKG_DBDIR
Specifies an alternative location for the installed package database.
.It Ev PORTSDIR
Location of the ports tree.
.El
.Sh FILES
.Bl -tag -width /var/db/pkg -compact
.It Pa /var/db/pkg
Default location of the installed package database.
.It Pa /usr/ports
The default ports directory and default location of the UPDATING file.
.El
.Sh EXAMPLES
Shows all entries of all installed ports:
.Dl % pkg_updating
.Pp
Shows all entries of all installed ports since 2007-01-01:
.Dl % pkg_updating -d 20070101
.Pp
Shows all entries for all apache and mysql ports:
.Dl % pkg_updating apache mysql
.Pp
Shows all apache entries since 2006-01-01:
.Dl % pkg_updating -d 20060101 apache
.Pp
Defines that the UPDATING file is in /tmp and shows all entries of all
installed ports:
.Dl % pkg_updating -f /tmp/UPDATING
.Pp
Fetch UPDATING file from ftp mirror and show all entries of all
installed ports:
.Dl % pkg_updating -f ftp://ftp.freebsd.org/pub/FreeBSD/ports/packages/UPDATING
.Sh ENVRIOMENT
.Bl -tag -width indent
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_version 1
.Sh AUTHORS
.An Beat G\(:atzi Aq beat@chruetertee.ch
.Sh CONTRIBUTORS
.An Martin Tournoij Aq carpetsmoker@xs4all.nl
.Sh BUGS
Sure to be some.

View File

@ -1,16 +0,0 @@
# $FreeBSD$
PROG= pkg_version
SRCS= main.c perform.c
CFLAGS+= -I${.CURDIR}/../lib
WFORMAT?= 1
DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD}
LDADD= ${LIBINSTALL} -lfetch -lmd
test:
sh ${.CURDIR}/test-pkg_version.sh
.include <bsd.prog.mk>

View File

@ -1,138 +0,0 @@
/*
* 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.
*
* Jeremy D. Lea.
* 11 May 2002
*
* This is the version module. Based on pkg_version.pl by Bruce A. Mah.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <getopt.h>
#include <err.h>
#include "lib.h"
#include "version.h"
char *LimitChars = NULL;
char *PreventChars = NULL;
char *MatchName = NULL;
char *LookUpOrigin = NULL;
Boolean RegexExtended = FALSE;
Boolean UseINDEXOnly = FALSE;
Boolean ShowOrigin = FALSE;
static void usage(void);
static char opts[] = "dIhl:L:qs:XtTO:ov";
static struct option longopts[] = {
{ "extended", no_argument, NULL, 'X' },
{ "help", no_argument, NULL, 'h' },
{ "match", required_argument, NULL, 's' },
{ "no-status", required_argument, NULL, 'L' },
{ "origin", required_argument, NULL, 'O' },
{ "quiet", no_argument, NULL, 'q' },
{ "show-origin",no_argument, NULL, 'o' },
{ "status", required_argument, NULL, 'l' },
{ "index-only", no_argument, NULL, 'I' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
int
main(int argc, char **argv)
{
int ch, cmp = 0;
warnpkgng();
if (argc == 4 && !strcmp(argv[1], "-t")) {
cmp = version_cmp(argv[2], argv[3]);
printf(cmp > 0 ? ">\n" : (cmp < 0 ? "<\n" : "=\n"));
exit(0);
}
else if (argc == 4 && !strcmp(argv[1], "-T")) {
cmp = version_match(argv[3], argv[2]);
exit(cmp == 1 ? 0 : 1);
}
else while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
switch(ch) {
case 'v':
Verbose++;
break;
case 'I':
UseINDEXOnly = TRUE;
break;
case 'l':
LimitChars = optarg;
break;
case 'L':
PreventChars = optarg;
break;
case 'q':
Quiet = TRUE;
break;
case 's':
MatchName = optarg;
break;
case 'O':
LookUpOrigin = optarg;
break;
case 'o':
ShowOrigin = TRUE;
break;
case 't':
errx(2, "Invalid -t usage.");
break;
case 'T':
errx(2, "Invalid -T usage.");
break;
case 'X':
RegexExtended = TRUE;
break;
case 'h':
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
return pkg_perform(argv);
}
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n",
"usage: pkg_version [-hIoqv] [-l limchar] [-L limchar] [[-X] -s string] [-O origin] [index]",
" pkg_version -t v1 v2",
" pkg_version -T name pattern");
exit(1);
}

View File

@ -1,434 +0,0 @@
/*
* 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.
*
* Jeremy D. Lea.
* 11 May 2002
*
* This is the version module. Based on pkg_version.pl by Bruce A. Mah.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "lib.h"
#include "version.h"
#include <err.h>
#include <fetch.h>
#include <signal.h>
static FILE *IndexFile;
static char IndexPath[PATH_MAX] = "";
static struct index_head Index = SLIST_HEAD_INITIALIZER(Index);
static int pkg_do(char *);
static void show_version(Package, const char *, const char *);
/*
* This is the traditional pkg_perform, except that the argument is _not_ a
* list of packages. It is the index file from the command line.
*
* We loop over the installed packages, matching them with the -s flag if
* needed and calling pkg_do(). Beforehand we set up a few things, and after
* we tear them down...
*
* Returns 0 on success, non-zero on failure, corresponding to the number of
* failed attempts to access the INDEX.
*/
int
pkg_perform(char **indexarg)
{
char **pkgs, *pat[2], **patterns;
struct index_entry *ie;
int i, err_cnt = 0, rel_major_ver;
int MatchType;
struct utsname u;
if (uname(&u) == -1) {
warn("%s: failed to determine uname information", __func__);
return 1;
} else if ((rel_major_ver = (int) strtol(u.release, NULL, 10)) <= 0) {
warnx("%s: bad release version specified: %s", __func__, u.release);
return 1;
}
/*
* Try to find and open the INDEX. We only check IndexFile != NULL
* later, if we actually need the INDEX.
*/
if (*indexarg == NULL) {
snprintf(IndexPath, sizeof(IndexPath), "%s/INDEX-%d", PORTS_DIR,
rel_major_ver);
} else
strlcpy(IndexPath, *indexarg, sizeof(IndexPath));
if (isURL(IndexPath))
IndexFile = fetchGetURL(IndexPath, "");
else
IndexFile = fopen(IndexPath, "r");
/* Get either a list of matching or all packages */
if (MatchName != NULL) {
pat[0] = MatchName;
pat[1] = NULL;
MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
patterns = pat;
} else {
MatchType = MATCH_ALL;
patterns = NULL;
}
if (LookUpOrigin != NULL)
pkgs = matchbyorigin(LookUpOrigin, &err_cnt);
else
pkgs = matchinstalled(MatchType, patterns, &err_cnt);
if (err_cnt != 0)
errx(2, "Unable to find package database directory!");
if (pkgs == NULL) {
if (LookUpOrigin != NULL) {
warnx("no packages recorded with this origin");
return (1);
} else {
switch (MatchType) {
case MATCH_ALL:
warnx("no packages installed");
return (0);
case MATCH_EREGEX:
case MATCH_REGEX:
warnx("no packages match pattern");
return (1);
default:
break;
}
}
}
for (i = 0; pkgs[i] != NULL; i++)
err_cnt += pkg_do(pkgs[i]);
/* If we opened the INDEX in pkg_do(), clean up. */
while (!SLIST_EMPTY(&Index)) {
ie = SLIST_FIRST(&Index);
SLIST_REMOVE_HEAD(&Index, next);
if (ie->name != NULL)
free(ie->name);
if (ie->origin != NULL)
free(ie->origin);
free(ie);
}
if (IndexFile != NULL)
fclose(IndexFile);
return err_cnt;
}
/*
* Traditional pkg_do(). We take the package name we are passed and
* first slurp in the CONTENTS file, getting name and origin, then
* we look for it's corresponding Makefile. If that fails we pull in
* the INDEX, and check there.
*/
static int
pkg_do(char *pkg)
{
char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL;
Package plist;
struct index_entry *ie;
FILE *fp;
size_t len;
/* Suck in the contents list. */
plist.head = plist.tail = NULL;
plist.name = plist.origin = NULL;
snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME);
fp = fopen(tmp, "r");
if (!fp) {
warnx("the package info for package '%s' is corrupt", pkg);
return 1;
}
read_plist(&plist, fp);
fclose(fp);
if (plist.name == NULL) {
warnx("%s does not appear to be a valid package!", pkg);
return 1;
}
/*
* First we check if the installed package has an origin, and try
* looking for it's Makefile. If we find the Makefile we get the
* latest version from there. If we fail, we start looking in the
* INDEX, first matching the origin and then the package name.
*/
if (plist.origin != NULL && !UseINDEXOnly) {
snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin);
if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) {
if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL)
warnx("Failed to get PKGNAME from %s/Makefile!", tmp);
else
show_version(plist, latest, "port");
}
}
if (latest == NULL) {
/* Report package as not found in INDEX if the INDEX is not required. */
if (IndexFile == NULL && !UseINDEXOnly)
show_version(plist, NULL, plist.origin);
else {
/* We only pull in the INDEX once, if needed. */
if (SLIST_EMPTY(&Index)) {
if (!IndexFile)
errx(2, "Unable to open %s in %s.", IndexPath, __func__);
while ((ch = fgetln(IndexFile, &len)) != NULL) {
/*
* Don't use strlcpy() because fgetln() doesn't
* return a valid C string.
*/
strncpy(tmp, ch, MIN(len, PATH_MAX));
tmp[PATH_MAX-1] = '\0';
/* The INDEX has pkgname|portdir|... */
if ((ch = strchr(tmp, '|')) != NULL)
ch[0] = '\0';
if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL)
ch[0] = '\0';
/* Look backwards for the last two dirs = origin */
while (ch != NULL && *--ch != '/')
if (ch[0] == '\0')
ch = NULL;
while (ch != NULL && *--ch != '/')
if (ch[0] == '\0')
ch = NULL;
if (ch == NULL)
errx(2, "The INDEX does not appear to be valid!");
if ((ie = malloc(sizeof(struct index_entry))) == NULL)
errx(2, "Unable to allocate memory in %s.", __func__);
bzero(ie, sizeof(struct index_entry));
ie->name = strdup(tmp);
ie->origin = strdup(&ch[1]);
/* Who really cares if we reverse the index... */
SLIST_INSERT_HEAD(&Index, ie, next);
}
}
/* Now that we've slurped in the INDEX... */
SLIST_FOREACH(ie, &Index, next) {
if (plist.origin != NULL) {
if (strcmp(plist.origin, ie->origin) == 0)
latest = strdup(ie->name);
} else {
strlcpy(tmp, ie->name, PATH_MAX);
strlcpy(tmp2, plist.name, PATH_MAX);
/* Chop off the versions and compare. */
if ((ch = strrchr(tmp, '-')) == NULL)
errx(2, "The INDEX does not appear to be valid!");
ch[0] = '\0';
if ((ch = strrchr(tmp2, '-')) == NULL)
warnx("%s is not a valid package!", plist.name);
else
ch[0] = '\0';
if (strcmp(tmp2, tmp) == 0) {
if (latest != NULL) {
/* Multiple matches */
snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name);
free(latest);
latest = strdup(tmp);
} else
latest = strdup(ie->name);
}
}
}
if (latest == NULL)
show_version(plist, NULL, NULL);
else
show_version(plist, latest, "index");
}
}
if (latest != NULL)
free(latest);
free_plist(&plist);
return 0;
}
#define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \
(LimitChars != NULL && strchr(LimitChars, (c))) || \
(PreventChars == NULL && LimitChars == NULL))
/*
* Do the work of comparing and outputing. Ugly, but well that's what
* You get when you try to match perl output in C ;-).
*/
void
show_version(Package plist, const char *latest, const char *source)
{
char *ch, tmp[PATH_MAX];
const char *ver;
int cmp = 0;
if (!plist.name || strlen(plist.name) == 0)
return;
if (ShowOrigin != FALSE && plist.origin != NULL)
strlcpy(tmp, plist.origin, PATH_MAX);
else {
strlcpy(tmp, plist.name, PATH_MAX);
if (!Verbose) {
if ((ch = strrchr(tmp, '-')) != NULL)
ch[0] = '\0';
}
}
if (latest == NULL) {
if (source == NULL && OUTPUT('!')) {
printf("%-34s !", tmp);
if (Verbose)
printf(" Comparison failed");
printf("\n");
} else if (OUTPUT('?')) {
printf("%-34s ?", tmp);
if (Verbose)
printf(" orphaned: %s", plist.origin);
printf("\n");
}
} else if (strchr(latest,'|') != NULL) {
if (OUTPUT('*')) {
printf("%-34s *", tmp);
if (Verbose) {
strlcpy(tmp, latest, PATH_MAX);
ch = strchr(tmp, '|');
ch[0] = '\0';
ver = strrchr(tmp, '-');
ver = ver ? &ver[1] : tmp;
printf(" multiple versions (index has %s", ver);
do {
ver = strrchr(&ch[1], '-');
ver = ver ? &ver[1] : &ch[1];
if ((ch = strchr(&ch[1], '|')) != NULL)
ch[0] = '\0';
printf(", %s", ver);
} while (ch != NULL);
printf(")");
}
printf("\n");
}
} else {
cmp = version_cmp(plist.name, latest);
ver = strrchr(latest, '-');
ver = ver ? &ver[1] : latest;
if (cmp < 0 && OUTPUT('<')) {
if (Quiet)
printf("%s", tmp);
else {
printf("%-34s <", tmp);
if (Verbose)
printf(" needs updating (%s has %s)", source, ver);
}
printf("\n");
} else if (cmp == 0 && OUTPUT('=')) {
if (Quiet)
printf("%s", tmp);
else {
printf("%-34s =", tmp);
if (Verbose)
printf(" up-to-date with %s", source);
}
printf("\n");
} else if (cmp > 0 && OUTPUT('>')) {
if (Quiet)
printf("%s", tmp);
else {
printf("%-34s >", tmp);
if (Verbose)
printf(" succeeds %s (%s has %s)", source, source, ver);
}
printf("\n");
}
}
}
int
version_match(char *pattern, const char *pkgname)
{
int ret = 0;
int matchstream = 0;
FILE *fp = NULL;
Boolean isTMP = FALSE;
if (isURL(pkgname)) {
fp = fetchGetURL(pkgname, "");
isTMP = TRUE;
matchstream = 1;
if (fp == NULL)
errx(2, "Unable to open %s.", pkgname);
} else if (pkgname[0] == '/') {
fp = fopen(pkgname, "r");
isTMP = TRUE;
matchstream = 1;
if (fp == NULL)
errx(2, "Unable to open %s.", pkgname);
} else if (strcmp(pkgname, "-") == 0) {
fp = stdin;
matchstream = 1;
} else if (isURL(pattern)) {
fp = fetchGetURL(pattern, "");
isTMP = TRUE;
matchstream = -1;
if (fp == NULL)
errx(2, "Unable to open %s.", pattern);
} else if (pattern[0] == '/') {
fp = fopen(pattern, "r");
isTMP = TRUE;
matchstream = -1;
if (fp == NULL)
errx(2, "Unable to open %s.", pattern);
} else if (strcmp(pattern, "-") == 0) {
fp = stdin;
matchstream = -1;
} else {
ret = pattern_match(MATCH_GLOB, pattern, pkgname);
}
if (fp != NULL) {
size_t len;
char *line;
while ((line = fgetln(fp, &len)) != NULL) {
int match;
char *ch, ln[2048];
size_t lnlen;
if (len > 0 && line[len-1] == '\n')
len --;
lnlen = len;
if (lnlen > sizeof(ln)-1)
lnlen = sizeof(ln)-1;
memcpy(ln, line, lnlen);
ln[lnlen] = '\0';
if ((ch = strchr(ln, '|')) != NULL)
ch[0] = '\0';
if (matchstream > 0)
match = pattern_match(MATCH_GLOB, pattern, ln);
else
match = pattern_match(MATCH_GLOB, ln, pkgname);
if (match == 1) {
ret = 1;
printf("%.*s\n", (int)len, line);
}
}
if (isTMP)
fclose(fp);
}
return ret;
}
void
cleanup(int sig)
{
if (sig)
exit(1);
}

View File

@ -1,263 +0,0 @@
.\"
.\" Copyright 1998 Bruce A. Mah
.\"
.\" 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 DEVELOPERS ``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 DEVELOPERS 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$
.\"
.Dd May 18, 2013
.Dt PKG_VERSION 1
.Os
.Sh NAME
.Nm pkg_version
.Nd summarize installed versions of packages
.Sh SYNOPSIS
.Nm
.Op Fl hIoqv
.Op Fl l Ar limchar
.Op Fl L Ar limchar
.Oo
.Op Fl X
.Fl s Ar string
.Oc
.Op Fl O Ar origin
.Op Ar index
.Nm
.Fl t Ar version1 version2
.Nm
.Fl T Ar pkgname pattern
.Sh DESCRIPTION
The
.Nm
command is used to produce a report of non-base software packages
installed using the
.Xr pkg_add 1
command.
.Pp
Each package's version number is checked against one of two sources to
see if that package may require updating.
If the package contains
information about its origin in the
.Fx
ports tree, and a version number can be determined from the port's
.Pa Makefile ,
then the version number from the
.Pa Makefile
will be used to determine whether the installed package is up-to-date
or requires updating.
.Pp
If no origin for a package can be found, or if the port's
.Pa Makefile
cannot be located,
.Nm
will search for the package in the ports collection index file
(typically
.Pa /usr/ports/INDEX-10 ) .
Any matching version number(s) there will be used to determine whether
the installed package is up-to-date or requires updating.
.Pp
Generally, using the version number from a port's
.Pa Makefile
will provide a more accurate result, since, unlike the index file, it
provides an unambiguous current version number, even when multiple
versions of a port exist in the ports collection.
Moreover, the ports collection index file is only updated at
intervals, meaning that it may not completely reflect the version
numbers of the software contained in the ports collection.
.Pp
Each package name is printed, along with a one-character status flag:
.Bl -tag -width indent
.It Li =
The installed version of the package is current.
.It Li \&<
The installed version of the package is older than the current version.
.It Li \&>
The installed version of the package is newer than the current version.
This situation can arise with an out-of-date index file, or when
testing new ports.
.It Li \&?
The installed package does not appear in the index.
This could be due to an out of date index or a package taken from a PR
that has not yet been committed.
.It Li *
There are multiple versions of a particular software package
listed in the index file.
Examples from the
.Fx
ports collection are the Tcl toolkit or the
.Tn EMACS
editor.
.It Li \&!
The installed package exists in the index but for some reason,
.Nm
was unable to compare the version number of the installed package
with the corresponding entry in the index.
.El
.Sh OPTIONS
The
.Nm
utility supports several command-line arguments:
.Bl -tag -width indent
.It Fl h , -help
Print help message.
.It Fl I , -index-only
Use only the index file for determining if a package is out of date.
This is much faster than using the version number from a port's
Makefile, at the expense of potentially giving an incorrect result if
the index file is out of date.
.It Fl l , -status Ar limchar
Limit the output to those packages whose status flag matches the
character(s) in
.Ar limchar .
More than one character can be specified in
.Ar limchar .
Note that because some of the status flag characters are also special
to the shell, it is best to quote
.Ar limchar
with single quotes.
.It Fl L , -no-status Ar limchar
Limit the output to those packages whose status flag does not match
.Ar limchar .
You may specify more than one character to match in
.Ar limchar .
Note that because some of the status flag characters are also special
to the shell, it is best to quote
.Ar limchar
with single quotes.
.It Fl o , -show-origin
Show the origin recorded on package generation instead of the package
name.
.It Fl O , -origin Ar origin
Only list packages whose registered origin is
.Ar origin .
.It Fl q , -quiet
Enable quiet output.
Quiet output precludes printing the
.Ar limchar
when used with
.Fl l
or
.Fl L .
This is useful when used as the input to
.Xr portupgrade 8 .
.It Fl s , -match Ar string
Limit the output to those packages whose names match a given
.Ar string .
.It Fl X , -extended
Interpret
.Ar string
as a extended regular expression.
.It Fl t
Test a pair of version number strings and exit.
The output consists of one of the single characters
.Li =
(equal),
.Li \&<
(right-hand number greater), or
.Li \&>
(left-hand number greater) on standard output.
This flag is mostly useful for scripts or for testing.
.It Fl T
Test whether
.Ar pkgname
is matched by
.Ar pattern
and set the exit code accordingly.
.Fl T
can also be used in `filter mode':
When one of the arguments is `-', standard input is used, and lines
with matching package names/patterns are echoed to standard output.
.It Fl v
Enable verbose output.
Verbose output includes some English-text
interpretations of the version number comparisons, as well as the
version numbers compared for each package.
Non-verbose output is
probably easier for programs or scripts to parse.
.It Ar index
Specify the index to be used as a basis of comparison.
This index can
be specified as a filename (in the local file system) or a URL.
Any
URL understandable by
.Xr fetch 1
can be used here.
If no
.Ar index
file is specified on the command line,
.Pa /usr/ports/INDEX-10
is used.
.El
.Sh FILES
.Bl -tag -width /usr/ports/INDEX-10 -compact
.It Pa /usr/ports/INDEX-10
Default index file.
.El
.Sh EXAMPLES
The following is a typical invocation of the
.Nm
command, which checks the installed packages against the local ports
index file:
.Pp
.Dl % pkg_version -v
.Pp
The command below generates a report against
the version numbers in the on-line ports collection:
.Pp
.Dl % pkg_version http://www.FreeBSD.org/ports/INDEX-10
.Pp
The following command compares two package version strings:
.Pp
.Dl % pkg_version -t 1.5 1.5.1
.Sh COMPATIBILITY
The
.Fl c
option has been deprecated and is no longer supported.
.Sh ENVRIOMENT
.Bl -tag -width indent
.It Ev PKG_OLD_NOWARN
If set
.Nm
will not warn about its use in the presence of pkgng databases.
.El
.Sh SEE ALSO
.Xr fetch 1 ,
.Xr pkg_add 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_info 1 ,
.Xr portupgrade 8
.Sh AUTHORS
The
.Nm
utility was written by
.An Jeremy D. Lea Aq reg@FreeBSD.org ,
partially based on a Perl script written by
.An Bruce A. Mah Aq bmah@FreeBSD.org .
.Sh CONTRIBUTORS
.An Nik Clayton Aq nik@FreeBSD.org ,
.An Dominic Mitchell Aq dom@palmerharvey.co.uk ,
.An Mark Ovens Aq marko@FreeBSD.org ,
.An Doug Barton Aq DougB@gorean.org ,
.An Akinori MUSHA Aq knu@FreeBSD.org ,
.An Oliver Eikemeier Aq eik@FreeBSD.org

View File

@ -1,94 +0,0 @@
#!/bin/sh
#
# Copyright 2001 Bruce A. Mah
#
# 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 DEVELOPERS ``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 DEVELOPERS 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.
#
# test-pkg_version.sh
#
# Regression testing for pkg_version
# Originally from an idea by "Akinori MUSHA" <knu@iDaemons.org>
#
# $FreeBSD$
#
ECHO=echo
PKG_VERSION=./pkg_version
test-pv ( ) { \
setvar v1 $1
setvar answer $2
setvar v2 $3
setvar type $4
res=`${PKG_VERSION} -t ${v1} ${v2}`
if [ ${res} != ${answer} ]; then \
${ECHO} "${type} test failed (${v1} ${res} ${v2}, should have been ${answer})"; \
fi
}
# Test coercion of default PORTREVISION and PORTEPOCH
test-pv 0.10 "=" 0.10_0 coercion
test-pv 0.10 "=" 0.10,0 coercion
test-pv 0.10 "=" 0.10_0,0 coercion
# Test various comparisons
test-pv 1.0 "=" 1.0 equality
test-pv 2.15a "=" 2.15a equality
test-pv 0.10 ">" 0.9 inequality
test-pv 0.9 "<" 0.10 inequality
test-pv 2.3p10 ">" 2.3p9 number/letter
test-pv 1.6.0 ">" 1.6.0.p3 number/letter
test-pv 1.0.b ">" 1.0.a3 number/letter
test-pv 1.0a ">" 1.0 number/letter
test-pv 1.0a "<" 1.0b number/letter
test-pv 5.0a ">" 5.0.b number/letter
test-pv 1.5_1 ">" 1.5 portrevision
test-pv 1.5_2 ">" 1.5_1 portrevision
test-pv 1.5_1 "<" 1.5.0.1 portrevision
test-pv 1.5 "<" 1.5.0.1 portrevision
test-pv 00.01.01,1 ">" 99.12.31 portepoch
test-pv 0.0.1_1,2 ">" 0.0.1,2 portrevision/portepoch
test-pv 0.0.1_1,3 ">" 0.0.1_2,2 portrevision/portepoch
test-pv 2.0 ">" 2.a2 number/letter
test-pv 3 "=" 3.0 equality
test-pv 4a "<" 4a0 letter/zero
test-pv 10a1b2 "=" 10a1.b2 separator
test-pv 7pl "=" 7.pl patchevel
test-pv 8.0.a "=" 8.0alpha alpha
test-pv 9.b3.0 "=" 9beta3 beta
test-pv 10.pre7 "=" 10pre7.0 pre
test-pv 11.r "=" 11.rc rc
test-pv 12pl "<" 12alpha alpha/patchevel
test-pv 13.* "<" 13.pl star/patchevel
test-pv 1.0.0+2003.09.06 "=" 1.0+2003.09.06 plus/multiple
test-pv 1.0.1+2003.09.06 ">" 1.0+2003.09.06 plus/multiple
test-pv 1.0.0+2003.09.06 "<" 1.0+2003.09.06_1 plus/portrevision
test-pv 1.0.1+2003.09.06 ">" 1.0+2003.09.06_1 plus/portrevision

View File

@ -1,43 +0,0 @@
/* $FreeBSD$ */
/*
* 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.
*
* Jeremy D. Lea.
* 11 May 2002
*
* This is the version module. Based on pkg_version.pl by Bruce A. Mah.
*
*/
#ifndef _INST_VERSION_H_INCLUDE
#define _INST_VERSION_H_INCLUDE
struct index_entry {
SLIST_ENTRY(index_entry) next;
char *name;
char *origin;
};
SLIST_HEAD(index_head, index_entry);
extern char *LimitChars;
extern char *PreventChars;
extern char *MatchName;
extern char *LookUpOrigin;
extern Boolean RegexExtended;
extern Boolean UseINDEXOnly;
extern Boolean ShowOrigin;
extern int version_match(char *, const char *);
#endif /* _INST_VERSION_H_INCLUDE */