After around 20 years of duty it is time for pkg_install to retire
This commit is contained in:
parent
8cf0e32801
commit
c92d635ad3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=257444
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -29,8 +29,4 @@ FILES+= 500.ipfwdenied \
|
||||
FILES+= 520.pfdenied
|
||||
.endif
|
||||
|
||||
.if ${MK_PKGTOOLS} != "no"
|
||||
FILES+= 460.chkportsum
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -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
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,4 +0,0 @@
|
||||
.\" $FreeBSD$
|
||||
Set to build
|
||||
.Xr pkg_add 8
|
||||
and related programs.
|
@ -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
|
||||
|
@ -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})
|
||||
|
||||
|
@ -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"
|
@ -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! :-)
|
@ -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>
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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.
|
@ -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>
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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.
|
@ -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);
|
||||
}
|
@ -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>
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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.
|
@ -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>
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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.
|
@ -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);
|
||||
}
|
@ -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>
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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';
|
||||
}
|
@ -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. */
|
@ -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_ */
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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));
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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:
|
@ -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>
|
@ -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);
|
||||
}
|
@ -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)
|
@ -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.
|
@ -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>
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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
|
@ -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 */
|
Loading…
Reference in New Issue
Block a user