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 +# 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 +#include #include #include #include @@ -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;