summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2008-04-22 08:16:26 +0000
committerTimo Teras <timo.teras@iki.fi>2008-04-22 08:16:26 +0000
commit219a1b2ee8f4c3c2caf57e79bcb9780e32da7155 (patch)
tree0a4d20d18de572e5eba37138ca5176fee051d981
parent384c2f1d94282ff5564a5f6c5ab9e51c975f83a6 (diff)
downloadapk-tools-219a1b2ee8f4c3c2caf57e79bcb9780e32da7155.tar.gz
apk-tools-219a1b2ee8f4c3c2caf57e79bcb9780e32da7155.tar.bz2
apk-tools-219a1b2ee8f4c3c2caf57e79bcb9780e32da7155.tar.xz
apk-tools-219a1b2ee8f4c3c2caf57e79bcb9780e32da7155.zip
Overwriting of bb files, apk_create (from old apk-tools), chdir changes,
other stuff.
-rw-r--r--Makefile8
-rw-r--r--scripts/Makefile19
-rwxr-xr-xscripts/apk_create195
-rwxr-xr-xscripts/libutil.sh275
-rw-r--r--src/apk.c3
-rw-r--r--src/apk_defines.h26
-rw-r--r--src/apk_package.h2
-rw-r--r--src/database.c74
-rw-r--r--src/package.c16
9 files changed, 565 insertions, 53 deletions
diff --git a/Makefile b/Makefile
index ee4ca1e..7764fcc 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@
# under the terms of the GNU General Public License version 3 as published
# by the Free Software Foundation. See http://www.gnu.org/ for details.
-VERSION := 2.0-pre0
+VERSION := 2.0_pre0
SVN_REV := $(shell svn info 2> /dev/null | grep ^Revision | cut -d ' ' -f 2)
ifneq ($(SVN_REV),)
@@ -20,7 +20,7 @@ CC=gcc
INSTALL=install
INSTALLDIR=$(INSTALL) -d
-CFLAGS=-O2 -g -D_GNU_SOURCE -Werror -Wall -Wstrict-prototypes -std=gnu99 \
+CFLAGS=-g -D_GNU_SOURCE -Werror -Wall -Wstrict-prototypes -std=gnu99 \
-DAPK_VERSION=\"$(FULL_VERSION)\"
LDFLAGS=-g -nopie
LIBS=-lpthread
@@ -31,12 +31,12 @@ LDFLAGS+=-static
endif
DESTDIR=
-SBINDIR=/usr/sbin
+SBINDIR=/sbin
CONFDIR=/etc/apk
MANDIR=/usr/share/man
DOCDIR=/usr/share/doc/apk
-SUBDIRS=src
+SUBDIRS=src scripts
.PHONY: compile install clean all
diff --git a/scripts/Makefile b/scripts/Makefile
new file mode 100644
index 0000000..817205b
--- /dev/null
+++ b/scripts/Makefile
@@ -0,0 +1,19 @@
+# Makefile - one file to rule them all, one file to bind them
+#
+# Copyright (C) 2007 Timo Teräs <timo.teras@iki.fi>
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 3 as published
+# by the Free Software Foundation. See http://www.gnu.org/ for details.
+
+all:
+
+clean:
+
+install::
+ $(INSTALLDIR) $(DESTDIR)$(SBINDIR)
+ $(INSTALL) apk_create $(DESTDIR)$(SBINDIR)
+ $(INSTALLDIR) $(DESTDIR)/lib/apk
+ $(INSTALL) libutil.sh $(DESTDIR)/lib/apk
+
diff --git a/scripts/apk_create b/scripts/apk_create
new file mode 100755
index 0000000..6bbb9ee
--- /dev/null
+++ b/scripts/apk_create
@@ -0,0 +1,195 @@
+#!/bin/sh
+#
+# apk_create - a utility for creating software packages.
+#
+# Copyright (c) 2005 Natanael Copa
+#
+# Distributed under GPL-2
+#
+
+PROGRAM=apk_create
+
+#load the libraries
+. "${APK_LIBS:=/lib/apk}/libutil.sh"
+#. "$APK_LIBS/libfetch.sh"
+#. "$APK_LIBS/libindex.sh"
+#. "$APK_LIBS/libdb.sh"
+#. "$APK_LIBS/libpkgf.sh"
+
+# print usage and die
+usage() {
+ echo "$PROGRAM $VERSION"
+ echo "
+Usage: apk_create [hvS] [-a [+]arch] [-c [+]desc] [-i iscript] [-I piscript]
+ [-k dscript] [-K pdscript] [-l [+]license] [-m metadir] [-o owners]
+ [-p package] [-P [+]pkgs] [-s srcdir] [-u uscript] [-U puscript]
+ [-x excludepattern] [-X excludefile ] [-w [+]uri] pkg-filename
+
+Options:
+ -a Read package architecture from arch or use the argument itself, if
+ preceded with an '+'.
+ -c Read package description from desc or use the argument itself, if
+ preceded with an '+'.
+ -f Use fakeroot when creating the package.
+ -h Show help and exit.
+ -i Use iscript as pre-install script.
+ -I Use piscript as post-install script.
+ -k Use dscript as deinstall script.
+ -K Use pdscript as post-deinstall script.
+ -l Read package license from license or use the argument itself, if
+ preceded with an '+'.
+ -m Use all metafiles found in metadir.
+ -o Use file as OWNERS file.
+ -p Use package as source in addition to or instead of source dir.
+ -P Read space separated dependencies from pkgs or use the argument itself,
+ if preceded with an '+'.
+ -s Set source directory to srcdir.
+ -S Strip ELF files with sstrip.
+ -T Include files listed in includefile.
+ -u Use uscript as pre-update script.
+ -U Use puscript as post-upgrade script.
+ -v Turn on verbose output.
+ -w Read webpage URI from uri or use the argument itself. if preceded
+ with an '+'.
+ -x Exclude files matching excludepattern.
+ -X Exclude files listed in excludefile.
+ "
+ exit 1
+}
+
+# if $1 start with a '+', strip the '+' and echo the reset
+# otherwise read contents from file $1
+get_arg_or_file() {
+ local tmp
+ # we can do this with awk
+ # but we want it more readable...
+ # echo "$1" | awk '
+ # /^\+/ { print substr($0, 2)}
+ # /^[^\+]/ { readline < $0 ; print}'
+ if echo "$1" | grep '^+' > /dev/null; then
+ echo "$1" | sed 's/^\+//'
+ return 0
+ fi
+ cat "$1" || die "Could not read file '$1'"
+}
+
+#parse args
+unset vflag
+
+
+while getopts "a:c:fhi:I:k:K:l:m:o:p:P:Ss:T:u:U:vX:x:w:" opt ; do
+ case "$opt" in
+ a) ARCH=`get_arg_or_file "$OPTARG"`;;
+ h) usage;;
+ c) DESC=`get_arg_or_file "$OPTARG"`;;
+ i) PRE_INSTALL="$OPTARG";;
+ I) POST_INSTALL="$OPTARG";;
+ k) DSCRIPT="$OPTARG";;
+ K) POST_DEINSTALL="$OPTARG";;
+ l) LICENSE=`get_arg_or_file "$OPTARG"`;;
+ m) METADIR="$OPTARG";;
+ o) OWNERS="$OPTARG";;
+ p) case "$OPTARG" in
+ *.tar.bz) UNTAR="tar -zxf \"$OPTARG\"";;
+ *.tar.bz2) UNTAR="tar -jxf \"$OPTARG\"";;
+ *) die "Only .tar.gz and .tar.bz2 are supported";;
+ esac;;
+ P) DEPEND=`get_arg_or_file "$OPTARG"`;;
+ s) SRCDIR="$OPTARG";;
+ S) SSTRIP="-S";;
+ T) INCLUDE_FROM="$INCLUDE_FROM --include-from=$OPTARG";;
+ u) PRE_UPDATE="$OPTARG";;
+ U) POST_UPDATE="$OPTARG";;
+ v) VERBOSE="-v" ;;
+ x) EXCLUDE="$EXCLUDE --exclude=$OPTARG";;
+ X) EXCLUDE_FROM="$EXCLUDE_FROM --exclude-from=$OPTARG";;
+ w) WWW=`get_arg_or_file "$OPTARG"`;;
+ \?) usage;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# if -s and -p is not specified, use current dir as default.
+[ -z "$SRCDIR$UNTAR" ] && SRCDIR="."
+
+[ $# -ne 1 ] && usage
+
+which rsync > /dev/null || die "This program depends on rsync."
+
+if [ "`whoami`" != "root" ] ; then
+ SUDO=sudo
+fi
+
+# find absolute path to package
+case "$1" in
+ /*) PKGVF="$1";;
+ *) PKGVF="$PWD/$1";;
+esac
+
+PV="`basename \"$PKGVF\" .apk`"
+echo "$PV" | grep -- '-[0-9].*' > /dev/null || die "Package name $PKGVF does not have any version."
+P="`echo $PV | sed 's/-[0-9].*//'`"
+V="`echo $PV | sed 's/^'$P'-//'`"
+
+# clean temp dir
+tmp="$APK_TMPDIR/$PV"
+rm -rf "$tmp"
+
+# copy files
+if [ "$UNTAR" ] ; then
+ $UNTAR $INCLUDE_FROM $EXCLUDE $EXCLUDE_FROM -C "$tmp" || \
+ die "Failed to unpack"
+fi
+
+if [ "$SRCDIR" ] ; then
+ rsync -ra $INCLUDE_FROM $EXCLUDE $EXCLUDE_FROM "$SRCDIR/." "$tmp" ||\
+ die "Failed to copy files from '$SRCDIR/.' to '$tmp'".
+fi
+
+# run sstrip
+[ "$SSTRIP" ] && find "$tmp" -type f \
+ | xargs -n1 file \
+ | grep ELF \
+ | grep -v relocatable \
+ | cut -d : -f 1 \
+ | while read f ; do
+ $SUDO sstrip "$f"
+ done
+
+# create meta data
+dbdir=`beautify_path "$tmp/$APK_DBDIR"`
+db="$dbdir/$PV"
+mkdir -p "$db"
+
+if [ "$METADIR" ] ; then
+ cp $METADIR/* "$db/" || die "Failed to copy files from '$METADIR'"
+fi
+[ "$ARCH" ] && echo "$ARCH" > "$db/ARCH"
+[ "$DEPEND" ] && echo "$DEPEND" > "$db/DEPEND"
+[ "$DESC" ] && echo "$DESC" > "$db/DESC"
+[ "$LICENSE" ] && echo "$LICENSE" > "$db/LICENSE"
+[ "$WWW" ] && echo "$WWW" > "$db/WWW"
+
+[ "$PRE_INSTALL" ] && cp -a "$PRE_INSTALL" "$db/pre-install"
+[ "$POST_INSTALL" ] && cp -a "$POST_INSTALL" "$db/post-install"
+[ "$DSCRIPT" ] && cp -a "$DSCRIPT" "$db/pre-deinstall"
+[ "$POST_DEINSTALL" ] && cp -a "$POST_DEINSTALL" "$db/post-deinstall"
+[ "$PRE_UPDATE" ] && cp -a "$PRE_UPDATE" "$db/pre-update"
+[ "$POST_UPDATE" ] && cp -a "$POST_UPDATE" "$db/post-update"
+[ "$OWNERS" ] && cp -a "$OWNERS" "$db/OWNERS"
+
+# check if var/db/apk contains more than it should
+[ `ls "$dbdir" | wc -l` -gt 1 ] && die "$APK_DBDIR should only contain the directory $PV."
+
+# check if arch, desc, license and www info is there
+[ -f "$db/ARCH" ] || die "Architecture not set. Use -a."
+[ -f "$db/DESC" ] || die "Description not set. Use -c."
+[ -f "$db/LICENSE" ] || die "License not set. Use -l."
+[ -f "$db/WWW" ] || eecho "Warning: Homepage not set (use -w)."
+
+# now, lets create the package
+cd "$tmp"
+tar --owner=root --group=root $VERBOSE -zcf "$PKGVF" *
+
+# cleanup
+rm -rf "$tmp"
diff --git a/scripts/libutil.sh b/scripts/libutil.sh
new file mode 100755
index 0000000..229b275
--- /dev/null
+++ b/scripts/libutil.sh
@@ -0,0 +1,275 @@
+#!/bin/sh
+
+# libutil.sh - Utility functions
+#
+# Copyright(c) 2005 Natanael Copa
+#
+# Distributed under GPL-2
+#
+
+VERSION=0.13.1
+
+# echo to stderr
+eecho() {
+ echo $* >&2
+}
+
+# echo to stderr and die
+die() {
+ echo -n "$PROGRAM: " >&2
+ eecho $*
+ exit 1
+}
+
+die_unless_force() {
+ echo "$PROGRAM: $*" >&2
+ [ -z "$FORCE" ] && exit 1
+}
+
+# remove double / and ./ in pathnames
+beautify_path() {
+ echo "$1" | sed 's:/^[^\.]\./::g; s:/\{2,\}:/:g; s:/\./:/:g'
+}
+
+# check if parameter is an uri or not
+is_uri() {
+ echo "$1" | grep "^[a-z][a-z0-9+]*:/" >/dev/null
+}
+
+# check if parameter is an apk package (contains a / or .apk at the end)
+is_apk() {
+ #echo "$1" | grep '/' >/dev/null && return 0
+ [ -z "${1%%*/*}" ] && return 0
+
+ #echo "$1" | grep ".apk$" >/dev/null
+ [ -z "${1%%*.apk}" ]
+}
+
+# check if path start with a '/'
+is_absolute_path() {
+ test -z "${1##/*}"
+}
+
+# if path dont start with '/' then append $PWD
+get_absolute_path() {
+ if is_absolute_path "$1" ; then
+ echo "$1"
+ else
+ beautify_path "$PWD/$1"
+ fi
+}
+
+# check if parameter has version number (i.e. if it is an pkgv or pkg)
+has_version() {
+ echo "$1" | grep -- '-[0-9].*' >/dev/null
+}
+
+# check if parameter has some kind of wildcard
+has_wildcard() {
+ echo "$1" | grep "[\*\?\[]" >/dev/null
+}
+
+# get the scheme for an uri (echo everything before the first ':')
+get_uri_scheme() {
+ echo "$1" | cut -d : -f 1
+}
+
+# remove version number from package name
+rm_ver() {
+ echo "$1" | sed 's/\(.*\)-[0-9].*/\1/'
+}
+
+# get version number from package name or file
+get_ver() {
+ basename "$1" .apk | sed 's/.*-\([0-9].*\)/\1/'
+}
+
+# initialize a temp directory
+# $1 contains the variable name for the directory
+# the directory will automatically be deleted upon exit
+init_tmpdir() {
+ local omask=`umask`
+ local __tmpd="$APK_TMPDIR/$PROGRAM-${$}-`date +%s`"
+ umask 077 || die "umask"
+ mkdir "$__tmpd" || exit 1
+ trap "rm -fr \"$__tmpd\"; exit" 0
+ umask $omask
+ eval "$1=\"$__tmpd\""
+}
+
+# remove files and empty dirs in specified list.
+# also remove APK_LBUFILES from default.tdb
+# environment:
+# ROOT: all files are relative this path
+# VERBOSE: echo filenames to stdout
+# DRYRUN: don't delete anything, just simulate
+my_rm() {
+ rm "$1" 2>/dev/null || busybox rm "$1"
+}
+
+list_uninstall() {
+ local f p
+ local root=${ROOT:-"/"}
+ sort -r "$1" | while read f ; do
+ p="`beautify_path \"$root/$f\"`"
+ if [ "$DRYRUN" ] ; then
+ [ "$VERBOSE" ] && echo "$p"
+ else
+ if [ -d "$p" ] ; then
+ # try to remove dir, but ignore errors. It might
+ if rmdir "$p" 2>/dev/null ; then
+ [ "$VERBOSE" ] && echo "$p"
+ [ "$2" ] && echo "$f" >> "$2"
+ fi
+ else
+ my_rm "$p" && [ "$VERBOSE" ] && echo "$p"
+ [ "$2" ] && echo "$f" >> "$2"
+ fi
+ fi
+ done
+ return 0
+}
+
+# list all lines that occur in first list but not second
+# the files cannot contain duplicate lines.
+list_subtract() {
+ (
+ # first we find all uniq lines
+ cat "$1" "$2" | sort | uniq -u
+
+ # then we combine uniq lines with first file ...
+ cat "$1"
+
+ # ...and find all duplicates. Those only exist in first file
+ ) | sort | uniq -d
+}
+
+# insert an element first in APK_PATH if its not already there
+insert_apk_path() {
+ if [ "$1" != "`echo "$APK_PATH" | cut -d\; -f1`" ] ; then
+ [ "$APK_PATH" ] && APK_PATH=";$APK_PATH"
+ APK_PATH="$1$APK_PATH"
+ fi
+}
+
+lbu_filter() {
+ # Ok... I give up. shell is too slow. lets do it in awk.
+ awk 'BEGIN {
+ APK_LBUDIRS="'"$APK_LBUDIRS"'";
+ numdirs = split(APK_LBUDIRS, lbudir, ":");
+ #precalc lengths to save a few cpu cycles in loop
+ for (i = 1; i <= numdirs; i++)
+ len[i] = length(lbudir[i]);
+ }
+
+ # main loop
+ {
+ for (i = 1; i <= numdirs; i++) {
+ if (index($0, lbudir[i]) == 1 && (len[i] == length() || substr($0, len[i] + 1, 1) == "/")) {
+ print $0;
+ }
+ }
+ }'
+}
+
+is_lbu_file() {
+ # just run test
+ [ "$(echo "$1" | lbu_filter)" ]
+}
+
+# assign a value to a global var, either from environment or
+# from configuraion file
+# usage: get_var VARIBALE_NAME DEFAULT_VALUE
+get_var() {
+ local var
+ # first we check if the envvar is set
+ eval "var=\$$1"
+ if [ "$var" ] ; then
+ echo "$var"
+ elif [ -f ${APKTOOLS_CONF:="$ROOT/etc/apk.conf"} ] ; then
+ # then we check the conf file
+ var=`awk -F = '/^'$1'=/ { print $2 }' "$APKTOOLS_CONF"`
+ if [ "$var" ] ; then
+ echo "$var"
+ else
+ # else we use the default
+ echo "$2"
+ fi
+ else
+ # no conf file found use default
+ echo "$2"
+ fi
+}
+
+##########################################################
+# last_pkgf
+# find the latest package in a list, return 1 if not found
+last_pkgf() {
+ local pkgf last status
+ while read pkgf ; do
+ apk_version -q -t "$pkgf" "$last"
+ [ $? -eq 2 ] && last="$pkgf"
+ done
+ [ -z "$last" ] && return 1
+ echo "$last"
+}
+
+###########################################################
+# dump global variables
+dump_env() {
+ echo "ROOT=$ROOT"
+ echo "APKTOOLS_CONF=$APKTOOLS_CONF"
+ echo "APK_PATH=$APK_PATH"
+ echo "APK_DBDIR=$APK_DBDIR"
+ echo "APK_TMPDIR=$APK_TMPDIR"
+ echo "APK_FETCH=$APK_FETCH"
+ echo "APK_DATA=$APK_DATA"
+ echo "APK_DATALEVEL=$APK_DATALEVEL"
+ echo "APK_LIBS=$APK_LIBS"
+ echo "PACKAGES=$PACKAGES"
+
+ echo "APKDB=$APKDB"
+ echo "APK_NOCOMPRESS=$APK_NOCOMPRESS"
+ echo "REP_DIR=$REP_DIR"
+ echo "REP_SCHEME=$REP_SCHEME"
+ echo "CACHED_INDEX=$CACHED_INDEX"
+}
+
+#############################################################################
+# init_globals sets up the global variables
+
+APK_PREFIX_IN_PKG="`get_var APK_PREFIX_IN_PKG ''`"
+
+ROOT="`get_var ROOT /`"
+echo "$ROOT" | grep -v "^/" > /dev/null && ROOT="$PWD/$ROOT"
+
+APKTOOLS_CONF="`get_var APKTOOLS_CONF \"$(beautify_path /etc/apk/apk.conf)\"`"
+APK_PATH=`get_var APK_PATH ""`
+APK_DBDIR="`get_var APK_DBDIR \"$(beautify_path \"$ROOT/var/db/apk\")\"`"
+APK_DBDIR_IN_PKG="`get_var APK_DBDIR_IN_PKG ${APK_PREFIX_IN_PKG}var/db/apk`"
+APK_TMPDIR="`get_var \"APK_TMPDIR\" /tmp`"
+APK_ADD_TMP="`get_var \"APK_ADD_TMP\" \"$ROOT/usr/tmp\"`"
+APK_DATA="`get_var APK_DATA \"$(beautify_path \"$ROOT/var/lib/apk\")\"`"
+APK_KEEPCACHE="`get_var APK_KEEPCACHE no`"
+APK_LIBS="`get_var APK_LIBS /lib/apk`"
+PACKAGES="`get_var PACKAGES \"$(beautify_path \"$ROOT/var/cache/packages\")\"`"
+
+APKDB="`beautify_path \"$APK_DBDIR\"`"
+APK_NOCOMPRESS=`get_var APK_NOCOMPRESS ""`
+
+INDEX="INDEX.md5.gz"
+CACHED_INDEX="$APK_DATA/$INDEX"
+
+APK_SUM=`get_var APK_SUM md5`
+APK_MKSUM=`get_var APK_MKSUM "${APK_SUM}sum"`
+APK_CHKSUM=`get_var APK_CHKSUM "${APK_SUM}sum -c"`
+
+APK_DEFAULT_TDB=`get_var APK_DEFAULT_TDB "$APK_DATA/default.tdb"`
+SFIC=`which sfic 2>/dev/null`
+APK_GZSIGN_CERT=`get_var APK_GZSIGN_KEY /etc/apk/apk.crt`
+
+# confdirs are a : spearate list of dirs relative $ROOT that are to be
+# considered for local backups.
+# for example: APK_LBUDIRS="etc:usr/local/etc"
+APK_LBUDIRS=`get_var APK_LBUDIRS 'etc'`
+
diff --git a/src/apk.c b/src/apk.c
index 588112b..ddaf12b 100644
--- a/src/apk.c
+++ b/src/apk.c
@@ -10,6 +10,7 @@
*/
#include <stdio.h>
+#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -22,6 +23,7 @@
const char *apk_root = "/";
const char *apk_repository = NULL;
int apk_quiet = 0;
+int apk_cwd_fd;
void apk_log(const char *prefix, const char *format, ...)
{
@@ -78,6 +80,7 @@ int main(int argc, char **argv)
int r;
umask(0);
+ apk_cwd_fd = open(".", O_RDONLY);
prog = strrchr(argv[0], '/');
if (prog == NULL)
diff --git a/src/apk_defines.h b/src/apk_defines.h
index c9c64f5..d6557a2 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -44,9 +44,9 @@ typedef struct md5_ctx csum_ctx_t;
#define csum_finish(ctx, buf) md5_finish(ctx, buf)
#endif
-extern int apk_quiet;
+extern int apk_cwd_fd, apk_quiet;
-#define apk_error(args...) if (!apk_quiet) { apk_log("ERROR: ", args); }
+#define apk_error(args...) apk_log("ERROR: ", args);
#define apk_warning(args...) if (!apk_quiet) { apk_log("WARNING: ", args); }
#define apk_message(args...) if (!apk_quiet) { apk_log(NULL, args); }
@@ -101,12 +101,18 @@ static inline int hlist_hashed(const struct hlist_node *n)
static inline void __hlist_del(struct hlist_node *n, struct hlist_node **pprev)
{
*pprev = n->next;
+ n->next = NULL;
}
-static inline void hlist_del(struct hlist_node *n, struct hlist_node **pprev)
+static inline void hlist_del(struct hlist_node *n, struct hlist_head *h)
{
- __hlist_del(n, pprev);
- n->next = LIST_POISON1;
+ struct hlist_node **pp = &h->first;
+
+ while (*pp != NULL && *pp != LIST_END && *pp != n)
+ pp = &(*pp)->next;
+
+ if (*pp == n)
+ __hlist_del(n, pp);
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
@@ -123,6 +129,16 @@ static inline void hlist_add_after(struct hlist_node *n, struct hlist_node **pre
*prev = n;
}
+static inline struct hlist_node **hlist_tail_ptr(struct hlist_head *h)
+{
+ struct hlist_node *n = h->first;
+ if (n == NULL || n == LIST_END)
+ return &h->first;
+ while (n->next != NULL && n->next != LIST_END)
+ n = n->next;
+ return &n->next;
+}
+
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
diff --git a/src/apk_package.h b/src/apk_package.h
index cdcce49..c3649fd 100644
--- a/src/apk_package.h
+++ b/src/apk_package.h
@@ -75,7 +75,7 @@ void apk_pkg_free(struct apk_package *pkg);
int apk_pkg_get_state(struct apk_package *pkg);
int apk_pkg_add_script(struct apk_package *pkg, int fd,
unsigned int type, unsigned int size);
-int apk_pkg_run_script(struct apk_package *pkg, const char *root,
+int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
unsigned int type);
struct apk_package *apk_pkg_parse_index_entry(struct apk_database *db, apk_blob_t entry);
diff --git a/src/database.c b/src/database.c
index 174b6f6..8da8d6f 100644
--- a/src/database.c
+++ b/src/database.c
@@ -183,10 +183,11 @@ static void apk_db_file_set_owner(struct apk_database *db,
int create_dir,
struct hlist_node **after)
{
- if (file->owner != NULL)
- return;
-
- db->installed.stats.files++;
+ if (file->owner != NULL) {
+ hlist_del(&file->pkg_files_list, &file->owner->owned_files);
+ } else {
+ db->installed.stats.files++;
+ }
file->dir = apk_db_dir_ref(db, file->dir, create_dir);
file->owner = owner;
hlist_add_after(&file->pkg_files_list, after);
@@ -215,7 +216,7 @@ static struct apk_db_file *apk_db_file_get(struct apk_database *db,
dir = apk_db_dir_get(db, bdir);
if (ctx != NULL && dir != ctx->dircache) {
ctx->dircache = dir;
- ctx->file_dir_node = &dir->files.first;
+ ctx->file_dir_node = hlist_tail_ptr(&dir->files);
}
hlist_for_each_entry(file, cur, &dir->files, dir_files_list) {
@@ -274,7 +275,7 @@ static int apk_db_read_fdb(struct apk_database *db, int fd)
}
dir = NULL;
file_dir_node = NULL;
- file_pkg_node = &pkg->owned_files.first;
+ file_pkg_node = hlist_tail_ptr(&pkg->owned_files);
break;
case 'D':
if (pkg == NULL) {
@@ -282,7 +283,7 @@ static int apk_db_read_fdb(struct apk_database *db, int fd)
return -1;
}
dir = apk_db_dir_get(db, l);
- file_dir_node = &dir->files.first;
+ file_dir_node = hlist_tail_ptr(&dir->files);
break;
case 'F':
if (dir == NULL) {
@@ -388,29 +389,23 @@ static int apk_db_read_scriptdb(struct apk_database *db, int fd)
return 0;
}
-static const char *get_db_path(const char *root, const char *f)
-{
- static char fn[1024];
-
- snprintf(fn, sizeof(fn), "%s/%s", root, f);
-
- return fn;
-}
-
int apk_db_create(const char *root)
{
apk_blob_t deps = APK_BLOB_STR("busybox, alpine-baselayout, "
- "apk-tools, alpine-conf");
+ "apk-tools, alpine-conf\n");
int fd;
- mkdir(get_db_path(root, "tmp"), 01777);
- mkdir(get_db_path(root, "dev"), 0755);
- mknod(get_db_path(root, "dev/null"), 0666, makedev(1, 3));
- mkdir(get_db_path(root, "var"), 0755);
- mkdir(get_db_path(root, "var/lib"), 0755);
- mkdir(get_db_path(root, "var/lib/apk"), 0755);
+ fchdir(apk_cwd_fd);
+ chdir(root);
- fd = creat(get_db_path(root, "var/lib/apk/world"), 0600);
+ mkdir("tmp", 01777);
+ mkdir("dev", 0755);
+ mknod("dev/null", 0666, makedev(1, 3));
+ mkdir("var", 0755);
+ mkdir("var/lib", 0755);
+ mkdir("var/lib/apk", 0755);
+
+ fd = creat("var/lib/apk/world", 0600);
if (fd < 0)
return -1;
write(fd, deps.ptr, deps.len);
@@ -436,7 +431,9 @@ static int apk_db_read_config(struct apk_database *db)
* 5. files db
* 6. script db
*/
- fd = open(get_db_path(db->root, "var/lib/apk/world"), O_RDONLY);
+ fchdir(db->root_fd);
+
+ fd = open("var/lib/apk/world", O_RDONLY);
if (fd < 0)
return -1;
@@ -447,13 +444,13 @@ static int apk_db_read_config(struct apk_database *db)
APK_BLOB_PTR_LEN(buf, st.st_size));
close(fd);
- fd = open(get_db_path(db->root, "var/lib/apk/files"), O_RDONLY);
+ fd = open("var/lib/apk/files", O_RDONLY);
if (fd >= 0) {
apk_db_read_fdb(db, fd);
close(fd);
}
- fd = open(get_db_path(db->root, "var/lib/apk/scripts"), O_RDONLY);
+ fd = open("var/lib/apk/scripts", O_RDONLY);
if (fd >= 0) {
apk_db_read_scriptdb(db, fd);
close(fd);
@@ -496,20 +493,22 @@ static int apk_db_write_config(struct apk_database *db)
if (db->root == NULL)
return 0;
- fd = creat(get_db_path(db->root, "var/lib/apk/world"), 0600);
+ fchdir(db->root_fd);
+
+ fd = creat("var/lib/apk/world", 0600);
if (fd < 0)
return -1;
n = apk_deps_format(buf, sizeof(buf), db->world);
write(fd, buf, n);
close(fd);
- fd = creat(get_db_path(db->root, "var/lib/apk/files"), 0600);
+ fd = creat("var/lib/apk/files", 0600);
if (fd < 0)
return -1;
apk_db_write_fdb(db, fd);
close(fd);
- fd = creat(get_db_path(db->root, "var/lib/apk/scripts"), 0600);
+ fd = creat("var/lib/apk/scripts", 0600);
if (fd < 0)
return -1;
apk_db_write_scriptdb(db, fd);
@@ -690,7 +689,7 @@ static int apk_db_install_archive_entry(struct apk_archive_entry *ae,
type, ae->size);
if (type == ctx->script) {
- r = apk_pkg_run_script(pkg, db->root, type);
+ r = apk_pkg_run_script(pkg, db->root_fd, type);
if (r != 0)
apk_error("%s-%s: Failed to execute pre-install/upgrade script",
pkg->name->name, pkg->version);
@@ -700,7 +699,7 @@ static int apk_db_install_archive_entry(struct apk_archive_entry *ae,
}
if (ctx->file_pkg_node == NULL)
- ctx->file_pkg_node = &pkg->owned_files.first;
+ ctx->file_pkg_node = hlist_tail_ptr(&pkg->owned_files);
if (!S_ISDIR(ae->mode)) {
file = apk_db_file_get(db, name, ctx);
@@ -708,7 +707,8 @@ static int apk_db_install_archive_entry(struct apk_archive_entry *ae,
return -1;
if (file->owner != NULL &&
- file->owner->name != pkg->name) {
+ file->owner->name != pkg->name &&
+ strcmp(file->owner->name->name, "busybox") != 0) {
apk_error("%s: Trying to overwrite %s owned by %s.\n",
pkg->name->name, ae->name,
file->owner->name->name);
@@ -749,7 +749,7 @@ static void apk_db_purge_pkg(struct apk_database *db,
unlink(fn);
apk_db_dir_unref(db, file->dir);
- hlist_del(c, &pkg->owned_files.first);
+ __hlist_del(c, &pkg->owned_files.first);
db->installed.stats.files--;
}
@@ -772,14 +772,14 @@ int apk_db_install_pkg(struct apk_database *db,
/* Purge the old package if there */
if (oldpkg != NULL) {
if (newpkg == NULL) {
- r = apk_pkg_run_script(oldpkg, db->root,
+ r = apk_pkg_run_script(oldpkg, db->root_fd,
APK_SCRIPT_PRE_DEINSTALL);
if (r != 0)
return r;
}
apk_db_purge_pkg(db, oldpkg);
if (newpkg == NULL) {
- apk_pkg_run_script(oldpkg, db->root,
+ apk_pkg_run_script(oldpkg, db->root_fd,
APK_SCRIPT_POST_DEINSTALL);
return 0;
}
@@ -820,7 +820,7 @@ int apk_db_install_pkg(struct apk_database *db,
apk_warning("%s-%s: checksum does not match",
newpkg->name->name, newpkg->version);
- r = apk_pkg_run_script(newpkg, db->root,
+ r = apk_pkg_run_script(newpkg, db->root_fd,
(oldpkg == NULL) ?
APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE);
if (r != 0) {
diff --git a/src/package.c b/src/package.c
index 04ec2be..5cde906 100644
--- a/src/package.c
+++ b/src/package.c
@@ -320,15 +320,20 @@ int apk_pkg_add_script(struct apk_package *pkg, int fd,
return r;
}
-int apk_pkg_run_script(struct apk_package *pkg, const char *root,
+int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
unsigned int type)
{
+ static const char * const environment[] = {
+ "PATH=/usr/sbin:/usr/bin:/sbin:/bin",
+ NULL
+ };
struct apk_script *script;
struct hlist_node *c;
int fd, status;
pid_t pid;
char fn[1024];
+ fchdir(root_fd);
hlist_for_each_entry(script, c, &pkg->scripts, script_list) {
if (script->type != type)
continue;
@@ -349,14 +354,13 @@ int apk_pkg_run_script(struct apk_package *pkg, const char *root,
if (pid == -1)
return -1;
if (pid == 0) {
- chroot(root);
- fn[2] = '.';
- execl(&fn[2], script_types[script->type],
- pkg->version, "", NULL);
+ chroot(".");
+ execle(fn, script_types[script->type],
+ pkg->version, "", NULL, environment);
exit(1);
}
waitpid(pid, &status, 0);
- unlink(fn);
+ //unlink(fn);
if (WIFEXITED(status))
return WEXITSTATUS(status);
return -1;