# HG changeset patch # User Michael Schloh von Bennewitz # Date 1343730222 -7200 # Node ID f880f219c5664209071392c99a90cf5358839079 # Parent 71503088f51b4f6ec1f6690f6965ed068da0ea8f Resynchronize with upstream package maintainer version. diff -r 71503088f51b -r f880f219c566 openpkg/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/Makefile Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,177 @@ +## +## Makefile -- OpenPKG Framework Developer Procedures +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +PATH = /usr/opkg/bin:/usr/opkg/sbin:/bin:/sbin:/usr/bin:/usr/sbin +PREFIX = /openpkg +USER = openpkg +GROUP = openpkg +TAG = openpkg + +SH = /bin/sh +RPM = $(PREFIX)/bin/openpkg rpm +SUDO = sudo +SCP = scp +RSYNC = rsync +RSYNC_REM = /v/openpkg/sw/bin/rsync +MTN = mtn + +UPLOAD1 = openpkg@experimental.openpkg.org:/v/openpkg/download/data/framework/release/source/ +UPLOAD2 = openpkg@experimental.openpkg.org:/v/openpkg/download/data/components/cache/openpkg/ + +all: + @echo "Individual Steps:" + @echo " $(MAKE) fetch-sh fetch third-party distribution files (standalone)" + @echo " $(MAKE) fetch-rpm fetch third-party distribution files (requires $(PREFIX))" + @echo " $(MAKE) build-src-sh build SOURCE SHELL package (standalone)" + @echo " $(MAKE) build-bin-sh build BINARY SHELL package (standalone)" + @echo " $(MAKE) build-src-rpm build SOURCE RPM package (requires $(PREFIX))" + @echo " $(MAKE) build-bin-rpm build BINARY RPM package (requires $(PREFIX))" + @echo " $(MAKE) install-bin-sh install BINARY SHELL package (requires $(PREFIX))" + @echo " $(MAKE) install-bin-rpm install BINARY RPM package (requires $(PREFIX))" + @echo " $(MAKE) uninstall uninstall entire instance under $(PREFIX)" + @echo " $(MAKE) upload-dst upload latest DISTRIBUTION files" + @echo " $(MAKE) upload-pkg upload latest SOURCE SHELL+RPM packages" + @echo " $(MAKE) upload-src upload latest SOURCE repository revisions" + @echo " $(MAKE) clean remove temporary files" + @echo "" + @echo "All-In-One Steps:" + @echo " $(MAKE) bootstrap BOOTSTRAP instance under $(PREFIX) from scratch" + @echo " $(MAKE) update UPDATE instance under $(PREFIX)" + @echo " $(MAKE) upload upload all results" + +## +## Individual Steps +## + +fetch-sh: + @echo "++ fetching third-party distribution files (manually)"; \ + eval `egrep '^%define *V_.*' openpkg.spec | \ + sed -e 's%^.*\(V_[a-z][a-zA-Z0-9_]*\) *\([^ ][^ ]*\).*$$%\1="\2";%'`; \ + for url in \ + `egrep '^Source[0-9][0-9]*: *(http|ftp)://' openpkg.spec | \ + sed -e 's;^Source[0-9][0-9]*: *;;' -e 's;%{\(V_[a-z][a-zA-Z0-9_]*\)};$${\1};g'`; do \ + eval "url=\"$$url\""; \ + file=`echo "$$url" | sed -e 's;^.*/\([^/]*\)$$;../dst/\1;'`; \ + if [ ! -f $$file ]; then \ + echo "-- downloading $$url"; \ + if [ ".`(which curl) 2>/dev/null | egrep '^/'`" != . ]; then \ + curl -s -L -o "$$file" "$$url" || true; \ + elif [ ".`(which wget) 2>/dev/null | egrep '^/'`" != . ]; then \ + wget -q -O "$$file" "$$url" || true; \ + elif [ ".`(which fetch) 2>/dev/null | egrep '^/'`" != . ]; then \ + fetch -o "$$file" "$$url" || true; \ + elif [ ".`(which lwp-download) 2>/dev/null | egrep '^/'`" != . ]; then \ + lwp-download "$$url" "$$file" || true; \ + else \ + echo "ERROR: sorry, no download tool found in \$$PATH (\"curl\", \"wget\", \"fetch\", \"lwp-download\")" 1>&2; \ + exit 1; \ + fi; \ + if [ ! -f "$$file" ]; then \ + echo "ERROR: failed to download \"$$url\"" 1>&2; \ + exit 1; \ + fi; \ + fi; \ + done + +fetch-rpm: + @echo "++ fetching third-party distribution files (via RPM)"; \ + PATH="$(PATH)" $(RPM) -bf *.spec + +build-src-sh: + @echo "++ building SOURCE SHELL package"; \ + PATH="$(PATH)" $(SH) openpkg.boot -s + +build-bin-sh: + @echo "++ building BINARY SHELL package"; \ + cd ../pkg && TMPDIR="`cd ../tmp && pwd`" && export TMPDIR && \ + PATH="$(PATH)" $(SH) openpkg-*-`date '+%Y%m%d'`.src.sh \ + --prefix=$(PREFIX) \ + --user=$(USER) \ + --group=$(GROUP) \ + --tag=$(TAG) + +build-src-rpm: + @echo "++ building SOURCE RPM package"; \ + PATH="$(PATH)" $(RPM) -bs openpkg.spec + +build-bin-rpm: + @echo "++ building BINARY RPM package"; \ + PATH="$(PATH)" $(RPM) -bb openpkg.spec + +install-bin-sh: + @echo "++ installing BINARY SHELL package"; \ + d=`cd ../pkg && pwd` && cd / && PATH="$(PATH)" $(SUDO) $(SH) $$d/openpkg-*-`date '+%Y%m%d'`.*-*-*.sh + +install-bin-rpm: + @echo "++ installing BINARY RPM package"; \ + d=`cd ../pkg && pwd` && cd / && PATH="$(PATH)" $(SUDO) $(RPM) -Uvh --replacepkgs $$d/openpkg-*-`date '+%Y%m%d'`.*-*-*.rpm + +uninstall: + -@echo "++ uninstalling ENTIRE instance"; \ + cd /; $(RPM) -qa | grep -v '^openpkg-[0-9]' | xargs $(SUDO) $(RPM) -e; \ + $(SUDO) $(RPM) -e openpkg + +upload-dst: + @echo "++ uploading vendor DISTRIBUTION files:"; \ + $(RSYNC) -raH --delete -v --progress --rsync-path=$(RSYNC_REM) ../dst/ $(UPLOAD2) + +upload-pkg: + @echo "++ uploading SOURCE SHELL/RPM package(s):"; \ + $(RSYNC) -raH --delete -v --progress --rsync-path=$(RSYNC_REM) ../pkg/*.src.* $(UPLOAD1) + +upload-src: + @echo "++ uploading SOURCE repository revision(s):"; \ + $(MTN) sync + +clean: + -rm -rf ../tmp/* + +pod2man: + pod2man --section=1 --center="OpenPKG" --release="OPENPKG(8)" --date="OpenPKG" --quotes=none openpkg.pod >openpkg.1 + pod2man --section=8 --center="OpenPKG" --release="RC(8)" --date="OpenPKG" --quotes=none rc.pod >rc.8 + pod2man --section=8 --center="OpenPKG" --release="RPMTOOL(8)" --date="OpenPKG" --quotes=none rpmtool.pod >rpmtool.8 + pod2man --section=8 --center="OpenPKG" --release="LSYNC(8)" --date="OpenPKG" --quotes=none lsync.pod >lsync.8 + pod2man --section=8 --center="OpenPKG" --release="RPM-CONFIG(8)" --date="OpenPKG" --quotes=none rpm-config.pod >rpm-config.8 + pod2man --section=8 --center="OpenPKG" --release="UUID(8)" --date="OpenPKG" --quotes=none uuid.pod >uuid.8 + pod2man --section=8 --center="OpenPKG" --release="RELEASE(8)" --date="OpenPKG" --quotes=none release.pod >release.8 + pod2man --section=8 --center="OpenPKG" --release="BUILD(8)" --date="OpenPKG" --quotes=none build.pod >build.8 + pod2man --section=8 --center="OpenPKG" --release="INDEX(8)" --date="OpenPKG" --quotes=none index.pod >index.8 + pod2man --section=8 --center="OpenPKG" --release="SEARCH(8)" --date="OpenPKG" --quotes=none search.pod >search.8 + pod2man --section=8 --center="OpenPKG" --release="MIRROR(8)" --date="OpenPKG" --quotes=none mirror.pod >mirror.8 + pod2man --section=8 --center="OpenPKG" --release="MAKEPROXY(8)" --date="OpenPKG" --quotes=none makeproxy.pod >makeproxy.8 + pod2man --section=8 --center="OpenPKG" --release="REGISTER(8)" --date="OpenPKG" --quotes=none register.pod >register.8 + pod2man --section=8 --center="OpenPKG" --release="LICENSE(8)" --date="OpenPKG" --quotes=none license.pod >license.8 + pod2man --section=8 --center="OpenPKG" --release="DEV(8)" --date="OpenPKG" --quotes=none dev.pod >dev.8 + pod2man --section=8 --center="OpenPKG" --release="SEA(8)" --date="OpenPKG" --quotes=none sea.pod >sea.8 + pod2man --section=8 --center="OpenPKG" --release="STACK(8)" --date="OpenPKG" --quotes=none stack.pod >stack.8 + +## +## All-In-One Steps +## + +bootstrap: build-src-sh build-bin-sh install-bin-sh + +update: build-bin-rpm install-bin-rpm + +upload: build-src-sh build-src-rpm upload-pkg upload-src + diff -r 71503088f51b -r f880f219c566 openpkg/README --- a/openpkg/README Tue Jul 31 12:12:54 2012 +0200 +++ b/openpkg/README Tue Jul 31 12:23:42 2012 +0200 @@ -1,52 +1,60 @@ - OpenPKG Boostrap Package Source Tree - ==================================== + OpenPKG Framework Bootstrap Package, Source Tree + ================================================ - This is the source code tree for the OpenPKG bootstrap package. What - you find here is rather complex and tricky stuff, so don't be confused - if you don't understand everything immediately. + This is the source tree for the OpenPKG Framework "bootstrap" package. + What you find here is rather complex and tricky stuff, so don't be + confused if you don't understand everything immediately. The Files --------- README .................. this file ;-) - HISTORY ................. change history tracking of this package openpkg.spec ............ the regular build procedure openpkg.boot ............ the bootstrapping procedure - gzip-*.tar .............. untouched distribution tarball of the GNU gzip tool - make-*.tar.gz ........... untouched distribution tarball of the GNU make tool patch-*.tar.gz .......... untouched distribution tarball of the GNU patch tool bash-*.tar.gz ........... untouched distribution tarball of the GNU bash tool + make-*.tar.gz ........... untouched distribution tarball of the GNU make tool tar-*.tar.gz ............ untouched distribution tarball of the GNU tar tool + config-*.tar.gz ......... untouched distribution tarball of the GNU config scripts + gzip-*.tar .............. pre-unpacked distribution tarball of the GNU gzip tool + gzip-*-openpkg-r*.tar ... pre-patched distribution files of the GNU gzip tool + perl-*-mini.tar.gz ...... stripped down distribution tarball of the Perl tool + rpm-*.tar.gz ............ untouched distribution tarball of the RPM tool + openssl-*.tar.gz ........ untouched distribution tarball of the OpenSSL toolkit uuid-*.tar.gz ........... untouched distribution tarball of the OSSP uuid tool curl-*.tar.gz ........... untouched distribution tarball of the cURL tool + beecrypt-*.tar.gz ....... untouched distribution tarball of the BeeCrypt library bzip2-*.tar.gz .......... untouched distribution tarball of the BZIP2 library zlib-*.tar.gz ........... untouched distribution tarball of the ZLIB library - beecrypt-*.tar.gz ....... untouched distribution tarball of the BeeCrypt library - rpm-*.tar.gz ............ untouched distribution tarball of the RPM tool - config-*.tar.gz ......... untouched distribution tarball of the GNU config scripts - openpkg-registry-*.tar.gz untouched distribution tarball of the OpenPKG Registry - openpkg-tools-*.tar.gz .. untouched distribution tarball of the OpenPKG Tool Chain - openssl-*.tar.gz ........ untouched distribution tarball of the OpenSSL toolkit - perl-*-mini.tar.gz ...... stripped down distribution tarball of the Perl tool + popt-*.tar.gz ........... untouched distribution tarball of the POPT library + sqlite-*.tar.gz ......... untouched distribution tarball of the SQLite library + pcre-*.tar.gz ........... untouched distribution tarball of the SQLite library + diffutils-*.tar.gz ...... untouched distribution tarball of the GNU diffutils toolkit + svs-*.tar.gz ............ untouched distribution tarball of the OSSP svs tool + xz-*.tar.gz ............. untouched distribution tarball of the XZ tool - make.patch .............. patch for GNU make - bash.patch .............. patch for GNU bash - tar.patch ............... patch for GNU tar - beecrypt.patch .......... patch for BeeCrypt - openssl.patch ........... patch for OpenSSL - perl.patch .............. patch for Perl - gzip.c .................. replacement file for GNU gzip - rpm.patch.bugfix ........ patch for RPM (bugfixing parts) - rpm.patch.feature ....... patch for RPM (new features parts) - rpm.patch.porting ....... patch for RPM (portability enhancement parts) - rpm.patch.regen ......... patch for RPM (re-generated files parts) + bash.patch .............. patch for GNU bash tool + bash.patch.vendor ....... patch for GNU bash tool (upstream vendor only) + bash.patch.vendor.sh .... patch for GNU bash tool (generation utility, NOT BUNDLED) + beecrypt.patch .......... patch for BeeCrypt library + make.patch .............. patch for GNU make tool + openssl.patch ........... patch for OpenSSL toolkit + perl.patch .............. patch for Perl tool + tar.patch ............... patch for GNU tar tool + rpm.patch ............... patch for RPM tool + popt.patch .............. patch for POPT library + sqlite.patch ............ patch for SQLite library + curl.patch .............. patch for cURL library + diffutils.patch ......... patch for GNU diffutils tool + libarchive.patch ........ patch for BSD libarchive tool + pcre.patch .............. patch for PCRE library + xz.patch ................ patch for XZ tool rpmpopt ................. replacements/extensions for RPM's POPT configuration rpmmacros ............... replacements/extensions for RPM's macros - rpmrc ................... replacements for RPM's run-command configuration root.README ............. the source for installed /README local.README ............ the source for installed /local/README @@ -55,6 +63,7 @@ dot.lsyncrc ............. the source for installed /local/.lsyncrc openpkg.c ............... the OpenPKG frontend (set-uid wrapper) + openpkg.mk .............. the OpenPKG frontend (build procedure) openpkg.sh .............. the OpenPKG frontend (main script) openpkg.pod ............. the OpenPKG frontend manual page (source) openpkg.1 ............... the OpenPKG frontend manual page (pre-generated output) @@ -89,31 +98,74 @@ lsync.8 ................. the lsync tool (manual page) lsync.pod ............... the lsync tool (manual page source) - aux.usrgrp.sh ........... user/group name/id determination script - aux.prereq.sh ........... prerequisite checking script - aux.wrapsrc.sh .......... wrapper script for generating openpkg-V-R.src.sh - aux.wrapbin.sh .......... wrapper script for generating openpkg-V-R.P-L.sh + etc.usrgrp.sh ........... user/group name/id determination script + etc.prereq.sh ........... prerequisite checking script + etc.wrapsrc.sh .......... wrapper script for generating openpkg-V-R.src.sh + etc.wrapbin.sh .......... wrapper script for generating openpkg-V-R.P-L.sh - pod2man.sh .............. helper script for pre-generating manual page outputs man.sh .................. helper script for "openpkg man" command - install.sh .............. helper script for "openpkg install" command + + rpm.sh .................. wrapper for RPM + curl.sh ................. wrapper for cURL + + dev.pl .................. the OpenPKG package development utility script + dev.pod ................. the OpenPKG package development utility manual page (source) + dev.8 ................... the OpenPKG package development utility manual page (pre-generated output) + + index.pl ................ the OpenPKG package indexing utility script + index.pod ............... the OpenPKG package indexing utility manual page (source) + index.8 ................. the OpenPKG package indexing utility manual page (pre-generated output) + + search.pl ............... the OpenPKG package searching utility script + search.pod .............. the OpenPKG package searching utility manual page (source) + search.8 ................ the OpenPKG package searching utility manual page (pre-generated output) + + sea.sh .................. the OpenPKG shell execution archive utility script + sea.pod ................. the OpenPKG shell execution archive utility manual page (source) + sea.8 ................... the OpenPKG shell execution archive utility manual page (pre-generated output) + + mirror.pl ............... the OpenPKG package mirroing utility script + mirror.pod .............. the OpenPKG package mirroing utility manual page (source) + mirror.8 ................ the OpenPKG package mirroing utility manual page (pre-generated output) + + build.pl ................ the OpenPKG package building utility script + build.pod ............... the OpenPKG package building utility manual page (source) + build.8 ................. the OpenPKG package building utility manual page (pre-generated output) + + makeproxy.pl ............ the OpenPKG proxy package building utility script + makeproxy.pod ........... the OpenPKG proxy package building utility manual page (source) + makeproxy.8 ............. the OpenPKG proxy package building utility manual page (pre-generated output) openpkg.org.pgp ......... the OpenPGP public key "OpenPKG " openpkg.com.pgp ......... the OpenPGP public key "OpenPKG GmbH " openpkg.net.pgp ......... the OpenPGP public key "OpenPKG Foundation e.V. " + license.sh .............. the OpenPKG license management utility script + license.pod ............. the OpenPKG license management utility manual page (source) + license.8 ............... the OpenPKG license management utility manual page (pre-generated output) + license-BOOT.txt ........ the OpenPKG Framework Bootstrapping License + license-COMMUNITY.txt ... the OpenPKG Framework Community License + license-EVAL.txt ........ the OpenPKG Framework Evaluation License + license-EXAMPLE.txt ..... the OpenPKG Framework Example License + license-PROMO.txt ....... the OpenPKG Framework Promotion License + license-RECOVERY.txt .... the OpenPKG Framework Recovery License + license.lua ............. the OpenPKG Framework license processor script + + Makefile ................ development build procedures + The Bootstrapping Procedure --------------------------- The complexity of this OpenPKG RPM package results from the fact that we force us to treat this bootstrapping package equal to every other regular OpenPKG RPM package. First, this implies that the packaging - tool RPM is packaged with itself as an OpenPKG RPM package (means: its - build procedure is a real RPM .spec file and it can be installed and - upgraded through a binary or source RPM). Second, RPM is installed - into the same filesystem hierarchy as all other packages. Third, RPM - manages its own files. The reason for this approach should be obvious: - 100% consistency for the whole OpenPKG software packaging facility! + tool RPM is packaged with itself as an OpenPKG RPM package -- which + means that its build procedure is a real RPM .spec file and it can be + installed and upgraded through a binary or source RPM. Second, RPM is + installed into the same filesystem hierarchy as all other packages. + Third, RPM manages its own files. The reason for this approach should + be obvious: 100% consistency for the whole OpenPKG software packaging + facility! The drawback is that this package requires a very tricky bootstrapping procedure which had cost a lot of time to figure out and establish. If @@ -137,17 +189,17 @@ scripts of "openpkg.spec", there is a fresh version of the target filesystem hierarchy staying under a temporary "build root". The "openpkg.boot" script then creates a very special temporary "openpkg - rpm" command which allows the installed "openpkg rpm" command inside - the "build root" to work (although it is built for the final target - filesystem path). Then the $RPM_BOOT variable is set and the package - is _again_ build via "openpkg.spec" -- but this time with the real - OpenPKG RPM. To avoid unneccessary re-compilation, the "openpkg.spec" - skips "%prep", "%build" and "%install" sections if $RPM_BOOT is - defined. So, on this second build phase, only the "%files" section is - executed, i.e., a binary OpenPKG RPM package "openpkg-V-R.P-T.rpm" - is rolled from the files in the "build root". Additionally, a source - OpenPKG RPM package "openpkg-V-R.src.rpm" is rolled for consistency - reasons. + rpm" command which allows the installed "openpkg rpm" command + inside the "build root" to work (although it is built for the + final target filesystem path). Then the $OPENPKG_BOOT variable + is set and the package is _again_ build via "openpkg.spec" -- + but this time with the real OpenPKG RPM. To avoid unneccessary + re-compilation, the "openpkg.spec" skips "%prep", "%build" and + "%install" sections if $OPENPKG_BOOT is defined. So, on this second + build phase, only the "%files" section is effectively executed, i.e., + a binary OpenPKG RPM package "openpkg-V-R.P-T.rpm" is rolled from the + files in the "build root". Additionally, a source OpenPKG RPM package + "openpkg-V-R.src.rpm" is rolled for consistency reasons, too. Finally, we override the installation in the "build root" again by installing the now rolled binary OpenPKG RPM package @@ -169,14 +221,14 @@ is packed into a "tarball", compressed, again wrapped into another tarball together with the uncompression tools ("bzip2" and "tar"), and finally wrapped into a self-extracting shell script by appending - "aux.wrapbin.sh" (padded to 64KB for easier unpacking of the attached + "etc.wrapbin.sh" (padded to 64KB for easier unpacking of the attached tarball) to its front. The result is the binary bootstrap script "openpkg-V-R.P-T.sh" which - can be used to install the target hierarchy from scratch without any - pre-installed OpenPKG RPM. Nevetheless, the installed target hierarchy - looks _exactly_ as it would have been installed with OpenPKG RPM. - If one later wants to upgrade this hierarchy one can just use the + can be used to install the target hierarchy from scratch without + any pre-installed OpenPKG RPM. Nevertheless, the installed target + hierarchy looks _exactly_ as it would have been installed with OpenPKG + RPM. If one later wants to upgrade this hierarchy one can just use the generated (or a newer) "openpkg-V-R.P-T.rpm". To allow one to easily repeat this from-source bootstrapping procedure diff -r 71503088f51b -r f880f219c566 openpkg/bash.patch --- a/openpkg/bash.patch Tue Jul 31 12:12:54 2012 +0200 +++ b/openpkg/bash.patch Tue Jul 31 12:23:42 2012 +0200 @@ -2,9 +2,9 @@ line options "-v" and "-x". It is derived from Debian GNU/Linux. Index: doc/bash.1 ---- doc/bash.1.orig 2004-07-12 17:27:08 +0200 -+++ doc/bash.1 2004-07-27 19:47:10 +0200 -@@ -116,6 +116,12 @@ +--- doc/bash.1.orig 2011-01-16 21:31:39.000000000 +0100 ++++ doc/bash.1 2011-02-21 18:56:01.000000000 +0100 +@@ -117,6 +117,12 @@ This option allows the positional parameters to be set when invoking an interactive shell. .TP @@ -23,9 +23,9 @@ Port to HP-UX 11i and similar less smart platforms. Index: configure ---- configure.orig 2004-07-21 22:18:56 +0200 -+++ configure 2004-07-27 19:47:10 +0200 -@@ -1517,6 +1517,7 @@ +--- configure.orig 2011-02-07 23:03:22.000000000 +0100 ++++ configure 2011-02-21 18:56:01.000000000 +0100 +@@ -2202,6 +2202,7 @@ *-beos*) opt_bash_malloc=no ;; # they say it's suitable *-cygwin*) opt_bash_malloc=no ;; # Cygnus's CYGWIN environment *-opennt*|*-interix*) opt_bash_malloc=no ;; # Interix, now owned by Microsoft @@ -33,7 +33,7 @@ esac # memory scrambling on free() -@@ -1662,7 +1663,7 @@ +@@ -2270,7 +2271,7 @@ else MALLOC_LIB= @@ -43,8 +43,8 @@ MALLOC_DEP= fi Index: syntax.h ---- syntax.h.orig 2004-04-15 05:19:36 +0200 -+++ syntax.h 2004-07-27 19:47:10 +0200 +--- syntax.h.orig 2009-01-04 20:32:42.000000000 +0100 ++++ syntax.h 2011-02-21 18:56:01.000000000 +0100 @@ -21,6 +21,8 @@ #ifndef _SYNTAX_H_ #define _SYNTAX_H_ @@ -60,303 +60,70 @@ This adds the OpenPKG packaging brand. Index: version.c ---- version.c.orig 2003-12-19 22:34:02 +0100 -+++ version.c 2004-07-27 19:47:10 +0200 -@@ -77,7 +77,7 @@ +--- version.c.orig 2011-01-28 17:32:36.000000000 +0100 ++++ version.c 2011-02-21 18:56:01.000000000 +0100 +@@ -83,7 +83,7 @@ show_shell_version (extended) int extended; { -- printf ("GNU bash, version %s (%s)\n", shell_version_string (), MACHTYPE); -+ printf ("GNU bash, version %s (%s) [@l_openpkg_release@]\n", shell_version_string (), MACHTYPE); +- printf (_("GNU bash, version %s (%s)\n"), shell_version_string (), MACHTYPE); ++ printf (_("GNU bash, version %s (%s) [@l_openpkg_release@]\n"), shell_version_string (), MACHTYPE); if (extended) - printf (_("Copyright (C) 2005 Free Software Foundation, Inc.\n")); - } + { + printf ("%s\n", _(bash_copyright)); ----------------------------------------------------------------------------- -Accumulated vendor patches Bash 3.2 001-005 +Ensure that Autoconf and friends are not run. -Generated via: - -$ gunzip /tmp/bash.patch -$ popd -$ rm -rf bash-3.2 - -Index: parse.y ---- parse.y.orig 2006-09-19 22:37:21 +0200 -+++ parse.y 2006-12-06 13:32:45 +0100 -@@ -1029,6 +1029,7 @@ - #define PST_CMDTOKEN 0x1000 /* command token OK - unused */ - #define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */ - #define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ -+#define PST_REGEXP 0x8000 /* parsing an ERE/BRE as a single word */ +Index: Makefile.in +--- Makefile.in.orig 2010-12-01 01:22:42.000000000 +0100 ++++ Makefile.in 2011-02-21 18:56:01.000000000 +0100 +@@ -711,7 +711,6 @@ - /* Initial size to allocate for tokens, and the - amount to grow them by. */ -@@ -2591,6 +2592,9 @@ - return (character); - } + # comment out for distribution + $(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4 $(srcdir)/config.h.in +- cd $(srcdir) && autoconf -+ if (parser_state & PST_REGEXP) -+ goto tokword; -+ - /* Shell meta-characters. */ - if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) - { -@@ -2698,6 +2702,7 @@ - if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) - return (character); - -+tokword: - /* Okay, if we got this far, we have to read a word. Read one, - and then check it against the known ones. */ - result = read_token_word (character); -@@ -2735,7 +2740,7 @@ - /* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - pass_next_character = backq_backslash = was_dollar = in_comment = 0; -- check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0; -+ check_comment = (flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); -@@ -3202,8 +3207,11 @@ - if (tok == WORD && test_binop (yylval.word->word)) - op = yylval.word; - #if defined (COND_REGEXP) -- else if (tok == WORD && STREQ (yylval.word->word,"=~")) -- op = yylval.word; -+ else if (tok == WORD && STREQ (yylval.word->word, "=~")) -+ { -+ op = yylval.word; -+ parser_state |= PST_REGEXP; -+ } - #endif - else if (tok == '<' || tok == '>') - op = make_word_from_token (tok); /* ( */ -@@ -3234,6 +3242,7 @@ - - /* rhs */ - tok = read_token (READ); -+ parser_state &= ~PST_REGEXP; - if (tok == WORD) - { - tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); -@@ -3419,9 +3428,34 @@ - goto next_character; - } - -+#ifdef COND_REGEXP -+ /* When parsing a regexp as a single word inside a conditional command, -+ we need to special-case characters special to both the shell and -+ regular expressions. Right now, that is only '(' and '|'. */ /*)*/ -+ if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ -+ { -+ if (character == '|') -+ goto got_character; -+ -+ push_delimiter (dstack, character); -+ ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); -+ pop_delimiter (dstack); -+ if (ttok == &matched_pair_error) -+ return -1; /* Bail immediately. */ -+ RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, -+ token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); -+ token[token_index++] = character; -+ strcpy (token + token_index, ttok); -+ token_index += ttoklen; -+ FREE (ttok); -+ dollar_present = all_digit_token = 0; -+ goto next_character; -+ } -+#endif /* COND_REGEXP */ -+ - #ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ -- if (extended_glob && PATTERN_CHAR (character)) -+ if MBTEST(extended_glob && PATTERN_CHAR (character)) - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '(') /* ) */ -Index: patchlevel.h ---- patchlevel.h.orig 2006-04-13 14:31:04 +0200 -+++ patchlevel.h 2006-12-06 13:32:45 +0100 -@@ -25,6 +25,6 @@ - regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh - looks for to find the patch level (for the sccs version string). */ - --#define PATCHLEVEL 0 -+#define PATCHLEVEL 5 - - #endif /* _PATCHLEVEL_H_ */ -Index: subst.c ---- subst.c.orig 2006-09-19 14:35:09 +0200 -+++ subst.c 2006-12-06 13:32:45 +0100 -@@ -5707,6 +5707,11 @@ - vtype &= ~VT_STARSUB; - - mflags = 0; -+ if (patsub && *patsub == '/') -+ { -+ mflags |= MATCH_GLOBREP; -+ patsub++; -+ } - - /* Malloc this because expand_string_if_necessary or one of the expansion - functions in its call chain may free it on a substitution error. */ -@@ -5741,13 +5746,12 @@ - } - - /* ksh93 doesn't allow the match specifier to be a part of the expanded -- pattern. This is an extension. */ -+ pattern. This is an extension. Make sure we don't anchor the pattern -+ at the beginning or end of the string if we're doing global replacement, -+ though. */ - p = pat; -- if (pat && pat[0] == '/') -- { -- mflags |= MATCH_GLOBREP|MATCH_ANY; -- p++; -- } -+ if (mflags & MATCH_GLOBREP) -+ mflags |= MATCH_ANY; - else if (pat && pat[0] == '#') - { - mflags |= MATCH_BEG; -Index: y.tab.c ---- y.tab.c.orig 2006-09-25 14:15:16 +0200 -+++ y.tab.c 2006-12-06 13:39:36 +0100 -@@ -2359,6 +2359,7 @@ - #define PST_CMDTOKEN 0x1000 /* command token OK - unused */ - #define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */ - #define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ -+#define PST_REGEXP 0x8000 /* parsing an ERE/BRE as a single word */ - - /* Initial size to allocate for tokens, and the - amount to grow them by. */ -@@ -3921,6 +3922,9 @@ - return (character); - } - -+ if (parser_state & PST_REGEXP) -+ goto tokword; -+ - /* Shell meta-characters. */ - if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) - { -@@ -4028,6 +4032,7 @@ - if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) - return (character); - -+tokword: - /* Okay, if we got this far, we have to read a word. Read one, - and then check it against the known ones. */ - result = read_token_word (character); -@@ -4065,7 +4070,7 @@ - /* itrace("parse_matched_pair: open = %c close = %c", open, close); */ - count = 1; - pass_next_character = backq_backslash = was_dollar = in_comment = 0; -- check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0; -+ check_comment = (flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0; - - /* RFLAGS is the set of flags we want to pass to recursive calls. */ - rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); -@@ -4532,8 +4537,11 @@ - if (tok == WORD && test_binop (yylval.word->word)) - op = yylval.word; - #if defined (COND_REGEXP) -- else if (tok == WORD && STREQ (yylval.word->word,"=~")) -- op = yylval.word; -+ else if (tok == WORD && STREQ (yylval.word->word, "=~")) -+ { -+ op = yylval.word; -+ parser_state |= PST_REGEXP; -+ } - #endif - else if (tok == '<' || tok == '>') - op = make_word_from_token (tok); /* ( */ -@@ -4564,6 +4572,7 @@ - - /* rhs */ - tok = read_token (READ); -+ parser_state &= ~PST_REGEXP; - if (tok == WORD) - { - tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); -@@ -4749,9 +4758,34 @@ - goto next_character; - } - -+#ifdef COND_REGEXP -+ /* When parsing a regexp as a single word inside a conditional command, -+ we need to special-case characters special to both the shell and -+ regular expressions. Right now, that is only '(' and '|'. */ /*)*/ -+ if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/ -+ { -+ if (character == '|') -+ goto got_character; -+ -+ push_delimiter (dstack, character); -+ ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0); -+ pop_delimiter (dstack); -+ if (ttok == &matched_pair_error) -+ return -1; /* Bail immediately. */ -+ RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2, -+ token_buffer_size, TOKEN_DEFAULT_GROW_SIZE); -+ token[token_index++] = character; -+ strcpy (token + token_index, ttok); -+ token_index += ttoklen; -+ FREE (ttok); -+ dollar_present = all_digit_token = 0; -+ goto next_character; -+ } -+#endif /* COND_REGEXP */ -+ - #ifdef EXTENDED_GLOB - /* Parse a ksh-style extended pattern matching specification. */ -- if (extended_glob && PATTERN_CHAR (character)) -+ if MBTEST(extended_glob && PATTERN_CHAR (character)) - { - peek_char = shell_getc (1); - if MBTEST(peek_char == '(') /* ) */ + # for chet + reconfig: force ----------------------------------------------------------------------------- -Do not require autoconf. Fixes build on Solaris 10 8/07 u4 on sparc64 +Fix Bash getcwd(3) run-time issue seen on Solaris where size argument +of 0 does not malloc buffer as expected by Bash code. -Index: Makefile.in ---- Makefile.in.orig 2006-08-17 20:03:35 +0200 -+++ Makefile.in 2007-10-15 13:00:34 +0200 -@@ -682,13 +682,9 @@ - stamp-h: config.status $(srcdir)/config.h.in $(srcdir)/config-top.h $(srcdir)/config-bot.h - CONFIG_FILES= CONFIG_HEADERS=config.h $(SHELL) ./config.status +Index: builtins/common.c +--- builtins/common.c.orig 2011-01-05 23:51:26.000000000 +0100 ++++ builtins/common.c 2011-02-21 18:56:01.000000000 +0100 +@@ -553,10 +553,11 @@ --config.status: $(srcdir)/configure -+config.status: - $(SHELL) ./config.status --recheck + if (the_current_working_directory == 0) + { ++ char *t = xmalloc(PATH_MAX); + #if defined (GETCWD_BROKEN) +- the_current_working_directory = getcwd (0, PATH_MAX); ++ the_current_working_directory = getcwd (t, PATH_MAX); + #else +- the_current_working_directory = getcwd (0, 0); ++ the_current_working_directory = getcwd (t, PATH_MAX); + #endif + if (the_current_working_directory == 0) + { + +----------------------------------------------------------------------------- + +Fix building under Linux. + +Index: externs.h +--- externs.h.orig 2010-11-30 02:59:20.000000000 +0100 ++++ externs.h 2011-02-21 18:56:01.000000000 +0100 +@@ -25,6 +25,7 @@ + # define _EXTERNS_H_ --# comment out for distribution --$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4 $(srcdir)/config.h.in -- cd $(srcdir) && autoconf -- - # for chet - reconfig: force - sh $(srcdir)/configure -C + #include "stdc.h" ++#include + + /* Functions from expr.c. */ + extern intmax_t evalexp __P((char *, int *)); + diff -r 71503088f51b -r f880f219c566 openpkg/bash.patch.vendor --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/bash.patch.vendor Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,1507 @@ +Index: assoc.c +--- assoc.c.orig 2009-08-06 02:19:40.000000000 +0200 ++++ assoc.c 2012-06-27 10:31:02.000000000 +0200 +@@ -77,6 +77,11 @@ + b = hash_search (key, hash, HASH_CREATE); + if (b == 0) + return -1; ++ /* If we are overwriting an existing element's value, we're not going to ++ use the key. Nothing in the array assignment code path frees the key ++ string, so we can free it here to avoid a memory leak. */ ++ if (b->key != key) ++ free (key); + FREE (b->data); + b->data = value ? savestring (value) : (char *)0; + return (0); +Index: bashline.c +--- bashline.c.orig 2011-01-16 21:32:47.000000000 +0100 ++++ bashline.c 2012-06-27 10:31:03.000000000 +0200 +@@ -121,6 +121,9 @@ + static int filename_completion_ignore __P((char **)); + static int bash_push_line __P((void)); + ++static rl_icppfunc_t *save_directory_hook __P((void)); ++static void reset_directory_hook __P((rl_icppfunc_t *)); ++ + static void cleanup_expansion_error __P((void)); + static void maybe_make_readline_line __P((char *)); + static void set_up_new_line __P((char *)); +@@ -243,10 +246,17 @@ + /* Perform spelling correction on directory names during word completion */ + int dircomplete_spelling = 0; + ++/* Expand directory names during word/filename completion. */ ++int dircomplete_expand = 0; ++int dircomplete_expand_relpath = 0; ++ + static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; + static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; + /* )) */ + ++static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ ++static char *custom_filename_quote_characters = 0; ++ + static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; + + static int dot_in_path = 0; +@@ -501,7 +511,7 @@ + + /* Tell the completer that we might want to follow symbolic links or + do other expansion on directory names. */ +- rl_directory_rewrite_hook = bash_directory_completion_hook; ++ set_directory_hook (); + + rl_filename_rewrite_hook = bash_filename_rewrite_hook; + +@@ -529,7 +539,7 @@ + enable_hostname_completion (perform_hostname_completion); + + /* characters that need to be quoted when appearing in filenames. */ +- rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ ++ rl_filename_quote_characters = default_filename_quote_characters; + + rl_filename_quoting_function = bash_quote_filename; + rl_filename_dequoting_function = bash_dequote_filename; +@@ -564,8 +574,10 @@ + tilde_initialize (); + rl_attempted_completion_function = attempt_shell_completion; + rl_completion_entry_function = NULL; +- rl_directory_rewrite_hook = bash_directory_completion_hook; + rl_ignore_some_completions_function = filename_completion_ignore; ++ rl_filename_quote_characters = default_filename_quote_characters; ++ ++ set_directory_hook (); + } + + /* Contains the line to push into readline. */ +@@ -1279,6 +1291,9 @@ + matches = (char **)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + ++ rl_filename_quote_characters = default_filename_quote_characters; ++ set_directory_hook (); ++ + /* Determine if this could be a command word. It is if it appears at + the start of the line (ignoring preceding whitespace), or if it + appears after a character that separates commands. It cannot be a +@@ -1591,6 +1606,12 @@ + } + else + { ++ if (dircomplete_expand && dot_or_dotdot (filename_hint)) ++ { ++ dircomplete_expand = 0; ++ set_directory_hook (); ++ dircomplete_expand = 1; ++ } + mapping_over = 4; + goto inner; + } +@@ -1791,6 +1812,9 @@ + + inner: + val = rl_filename_completion_function (filename_hint, istate); ++ if (mapping_over == 4 && dircomplete_expand) ++ set_directory_hook (); ++ + istate = 1; + + if (val == 0) +@@ -2693,6 +2717,52 @@ + return conv; + } + ++/* Functions to save and restore the appropriate directory hook */ ++/* This is not static so the shopt code can call it */ ++void ++set_directory_hook () ++{ ++ if (dircomplete_expand) ++ { ++ rl_directory_completion_hook = bash_directory_completion_hook; ++ rl_directory_rewrite_hook = (rl_icppfunc_t *)0; ++ } ++ else ++ { ++ rl_directory_rewrite_hook = bash_directory_completion_hook; ++ rl_directory_completion_hook = (rl_icppfunc_t *)0; ++ } ++} ++ ++static rl_icppfunc_t * ++save_directory_hook () ++{ ++ rl_icppfunc_t *ret; ++ ++ if (dircomplete_expand) ++ { ++ ret = rl_directory_completion_hook; ++ rl_directory_completion_hook = (rl_icppfunc_t *)NULL; ++ } ++ else ++ { ++ ret = rl_directory_rewrite_hook; ++ rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; ++ } ++ ++ return ret; ++} ++ ++static void ++restore_directory_hook (hookf) ++ rl_icppfunc_t *hookf; ++{ ++ if (dircomplete_expand) ++ rl_directory_completion_hook = hookf; ++ else ++ rl_directory_rewrite_hook = hookf; ++} ++ + /* Handle symbolic link references and other directory name + expansions while hacking completion. This should return 1 if it modifies + the DIRNAME argument, 0 otherwise. It should make sure not to modify +@@ -2702,20 +2772,31 @@ + char **dirname; + { + char *local_dirname, *new_dirname, *t; +- int return_value, should_expand_dirname; ++ int return_value, should_expand_dirname, nextch, closer; + WORD_LIST *wl; + struct stat sb; + +- return_value = should_expand_dirname = 0; ++ return_value = should_expand_dirname = nextch = closer = 0; + local_dirname = *dirname; + +- if (mbschr (local_dirname, '$')) +- should_expand_dirname = 1; ++ if (t = mbschr (local_dirname, '$')) ++ { ++ should_expand_dirname = '$'; ++ nextch = t[1]; ++ /* Deliberately does not handle the deprecated $[...] arithmetic ++ expansion syntax */ ++ if (nextch == '(') ++ closer = ')'; ++ else if (nextch == '{') ++ closer = '}'; ++ else ++ nextch = 0; ++ } + else + { + t = mbschr (local_dirname, '`'); + if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) +- should_expand_dirname = 1; ++ should_expand_dirname = '`'; + } + + #if defined (HAVE_LSTAT) +@@ -2739,6 +2820,23 @@ + free (new_dirname); + dispose_words (wl); + local_dirname = *dirname; ++ /* XXX - change rl_filename_quote_characters here based on ++ should_expand_dirname/nextch/closer. This is the only place ++ custom_filename_quote_characters is modified. */ ++ if (rl_filename_quote_characters && *rl_filename_quote_characters) ++ { ++ int i, j, c; ++ i = strlen (default_filename_quote_characters); ++ custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1); ++ for (i = j = 0; c = default_filename_quote_characters[i]; i++) ++ { ++ if (c == should_expand_dirname || c == nextch || c == closer) ++ continue; ++ custom_filename_quote_characters[j++] = c; ++ } ++ custom_filename_quote_characters[j] = '\0'; ++ rl_filename_quote_characters = custom_filename_quote_characters; ++ } + } + else + { +@@ -2758,11 +2856,31 @@ + local_dirname = *dirname = new_dirname; + } + ++ /* no_symbolic_links == 0 -> use (default) logical view of the file system. ++ local_dirname[0] == '.' && local_dirname[1] == '/' means files in the ++ current directory (./). ++ local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames ++ in the current directory (e.g., lib/sh). ++ XXX - should we do spelling correction on these? */ ++ ++ /* This is test as it was in bash-4.2: skip relative pathnames in current ++ directory. Change test to ++ (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/')) ++ if we want to skip paths beginning with ./ also. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + int len1, len2; + ++ /* If we have a relative path ++ (local_dirname[0] != '/' && local_dirname[0] != '.') ++ that is canonical after appending it to the current directory, then ++ temp1 = temp2+'/' ++ That is, ++ strcmp (temp1, temp2) == 0 ++ after adding a slash to temp2 below. It should be safe to not ++ change those. ++ */ + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); +@@ -2797,7 +2915,15 @@ + temp2[len2 + 1] = '\0'; + } + } +- return_value |= STREQ (local_dirname, temp2) == 0; ++ ++ /* dircomplete_expand_relpath == 0 means we want to leave relative ++ pathnames that are unchanged by canonicalization alone. ++ *local_dirname != '/' && *local_dirname != '.' == relative pathname ++ (consistent with general.c:absolute_pathname()) ++ temp1 == temp2 (after appending a slash to temp2) means the pathname ++ is not changed by canonicalization as described above. */ ++ if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0)) ++ return_value |= STREQ (local_dirname, temp2) == 0; + free (local_dirname); + *dirname = temp2; + free (temp1); +@@ -3002,12 +3128,13 @@ + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; +- orig_dir_func = rl_directory_rewrite_hook; + orig_ignore_func = rl_ignore_some_completions_function; + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; ++ ++ orig_dir_func = save_directory_hook (); ++ + rl_completion_entry_function = rl_filename_completion_function; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; +- rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_completer_word_break_characters = " \t\n\"\'"; + +@@ -3015,10 +3142,11 @@ + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; +- rl_directory_rewrite_hook = orig_dir_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; + ++ restore_directory_hook (orig_dir_func); ++ + return r; + } + +Index: bashline.h +--- bashline.h.orig 2009-01-04 20:32:22.000000000 +0100 ++++ bashline.h 2012-06-27 10:31:03.000000000 +0200 +@@ -33,10 +33,15 @@ + extern void bashline_reinitialize __P((void)); + extern int bash_re_edit __P((char *)); + ++extern void bashline_set_event_hook __P((void)); ++extern void bashline_reset_event_hook __P((void)); ++ + extern int bind_keyseq_to_unix_command __P((char *)); + + extern char **bash_default_completion __P((const char *, int, int, int, int)); + ++void set_directory_hook __P((void)); ++ + /* Used by programmable completion code. */ + extern char *command_word_completion_function __P((const char *, int)); + extern char *bash_groupname_completion_function __P((const char *, int)); +Index: builtins/declare.def +--- builtins/declare.def.orig 2010-05-31 00:25:21.000000000 +0200 ++++ builtins/declare.def 2012-06-27 10:31:02.000000000 +0200 +@@ -513,6 +513,11 @@ + *subscript_start = '['; /* ] */ + var = assign_array_element (name, value, 0); /* XXX - not aflags */ + *subscript_start = '\0'; ++ if (var == 0) /* some kind of assignment error */ ++ { ++ assign_error++; ++ NEXT_VARIABLE (); ++ } + } + else if (simple_array_assign) + { +Index: builtins/fc.def +--- builtins/fc.def.orig 2010-05-31 00:25:38.000000000 +0200 ++++ builtins/fc.def 2012-06-27 10:31:02.000000000 +0200 +@@ -304,7 +304,7 @@ + last_hist = i - rh - hist_last_line_added; + + /* XXX */ +- if (saved_command_line_count > 0 && i == last_hist && hlist[last_hist] == 0) ++ if (i == last_hist && hlist[last_hist] == 0) + while (last_hist >= 0 && hlist[last_hist] == 0) + last_hist--; + if (last_hist < 0) +@@ -475,7 +475,7 @@ + HIST_ENTRY **hlist; + { + int sign, n, clen, rh; +- register int i, j; ++ register int i, j, last_hist; + register char *s; + + sign = 1; +@@ -495,7 +495,15 @@ + has been enabled (interactive or not) should use it in the last_hist + calculation as if it were on. */ + rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list); +- i -= rh + hist_last_line_added; ++ last_hist = i - rh - hist_last_line_added; ++ ++ if (i == last_hist && hlist[last_hist] == 0) ++ while (last_hist >= 0 && hlist[last_hist] == 0) ++ last_hist--; ++ if (last_hist < 0) ++ return (-1); ++ ++ i = last_hist; + + /* No specification defaults to most recent command. */ + if (command == NULL) +Index: builtins/printf.def +--- builtins/printf.def.orig 2010-11-23 16:02:55.000000000 +0100 ++++ builtins/printf.def 2012-06-27 10:31:02.000000000 +0200 +@@ -255,6 +255,8 @@ + #endif + { + vflag = 1; ++ if (vbsize == 0) ++ vbuf = xmalloc (vbsize = 16); + vblen = 0; + if (vbuf) + vbuf[0] = 0; +@@ -465,6 +467,9 @@ + secs = shell_start_time; /* roughly $SECONDS */ + else + secs = arg; ++#if defined (HAVE_TZSET) ++ sv_tz ("TZ"); /* XXX -- just make sure */ ++#endif + tm = localtime (&secs); + n = strftime (timebuf, sizeof (timebuf), timefmt, tm); + free (timefmt); +Index: builtins/read.def +--- builtins/read.def.orig 2011-01-04 17:43:36.000000000 +0100 ++++ builtins/read.def 2012-06-27 10:31:02.000000000 +0200 +@@ -642,6 +642,12 @@ + xfree (input_string); + return EXECUTION_FAILURE; /* readonly or noassign */ + } ++ if (assoc_p (var)) ++ { ++ builtin_error (_("%s: cannot convert associative to indexed array"), arrayname); ++ xfree (input_string); ++ return EXECUTION_FAILURE; /* existing associative array */ ++ } + array_flush (array_cell (var)); + + alist = list_string (input_string, ifs_chars, 0); +@@ -731,7 +737,7 @@ + xfree (t1); + } + else +- var = bind_read_variable (varname, t); ++ var = bind_read_variable (varname, t ? t : ""); + } + else + { +@@ -792,7 +798,7 @@ + xfree (t); + } + else +- var = bind_read_variable (list->word->word, input_string); ++ var = bind_read_variable (list->word->word, input_string ? input_string : ""); + + if (var) + { +Index: builtins/shopt.def +--- builtins/shopt.def.orig 2010-07-03 04:42:44.000000000 +0200 ++++ builtins/shopt.def 2012-06-27 10:31:03.000000000 +0200 +@@ -61,6 +61,10 @@ + #include "common.h" + #include "bashgetopt.h" + ++#if defined (READLINE) ++# include "../bashline.h" ++#endif ++ + #if defined (HISTORY) + # include "../bashhist.h" + #endif +@@ -94,7 +98,7 @@ + extern int hist_verify, history_reediting, perform_hostname_completion; + extern int no_empty_command_completion; + extern int force_fignore; +-extern int dircomplete_spelling; ++extern int dircomplete_spelling, dircomplete_expand; + + extern int enable_hostname_completion __P((int)); + #endif +@@ -121,6 +125,10 @@ + static int set_restricted_shell __P((char *, int)); + #endif + ++#if defined (READLINE) ++static int shopt_set_complete_direxpand __P((char *, int)); ++#endif ++ + static int shopt_login_shell; + static int shopt_compat31; + static int shopt_compat32; +@@ -150,6 +158,7 @@ + { "compat40", &shopt_compat40, set_compatibility_level }, + { "compat41", &shopt_compat41, set_compatibility_level }, + #if defined (READLINE) ++ { "direxpand", &dircomplete_expand, shopt_set_complete_direxpand }, + { "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL }, + #endif + { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL }, +@@ -535,6 +544,17 @@ + return 0; + } + ++#if defined (READLINE) ++static int ++shopt_set_complete_direxpand (option_name, mode) ++ char *option_name; ++ int mode; ++{ ++ set_directory_hook (); ++ return 0; ++} ++#endif ++ + #if defined (RESTRICTED_SHELL) + /* Don't allow the value of restricted_shell to be modified. */ + +Index: command.h +--- command.h.orig 2010-08-03 01:36:51.000000000 +0200 ++++ command.h 2012-06-27 10:31:02.000000000 +0200 +@@ -97,6 +97,7 @@ + #define W_HASCTLESC 0x200000 /* word contains literal CTLESC characters */ + #define W_ASSIGNASSOC 0x400000 /* word looks like associative array assignment */ + #define W_ARRAYIND 0x800000 /* word is an array index being expanded */ ++#define W_ASSNGLOBAL 0x1000000 /* word is a global assignment to declare (declare/typeset -g) */ + + /* Possible values for subshell_environment */ + #define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */ +Index: doc/bash.1 +--- doc/bash.1.orig 2011-01-16 21:31:39.000000000 +0100 ++++ doc/bash.1 2012-06-27 10:31:03.000000000 +0200 +@@ -8948,6 +8948,16 @@ + quoted. This is the behavior of posix mode through version 4.1. + The default bash behavior remains as in previous versions. + .TP 8 ++.B direxpand ++If set, ++.B bash ++replaces directory names with the results of word expansion when performing ++filename completion. This changes the contents of the readline editing ++buffer. ++If not set, ++.B bash ++attempts to preserve what the user typed. ++.TP 8 + .B dirspell + If set, + .B bash +Index: doc/bashref.texi +--- doc/bashref.texi.orig 2011-01-16 21:31:57.000000000 +0100 ++++ doc/bashref.texi 2012-06-27 10:31:03.000000000 +0200 +@@ -4535,6 +4535,13 @@ + quoted. This is the behavior of @sc{posix} mode through version 4.1. + The default Bash behavior remains as in previous versions. + ++@item direxpand ++If set, Bash ++replaces directory names with the results of word expansion when performing ++filename completion. This changes the contents of the readline editing ++buffer. ++If not set, Bash attempts to preserve what the user typed. ++ + @item dirspell + If set, Bash + attempts spelling correction on directory names during word completion +Index: error.c +--- error.c.orig 2009-08-22 04:31:31.000000000 +0200 ++++ error.c 2012-06-27 10:31:02.000000000 +0200 +@@ -200,7 +200,11 @@ + + va_end (args); + if (exit_immediately_on_error) +- exit_shell (1); ++ { ++ if (last_command_exit_value == 0) ++ last_command_exit_value = 1; ++ exit_shell (last_command_exit_value); ++ } + } + + void +Index: execute_cmd.c +--- execute_cmd.c.orig 2011-02-09 23:32:25.000000000 +0100 ++++ execute_cmd.c 2012-06-27 10:31:03.000000000 +0200 +@@ -2196,6 +2196,7 @@ + if (ignore_return && cmd) + cmd->flags |= CMD_IGNORE_RETURN; + ++#if defined (JOB_CONTROL) + lastpipe_flag = 0; + begin_unwind_frame ("lastpipe-exec"); + lstdin = -1; +@@ -2204,7 +2205,7 @@ + current shell environment. */ + if (lastpipe_opt && job_control == 0 && asynchronous == 0 && pipe_out == NO_PIPE && prev > 0) + { +- lstdin = move_to_high_fd (0, 0, 255); ++ lstdin = move_to_high_fd (0, 1, -1); + if (lstdin > 0) + { + do_piping (prev, pipe_out); +@@ -2215,15 +2216,19 @@ + lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ + add_unwind_protect (lastpipe_cleanup, lastpipe_jid); + } +- cmd->flags |= CMD_LASTPIPE; ++ if (cmd) ++ cmd->flags |= CMD_LASTPIPE; + } + if (prev >= 0) + add_unwind_protect (close, prev); ++#endif + + exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); + ++#if defined (JOB_CONTROL) + if (lstdin > 0) + restore_stdin (lstdin); ++#endif + + if (prev >= 0) + close (prev); +@@ -2246,7 +2251,9 @@ + unfreeze_jobs_list (); + } + ++#if defined (JOB_CONTROL) + discard_unwind_frame ("lastpipe-exec"); ++#endif + + return (exec_result); + } +@@ -3575,13 +3582,13 @@ + { + WORD_LIST *w; + struct builtin *b; +- int assoc; ++ int assoc, global; + + if (words == 0) + return; + + b = 0; +- assoc = 0; ++ assoc = global = 0; + + for (w = words; w; w = w->next) + if (w->word->flags & W_ASSIGNMENT) +@@ -3598,12 +3605,17 @@ + #if defined (ARRAY_VARS) + if (assoc) + w->word->flags |= W_ASSIGNASSOC; ++ if (global) ++ w->word->flags |= W_ASSNGLOBAL; + #endif + } + #if defined (ARRAY_VARS) + /* Note that we saw an associative array option to a builtin that takes + assignment statements. This is a bit of a kludge. */ +- else if (w->word->word[0] == '-' && strchr (w->word->word, 'A')) ++ else if (w->word->word[0] == '-' && (strchr (w->word->word+1, 'A') || strchr (w->word->word+1, 'g'))) ++#else ++ else if (w->word->word[0] == '-' && strchr (w->word->word+1, 'g')) ++#endif + { + if (b == 0) + { +@@ -3613,10 +3625,11 @@ + else if (b && (b->flags & ASSIGNMENT_BUILTIN)) + words->word->flags |= W_ASSNBLTIN; + } +- if (words->word->flags & W_ASSNBLTIN) ++ if ((words->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'A')) + assoc = 1; ++ if ((words->word->flags & W_ASSNBLTIN) && strchr (w->word->word+1, 'g')) ++ global = 1; + } +-#endif + } + + /* Return 1 if the file found by searching $PATH for PATHNAME, defaulting +Index: expr.c +--- expr.c.orig 2010-12-21 17:12:13.000000000 +0100 ++++ expr.c 2012-06-27 10:31:02.000000000 +0200 +@@ -476,19 +476,23 @@ + + if (special) + { ++ if ((op == DIV || op == MOD) && value == 0) ++ { ++ if (noeval == 0) ++ evalerror (_("division by 0")); ++ else ++ value = 1; ++ } ++ + switch (op) + { + case MUL: + lvalue *= value; + break; + case DIV: +- if (value == 0) +- evalerror (_("division by 0")); + lvalue /= value; + break; + case MOD: +- if (value == 0) +- evalerror (_("division by 0")); + lvalue %= value; + break; + case PLUS: +@@ -804,7 +808,12 @@ + val2 = exppower (); + + if (((op == DIV) || (op == MOD)) && (val2 == 0)) +- evalerror (_("division by 0")); ++ { ++ if (noeval == 0) ++ evalerror (_("division by 0")); ++ else ++ val2 = 1; ++ } + + if (op == MUL) + val1 *= val2; +Index: lib/glob/gmisc.c +--- lib/glob/gmisc.c.orig 2011-02-05 22:11:17.000000000 +0100 ++++ lib/glob/gmisc.c 2012-06-27 10:31:02.000000000 +0200 +@@ -77,8 +77,8 @@ + wchar_t *wpat; + size_t wmax; + { +- wchar_t wc, *wbrack; +- int matlen, t, in_cclass, in_collsym, in_equiv; ++ wchar_t wc; ++ int matlen, bracklen, t, in_cclass, in_collsym, in_equiv; + + if (*wpat == 0) + return (0); +@@ -118,58 +118,80 @@ + break; + case L'[': + /* scan for ending `]', skipping over embedded [:...:] */ +- wbrack = wpat; ++ bracklen = 1; + wc = *wpat++; + do + { + if (wc == 0) + { +- matlen += wpat - wbrack - 1; /* incremented below */ +- break; ++ wpat--; /* back up to NUL */ ++ matlen += bracklen; ++ goto bad_bracket; + } + else if (wc == L'\\') + { +- wc = *wpat++; +- if (*wpat == 0) +- break; ++ /* *wpat == backslash-escaped character */ ++ bracklen++; ++ /* If the backslash or backslash-escape ends the string, ++ bail. The ++wpat skips over the backslash escape */ ++ if (*wpat == 0 || *++wpat == 0) ++ { ++ matlen += bracklen; ++ goto bad_bracket; ++ } + } + else if (wc == L'[' && *wpat == L':') /* character class */ + { + wpat++; ++ bracklen++; + in_cclass = 1; + } + else if (in_cclass && wc == L':' && *wpat == L']') + { + wpat++; ++ bracklen++; + in_cclass = 0; + } + else if (wc == L'[' && *wpat == L'.') /* collating symbol */ + { + wpat++; ++ bracklen++; + if (*wpat == L']') /* right bracket can appear as collating symbol */ +- wpat++; ++ { ++ wpat++; ++ bracklen++; ++ } + in_collsym = 1; + } + else if (in_collsym && wc == L'.' && *wpat == L']') + { + wpat++; ++ bracklen++; + in_collsym = 0; + } + else if (wc == L'[' && *wpat == L'=') /* equivalence class */ + { + wpat++; ++ bracklen++; + if (*wpat == L']') /* right bracket can appear as equivalence class */ +- wpat++; ++ { ++ wpat++; ++ bracklen++; ++ } + in_equiv = 1; + } + else if (in_equiv && wc == L'=' && *wpat == L']') + { + wpat++; ++ bracklen++; + in_equiv = 0; + } ++ else ++ bracklen++; + } + while ((wc = *wpat++) != L']'); + matlen++; /* bracket expression can only match one char */ ++bad_bracket: + break; + } + } +@@ -213,8 +235,8 @@ + char *pat; + size_t max; + { +- char c, *brack; +- int matlen, t, in_cclass, in_collsym, in_equiv; ++ char c; ++ int matlen, bracklen, t, in_cclass, in_collsym, in_equiv; + + if (*pat == 0) + return (0); +@@ -254,58 +276,80 @@ + break; + case '[': + /* scan for ending `]', skipping over embedded [:...:] */ +- brack = pat; ++ bracklen = 1; + c = *pat++; + do + { + if (c == 0) + { +- matlen += pat - brack - 1; /* incremented below */ +- break; ++ pat--; /* back up to NUL */ ++ matlen += bracklen; ++ goto bad_bracket; + } + else if (c == '\\') + { +- c = *pat++; +- if (*pat == 0) +- break; ++ /* *pat == backslash-escaped character */ ++ bracklen++; ++ /* If the backslash or backslash-escape ends the string, ++ bail. The ++pat skips over the backslash escape */ ++ if (*pat == 0 || *++pat == 0) ++ { ++ matlen += bracklen; ++ goto bad_bracket; ++ } + } + else if (c == '[' && *pat == ':') /* character class */ + { + pat++; ++ bracklen++; + in_cclass = 1; + } + else if (in_cclass && c == ':' && *pat == ']') + { + pat++; ++ bracklen++; + in_cclass = 0; + } + else if (c == '[' && *pat == '.') /* collating symbol */ + { + pat++; ++ bracklen++; + if (*pat == ']') /* right bracket can appear as collating symbol */ +- pat++; ++ { ++ pat++; ++ bracklen++; ++ } + in_collsym = 1; + } + else if (in_collsym && c == '.' && *pat == ']') + { + pat++; ++ bracklen++; + in_collsym = 0; + } + else if (c == '[' && *pat == '=') /* equivalence class */ + { + pat++; ++ bracklen++; + if (*pat == ']') /* right bracket can appear as equivalence class */ +- pat++; ++ { ++ pat++; ++ bracklen++; ++ } + in_equiv = 1; + } + else if (in_equiv && c == '=' && *pat == ']') + { + pat++; ++ bracklen++; + in_equiv = 0; + } ++ else ++ bracklen++; + } + while ((c = *pat++) != ']'); + matlen++; /* bracket expression can only match one char */ ++bad_bracket: + break; + } + } +Index: lib/readline/callback.c +--- lib/readline/callback.c.orig 2010-06-06 18:18:58.000000000 +0200 ++++ lib/readline/callback.c 2012-06-27 10:31:02.000000000 +0200 +@@ -148,6 +148,9 @@ + eof = _rl_vi_domove_callback (_rl_vimvcxt); + /* Should handle everything, including cleanup, numeric arguments, + and turning off RL_STATE_VIMOTION */ ++ if (RL_ISSTATE (RL_STATE_NUMERICARG) == 0) ++ _rl_internal_char_cleanup (); ++ + return; + } + #endif +Index: lib/readline/vi_mode.c +--- lib/readline/vi_mode.c.orig 2010-11-21 01:51:39.000000000 +0100 ++++ lib/readline/vi_mode.c 2012-06-27 10:31:02.000000000 +0200 +@@ -1114,7 +1114,7 @@ + rl_beg_of_line (1, c); + _rl_vi_last_motion = c; + RL_UNSETSTATE (RL_STATE_VIMOTION); +- return (0); ++ return (vidomove_dispatch (m)); + } + #if defined (READLINE_CALLBACKS) + /* XXX - these need to handle rl_universal_argument bindings */ +Index: lib/sh/zread.c +--- lib/sh/zread.c.orig 2009-03-02 14:54:45.000000000 +0100 ++++ lib/sh/zread.c 2012-06-27 10:31:02.000000000 +0200 +@@ -160,14 +160,13 @@ + zsyncfd (fd) + int fd; + { +- off_t off; +- int r; ++ off_t off, r; + + off = lused - lind; + r = 0; + if (off > 0) + r = lseek (fd, -off, SEEK_CUR); + +- if (r >= 0) ++ if (r != -1) + lused = lind = 0; + } +Index: parse.y +--- parse.y.orig 2011-01-02 21:48:11.000000000 +0100 ++++ parse.y 2012-06-27 10:31:02.000000000 +0200 +@@ -2499,7 +2499,7 @@ + We do this only if it is time to do so. Notice that only here + is the mail alarm reset; nothing takes place in check_mail () + except the checking of mail. Please don't change this. */ +- if (prompt_is_ps1 && time_to_check_mail ()) ++ if (prompt_is_ps1 && parse_and_execute_level == 0 && time_to_check_mail ()) + { + check_mail (); + reset_mail_timer (); +@@ -3842,6 +3842,7 @@ + int flags; + { + sh_parser_state_t ps; ++ sh_input_line_state_t ls; + int orig_ind, nc, sflags; + char *ret, *s, *ep, *ostring; + +@@ -3849,10 +3850,12 @@ + orig_ind = *indp; + ostring = string; + ++/*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/ + sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; + if (flags & SX_NOLONGJMP) + sflags |= SEVAL_NOLONGJMP; + save_parser_state (&ps); ++ save_input_line_state (&ls); + + /*(*/ + parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ +@@ -3861,6 +3864,8 @@ + + restore_parser_state (&ps); + reset_parser (); ++ /* reset_parser clears shell_input_line and associated variables */ ++ restore_input_line_state (&ls); + if (interactive) + token_to_read = 0; + +@@ -5135,6 +5140,9 @@ + case 'A': + /* Make the current time/date into a string. */ + (void) time (&the_time); ++#if defined (HAVE_TZSET) ++ sv_tz ("TZ"); /* XXX -- just make sure */ ++#endif + tm = localtime (&the_time); + + if (c == 'd') +@@ -5905,6 +5913,12 @@ + ps->expand_aliases = expand_aliases; + ps->echo_input_at_read = echo_input_at_read; + ++ ps->token = token; ++ ps->token_buffer_size = token_buffer_size; ++ /* Force reallocation on next call to read_token_word */ ++ token = 0; ++ token_buffer_size = 0; ++ + return (ps); + } + +@@ -5946,6 +5960,42 @@ + + expand_aliases = ps->expand_aliases; + echo_input_at_read = ps->echo_input_at_read; ++ ++ FREE (token); ++ token = ps->token; ++ token_buffer_size = ps->token_buffer_size; ++} ++ ++sh_input_line_state_t * ++save_input_line_state (ls) ++ sh_input_line_state_t *ls; ++{ ++ if (ls == 0) ++ ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t)); ++ if (ls == 0) ++ return ((sh_input_line_state_t *)NULL); ++ ++ ls->input_line = shell_input_line; ++ ls->input_line_size = shell_input_line_size; ++ ls->input_line_len = shell_input_line_len; ++ ls->input_line_index = shell_input_line_index; ++ ++ /* force reallocation */ ++ shell_input_line = 0; ++ shell_input_line_size = shell_input_line_len = shell_input_line_index = 0; ++} ++ ++void ++restore_input_line_state (ls) ++ sh_input_line_state_t *ls; ++{ ++ FREE (shell_input_line); ++ shell_input_line = ls->input_line; ++ shell_input_line_size = ls->input_line_size; ++ shell_input_line_len = ls->input_line_len; ++ shell_input_line_index = ls->input_line_index; ++ ++ set_line_mbstate (); + } + + /************************************************ +Index: patchlevel.h +--- patchlevel.h.orig 2010-06-13 02:14:48.000000000 +0200 ++++ patchlevel.h 2012-06-27 10:31:03.000000000 +0200 +@@ -25,6 +25,6 @@ + regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh + looks for to find the patch level (for the sccs version string). */ + +-#define PATCHLEVEL 0 ++#define PATCHLEVEL 29 + + #endif /* _PATCHLEVEL_H_ */ +Index: pathexp.c +--- pathexp.c.orig 2010-08-14 05:21:57.000000000 +0200 ++++ pathexp.c 2012-06-27 10:31:02.000000000 +0200 +@@ -196,7 +196,7 @@ + { + if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') + continue; +- if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0) ++ if (pathname[i+1] != CTLESC && (qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0) + continue; + temp[j++] = '\\'; + i++; +Index: print_cmd.c +--- print_cmd.c.orig 2010-05-31 00:34:08.000000000 +0200 ++++ print_cmd.c 2012-06-27 10:31:02.000000000 +0200 +@@ -315,6 +315,7 @@ + cprintf ("( "); + skip_this_indent++; + make_command_string_internal (command->value.Subshell->command); ++ PRINT_DEFERRED_HEREDOCS (""); + cprintf (" )"); + break; + +@@ -592,6 +593,7 @@ + newline ("do\n"); + indentation += indentation_amount; + make_command_string_internal (arith_for_command->action); ++ PRINT_DEFERRED_HEREDOCS (""); + semicolon (); + indentation -= indentation_amount; + newline ("done"); +@@ -653,6 +655,7 @@ + } + + make_command_string_internal (group_command->command); ++ PRINT_DEFERRED_HEREDOCS (""); + + if (inside_function_def) + { +Index: shell.h +--- shell.h.orig 2011-01-07 04:16:55.000000000 +0100 ++++ shell.h 2012-06-27 10:31:02.000000000 +0200 +@@ -136,6 +136,9 @@ + int parser_state; + int *token_state; + ++ char *token; ++ int token_buffer_size; ++ + /* input line state -- line number saved elsewhere */ + int input_line_terminator; + int eof_encountered; +@@ -166,6 +169,16 @@ + + } sh_parser_state_t; + ++typedef struct _sh_input_line_state_t { ++ char *input_line; ++ int input_line_index; ++ int input_line_size; ++ int input_line_len; ++} sh_input_line_state_t; ++ + /* Let's try declaring these here. */ + extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *)); + extern void restore_parser_state __P((sh_parser_state_t *)); ++ ++extern sh_input_line_state_t *save_input_line_state __P((sh_input_line_state_t *)); ++extern void restore_input_line_state __P((sh_input_line_state_t *)); +Index: sig.c +--- sig.c.orig 2010-11-23 14:21:22.000000000 +0100 ++++ sig.c 2012-06-27 10:31:02.000000000 +0200 +@@ -46,6 +46,7 @@ + + #if defined (READLINE) + # include "bashline.h" ++# include + #endif + + #if defined (HISTORY) +@@ -62,6 +63,7 @@ + #if defined (HISTORY) + extern int history_lines_this_session; + #endif ++extern int no_line_editing; + + extern void initialize_siglist (); + +@@ -505,7 +507,10 @@ + { + #if defined (HISTORY) + /* XXX - will inhibit history file being written */ +- history_lines_this_session = 0; ++# if defined (READLINE) ++ if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0)) ++# endif ++ history_lines_this_session = 0; + #endif + terminate_immediately = 0; + termsig_handler (sig); +Index: subst.c +--- subst.c.orig 2011-01-02 22:12:51.000000000 +0100 ++++ subst.c 2012-06-27 10:31:03.000000000 +0200 +@@ -366,6 +366,11 @@ + f &= ~W_ASSNBLTIN; + fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : ""); + } ++ if (f & W_ASSNGLOBAL) ++ { ++ f &= ~W_ASSNGLOBAL; ++ fprintf (stderr, "W_ASSNGLOBAL%s", f ? "|" : ""); ++ } + if (f & W_COMPASSIGN) + { + f &= ~W_COMPASSIGN; +@@ -1379,10 +1384,12 @@ + slen = strlen (string + *sindex) + *sindex; + + /* The handling of dolbrace_state needs to agree with the code in parse.y: +- parse_matched_pair() */ +- dolbrace_state = 0; +- if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) +- dolbrace_state = (flags & SX_POSIXEXP) ? DOLBRACE_QUOTE : DOLBRACE_PARAM; ++ parse_matched_pair(). The different initial value is to handle the ++ case where this function is called to parse the word in ++ ${param op word} (SX_WORD). */ ++ dolbrace_state = (flags & SX_WORD) ? DOLBRACE_WORD : DOLBRACE_PARAM; ++ if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && (flags & SX_POSIXEXP)) ++ dolbrace_state = DOLBRACE_QUOTE; + + i = *sindex; + while (c = string[i]) +@@ -2801,7 +2808,7 @@ + } + else if (assign_list) + { +- if (word->flags & W_ASSIGNARG) ++ if ((word->flags & W_ASSIGNARG) && (word->flags & W_ASSNGLOBAL) == 0) + aflags |= ASS_MKLOCAL; + if (word->flags & W_ASSIGNASSOC) + aflags |= ASS_MKASSOC; +@@ -3371,7 +3378,7 @@ + if (string == 0 || *string == '\0') + return (WORD_LIST *)NULL; + +- td.flags = 0; ++ td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ + td.word = string; + tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, has_dollar_at); + return (tresult); +@@ -3704,7 +3711,10 @@ + break; + } + else if (string[i] == CTLNUL) +- i++; ++ { ++ i++; ++ continue; ++ } + + prev_i = i; + ADVANCE_CHAR (string, slen, i); +@@ -4156,7 +4166,7 @@ + simple = (wpat[0] != L'\\' && wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'['); + #if defined (EXTENDED_GLOB) + if (extended_glob) +- simple |= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ ++ simple &= (wpat[1] != L'(' || (wpat[0] != L'*' && wpat[0] != L'?' && wpat[0] != L'+' && wpat[0] != L'!' && wpat[0] != L'@')); /*)*/ + #endif + + /* If the pattern doesn't match anywhere in the string, go ahead and +@@ -4607,6 +4617,7 @@ + if (ifs_firstc == 0) + #endif + word->flags |= W_NOSPLIT; ++ word->flags |= W_NOSPLIT2; + result = call_expand_word_internal (word, quoted, 0, (int *)NULL, (int *)NULL); + expand_no_split_dollar_star = 0; + +@@ -5798,6 +5809,16 @@ + is the only expansion that creates more than one word. */ + if (qdollaratp && ((hasdol && quoted) || l->next)) + *qdollaratp = 1; ++ /* If we have a quoted null result (QUOTED_NULL(temp)) and the word is ++ a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the ++ flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the ++ expansion is quoted (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ++ (which is more paranoia than anything else), we need to return the ++ quoted null string and set the flags to indicate it. */ ++ if (l->next == 0 && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && QUOTED_NULL(temp) && QUOTED_NULL(l->word->word) && (l->word->flags & W_HASQUOTEDNULL)) ++ { ++ w->flags |= W_HASQUOTEDNULL; ++ } + dispose_words (l); + } + else if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) && hasdol) +@@ -7176,7 +7197,7 @@ + { + /* Extract the contents of the ${ ... } expansion + according to the Posix.2 rules. */ +- value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#') ? SX_POSIXEXP : 0); ++ value = extract_dollar_brace_string (string, &sindex, quoted, (c == '%' || c == '#' || c =='/' || c == '^' || c == ',' || c ==':') ? SX_POSIXEXP|SX_WORD : SX_WORD); + if (string[sindex] == RBRACE) + sindex++; + else +@@ -7268,6 +7289,7 @@ + default: + case '\0': + bad_substitution: ++ last_command_exit_value = EXECUTION_FAILURE; + report_error (_("%s: bad substitution"), string ? string : "??"); + FREE (value); + FREE (temp); +Index: subst.h +--- subst.h.orig 2010-12-03 02:21:29.000000000 +0100 ++++ subst.h 2012-06-27 10:31:02.000000000 +0200 +@@ -56,6 +56,7 @@ + #define SX_NOLONGJMP 0x0040 /* don't longjmp on fatal error */ + #define SX_ARITHSUB 0x0080 /* extracting $(( ... )) (currently unused) */ + #define SX_POSIXEXP 0x0100 /* extracting new Posix pattern removal expansions in extract_dollar_brace_string */ ++#define SX_WORD 0x0200 /* extracting word in ${param op word} */ + + /* Remove backslashes which are quoting backquotes from STRING. Modifies + STRING, and returns a pointer to it. */ +Index: support/shobj-conf +--- support/shobj-conf.orig 2009-10-28 14:20:21.000000000 +0100 ++++ support/shobj-conf 2012-06-27 10:31:02.000000000 +0200 +@@ -157,7 +157,7 @@ + ;; + + # Darwin/MacOS X +-darwin[89]*|darwin10*) ++darwin[89]*|darwin1[012]*) + SHOBJ_STATUS=supported + SHLIB_STATUS=supported + +@@ -186,7 +186,7 @@ + SHLIB_LIBSUFF='dylib' + + case "${host_os}" in +- darwin[789]*|darwin10*) SHOBJ_LDFLAGS='' ++ darwin[789]*|darwin1[012]*) SHOBJ_LDFLAGS='' + SHLIB_XLDFLAGS='-dynamiclib -arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' + ;; + *) SHOBJ_LDFLAGS='-dynamic' +Index: tests/shopt.right +--- tests/shopt.right.orig 2010-07-03 05:36:30.000000000 +0200 ++++ tests/shopt.right 2012-06-27 10:31:03.000000000 +0200 +@@ -12,6 +12,7 @@ + shopt -u compat32 + shopt -u compat40 + shopt -u compat41 ++shopt -u direxpand + shopt -u dirspell + shopt -u dotglob + shopt -u execfail +@@ -68,6 +69,7 @@ + shopt -u compat32 + shopt -u compat40 + shopt -u compat41 ++shopt -u direxpand + shopt -u dirspell + shopt -u dotglob + shopt -u execfail +@@ -101,6 +103,7 @@ + compat32 off + compat40 off + compat41 off ++direxpand off + dirspell off + dotglob off + execfail off +Index: variables.c +--- variables.c.orig 2011-01-25 02:07:48.000000000 +0100 ++++ variables.c 2012-06-27 10:31:02.000000000 +0200 +@@ -3653,6 +3653,22 @@ + return n; + } + ++int ++chkexport (name) ++ char *name; ++{ ++ SHELL_VAR *v; ++ ++ v = find_variable (name); ++ if (v && exported_p (v)) ++ { ++ array_needs_making = 1; ++ maybe_make_export_env (); ++ return 1; ++ } ++ return 0; ++} ++ + void + maybe_make_export_env () + { +@@ -4214,7 +4230,7 @@ + { "TEXTDOMAIN", sv_locale }, + { "TEXTDOMAINDIR", sv_locale }, + +-#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) ++#if defined (HAVE_TZSET) + { "TZ", sv_tz }, + #endif + +@@ -4558,12 +4574,13 @@ + } + #endif /* HISTORY */ + +-#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE) ++#if defined (HAVE_TZSET) + void + sv_tz (name) + char *name; + { +- tzset (); ++ if (chkexport (name)) ++ tzset (); + } + #endif + +Index: variables.h +--- variables.h.orig 2010-12-03 02:22:01.000000000 +0100 ++++ variables.h 2012-06-27 10:31:02.000000000 +0200 +@@ -313,6 +313,7 @@ + + extern void sort_variables __P((SHELL_VAR **)); + ++extern int chkexport __P((char *)); + extern void maybe_make_export_env __P((void)); + extern void update_export_env_inplace __P((char *, int, char *)); + extern void put_command_name_into_env __P((char *)); +Index: y.tab.c +--- y.tab.c.orig 2011-01-04 15:57:56.000000000 +0100 ++++ y.tab.c 2012-06-27 10:31:03.000000000 +0200 +@@ -4811,7 +4811,7 @@ + We do this only if it is time to do so. Notice that only here + is the mail alarm reset; nothing takes place in check_mail () + except the checking of mail. Please don't change this. */ +- if (prompt_is_ps1 && time_to_check_mail ()) ++ if (prompt_is_ps1 && parse_and_execute_level == 0 && time_to_check_mail ()) + { + check_mail (); + reset_mail_timer (); +@@ -6154,6 +6154,7 @@ + int flags; + { + sh_parser_state_t ps; ++ sh_input_line_state_t ls; + int orig_ind, nc, sflags; + char *ret, *s, *ep, *ostring; + +@@ -6161,10 +6162,12 @@ + orig_ind = *indp; + ostring = string; + ++/*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/ + sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE; + if (flags & SX_NOLONGJMP) + sflags |= SEVAL_NOLONGJMP; + save_parser_state (&ps); ++ save_input_line_state (&ls); + + /*(*/ + parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ +@@ -6173,6 +6176,8 @@ + + restore_parser_state (&ps); + reset_parser (); ++ /* reset_parser clears shell_input_line and associated variables */ ++ restore_input_line_state (&ls); + if (interactive) + token_to_read = 0; + +@@ -7447,6 +7452,9 @@ + case 'A': + /* Make the current time/date into a string. */ + (void) time (&the_time); ++#if defined (HAVE_TZSET) ++ sv_tz ("TZ"); /* XXX -- just make sure */ ++#endif + tm = localtime (&the_time); + + if (c == 'd') +@@ -8217,6 +8225,12 @@ + ps->expand_aliases = expand_aliases; + ps->echo_input_at_read = echo_input_at_read; + ++ ps->token = token; ++ ps->token_buffer_size = token_buffer_size; ++ /* Force reallocation on next call to read_token_word */ ++ token = 0; ++ token_buffer_size = 0; ++ + return (ps); + } + +@@ -8258,6 +8272,42 @@ + + expand_aliases = ps->expand_aliases; + echo_input_at_read = ps->echo_input_at_read; ++ ++ FREE (token); ++ token = ps->token; ++ token_buffer_size = ps->token_buffer_size; ++} ++ ++sh_input_line_state_t * ++save_input_line_state (ls) ++ sh_input_line_state_t *ls; ++{ ++ if (ls == 0) ++ ls = (sh_input_line_state_t *)xmalloc (sizeof (sh_input_line_state_t)); ++ if (ls == 0) ++ return ((sh_input_line_state_t *)NULL); ++ ++ ls->input_line = shell_input_line; ++ ls->input_line_size = shell_input_line_size; ++ ls->input_line_len = shell_input_line_len; ++ ls->input_line_index = shell_input_line_index; ++ ++ /* force reallocation */ ++ shell_input_line = 0; ++ shell_input_line_size = shell_input_line_len = shell_input_line_index = 0; ++} ++ ++void ++restore_input_line_state (ls) ++ sh_input_line_state_t *ls; ++{ ++ FREE (shell_input_line); ++ shell_input_line = ls->input_line; ++ shell_input_line_size = ls->input_line_size; ++ shell_input_line_len = ls->input_line_len; ++ shell_input_line_index = ls->input_line_index; ++ ++ set_line_mbstate (); + } + + /************************************************ diff -r 71503088f51b -r f880f219c566 openpkg/beecrypt.patch --- a/openpkg/beecrypt.patch Tue Jul 31 12:12:54 2012 +0200 +++ b/openpkg/beecrypt.patch Tue Jul 31 12:23:42 2012 +0200 @@ -1,50 +1,64 @@ -Index: gas/aesopt.x86.m4 ---- gas/aesopt.x86.m4.orig 2004-06-13 13:37:23 +0200 -+++ gas/aesopt.x86.m4 2004-07-28 20:02:07 +0200 -@@ -134,6 +134,9 @@ - pxor 6144(%esi,%edx,8),s0 - ') +Index: configure +--- configure.orig 2009-07-12 09:19:15 +0200 ++++ configure 2010-01-07 18:10:28 +0100 +@@ -2821,7 +2821,7 @@ + # Check whether --enable-expert-mode was given. + if test "${enable_expert_mode+set}" = set; then + enableval=$enable_expert_mode; +- ac_enable_expert_mode=yes ++ ac_enable_expert_mode=$enableval -+') -+ifdef(`USE_MMX',` -+ - define(`elr',` - movd 0(%ebp),s0 - movd t0,%eax -@@ -253,6 +256,9 @@ - ') + else +@@ -4502,13 +4502,7 @@ + if $ac_preproc_ok; then + : + else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } ++ : + fi -+') -+ifdef(`USE_MMX',` -+ - C_FUNCTION_BEGIN(aesEncrypt) - pushl %edi - pushl %esi -@@ -364,6 +370,9 @@ - pxor 6144(%esi,%edx,8),t2 - ') + ac_ext=c +@@ -6170,13 +6164,7 @@ + if $ac_preproc_ok; then + : + else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } ++ : + fi -+') -+ifdef(`USE_MMX',` -+ - define(`dsft',` - movd $1+ 0(%ebp),s0 - movd t0,%eax -@@ -490,6 +499,9 @@ - pxor t3,s2 - ') + ac_ext=c +@@ -6901,13 +6889,7 @@ + if $ac_preproc_ok; then + : + else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } ++ : + fi -+') -+ifdef(`USE_MMX',` -+ - define(`dblock',` - sxrk - + ac_ext=c Index: gnu.h.in ---- gnu.h.in.orig 2004-12-19 21:18:48 +0100 -+++ gnu.h.in 2005-03-08 19:34:03 +0100 -@@ -48,15 +48,6 @@ +--- gnu.h.in.orig 2009-06-18 21:56:25 +0200 ++++ gnu.h.in 2010-01-07 18:10:08 +0100 +@@ -59,15 +59,6 @@ @TYPEDEF_UINT32_T@ @TYPEDEF_UINT64_T@ diff -r 71503088f51b -r f880f219c566 openpkg/build.8 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/build.8 Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,513 @@ +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.22) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "BUILD 8" +.TH BUILD 8 "OpenPKG" "BUILD(8)" "OpenPKG" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +openpkg build \- OpenPKG Package Building and Installing +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBopenpkg\fR +\&\fBbuild\fR +[\fB\-R\fR \fIrpm\fR] +[\fB\-r\fR \fIrepository\fR] +[\fB\-f\fR \fIindex.rdf\fR] +[\fB\-u\fR] +[\fB\-U\fR] +[\fB\-z\fR] +[\fB\-Z\fR] +[\fB\-i\fR] +[\fB\-q\fR] +[\fB\-s\fR] +[\fB\-S\fR] +[\fB\-M\fR] +[\fB\-L\fR] +[\fB\-W\fR] +[\fB\-X\fR] +[\fB\-K\fR] +[\fB\-k\fR] +[\fB\-e\fR] +[\fB\-b\fR] +[\fB\-B\fR] +[\fB\-G\fR] +[\fB\-P\fR \fIpriv-cmd\fR] +[\fB\-N\fR \fInon-priv-cmd\fR] +[\fB\-p\fR \fIplatform\fR] +[\fB\-D\fR \fIvar\fR=\fIval\fR ...] +[\fB\-E\fR \fIname\fR ...] +[\fB\-H\fR \fIname\fR ...] +([\fB\-a\fR] [\fB\-A\fR] | \fIpattern\fR ...) +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fBopenpkg build\fR tool provides automated recursive from-scratch +installation of packages and the updating and upgrading of installed +packages. +.PP +It generates a Bourne-Shell script on standard output (\fIstdout\fR) +that can be executed to perform the package installation or +updating/upgrading procedure for all requested packages and their +dependencies. +.PP +Packages that are upgraded automatically trigger rebuilds of all +packages that depend on the upgraded package (\*(L"reverse dependencies\*(R"). +The dependency information is read from an \s-1XML/RDF\s0 index generated by +the companion tool \fBopenpkg index\fR. +.SH "ARGUMENTS" +.IX Header "ARGUMENTS" +Packages are selected by providing a list of name patterns. Each +pattern is either a package name or a name prefix followed by a '\fI*\fR' +character. Additionally, in order to resolve ambiguous dependencies, you +can append a discrimination prefix separated by a comma that matches +against the full "\fIname\fR\-\fIversion\fR\-\fIrevision\fR" string of a package. +.SH "OPTIONS" +.IX Header "OPTIONS" +The following command line options exist: +.IP "\fB\-R\fR \fIcommand\fR" 4 +.IX Item "-R command" +Specify the "\fBopenpkg rpm\fR" command with fully qualified path. +Several other internal paths are deduced from the \fIcommand\fR path, +so this has to be something like "\fIprefix\fR\f(CW\*(C`/bin/openpkg rpm\*(C'\fR". +.IP "\fB\-r\fR \fIrepository\fR" 4 +.IX Item "-r repository" +Specify the path to an OpenPKG \s-1RPM\s0 package repository. +This can be a \s-1URL\s0 (including \*(L"file://\*(R") to download packages from or +an absolute directory path (identified by leading \*(L"/\*(R") or +a relative directory path (identified by leading \*(L"./\*(R") to access packages directly. +The name of the package file is appended to this path. +The default is to use a \s-1URL\s0 pointing to the \fBOpenPKG\fR download service +as determined by the "\fBopenpkg release\fR" command. +.IP "\fB\-f\fR \fIindex.rdf\fR" 4 +.IX Item "-f index.rdf" +Specify the path to the primary \s-1XML/RDF\s0 index. This can be a \s-1URL\s0 or a +file path. If the index contains references to other indices, these +are recursively included automatically. The default is to use a \s-1URL\s0 +pointing to the \fBOpenPKG\fR \s-1FTP\s0 server as as determined by the "\fBopenpkg +release\fR" command. +.IP "\fB\-u\fR" 4 +.IX Item "-u" +The generated script will ignore binary RPMs that are stored on +your system. Instead it will either fetch binary RPMs or rebuild +from source RPMs fetched from the repository. +.IP "\fB\-U\fR" 4 +.IX Item "-U" +The generated script will try to upgrade all selected packages +including their dependencies to the most recent version. Use +this for usual upgrade tasks in combination with option "\fB\-a\fR". +.IP "\fB\-z\fR" 4 +.IX Item "-z" +The generated script will rebuild all selected packages +including their dependencies even when the most recent version +is already installed. +.IP "\fB\-Z\fR" 4 +.IX Item "-Z" +\&\fBopenpkg build\fR ignores all installed packages, the +generated script will rebuild all selected packages from scratch. +.IP "\fB\-i\fR" 4 +.IX Item "-i" +The generated script will ignore run-time errors. +.IP "\fB\-q\fR" 4 +.IX Item "-q" +Ignore all reverse dependencies. This means that all packages which are +rebuild do \fInot\fR trigger a rebuild of packages which depend on them. +\&\fI\s-1ATTENTION:\s0 this might break already installed packages and has to be +used with care! You should really know what you are doing.\fR +.IP "\fB\-s\fR" 4 +.IX Item "-s" +Generate a status map instead of the shell script. The map consists +of 3 columns: \fIold\fR, \fItag\fR and \fInew\fR. The \fIold\fR column shows +the installed version of a package (\fIname\fR\-\fIversion\fR\-\fIrelease\fR) +or just the package name (\fIname\fR) if no package of that name +is installed and the \fInew\fR column shows the repository version +(\fIname\fR\-\fIversion\fR\-\fIrelease\fR) of a package if it is considered for +installation. The \fItag\fR column shows the following possible values: +.RS 4 +.IP "\s-1OK\s0" 10 +.IX Item "OK" +The installed package is suitable and will not be touched. +.IP "\s-1ADD\s0" 10 +.IX Item "ADD" +There is no installed package yet. +.IP "\s-1UPGRADE\s0" 10 +.IX Item "UPGRADE" +The installed package is outdated and requires an update. +.IP "\s-1DEPEND\s0" 10 +.IX Item "DEPEND" +The installed package needs rebuilding because one of its +dependencies is rebuild. +.IP "\s-1MISMATCH\s0" 10 +.IX Item "MISMATCH" +The installed package needs rebuilding because it was build +with different parameters. +.IP "\s-1CONFLICT\s0" 10 +.IX Item "CONFLICT" +The required new package cannot be installed because it +conflicts with some already installed package. +.IP "\s-1UNDEF\s0" 10 +.IX Item "UNDEF" +The package has an invalid or ambiguous dependency. +.RE +.RS 4 +.RE +.IP "\fB\-S\fR" 4 +.IX Item "-S" +Similar to option "\fB\-s\fR" but also lists the newest versions in the +repository. The following \fItag\fR might appear in the map: +.RS 4 +.IP "\s-1NEW\s0" 10 +.IX Item "NEW" +The package exists in the repository but is not required yet. +.RE +.RS 4 +.RE +.IP "\fB\-M\fR" 4 +.IX Item "-M" +Similar to option "\fB\-s\fR" but print a short dependency map. +.IP "\fB\-L\fR" 4 +.IX Item "-L" +Print a list of packages in the repository that depend on the target. +.IP "\fB\-W\fR" 4 +.IX Item "-W" +Include all conditional dependencies as if all possible configuration +options had been switched on. This has little use in practice except for +generating an all-inclusive list with option "\fB\-L\fR". \fI\s-1ATTENTION:\s0 Even +mutually exclusive options are evaluated to be 'on', building packages +with option \*(L"\-W\*(R" therefore might fail or cause unusable results!\fR +.IP "\fB\-X\fR" 4 +.IX Item "-X" +Use the slower but more robust external Perl \s-1XML\s0 parser module +XML::Simple instead of the simple internal \s-1XML/RDF\s0 parser. +.IP "\fB\-K\fR" 4 +.IX Item "-K" +Keep packages that were installed temporarily during the build process. +Without this option those packages are removed. +.IP "\fB\-k\fR" 4 +.IX Item "-k" +Keep packages that were downloaded temporarily for installation or building. +Without this option those packages are removed. +.IP "\fB\-e\fR" 4 +.IX Item "-e" +Rebuild exact version of a package from repository even when you have +installed a newer version from another repository. +.IP "\fB\-b\fR" 4 +.IX Item "-b" +Wrap package rebuilding commands with script execution-time checks for +existing binary packages if the package is rebuild as a dependency. Wrap +package install commands with script execution-time checks for different +\&\s-1MD5\s0 signature checksums of binary packages and installed packages. This +is best to use with option "\fB\-u\fR" to defer all such checks until script +execution-time. +.IP "\fB\-B\fR" 4 +.IX Item "-B" +Same as option "\fB\-b\fR" but also check all explicit target packages for +existing binary packages at script execution-time. +.IP "\fB\-g\fR" 4 +.IX Item "-g" +The generated script will rebuild all packages selected even when the +most recent version is already installed. Dependencies are not affected. +Use this especially for updating a package with different build options +(see option "\fB\-D\fR"). +.IP "\fB\-P\fR \fIpriv-cmd\fR" 4 +.IX Item "-P priv-cmd" +Command prefix to use for generated script commands that require +elevated privileges (like "\fBopenpkg rpm \-Uvh\fR"). The most common tool +for this is \fIsudo\fR\|(8). If \fIpriv-cmd\fR starts with a dash it will be run +without the dash and the command line it should execute is passed as +a single quoted string. Use this option for upgrading privileges. For +instance, if you are running the \f(CW\*(C`openpkg build\*(C'\fR\*(L" command as the +management user, use \*(R"\f(CW\*(C`\-P sudo\*(C'\fR\*(L" to make sure that the \*(R"\fBopenpkg rpm +\&\-Uvh\fR" commands in the generated script execute with necessary elevated +privileges. +.IP "\fB\-N\fR \fInon-priv-cmd\fR" 4 +.IX Item "-N non-priv-cmd" +Command prefix to use for generated script commands that do \fInot\fR +require elevated privileges (like "\fBopenpkg rpm \-\-rebuild\fR"). The most +common tool for this is \fIsu\fR\|(8). If \fInon-priv-cmd\fR starts with a dash +it will be run without the dash and the command line it should execute +is passed as a single quoted string. Use this option for downgrading +privileges. For instance, if you are running the \f(CW\*(C`openpkg build\*(C'\fR" +command as the \fBroot\fR user, use "\f(CW\*(C`\-N \*(Aq\-su \- \*(C'\fR\fImusr\fR\f(CW\*(C` \-c\*(Aq\*(C'\fR" to make +sure that the non-privileged commands in the generated script execute +with privileges of the management user \fImusr\fR. +.IP "\fB\-p\fR \fIplatform\fR" 4 +.IX Item "-p platform" +The platform string that is matched against the \s-1XML/RDF\s0 index for binary +packages. The default is an empty \fIplatform\fR string so that no binary +packages are matched at all. +.IP "\fB\-D\fR \fIvar\fR=\fIval\fR" 4 +.IX Item "-D var=val" +Specify build options for selected packages. This can be either +"\fB\-D\fR \fIwith_xxx\fR=\fIyyy\fR\*(L" or just \*(R"\fB\-D\fR \fIwith_xxx\fR\*(L". The latter is +equivalent to a \*(R"\fB\-D\fR \fIwith_xxx\fR=\fIyes\fR\*(L". The parameters are matched +against selected packages that are already installed. If they do +indicate a change, the package is rebuild. There can be multiple \*(R"\fB\-D\fR" +options. +.Sp +If the option name is prefixed with a package name followed by +two colons then it applies only to the specified package, e.g., +"\fB\-D\fR\fIfoo::with_bar\fR". +.IP "\fB\-E\fR \fIname\fR" 4 +.IX Item "-E name" +Ignore a package with the specified \fIname\fR. This can be used to avoid +upgrading to a broken package in the repository or to skip a package +upgrade temporarily. If you use a wildcard pattern or the options +"\fB\-a\fR\*(L" or \*(R"\fB\-A\fR" then \fIname\fR will be excluded. There can be multiple +"\fB\-E\fR" options. +.IP "\fB\-H\fR \fIname\fR" 4 +.IX Item "-H name" +Hint about packages that should be preferred when more than one fits +a requirement. There can be multiple "\fB\-H\fR" options. +.IP "\fB\-a\fR" 4 +.IX Item "-a" +Select all installed packages. You cannot specify a pattern list together +with the "\fB\-a\fR" option. +.IP "\fB\-A\fR" 4 +.IX Item "-A" +Select all packages in the repository. You cannot specify a pattern list +together with the "\fB\-A\fR" option. +.SH "ARGUMENTS" +.IX Header "ARGUMENTS" +In case neither option \fB\-a\fR nor option \fB\-A\fR are specified, +the command line has to contain one or more package \fIpattern\fR +arguments. Each \fIpattern\fR can have the following forms: +.IP "\fIname\fR" 4 +.IX Item "name" +A regular package name. +.IP "\fIname\fR\fB*\fR" 4 +.IX Item "name*" +A package name wildcard pattern. +.IP "\fIname\fR\fB,\fR\fIname\fR[\fB\-\fR\fIversion\fR[\fB\-\fR\fIrelease\fR]]" 4 +.IX Item "name,name[-version[-release]]" +A regular package name followed by a constraint +which particular package should be chosen. +.SH "CONFIGURATION" +.IX Header "CONFIGURATION" +\&\fBopenpkg build\fR reads the configuration file \fI\f(CI$HOME\fI/.openpkg/build\fR. +The file lists default options, one option per line and section tags +of the form \f(CW\*(C`[\*(C'\fR\fIprefix\fR\f(CW\*(C`]\*(C'\fR. Options following such a tag are only +evaluated for the particular \fBOpenPKG\fR instance so that you can +define default options for multiple \fBOpenPKG\fR instances. +.PP +Example: +.PP +.Vb 2 +\& # global options +\& \-X +\& +\& [/openpkg/current] +\& # options for CURRENT stack only +\& \-r http://download.openpkg.org/stacks/current/source/ +\& +\& [/openpkg/foo] +\& # options for a FOO stack only +\& \-r http://download.openpkg.org/stacks/foo/source/ +.Ve +.SH "EXAMPLES" +.IX Header "EXAMPLES" +The following shows a few typical OpenPKG instance +maintenance tasks which involve the \fBopenpkg build\fR command: +.SS "Installation" +.IX Subsection "Installation" +The following examples shows how to initially install an OpenPKG +instance under \fI/openpkg\fR with Apache/PHP & MySQL: +.PP +.Vb 5 +\& # bootstrap the OpenPKG instance +\& $ curl \-L \-O http://openpkg.org/go/download/openpkg.src.sh +\& $ sh openpkg\-*\-*.src.sh \-\-prefix=/openpkg \e +\& \-\-user=openpkg \-\-group=openpkg \-\-tag=openpkg +\& $ sh openpkg\-*\-*.*\-*\-openpkg.sh +\& +\& # install Apache/PHP & MySQL +\& $ /openpkg/bin/openpkg build \e +\& \-D apache\-php::with_mysql=yes \e +\& apache apache\-php mysql | sh +.Ve +.SS "Reinstallation" +.IX Subsection "Reinstallation" +The following example shows how to rebuild and reinstall the already +installed package \*(L"foo\*(R": +.PP +.Vb 2 +\& # rebuild and reinstall package +\& $ /openpkg/bin/openpkg build \-g \-u foo | sh +.Ve +.SS "Change" +.IX Subsection "Change" +The following fictive example shows how to change the already +installed package \*(L"foo\*(R" by rebuilding and reinstalling it with the +"\f(CW\*(C`foo::with_bar\*(C'\fR" build-time option enabled. +.PP +.Vb 2 +\& # change a package +\& $ /openpkg/bin/openpkg build \-g \-D with_bar=yes foo | sh +.Ve +.SS "Update" +.IX Subsection "Update" +The following example shows how to update (no major +OpenPKG version change) an OpenPKG instance under \fI/openpkg\fR: +.PP +.Vb 2 +\& # update all packages to their latest version +\& $ /openpkg/bin/openpkg build \-Ua | sh +.Ve +.SS "Upgrade" +.IX Subsection "Upgrade" +The following examples shows a complete procedure for upgrading (major +OpenPKG version change) the instance under \fI/openpkg\fR to OpenPKG +4.X: +.PP +.Vb 3 +\& # upgrade the bootstrap package +\& $ /openpkg/bin/openpkg build \e +\& \-r http://download.openpkg.org/stacks/current/source/ openpkg | sh +\& +\& # upgrade the whole OpenPKG instance, in correct dependency +\& # order and by keeping all chosen build\-time options. +\& $ /openpkg/bin/openpkg build \-ZaKB | sh +.Ve +.SS "Deinstallation" +.IX Subsection "Deinstallation" +The following example shows how to deinstall +an entire OpenPKG intance under \fI/openpkg\fR: +.PP +.Vb 3 +\& # remove all packages and the instance itself +\& $ /openpkg/bin/openpkg rpm \-e \e +\& \`/openpkg/bin/openpkg rpm \-qa\` +.Ve +.SH "CAVEATS" +.IX Header "CAVEATS" +Parallel execution of \fBopenpkg build\fR causes undefined effects. +.SH "HISTORY" +.IX Header "HISTORY" +The \fBopenpkg build\fR command was invented in November 2002 by \fIMichael +van Elst\fR under contract with \fICable +& Wireless\fR for use inside the \fBOpenPKG\fR +project . It was then further +refined by the \fBOpenPKG Foundation e.V.\fR as part of the OpenPKG Tool Chain. diff -r 71503088f51b -r f880f219c566 openpkg/build.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/build.pl Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,2603 @@ +## +## build.pl -- OpenPKG Package Building and Installing +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +############################################################################# +## +## MAIN PROCEDURE +## +############################################################################# + +require 5; +#use strict; +my ( + $opt_h, + $opt_R, $opt_r, $opt_f, $opt_u, $opt_U, $opt_a, $opt_A, + $opt_z, $opt_Z, $opt_P, $opt_N, $opt_E, $opt_H, $opt_i, + $opt_D, $opt_p, $opt_q, $opt_s, $opt_S, $opt_X, $opt_M, + $opt_L, $opt_W, $opt_K, $opt_e, $opt_b, $opt_B, $opt_g, + $opt_k +); + +# global context variables +my $prg = "openpkg build"; +my %env = ('' => {}); + +## +## OPTION PARSING +## + +# parse command line options +my $getopts = 'hR:r:f:uUaAzZP:N:E:H:iD:p:qsSXMLWKebBgk'; +getopts($getopts); + +# parse configuration script options +if (open(FH, "<$ENV{'HOME'}/.openpkg/build")) { + my ($env) = $env{''}; + my ($go) = $getopts; + $go =~ s/[^a-zA-Z]//g; + while (my $line = ) { + if ($line =~ m/^\s*\[([^\]]*)\]/) { + $env{$1} = {} unless ($env{$1}); + $env = $env{$1}; + } elsif (my ($opt, $val) = ($line =~ m/^\-([$go])\s*(.*?)\s*$/)) { + $val = 1 unless (defined($val)); + if (exists($env->{$opt})) { + $env->{$opt} .= " " . $val; + } else { + $env->{$opt} = $val; + } + } + } + close(FH); +} + +# usage sanity check and usage help +sub usage { + my ($rc) = @_; + my $usage = + "openpkg:build:USAGE: $prg [options] [pattern ...]\n" . + " -a operate on all installed packages\n" . + " -A operate on all repository packages\n" . + " -R path to \"openpkg rpm\" command\n" . + " -r URL to package repository directory\n" . + " -f URL to package repository index file\n" . + " -u ignore local binary RPMs\n" . + " -U upgrade all selected packages including dependencies\n" . + " -z rebuild from zero all selected installed packages\n" . + " -Z rebuild from zero all selected available packages\n" . + " -i ignore errors in the generated script\n" . + " -q ignore all reverse dependencies\n" . + " -s generate status map instead of shell script\n" . + " -S generate status map instead of shell script (including new)\n" . + " -X use external XML/RDF parser instead of internal one\n" . + " -M generate short dependency map instead of shell script\n" . + " -L generate list of packages in repository depending on target\n" . + " -W include dependencies as if all build options are enabled\n" . + " -K keep temporarily installed packages\n" . + " -k keep temporarily downloaded packages\n" . + " -e rebuild exact version of a package from repository\n" . + " -b build-time check existing binaries for dependencies only\n" . + " -B build-time check existing binaries for dependencies and target\n" . + " -g rebuild packages even when most recent version is installed\n" . + " -P command prefix for privileged commands\n" . + " -N command prefix for non-privileged commands\n" . + " -p match platform against repository index for binary packages\n" . + " -E exclude package\n" . + " -H hint about packages to resolve ambiquity\n" . + " -D [=] set build option for packages\n"; + if ($rc == 0) { + print STDOUT $usage; + } + else { + print STDERR $usage; + } + exit($rc); +} +if ($opt_h) { + usage(0); +} +if (not ( ($#ARGV >= 0 && !($opt_a || $opt_A)) + || ($#ARGV == -1 && ($opt_a || $opt_A)))) { + usage(1); +}; + +# determine RPM run-time information +my $config = rpm_runtime_info(); + +# override command line options with configuration script options +# now that the effectively used OpenPKG RPM command is known +foreach my $env (sort { $a cmp $b } grep { + $config->{"rpm"} =~ m/^\Q$_\E/ # compatibility + or $config->{"prefix"} =~ m/^\Q$_\E/ # regular +} keys %env) { + while (my ($opt, $val) = each(%{$env{$env}})) { + eval "\$opt_$opt = '$val' unless defined \$opt_$opt;"; + } +} + +## +## OPTION POST-PROCESSING +## + +my ($url, $repository, $installed, $env, $list, $bonly, $clist); +my ($pattern, %with, %exclude, %hint); + +# determine package goal pattern +if ($opt_a) { + $pattern = undef; +} else { + $pattern = join(' ', @ARGV); +} +if ($opt_A) { + $pattern = '*'; +} + +# parse build options +%with = map { + m/([^\s=]+)(?:\=(\S+))?/ + ? ($1 => (defined($2) ? $2 : 'yes')) + : () +} split(/\s+/, $opt_D); + +# split accumulated option values +%exclude = map { $_ => 1 } split(/\s+/, $opt_E); +%hint = map { $_ => 1 } split(/\s+/, $opt_H); + +if (defined($opt_p)) { + $config->{platform} = $opt_p; +} + +# determine RPM package repository information +if (defined $opt_r) { + $url = $opt_r; + $url .= '/' unless $url =~ m/\/$/; +} else { + $url = rpm_release_url(); +} +# if we read the index from a file we can no longer deduce +# repository paths from index paths. For now lets assume +# that everything is below SRC/ to be compatible with +# existing file indexes. +if (defined($opt_f) and not defined($opt_r)) { + $url .= 'SRC/'; +} + +# determine information about INSTALLED packages (virtual and regular), +# including their options, provides and requirements +my $installed = get_installed(); + +# SPECIAL CASE post-processing for +# -Z (ignore installed packages) +# -a (operate for all installed packages) +if ($opt_a and $opt_Z) { + # This allows one to correctly upgrade an existing OpenPKG + # instance to a newer major version by querying all installed + # packages and their options (-a) but then ignore them (-Z) during + # the later processing and instead perform more or less a fresh + # rebuild from scratch. This ensures that during the process the + # installed packages are effectively picked up as dependencies + # only after they in turn were already updated. + foreach my $package (keys(%{$installed})) { + next if ($package =~ m/::/); + if (exists($installed->{$package}->{""})) { + # virtual package + $hint{$installed->{$package}->{""}->[0]->{"name"}} = 1 + if (exists($installed->{$package}->{""}->[0]->{"name"})); + } + else { + # regular package + $pattern .= " $package"; + foreach my $version (keys(%{$installed->{$package}})) { + foreach my $rec (@{$installed->{$package}->{$version}}) { + if (defined($rec->{"OPTIONS"})) { + my $options = $rec->{"OPTIONS"}; + foreach my $option (keys(%{$options})) { + $with{$package."::".$option} = $options->{$option}; + } + } + } + } + } + } +} +if ($opt_Z) { + $installed = {}; +} + +# determine information about AVAILABLE packages +# by fetching and parsing a package repository XML/RDF index +$repository = get_index( + $url . '00INDEX.rdf', + $opt_f, + $opt_X, + $config->{platform}, + $installed +); + +# assemble together all determined environment information +$env = { + config => $config, + installed => $installed, + repository => $repository, + built => {}, + revdep => undef, + with => \%with, + exclude => \%exclude, + hint => \%hint, + upgrade => ($opt_a || $opt_U), + zero => ($opt_z || $opt_Z), + exact => $opt_e, + quick => ($opt_q || $opt_z || $opt_Z), + status => ($opt_s || $opt_S), + fatal => [], + goals => $opt_g, + sourceonly => ($opt_u || $opt_U || $opt_z || $opt_Z) +}; + +## +## PERFORM REQUESTED OPERATION +## + +if ($opt_L) { + # case 1: calculate dependencies only and + # print packages depending on target + ($list) = build_deps($pattern, $env); + print_deps($list); +} else { + # case 2: calculate build commands and + # print results in different formats + ($list, $bonly, $clist) = build_list($pattern, $env); + die "openpkg:build:FATAL: cannot find package\n" if (not defined($list)); + if ($opt_M) { + print_map($installed, $repository, $list, $bonly, $clist); + } elsif ($opt_S) { + print_status($installed, $repository, $list, $bonly, $clist); + } elsif ($opt_s) { + print_status($installed, {}, $list, $bonly, $clist); + } else { + if (@{$env->{fatal}}) { + die "openpkg:build:FATAL: errors occured while building:\n", @{$env->{fatal}}, "\n"; + } + print_list1($list, $config, $opt_a || $opt_u || $opt_U, $env->{with}, $opt_i, $opt_b, $opt_B); + print_list2($bonly, $config) if (not $opt_K); + } +} + +# die gracefully +exit(0); + +############################################################################# +## +## FUNCTIONS: PARSING & RUN-TIME INFORMATION +## +############################################################################# + +# home-brewn getopt(3) style option parser +sub getopts ($) { + my ($opts) = @_; + my (%optf) = map { m/(\w)/; $1 => $_ } $opts =~ m/(\w:|\w)/g; + my (%opts, @argv, $optarg); + + foreach (@ARGV) { + if (@argv) { + push @argv, $_; + } elsif (defined $optarg) { + if (exists $opts{$optarg}) { + $opts{$optarg} .= " $_"; + } else { + $opts{$optarg} = $_; + } + $optarg = undef; + } elsif (!/^[-]/) { + push @argv, $_; + } else { + while (/^\-(\w)(.*)/) { + if (exists $optf{$1}) { + if (length($optf{$1}) > 1) { + if ($2 ne '') { + if (exists $opts{$1}) { + $opts{$1} .= " $2"; + } else { + $opts{$1} = $2; + } + } else { + $optarg = $1; + } + last; + } else { + $opts{$1} = 1; + } + } else { + warn "openpkg:build:WARNING: unknown option $_\n"; + } + $_ = "-$2"; + } + } + } + if (defined $optarg) { + warn "openpkg:build:WARNING: option $optarg requires an argument\n"; + } + foreach (keys %opts) { + eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";'; + } + @ARGV = @argv; +} + +# determine RPM run-time information +sub rpm_runtime_info () { + # determine OpenPKG instance prefix via + # 1. the environment of the "openpkg build" framework + # 2. the installation path of the script + # 3. the installation path of the Perl interpreter + # 4. the path of the "openpkg" command in $PATH + my $l_prefix = $ENV{'OPENPKG_PREFIX'}; + if (not $l_prefix) { + ($l_prefix) = ($0 =~ m/^(.+)\/lib(exec)?\/openpkg(-tools)?\/build(\.pl)?$/); + } + if (not $l_prefix) { + ($l_prefix) = ($^X =~ m/^(.+)\/bin\/perl.*$/); + } + if (not $l_prefix) { + $l_prefix = (`(which openpkg) 2>/dev/null` =~ m/^(.+)\/bin\/openpkg$/); + } + if (not -x "$l_prefix/bin/openpkg") { + die "openpkg:build:FATAL: cannot determine OpenPKG instance prefix"; + } + print "# operating with OpenPKG instance $l_prefix\n"; + + # determine OpenPKG RPM command + my $rpm = $opt_R || $env{''}->{'R'} || + ((-f "$l_prefix/bin/openpkg" && -f "$l_prefix/libexec/openpkg/rpm") ? + "$l_prefix/bin/openpkg rpm" : "$l_prefix/bin/rpm"); + $rpm = (`(which $rpm) 2>/dev/null` =~ m{^(/.*)})[0] if ($rpm !~ m|^/|); + die "openpkg:build:FATAL: cannot locate OpenPKG RPM in path" unless ($rpm =~ m{^/}); + print "# operating with OpenPKG RPM $rpm\n"; + + # determine additional tools + my $mkp = "$l_prefix/bin/openpkg makeproxy"; + my $rel = "$l_prefix/bin/openpkg release"; + my $bzip2 = $rpm; + $bzip2 =~ s/\/bin\/openpkg rpm$/\/lib\/openpkg\/bzip2/; + my $curl = $rpm; + $curl =~ s/\/bin\/openpkg rpm$/\/lib\/openpkg\/curl/; + $curl = "$l_prefix/bin/openpkg curl" if (system("$l_prefix/bin/openpkg curl file://$l_prefix/etc/openpkg/platform >/dev/null 2>&1") == 0); + + # expand RPM macros holding information + my $c = run("$rpm --eval '%{_rpmdir} %{_rpmfilename} %{_target_os} %{_target_cpu} %{_srcrpmdir}'"); + + # parse and post-process information + chomp($c); + my (@q) = split(/\s+/, $c); + $q[1] =~ s/%{OS}/$q[2]/; + $q[1] =~ s/%{ARCH}/$q[3]/; + + # expand RPM rc information about tools + $c = run("$rpm --showrc"); + my @g = ($c =~ m/\%\{l_tool_locate\s+([^\s\}]+)/g); + + # return accumulated information + return { + rpm => $rpm, + mkp => $mkp, + rel => $rel, + bzip2 => $bzip2, + curl => $curl, + rpmdir => $q[0], + srcrpmdir=> $q[4], + template => $q[1], + platform => '', + prefix => $l_prefix, + optreg => '(?:'. join('|', map { "\Quse_$_\E" } @g) .')' + }; +} + +# determine RPM release URL +sub rpm_release_url ($$) { + my ($rel, $url); + + # determine the release URL the newer way + $url = run("(".$config->{"rel"}." --fmt='%u') 2>/dev/null || true") || ""; + $url =~ s/^\s+//s; + $url =~ s/\s+$//s; + + # use a local jumpstart RDF + if (-f $config->{"prefix"}."/etc/openpkg/build.rdf") { + $url = "file://".$config->{"prefix"}."/etc/openpkg/build.rdf" + } + + return $url; +} + +############################################################################# +## +## FUNCTIONS: VERSION STRING HANDLING +## +############################################################################# + +# compare two package versions +# - "openpkg rpm": +# splits according to !isalnum(3) ([a-zA-Z0-9]) +# and between isdigit(3) ([0-9]) and isalpha(3) ([a-zA-Z]) +# - "openpkg build" (this): +# splits on "." characters +sub vcmp_version ($$) { + my ($a, $b) = @_; + my (@a, @b, $c); + my ($ax, $bx); + + # split according to dots + @a = split(/\./, $a); + @b = split(/\./, $b); + + # compare as long as components exist + while (@a && @b) { + if ($a[0] =~ m/^\d+$/ && $b[0] =~ m/^\d+$/) { + # numerical comparison + $c = $a[0] <=> $b[0]; + } elsif ((($a, $ax) = $a[0] =~ m/^(\d+)(.*)$/) && + (($b, $bx) = $b[0] =~ m/^(\d+)(.*)$/)) { + # numerical comparison for prefix, + # string comparison for remainder + $c = $a <=> $b; + $c = $ax cmp $bx unless ($c); + } else { + # string comparison + $c = $a[0] cmp $b[0]; + } + + # stop comparison if components already mismatched + return $c if ($c != 0); + + # else reduce by one component level + shift(@a); + shift(@b); + } + + # finally compare number of remaining components + # (in case one is more specific) + $c = (scalar(@a) <=> scalar(@b)); + return $c; +} + +# compare two package releases +# - "openpkg rpm": +# uses "vcmp_version" semantics 1:1 again +# - "openpkg build" (this): +# uses "vcmp_version" semantics 1:1 again (>= 20060719) +# trivial string comparison (<= 20060719) +sub vcmp_release ($$) { + my ($a, $b) = @_; + + return vcmp_version($a, $b); +} + +# compare two package "version" or "version-release" strings +# - "openpkg rpm": +# compares "epoch", "version", "release" (in this order) +# - "openpkg build" (this): +# compares "release", "version", (in this order) +sub vcmp ($$) { + my ($a, $b) = @_; + my ($c); + + # short-circuit comparison for simple case + return 0 if ($a eq $b); + + # split into "version" and "release" + my ($av, $ar) = ($a =~ m/^(.*?)(?:\-([\d\.]+))?$/); + my ($bv, $br) = ($b =~ m/^(.*?)(?:\-([\d\.]+))?$/); + + # compare "release" + if (defined($ar) and defined($br)) { + $c = vcmp_release($ar, $br); + return $c if ($c); # short-circuit + } + + # compare "version" + if (defined($av) && defined($bv)) { + $c = vcmp_version($av, $bv); + return $c if ($c); # short-circuit + } + + # equality + return 0; +} + +# create "version" or "version-release" string +# from a provide object (see parse_provides) +sub vs ($) { + my ($t) = @_; + return ( + defined($t->{release}) + ? "$t->{version}-$t->{release}" + : $t->{version} + ); +} + +# create "name-version" or "name-version-release" string +# from a provide object (see parse_provides) +sub vsn ($) { + my ($t) = @_; + return "$t->{name}-".vs($t); +} + +############################################################################# +## +## FUNCTIONS: INSTALLATION INFORMATION +## +############################################################################# + +# parse OpenPKG RPM 'provide' string +# "" (virtual package) +# " = -" (regular package) +# "::ICI + +=item ICI + +=item ICI + +=item ICI + +=back + +This is just the "simple" filesystem layout (see below) with the +I set to IC. + +This is the filesystem layout used by default for building OpenPKG +packages during C or the underlying C commands. + +=item B + +=over 4 + +=item IC + +=item ICIC<.spec> + +=item ICI + +=item ICI + +=item ICI + +=item ICI + +=item ICI + +=back + +This puts everything into one directory. + +=item B + +=over 4 + +=item ICIC + +=item ICICIC<.spec> + +=item ICICI + +=item ICICI + +=item ICI + +=item ICI + +=item I<$TMPDIR>CI + +=back + +This is the simple filesystem layout of an unpacked +OpenPKG package. All files are simply put into a sub-directory with the +I of the package. + +This is the filesystem layout used for the quick patching of a single +OpenPKG package in a stand-alone environment. + +=item B + +=over 4 + +=item ICIC + +=item ICICIC<.spec> + +=item ICICI + +=item ICICI + +=item ICIC[C]I + +=item ICIC[C]I + +=item ICICI + +=back + +This is the structured (and default) filesystem layout of an unpacked +OpenPKG package. A top-level sub-directory with the I of the +package is created. There the package specification and all packaging +source files are put into the sub-directory I and all the +third-party distribution files are put into the sub-directory I. + +This is the filesystem layout used for the development of a single +OpenPKG package in a stand-alone environment. + +=item B + +=over 4 + +=item ICC<.openpkg/rpmmacros> + +=item ICCICIC<.spec> + +=item ICCICI + +=item ICCICI + +=item ICC[C]I + +=item ICC[C]I + +=item ICCI + +=back + +This is the distributed filesystem layout of an unpacked OpenPKG +package. It is similar to the structured filesystem layout but the +C and C directories and the I directory are swapped, +mainly with the intention of bundling together all third-party +distribution files of a large number of packages. + +This is the filesystem layout used for regular OpenPKG package +development. + +=back + + +=head1 LOCAL RPM MACROS FILE (.openpkg/rpmmacros) + +OpenPKG supports local RPM macros files F<.openpkg/rpmmacros> which +can be used to configure RPM in a local scope. This is especially +interesting to configure a local (even per-package) build environment +with the help of the C<%openpkg_layout> macro. + +C<%openpkg_layout> +[CI] +[CI] +[CI] +[CI] +[CI] +[CI] +[CI] +[CI] +[CI] +[CI] + +=over 4 + +=item CI + +Absolute file path of the C<.openpkg/rpmmacros> file where this +C<%openpkg_layout> macro is defined. Usually, the intended usage is to +leverage from OpenPKG RPM's special C<%{macrosfile}> macro by simply +using C. This parameter is important as +the default C is derived from it. + +=item CI + +Absolute directory path where the C<.openpkg/rpmmacros> file is +located under. Usually, the intended usage is to not explicitly +set this parameter but let it be determined indirectly via +C. The effective default value is equal to a value like +C<%{realpath:%{dirname:%{realpath:%{macrosfile}}}/..}> This parameter is +important as all standard filesystem layouts (see parameter C) +are always at least partially based on this base directory in order +to provide absolute-path-independent flexible filesystem layouts. + +=item CI + +The name of the filesystem layout type to use. The following standard +filesystem layout types are pre-defined: C, C, C, +C (default) and C. + + global macrosdir /etc/openpkg + global macrosfile /etc/openpkg/rpmmacros + global specdir /RPM/SRC/$name + global sourcedir /RPM/SRC/$name + global builddir /RPM/TMP + global tmpdir /RPM/TMP + global binrpmdir /RPM/PKG + global srcrpmdir /RPM/PKG + + local macrosdir /.openpkg + local macrosfile /.openpkg/rpmmacros + local specdir + local sourcedir + local builddir + local tmpdir + local binrpmdir + local srcrpmdir + + simple macrosdir /.openpkg + simple macrosfile /.openpkg/rpmmacros + simple specdir + simple sourcedir + simple builddir + simple tmpdir + simple binrpmdir /.. + simple srcrpmdir /.. + + structured macrosdir /.openpkg + structured macrosfile /.openpkg/rpmmacros + structured specdir /src + structured sourcedir /dst + structured builddir /tmp + structured tmpdir /tmp + structured binrpmdir /pkg/bin + structured srcrpmdir /pkg/src + + distributed macrosdir /.openpkg + distributed macrosfile /.openpkg/rpmmacros + distributed specdir /src/ + distributed sourcedir /dst/ + distributed builddir /tmp + distributed tmpdir /tmp + distributed binrpmdir /pkg/bin + distributed srcrpmdir /pkg/src + + +=item CI + +=item CI + +=item CI + +=item CI + +=item CI + +=item CI + +These parameters correspond to the six individual directories provided +by a standard layout and allow you to selectively adjust parts of a +standard layout to local needs and without having to define a full +standard layout yourself. + +The I is a whitespace-separated list of +I[C<:>[C<+>]I] specifications which are +"first-match" searched for existence. The last directory in the list +is always taken as the fallback and if it is not existing it is +even created on-the-fly. The IC<:>I +syntax variant allows the existence test to use I, +but expands to I (replace mode). The +IC<:+>I syntax variant allows +the existence test to use I, but expands to +II (append mode). For instance +C will first check for ~/tmp (and then use +~/tmp/openpkg), then for $TMPDIR (and use $TMPDIR/openpkg) and finally +it will use /tmp/$LOGNAME/openpkg at last resort. + +Paths are usually assembled by using RPM macros like +C<%{l_prefix}> (the instance prefix), C<%{__openpkg_basename}> (the +I parameter), C<%{realpath:} (path resolution), +C<%{dirname:} (directory name extraction), C<%{basename:} +(file name extraction), etc. + +=item CI + +This enables the I components in the standard filesystem +layouts by setting it to an automatically generated sub-directory named +IC<->I-I. This allows one to build the same OpenPKG +package in parallel on multiple hosts in a shared environment (usually +on an NFS based filesystem). + +=item CI + +This enables debug outputs which shows the effectively used directory +paths. + +=back + +The generated C<.openpkg/rpmmacros> file contains the generic filesystem +layout glue configuration for the particular filesystem I. + +=over 1 + +=item C<%openpkg_layout macrosfile=%{macrosfile} layout=>I + +=back + +=head1 CONFIGURATION + +=over 4 + + OPENPKG_NAME="Ralf S. Engelschall" + OPENPKG_MAIL="rse@openpkg.net" + OPENPKG_MODE="developer" + + OPENPKG_PREFIX="/openpkg" + OPENPKG_TMPDIR="${TMPDIR-/tmp}/openpkg" + + OPENPKG_VCS="cvs ci -m '' ." + OPENPKG_UPLD="scp openpkg-ftp@ftp.openpkg.org:/current/SRC/00UPLOAD/" + +=back + +=head1 ABOUT + +OpenPKG B is Ralf S. Engelschall's Perl-based clean-room partial +re-implementation of 2008 for OpenPKG 4.0 of Thomas Lotterer's original +OpenPKG B Bash-based shell from 2002. + +=cut + diff -r 71503088f51b -r f880f219c566 openpkg/diffutils.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/diffutils.patch Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,77 @@ +Index: lib/c-stack.c +--- lib/c-stack.c.orig 2011-08-28 13:55:52.000000000 +0200 ++++ lib/c-stack.c 2012-05-12 10:06:32.000000000 +0200 +@@ -35,6 +35,10 @@ + + #include + ++#if defined(__FreeBSD__) ++#include ++#endif ++ + #ifndef __attribute__ + # if __GNUC__ < 3 + # define __attribute__(x) +Index: man/diff3.1 +--- man/diff3.1.orig 2011-09-02 17:19:12.000000000 +0200 ++++ man/diff3.1 2012-05-12 10:06:32.000000000 +0200 +@@ -39,6 +39,9 @@ + \fB\-a\fR, \fB\-\-text\fR + treat all files as text + .TP ++\fB\-O\fR ++Always show content of OLDFILE in bracketing output of unmerged changes. (OpenPKG only) ++.TP + \fB\-\-strip\-trailing\-cr\fR + strip trailing carriage return on input + .TP +Index: src/diff3.c +--- src/diff3.c.orig 2011-07-03 22:42:54.000000000 +0200 ++++ src/diff3.c 2012-05-12 10:06:32.000000000 +0200 +@@ -158,6 +158,9 @@ + /* If nonzero, show information for DIFF_2ND diffs. */ + static bool show_2nd; + ++/* If nonzero, show information for DIFF_2ND on overlaps, too. */ ++static bool show_2nd_on_overlap; ++ + /* If nonzero, include `:wq' at the end of the script + to write out the file being edited. */ + static bool finalwrite; +@@ -237,7 +240,7 @@ + textdomain (PACKAGE); + c_stack_action (0); + +- while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != -1) ++ while ((c = getopt_long (argc, argv, "aeimvx3AEL:TXO", longopts, 0)) != -1) + { + switch (c) + { +@@ -272,6 +275,9 @@ + case 'e': + incompat++; + break; ++ case 'O': ++ show_2nd_on_overlap = true; ++ break; + case 'T': + initial_tab = true; + break; +@@ -1547,7 +1553,7 @@ + leading_dot = false; + if (type == DIFF_ALL) + { +- if (show_2nd) ++ if (show_2nd || show_2nd_on_overlap) + { + /* Append lines from FILE1. */ + fprintf (outputfile, "||||||| %s\n", file1); +@@ -1686,7 +1692,7 @@ + D_RELLEN (b, mapping[FILE0], i), outputfile); + } + +- if (show_2nd) ++ if (show_2nd || show_2nd_on_overlap) + { + /* Put in lines from FILE1 with bracket. */ + fprintf (outputfile, format_2nd, file1); diff -r 71503088f51b -r f880f219c566 openpkg/dot.bash_login --- a/openpkg/dot.bash_login Tue Jul 31 12:12:54 2012 +0200 +++ b/openpkg/dot.bash_login Tue Jul 31 12:23:42 2012 +0200 @@ -1,5 +1,24 @@ ## ## @l_prefix@/.bash_login -- Local Bash Login Script +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. ## # provide user and host information in default prompt diff -r 71503088f51b -r f880f219c566 openpkg/etc.prereq.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/etc.prereq.sh Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,86 @@ +#!/bin/sh +## +## etc.prereq.sh -- Platform Pre-Requisite Checks +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## +## Usage: etc.prereq.sh source|binary +## + +mode="$1" + +# CHECK: determine platform ids +platform_prod=`sh ./shtool platform -n -L -S "" -C "+" -F "%-%"` +platform_tech=`sh ./shtool platform -n -L -S "" -C "+" -F "%-%"` +echo "++ platform product: $platform_prod" +echo "++ platform technology: $platform_tech" + +# +# CHECK: diskspace requirement +# +if [ ".$mode" = .source ]; then + fs_path="${TMPDIR-/tmp}" + fs_need=150000 +else + fs_path="" # FIXME + fs_need=0 # FIXME +fi +fs_free="" +case "$platform_tech" in + *-freebsd* | *-netbsd* | *-linux* | *-sunos* ) + fs_free=`cd $fs_path && /bin/df -k . | sed -n -e '$p' | sed -e 's;^[^ ]*;;' -e 's; *;;' | awk '{ print $3; }'` + ;; +esac +if [ ".$fs_free" != . ]; then + if [ $fs_free -lt $fs_need ]; then + if [ ".$mode" = .source ]; then + echo "ERROR: temporary directory \"$fs_path\" has to reside on a partition" 1>&2 + echo " with at least $fs_need KB of free disk space. Set \$TMPDIR to" 1>&2 + echo " a directory on a partition with enough free disk space, please." 1>&2 + else + echo "ERROR: installation directory \"$fs_path\" has to reside on a partition" 1>&2 + echo " with at least $fs_need KB of free disk space. Make \"$fs_path\" a" 1>&2 + echo " symbolic link to a directory on a partition with enough free" 1>&2 + echo " disk space, please." 1>&2 + fi + exit 1 + fi +fi + +# +# CHECK: available vendor packages +# +# ...FIXME... + +# +# CHECK: available tools in $PATH +# +# ...FIXME... + +# +# CHECK: available devices /dev/random, etc. +# +# ...FIXME... + +# +# CHECK: consistency check for /prefix (symlink!) +# +# ...FIXME... + diff -r 71503088f51b -r f880f219c566 openpkg/etc.usrgrp.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/etc.usrgrp.sh Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,221 @@ +#!/bin/sh +## +## etc.usrgrp.sh -- user/group name/id determination +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# command line parameters (defaults) +help=0 +usr=''; grp='' +susr=''; sgrp='' +musr=''; mgrp='' +rusr=''; rgrp='' +nusr=''; ngrp='' +suid=''; sgid='' +muid=''; mgid='' +ruid=''; rgid='' +nuid=''; ngid='' + +# parse command line options +for opt +do + case $opt in + -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;; + *) arg='' ;; + esac + case $opt in + -h | --help ) help=1 ;; + --usr=* | --user=* ) usr=$arg ;; + --grp=* | --group=* ) grp=$arg ;; + --susr=* ) susr=$arg ;; + --sgrp=* ) sgrp=$arg ;; + --musr=* ) musr=$arg ;; + --mgrp=* ) mgrp=$arg ;; + --rusr=* ) rusr=$arg ;; + --rgrp=* ) rgrp=$arg ;; + --nusr=* ) nusr=$arg ;; + --ngrp=* ) ngrp=$arg ;; + --suid=* ) suid=$arg ;; + --sgid=* ) sgid=$arg ;; + --muid=* ) muid=$arg ;; + --mgid=* ) mgid=$arg ;; + --ruid=* ) ruid=$arg ;; + --rgid=* ) rgid=$arg ;; + --nuid=* ) nuid=$arg ;; + --ngid=* ) ngid=$arg ;; + * ) help=1 ;; + esac +done +if [ ".$help" = .1 ]; then + echo "Usage: sh $0 [-h|--help]" 2>&1 + echo " [--[smrn]?usr=] [--[smrn]?grp=]" 2>&1 + echo " [--[smrn]uid=] [--[smrn]gid=]" 2>&1 + exit 1 +fi + +# determine cusr/cgrp +cusr=`(id -un) 2>/dev/null ||\ + (id | sed -e 's;^[^(]*(\([^)]*\)).*;\1;') 2>/dev/null ||\ + (whoami) 2>/dev/null ||\ + (who am i | cut "-d " -f1) 2>/dev/null ||\ + echo $LOGNAME` +cgid=`(id -g $cusr) 2>/dev/null ||\ + ((getent passwd "${cusr}"; grep "^${cusr}:" /etc/passwd; ypmatch "${cusr}" passwd; nismatch "${cusr}" passwd; nidump passwd . | grep "^${cusr}:") 2>/dev/null |\ + sed -n -e '1p' | awk -F: '{ print $4; }')` +cgrp=`(id -gn $cusr) 2>/dev/null ||\ + ((getent group; cat /etc/group; ypcat group; niscat group; nidump group .) 2>/dev/null | grep "^[^:]*:[^:]*:${cgid}:" |\ + sed -n -e '1p' | awk -F: '{ print $1; }')` +[ ".$cgrp" = . ] && cgrp="$cusr" + +# determine OpenPKG susr/sgrp +if [ ".$susr" = . ]; then + if [ ".$usr" = . ]; then + susr="$cusr" + else + susr="root" + fi +fi +if [ ".$sgrp" = . ]; then + sgrp=`(id -gn $susr) 2>/dev/null` + if [ ".$sgrp" = . ]; then + tgid=`(getent passwd "${susr}"; grep "^${susr}:" /etc/passwd; ypmatch "${susr}" passwd; nismatch "${susr}" passwd; nidump passwd . | grep "^${susr}:") 2>/dev/null |\ + sed -n -e '1p' | awk -F: '{ print $4; }'` + if [ ".$tgid" != . ]; then + sgid="${tgid}" + sgrp=`(getent group; cat /etc/group; ypcat group; niscat group; nidump group .) 2>/dev/null |\ + grep "^[^:]*:[^:]*:${sgid}:" | sed -n -e '1p' | awk -F: '{ print $1; }'` + fi + if [ ".$sgrp" = . ]; then + sgrp="wheel" + fi + fi +fi + +# determine OpenPKG musr/mgrp +if [ ".$musr" = . ]; then + musr="$usr" +fi +if [ ".$musr" = . ]; then + musr="$cusr" +fi +if [ ".$mgrp" = . ]; then + mgrp=`(id -gn $musr) 2>/dev/null` + if [ ".$mgrp" = . ]; then + tgid=`(getent passwd "${musr}"; grep "^${musr}:" /etc/passwd; ypmatch "${musr}" passwd; nismatch "${musr}" passwd; nidump passwd . | grep "^${musr}:") 2>/dev/null |\ + sed -n -e '1p' | awk -F: '{ print $4; }'` + if [ ".$tgid" != . ]; then + mgid="${tgid}" + mgrp=`(getent group; cat /etc/group; ypcat group; niscat group; nidump group .) 2>/dev/null |\ + grep "^[^:]*:[^:]*:${mgid}:" | sed -n -e '1p' | awk -F: '{ print $1; }'` + fi + if [ ".$mgrp" = . ]; then + mgrp="$grp" + fi + if [ ".$mgrp" = . ]; then + mgrp="$cgrp" + fi + fi +fi + +# determine OpenPKG rusr/rgrp +if [ ".$rusr" = . ]; then + rusr="${usr}-r" +fi +if [ ".$rusr" = ".-r" ]; then + rusr="$cusr" +fi +if [ ".$rgrp" = . ]; then + rgrp=`(id -gn $rusr) 2>/dev/null` + if [ ".$rgrp" = . ]; then + tgid=`(getent passwd "${rusr}"; grep "^${rusr}:" /etc/passwd; ypmatch "${rusr}" passwd; nismatch "${rusr}" passwd; nidump passwd . | grep "^${rusr}:") 2>/dev/null |\ + sed -n -e '1p' | awk -F: '{ print $4; }'` + if [ ".$tgid" != . ]; then + rgid="${tgid}" + rgrp=`(getent group; cat /etc/group; ypcat group; nismatch group; nidump group .) 2>/dev/null |\ + grep "^[^:]*:[^:]*:${rgid}:" | sed -n -e '1p' | awk -F: '{ print $1; }'` + fi + if [ ".$rgrp" = . ]; then + rgrp="${grp}-r" + fi + if [ ".$rgrp" = ".-r" ]; then + rgrp="$cgrp" + fi + fi +fi + +# determine OpenPKG nusr/ngrp +if [ ".$nusr" = . ]; then + nusr="${usr}-n" +fi +if [ ".$nusr" = ".-n" ]; then + nusr="$cusr" +fi +if [ ".$ngrp" = . ]; then + ngrp=`(id -gn $nusr) 2>/dev/null` + if [ ".$ngrp" = . ]; then + tgid=`(getent passwd "${nusr}"; grep "^${nusr}:" /etc/passwd; ypmatch "${nusr}" passwd; nismatch "${nusr}" passwd; nidump passwd . | grep "^${nusr}:") 2>/dev/null |\ + sed -n -e '1p' | awk -F: '{ print $4; }'` + if [ ".$tgid" != . ]; then + ngid="${tgid}" + ngrp=`(getent group; cat /etc/group; ypcat group; niscat group; nidump group .) 2>/dev/null |\ + grep "^[^:]*:[^:]*:${ngid}:" | sed -n -e '1p' | awk -F: '{ print $1; }'` + fi + if [ ".$ngrp" = . ]; then + ngrp="${grp}-n" + fi + if [ ".$ngrp" = ".-n" ]; then + ngrp="$cgrp" + fi + fi +fi + +# determine OpenPKG suid/sgid +# (currently not necessary) + +# determine OpenPKG muid/mgid +# (currently not necessary) + +# determine OpenPKG ruid/rgid +# (currently not necessary) + +# determine OpenPKG nuid/ngid +# (currently not necessary) + +# print results +output="" +for var in \ + susr sgrp \ + musr mgrp \ + rusr rgrp \ + nusr ngrp \ + suid sgid \ + muid mgid \ + ruid rgid \ + nuid ngid; do + eval "val=\"\$$var\"" + if [ ".$output" = . ]; then + output="$var=\"$val\"" + else + output="$output; $var=\"$val\"" + fi +done +echo $output + diff -r 71503088f51b -r f880f219c566 openpkg/etc.wrapbin.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/etc.wrapbin.sh Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,267 @@ +#!/bin/sh +#![OpenPKG] +## +## OpenPKG Binary Bootstrap Package (self-extracting shell script) +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# configuration +l_me="$0" +o_help=no +o_version=no +o_tar=no +l_prefix='@l_prefix@' +l_musr='@MUSR@' +l_mgrp='@MGRP@' +l_platform="@l_platform@" +l_release="@l_release@" +l_version="@l_version@" +l_unprivileged="@l_unprivileged@" + +# establish standard environment +PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin" +LC_CTYPE=C +export LC_CTYPE +umask 022 + +# parse command line options +for opt +do + case $opt in + -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;; + *) arg='' ;; + esac + case $opt in + -h | --help ) o_help=yes ;; + -v | --version ) o_version=yes ;; + -t | --tar ) o_tar=yes ;; + --prefix=* ) l_prefix=$arg ;; + * ) o_help=yes ;; + esac +done +if [ ".$o_version" = .no -a ".$l_prefix" = . ]; then + o_help=yes +fi +if [ ".$o_help" = .yes ]; then + echo "Usage: sh $l_me" 2>&1 + echo " [--prefix=] [-t|--tar]" 2>&1 + echo " [-h|--help] [-v|--version]" 2>&1 + exit 1 +fi + +# make sure all essential installation tools are available +for tool in sed mkdir dd tar chown chgrp; do + found=no + case $tool in + /* ) + if [ -f $tool ]; then + found=yes + fi + ;; + * ) + for p in `IFS=:; echo $PATH`; do + if [ -f "$p/$tool" ]; then + found=yes + break + fi + done + ;; + esac + if [ ".$found" = .no ]; then + echo "$l_me:ERROR: unable to find installation tool \"$tool\"" 1>&2 + exit 1 + fi +done + +# optionally extract the embedded tarball only +if [ ".$o_tar" = .yes ]; then + tmpdir="${TMPDIR-/tmp}/openpkg.$$" + ( umask 077 && mkdir $tmpdir) || exit 1 + dd if=$l_me bs=8192 skip=8 2>/dev/null |\ + ( cd $tmpdir || exit 1 + tar xf - 2>/dev/null || exit 1 + ./openpkg.bzip2 -d -c openpkg.tar.bz2 + ) || exit 1 + rm -rf $tmpdir + exit 0 +fi + +# display version and copyright header +echo "OpenPKG ${l_release} Binary Bootstrap Package, version ${l_version}" +echo "Built for prefix ${l_prefix} on target platform ${l_platform}" +if [ ".$o_version" = .yes ]; then + exit 0 +fi + +# determine current username +cusr=`(id -un) 2>/dev/null ||\ + (id | sed -e 's;^[^(]*(\([^)]*\)).*;\1;') 2>/dev/null ||\ + (whoami) 2>/dev/null ||\ + (who am i | cut "-d " -f1) 2>/dev/null ||\ + echo ${LOGNAME-"NN"}` + +# running the embedded %pre script for hooking into the system environment +echo "++ hooking OpenPKG instance into system environment" +prefix="$l_prefix" +susr='@SUSR@'; sgrp='@SGRP@' +musr='@MUSR@'; mgrp='@MGRP@' +rusr='@RUSR@'; rgrp='@RGRP@' +nusr='@NUSR@'; ngrp='@NGRP@' +suid='@SUID@'; sgid='@SGID@' +muid='@MUID@'; mgid='@MGID@' +ruid='@RUID@'; rgid='@RGID@' +nuid='@NUID@'; ngid='@NGID@' +unprivileged="$l_unprivileged" +set -- 1 # emulate RPM's $1 when executing scripts +# ---- BEGIN EMBEDDED %pre SCRIPT ---- +@PRE@ +# ---- END EMBEDDED %pre SCRIPT ---- + +# make sure prefix/root directory exists +# and has correct permissions and owner/group +if [ ! -d $l_prefix ]; then + # create prefix/root directory from scratch + echo "++ creating OpenPKG instance root directory \"$l_prefix\"" + d='' + for c in `IFS=/; echo $l_prefix`; do + d="$d/$c" + if [ ! -d $d ]; then + mkdir $d || exit 1 + chmod 755 $d || exit 1 + if [ ".$cusr" = .root ]; then + chown $musr $d >/dev/null 2>&1 || true + chgrp $mgrp $d >/dev/null 2>&1 || true + fi + fi + done +else + # adjust already existing prefix/root directory + echo "++ fixating OpenPKG instance root directory \"$l_prefix\"" + ( cd $l_prefix || exit 1 + chmod 755 . || exit 1 + if [ ".$cusr" = .root ]; then + chown $musr . >/dev/null 2>&1 || true + chgrp $mgrp . >/dev/null 2>&1 || true + fi + ) || exit 1 +fi + +# extract and install binary distribution files +echo "++ extracting OpenPKG binary distribution" +dd if=$l_me bs=8192 skip=8 2>/dev/null |\ + (cd $l_prefix; tar xf - 2>/dev/null) +echo "++ installing OpenPKG binary distribution" +( cd $l_prefix || exit 1 + ./openpkg.bzip2 -d -c openpkg.tar.bz2 | ./openpkg.tar xf - 2>/dev/null + rm -f openpkg.tar openpkg.bzip2 openpkg.tar.bz2 >/dev/null 2>&1 || true +) || exit 1 + +# immediately activate BOOT license to let the +# following early RPM usage already work correctly +echo "BOOT" >$l_prefix/etc/openpkg/license + +# fixate installation files +# (ATTENTION: order of chgrp/chown and chmod is important because of "set-UID" bits) +echo "++ fixating OpenPKG instance filesystem hierarchy" +( echo 'fixate () {' + echo ' chgrp "$3" "$4"' + echo ' chown "$2" "$4"' + echo ' chmod "$1" "$4"' + echo '}' + cd / && $l_prefix/bin/openpkg --keep-privileges rpm -q openpkg \ + --qf '[fixate %7.7{FILEMODES:octal} %{FILEUSERNAME:shescape} %{FILEGROUPNAME:shescape} ::%{FILENAMES:shescape}\n]' |\ + grep -v '(none)' | sed 's/^fixate .../fixate /' | sed -e "s; ::\\(.\\)@l_prefix@; \\1$l_prefix;" +) | sh 2>/dev/null || true + +# running the embedded %post script +echo "++ post-processing OpenPKG bootstrap installation" +prefix="$l_prefix" +susr='@SUSR@'; sgrp='@SGRP@' +musr='@MUSR@'; mgrp='@MGRP@' +rusr='@RUSR@'; rgrp='@RGRP@' +nusr='@NUSR@'; ngrp='@NGRP@' +suid='@SUID@'; sgid='@SGID@' +muid='@MUID@'; mgid='@MGID@' +ruid='@RUID@'; rgid='@RGID@' +nuid='@NUID@'; ngid='@NGID@' +unprivileged="$l_unprivileged" +set -- 1 # emulate RPM's $1 when executing scripts +# ---- BEGIN EMBEDDED %post SCRIPT ---- +@POST@ +# ---- END EMBEDDED %post SCRIPT ---- + +# display final information +( echo "Congratulations!" + echo "" + echo "You have successfully installed an OpenPKG ${l_release} instance" + echo "under prefix ${l_prefix} on target platform ${l_platform}." + echo "" + echo "For details about this OpenPKG instance, run any of the" + echo "following typical OpenPKG RPM query commands:" + echo "" + echo " \$ ${l_prefix}/bin/openpkg rpm -qa" + echo " \$ ${l_prefix}/bin/openpkg rpm -qi openpkg" + echo " \$ ${l_prefix}/bin/openpkg rpm -qlv openpkg" + echo "" + echo "To check the integrity of the entire OpenPKG instance," + echo "run the following OpenPKG RPM verify command:" + echo "" + echo " \$ ${l_prefix}/bin/openpkg rpm -Va" + echo "" + echo "To install software packages into this OpenPKG instance, run" + echo "the following two OpenPKG RPM build commands for each package:" + echo "" + echo " \$ ${l_prefix}/bin/openpkg rpm --rebuild /path/to/foo-*.src.rpm" + echo " \$ ${l_prefix}/bin/openpkg rpm -Uvh ${l_prefix}/RPM/PKG/foo-*.rpm" + echo "" + echo "To leverage from remote indexes on download.openpkg.org and" + echo "conveniently generate a shell script for all-in-one downloading" + echo "(openpkg curl), building (openpkg rpm --rebuild) and installing" + echo "(openpkg rpm -Uvh) one or more OpenPKG RPM packages, including all" + echo "their transitive dependencies, in topologically correct order:" + echo "" + echo " \$ ${l_prefix}/bin/openpkg build foo bar quux | sh" + echo "" + echo "To remove a software package later, just run:" + echo "" + echo " \$ ${l_prefix}/bin/openpkg rpm -e foo" + echo "" + echo "To remove the whole OpenPKG instance under prefix ${l_prefix}," + echo "just remove every package as shown above. As you finally" + echo "remove the package \"openpkg\", the OpenPKG instance itself" + echo "will be unlinked from the system and removed as well." + echo "" + echo "Thank you for flying OpenPKG..." + echo " Ralf S. Engelschall" + echo " OpenPKG GmbH" + echo " openpkg.com" +) | $l_prefix/lib/openpkg/rpmtool msg -b -t info + +# die explicitly just before the shell would discover +# that we carry mega-bytes of data with us... ;-) +exit 0 + +# the distribution tarball is appended in raw format directly to the +# end of this script, just leaded by padding whitespaces which make +# sure that the tarball data starts at the pre-defined offset of 64KB. +# This allows us to unpack the tarball by just skipping the leading +# 64KB (= 8192*8, see above). + diff -r 71503088f51b -r f880f219c566 openpkg/etc.wrapsrc.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/etc.wrapsrc.sh Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,157 @@ +#!/bin/sh +#![OpenPKG] +## +## OpenPKG Source Bootstrap Package (self-extracting shell script) +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# configuration +l_me="$0" +o_help=no +o_version=no +o_tar=no +l_prefix='/openpkg' +l_dir='@l_dir@' +l_release="@l_release@" +l_version="@l_version@" + +# establish standard environment +PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin" +LC_CTYPE=C +export LC_CTYPE +umask 022 + +# pre-parse command line options +for opt +do + case $opt in + -*=*) arg=`echo "$opt" | sed 's/^[-_a-zA-Z0-9]*=//'` ;; + *) arg='' ;; + esac + case $opt in + -h | --help ) o_help=yes ;; + -v | --version ) o_version=yes ;; + -t | --tar ) o_tar=yes ;; + --prefix=* ) l_prefix=$arg ;; + esac +done +if [ ".$o_help" = .yes ]; then + echo "Usage: sh $l_me" 2>&1 + echo " [--prefix=] [--tag=]" 2>&1 + echo " [--stack=] [--unprivileged]" 2>&1 + echo " [--user=] [--group=]" 2>&1 + echo " [--{s,m,r,n}usr=] [--{s,m,r,n}grp=]" 2>&1 + echo " [--{s,m,r,n}uid=] [--{s,m,r,n}gid=]" 2>&1 + echo " [--use_tar=] [--use_make=] [--use_cc=]" 2>&1 + echo " [--use_ar=] [--use_ld=] [--use_as=] [--use_strip=]" 2>&1 + echo " [-t|--tar] [-h|--help] [-v|--version]" 2>&1 + exit 1 +fi + +# make sure all essential unpacking tools are available +# (the build tools are checked later from within openpkg.spec) +for tool in /bin/sh mkdir cat tar rm chown chgrp sed dd; do + found=no + case $tool in + /* ) + if [ -f $tool ]; then + found=yes + fi + ;; + * ) + for p in `IFS=:; echo $PATH`; do + if [ -f "$p/$tool" ]; then + found=yes + break + fi + done + ;; + esac + if [ ".$found" = .no ]; then + echo "$l_me:ERROR: unable to find bootstrap tool \"$tool\"" 1>&2 + exit 1 + fi +done + +# optionally extract the embedded tarball only +if [ ".$o_tar" = .yes ]; then + dd if=$l_me bs=8192 skip=8 2>/dev/null + exit 0 +fi + +# display version and copyright header +echo "OpenPKG ${l_release} Source Bootstrap Package, version ${l_version}" +if [ ".$o_version" = .yes ]; then + exit 0 +fi +echo "Building for prefix ${l_prefix} on current platform" + +# determine current user/group +cusr=`(id -un) 2>/dev/null ||\ + (id | sed -e 's;^[^(]*(\([^)]*\)).*;\1;') 2>/dev/null ||\ + (whoami) 2>/dev/null ||\ + (who am i | cut "-d " -f1) 2>/dev/null ||\ + echo $LOGNAME` +cgid=`(id -g $cusr) 2>/dev/null ||\ + ((getent passwd "${cusr}"; grep "^${cusr}:" /etc/passwd; ypmatch "${cusr}" passwd; nismatch "${cusr}" passwd; nidump passwd . | grep "^${cusr}:") 2>/dev/null |\ + sed -e 'q' | awk -F: '{ print $4; }')` +cgrp=`(id -gn $cusr) 2>/dev/null ||\ + ((getent group; cat /etc/group; ypcat group; niscat group; nidump group .) 2>/dev/null | grep "^[^:]*:[^:]*:${cgid}:" |\ + sed -e 'q' | awk -F: '{ print $1; }')` +if [ ".$cgrp" = . ]; then + cgrp="$cusr" +fi + +# extract the source distribution files +echo "++ extracting OpenPKG source distribution" +rm -rf $l_dir >/dev/null 2>&1 +mkdir $l_dir || exit 1 +dd if=$l_me bs=8192 skip=8 2>/dev/null | (cd $l_dir; tar xf - 2>/dev/null) +if [ ".$cusr" = .root ]; then + ( cd $l_dir || exit 1 + chown -R -h $cusr . >/dev/null 2>&1 || true + chgrp -R -h $cgrp . >/dev/null 2>&1 || true + ) || exit 1 +fi +if [ ! -f $l_dir/openpkg.boot ]; then + echo "$l_me:ERROR: failed to unpack into directory \"$l_dir\"" 1>&2 + exit 1 +fi + +# perform bootstrap procedure +echo "++ building OpenPKG binary distribution" +( cd $l_dir || exit 1 + sh ./openpkg.boot ${1+"$@"} || exit 1 +) || exit 1 + +# cleanup +rm -rf $l_dir >/dev/null 2>&1 + +# die explicitly just before the shell would discover +# that we carry mega-bytes of data with us... +exit 0 + +# the distribution tarball is appended in raw format directly to the +# end of this script, just leaded by padding whitespaces which make +# sure that the tarball data starts at the pre-defined offset of 64KB. +# This allows us to unpack the tarball by just skipping the leading +# 64KB (= 8192*8, see above). + diff -r 71503088f51b -r f880f219c566 openpkg/index.8 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/index.8 Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,218 @@ +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.22) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "INDEX 8" +.TH INDEX 8 "OpenPKG" "INDEX(8)" "OpenPKG" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +openpkg index \- OpenPKG Package Indexing +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBopenpkg\fR +\&\fBindex\fR +[\fB\-r\fR \fIresource\fR] +[\fB\-p\fR \fIplatform\fR] +[\fB\-S\fR] +[\fB\-T\fR] +[\fB\-D\fR] +[\fB\-C\fR \fIcache.db\fR] +[\fB\-o\fR \fIindex.rdf\fR] +[\fB\-c\fR] +[\fB\-i\fR] +\&\fIdir\fR ... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fBopenpkg index\fR tool is a frontend for indexing of \s-1RPM\s0 files. It +creates an \s-1XML/RDF\s0 based resource index for \s-1RPM\s0 \fI.spec\fR files in a +source tree or from an \s-1RPM\s0 package repository. The index holds enough +information to support an automated build process by \fBopenpkg build\fR. +.SH "OPTIONS" +.IX Header "OPTIONS" +The following command line options exist: +.IP "\fB\-r\fR \fIresource\fR" 4 +.IX Item "-r resource" +The name of the resource stored in the index. The default is +"\f(CW\*(C`OpenPKG\-CURRENT/Source/\*(C'\fR". +.IP "\fB\-p\fR \fIplatform\fR" 4 +.IX Item "-p platform" +\&\fBopenpkg index\fR adds a platform attribute for binary RPMs. This +must be unique to correctly identify a specific architecture, \s-1OS\s0 +and build environment. +.IP "\fB\-S\fR" 4 +.IX Item "-S" +Optionally determines and stores the size (in bytes) of each indexed file. +This is not required for the correct operation of the \fBopenpkg build\fR command, but +the \fBopenpkg mirror\fR command requires it. +.IP "\fB\-T\fR" 4 +.IX Item "-T" +Optionally determines and stores the modification time (\f(CW\*(C`mtime\*(C'\fR) of each indexed file. +This is not required for the correct operation of the \fBopenpkg build\fR command, but +the \fBopenpkg mirror\fR command requires it. +.IP "\fB\-D\fR" 4 +.IX Item "-D" +Optionally determines and stores the message digest (\f(CW\*(C`md5\*(C'\fR) of each indexed file. +This is not required for the correct operation of the \fBopenpkg build\fR command, but +the \fBopenpkg mirror\fR command requires it. +.IP "\fB\-C\fR \fIcache.db\fR" 4 +.IX Item "-C cache.db" +Cache all \fI.spec\fR files into this Berkeley-DB file when indexing source +RPMs. The cache is refreshed automatically when the source RPMs are more +recent than the cache entry. The \fB\-C\fR option requires an installed +DB_File perl module. +.IP "\fB\-o\fR \fIindex.rdf\fR" 4 +.IX Item "-o index.rdf" +Name of the output \s-1XML/RDF\s0 file, default is to write to \fIstdout\fR. +.IP "\fB\-c\fR" 4 +.IX Item "-c" +Compress output with \f(CW\*(C`bzip2\*(C'\fR. Use the \fB\-o\fR option to specify a \fI.bz2\fR +suffix. +.IP "\fB\-i\fR" 4 +.IX Item "-i" +The specified directories are \s-1RPM\s0 repositories. Build index over +all \fI.rpm\fR files in these directories and all subdirectories. +If a subdirectory already contains a \f(CW\*(C`00INDEX.rdf\*(C'\fR or \f(CW\*(C`00INDEX.rdf.*\*(C'\fR +file then skip scanning the subdirectory, instead add a reference +to the index file into the new index. +.Sp +Without this option the directories are source trees with a subdirectory +per package and a \fIpackage\fR\f(CW\*(C`.spec\*(C'\fR file inside each subdirectory. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIrpm\fR\|(8). +.SH "HISTORY" +.IX Header "HISTORY" +The \fBopenpkg index\fR command was invented in November 2002 by \fIMichael +van Elst\fR under contract with \fICable +& Wireless\fR for use inside the \fBOpenPKG\fR +project . +.SH "AUTHORS" +.IX Header "AUTHORS" +.Vb 2 +\& Michael van Elst +\& mlelstv@serpens.de +.Ve diff -r 71503088f51b -r f880f219c566 openpkg/index.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/index.pl Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,1173 @@ +## +## index.pl -- OpenPKG Maintenance Tool (backend for indexing) +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +############################################################################# +## +## MAIN PROCEDURE +## +############################################################################# + +require 5; +#use strict; + +# determine OpenPKG instance prefix via +# 1. the environment of the "openpkg build" framework +# 2. the installation path of the script +# 3. the installation path of the Perl interpreter +# 4. the path of the "openpkg" command in $PATH +my $l_prefix = $ENV{'OPENPKG_PREFIX'}; +if (not $l_prefix) { + ($l_prefix) = ($0 =~ m/^(.+)\/lib(exec)?\/openpkg(-tools)?\/build(\.pl)?$/); +} +if (not $l_prefix) { + ($l_prefix) = ($^X =~ m/^(.+)\/bin\/perl.*$/); +} +if (not $l_prefix) { + $l_prefix = (`(which openpkg) 2>/dev/null` =~ m/^(.+)\/bin\/openpkg$/); +} +if (not -x "$l_prefix/bin/openpkg") { + die "openpkg:index:FATAL: cannot determine OpenPKG instance prefix"; +} + +# determine tools +my $RPM = ((-f "$l_prefix/bin/openpkg" && -f "$l_prefix/libexec/openpkg/rpm") ? + "$l_prefix/bin/openpkg rpm" : "$l_prefix/bin/rpm"); +my $R2C = ((-f "$l_prefix/bin/openpkg" && -f "$l_prefix/libexec/openpkg/rpm2cpio") ? + "$l_prefix/bin/openpkg rpm2cpio" : "$l_prefix/bin/rpm2cpio"); +my $BZ = "$l_prefix/lib/openpkg/bzip2 -9"; +my $OPENSSL = "$l_prefix/lib/openpkg/openssl"; + +# parse command line +our ($opt_r, $opt_p, $opt_S, $opt_T, $opt_D, $opt_C, $opt_o, $opt_c, $opt_i); +my $getopts = 'r:p:STDC:o:ci'; +getopts($getopts); +if ($#ARGV < 0) { + print "openpkg:index:USAGE: openpkg index [-r resource] [-p platform] [-S] [-T] [-D] [-C cache.db] [-o index.rdf] [-c] [-i] dir ...\n"; + exit(1); +} + +# optionally open cache file +my %cache; +if ($opt_C) { + eval { + require DB_File; + }; + if ($@) { + die "openpkg:index:FATAL: The -C option requires an installed DB_File perl module."; + } + eval { + require Fcntl; + }; + if ($@) { + die "openpkg:index:FATAL: The -C option requires an installed Fcntl perl module."; + } + tie %cache, 'DB_File', $opt_C, Fcntl::O_CREAT()|Fcntl::O_RDWR(), 0666, $DB_File::DB_HASH + or die "openpkg:index:FATAL: cannot tie cache '$opt_C' ($!)"; +} + +# provide default for repository path +$opt_r = 'OpenPKG-CURRENT/Source/' if (not defined($opt_r)); + +# create make_resource function closure +my $make_resource = gen_make_resource(); + +# determine output channel +my $fh; +my $tmpo; +if (defined($opt_o)) { + $tmpo = $opt_o . '.tmp'; + if ($opt_c) { + open(FH, "| $BZ -c > '$tmpo'") + or die "openpkg:index:FATAL: cannot write '$tmpo' ($!)"; + } else { + open(FH, "> $tmpo") + or die "openpkg:index:FATAL: cannot write '$tmpo' ($!)"; + } +} else { + if ($opt_c) { + open(FH, "| $BZ -c") + or die "openpkg:index:FATAL: cannot write to stdout ($!)"; + } else { + open(FH, ">&=1") + or die "openpkg:index:FATAL: cannot write to stdout ($!)"; + } +} +$fh = \*FH; + +# generate XML/RDF output +xml_head($fh, $opt_r); +foreach my $prefix (@ARGV) { + my $list; + if (-d $prefix) { + if ($opt_i) { + $list = list_rpmdir($prefix); + } else { + $list = list_specdir($prefix); + } + } else { + $list = [ $prefix ]; + $prefix = dirname($prefix); + } + write_index($fh, $prefix, $opt_r, $opt_p, $list, $opt_C ? \%cache : undef); +} +xml_foot($fh); + +# close output channel +close($fh) + or die "openpkg:index:FATAL: write error on output ($!)"; + +# post-process output +if (defined($tmpo)) { + rename($tmpo, $opt_o) + or die "openpkg:index:FATAL: cannot rename $tmpo to $opt_o ($!)"; +} + +# die gracefully +exit(0); + +############################################################################# +## +## FUNCTIONS: PARSING +## +############################################################################# + +# home-brewn getopt(3) style option parser +sub getopts ($) { + my ($opts) = @_; + my (%optf) = map { m/(\w)/; $1 => $_ } $opts =~ m/(\w:|\w)/g; + my (%opts, @argv, $optarg); + + foreach (@ARGV) { + if (@argv) { + push @argv, $_; + } elsif (defined $optarg) { + if (exists $opts{$optarg}) { + $opts{$optarg} .= " $_"; + } else { + $opts{$optarg} = $_; + } + $optarg = undef; + } elsif (!/^[-]/) { + push @argv, $_; + } else { + while (/^\-(\w)(.*)/) { + if (exists $optf{$1}) { + if (length($optf{$1}) > 1) { + if ($2 ne '') { + if (exists $opts{$1}) { + $opts{$1} .= " $2"; + } else { + $opts{$1} = $2; + } + } else { + $optarg = $1; + } + last; + } else { + $opts{$1} = 1; + } + } else { + warn "openpkg:index:WARNING: unknown option $_\n"; + } + $_ = "-$2"; + } + } + } + if (defined $optarg) { + warn "openpkg:index:WARNING: option $optarg requires an argument\n"; + } + foreach (keys %opts) { + eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";'; + } + @ARGV = @argv; +} + +############################################################################# +## +## OpenPKG RPM Package Specification Parsing +## +############################################################################# + +# escape XML for output in RDF file +sub e ($) { + my ($s) = @_; + my ($i); + + # remove trailing whitespace + $s =~ s/\n+$//sg; + $s =~ s/[^\S\n]+$//mg; + + # remove common leading whitespace + $i = undef; + while ($s =~ m/^([^\S\n]+)/mg) { + $i = $1 if (!defined($i) || (length($1) < length($i))); + } + $s =~ s/^\Q$i\E//mg if (defined($i)); + + # escape XML special characters + $s =~ s/&/&/sg; + $s =~ s//>/sg; + + return $s; +} + +# make_resource closure +sub gen_make_resource { + # generate operator regular expression + # (used in make_resource below) + my %attrname = ( + '==' => 'equ', + '=' => 'equ', + '>=' => 'geq', + '=>' => 'geq', + '<=' => 'leq', + '=<' => 'leq', + '>' => 'gt', + '<' => 'lt' + ); + my ($opreg) = + join '|', + map { + "\Q$_\E" + } sort { + length($b) <=> length($a) + || $b cmp $a + } keys(%attrname); + + # return function which makes resource object + return sub ($) { + my ($s) = @_; + + if ($s =~ m/(\S+)\s*($opreg)\s*(.*?)\s*$/o) { + return { + resource => $1, + attrname => $attrname{$2}, + attrval => $3 + } + } + else { + return { + resource => $s + } + } + }; +}; + +# split string into array at comma seperator +# (optioanlly map resource operators into resource objects) +sub commasep ($$) { + my ($k, $v) = @_; + + if ($k =~ m/^(NoSource)$/) { + return split(/\s*,\s*/, $v); + } elsif ($k =~ /^(PreReq|BuildPreReq|Provides|Conflicts)$/) { + return map { &$make_resource($_) } + split(/\s*,\s*/, $v); + } + return $v; +} + +# escape option string +sub optesc ($) { + my ($s) = @_; + + $s =~ s/([\x00-\x1f\x80-\xbf\s\%])/sprintf("%%%02x", ord($1))/eg; + return $s; +} + +# variable substitution +sub vsub ($$) { + my ($var, $v) = @_; + + $v =~ s/\%\{([^}]+)\}/ + exists $var->{$1} ? $var->{$1} : '%{'.$1.'}'/emg; + return $v; +} + +# Umgekehrte Polnische Notation (UPN) +# Reverse Polish Notation (RPN) +# << ( %{foo} == "yes" ) && ( ! %{bar} == "no" ) || ( %{baz} == "yes" ) +# >> %{foo} %{bar} ! && %{baz} || +sub upn ($) { + my ($t) = @_; + my (@tok); + my (@out, $op, $o); + my (@save); + + # split string into tokens + @tok = ($t =~ m/(\(|\)|\&\&|\|\||\!|\S+)/g); + + # iterate over all tokens + $op = []; + foreach (@tok) { + if ($_ eq '(') { + push(@save, $op); + $op = []; + } elsif ($_ eq ')') { + die "openpkg:index:FATAL: unresolved operators in: @tok\n" if (@$op); + $op = pop(@save) + or die "openpkg:index:FATAL: unmatched closing parenthesis in: @tok\n"; + while ($o = pop(@$op)) { + push(@out, $o->[0]); + last if ($o->[1]); + } + } elsif ($_ eq '&&') { + push(@$op, [ '+', 1 ]); + } elsif ($_ eq '||') { + push(@$op, [ '|', 1 ]); + } elsif ($_ eq '!') { + push(@$op, [ '!', 0 ]); + } elsif (m/^\%\{(\S*?)\}$/) { + push(@out, $1); + while ($o = pop(@$op)) { + push(@out, $o->[0]); + last if ($o->[1]); # binary operator + } + } + } + return join (' ', @out); +} + +# deduce external variables from description +# (backward compatibility for times before openpkg-20021230) +sub find_options ($) { + my ($descr) = @_; + my $evar = {}; + $descr =~ s/--define\s*'(\S+)\s*\%\{\1\}'/$evar->{$1} = '%{'.$1.'}', ''/sge; + return $evar; +} + +# translate default section from spec-file into a hash +# - %if/%ifdef/%define... are translated to #/#ifdef/#define +# - #defines are interpolated (correct ?) +# - #if/#ifdef/... sections are stripped +# result is the same as if all conditions evaluate false (!) +# - all attributes are of the form key: value +# - repeated attributes are coalesced into a list +# hint: evar = expansion variables, ovar = option variables +sub package2data ($$) { + my ($s, $ovar) = @_; + my (%evar, %var); + my (@term, $term); + my (%attr, %avar); + my ($l, $v, $cond, $d, $p); + my ($re, @defs); + + # combine multilines (line continuation!) + $s =~ s/\\\n/ /sg; + + # map syntax of conditional variable macros + $s =~ s/^#\{\!\?([^:]*):\s*%(.*?)\s*\}\s*$/#ifndef $1\n#$2\n#endif/mg; + $s =~ s/^#\{\!\?([^:]*):\s*(.*?)\s*\}\s*$/#ifndef $1\n$2\n#endif/mg; + + # map syntax of option macro + $s =~ s/^#option\s+(\S+)\s*(.*?)\s*$/#ifndef $1\n#define $1 $2\n#endif\n#provides $1 $2/mg; + + # use option variables for expansion + %evar = %$ovar; + + # guess more external parameters by scanning for (and removing) "set option default" sections + $re = '^\#ifndef\s+[\w\_]+\s*\n((?:\#define\s+[\w\_]+\s.*\n)+)\#endif\n'; + @defs = ($s =~ m/$re/gm); + foreach (@defs) { + while (m/^\#define\s+([\w\_]+)\s(.*?)\s*$/mg) { + $ovar->{$1} = $2; + $evar{$1} = '%{'.$1.'}'; + } + } + $s =~ s/$re//gm; + + # add everything looking like a "with_xxx" variable + $re = '%{(with\_[\w\_]+)}'; + @defs = ($s =~ /$re/gm); + foreach (@defs) { + next if (exists($ovar->{$1})); + $ovar->{$1} = '%{'.$1.'}'; # unexpanded + $evar{$1} = '%{'.$1.'}'; + } + + # extract all conditional sections (#if/#else/#endif) + @term = (); + %var = (); + $cond = ''; + foreach $l (split(/\n/, $s)) { + # expand variables + $v = vsub(\%avar, vsub(\%var, $l)); + + if (($p) = ($v =~ /^\#if\s+(.*?)\s*$/)) { + # normalize "%{variable}" != ..." + $p =~ s/("\%\{[^}]+\}")\s*!=\s*"(yes|no)"/$1 . " == \"" . ($2 ne "yes" ? "yes" : "no") . "\""/sge; + + # normalize #if expressions + # - "%{variable}" == "yes" + # - "%{variable}" == "no" + # - operators ! && || + # warn on: + # - operator != + # - any other word + $term = ''; + while ($p =~ m/(!=)|(\!|\|\||\&\&|\(|\))|"\%\{([^}]+)\}"\s*==\s*"(yes|no)"|(\S+)/g) { + if (defined($1)) { + warn "openpkg:index:WARNING: unknown token '$1':\n< $l\n> $v"; + } elsif (defined($5)) { + warn "openpkg:index:WARNING: unknown token '$5':\n< $l\n> $v"; + } elsif (defined($2)) { + $term .= " $2 "; + } elsif (exists($evar{$3})) { + $term .= ($4 eq 'no' ? '! ' : '').vsub(\%evar, '%{'.$3.'}'); + } else { + warn "openpkg:index:WARNING: unknown condition variable '$3':\n< $l\n> $v"; + } + } + + # join with previous conditions for this #if/#endif block + if ($term ne '') { + push(@term, "( $term )"); + $cond = join(' && ', grep { $_ ne '' } @term) . ''; + } else { + push(@term, ''); + } + } + elsif ($v =~ /^\#else\s*$/) { + # reverse last condition + if (@term) { + $term[-1] = ' ! '. $term[-1]; + $cond = join(' && ', grep { $_ ne '' } @term) . ''; + } else { + die "openpkg:index:FATAL: \"else\" without \"if\""; + } + } + elsif ($v =~ /^\#endif\s*$/) { + # unwind last #if expression + pop(@term); + $cond = join(' && ', grep { $_ ne '' } @term) . ''; + } + elsif ($v =~ /^\#(?:define)\s*(\S+)\s*(.*?)\s*$/) { + # define conditional variables + # - truth-value becomes current condition + # define internal variables + # - store for subsequent substitution + if (exists($evar{$1})) { + if ($2 eq 'yes') { + if ($cond eq '') { + $evar{$1} = "( \%\{$1\} )"; + } else { + $evar{$1} = "( \%\{$1\} || ( $cond ) )"; + } + } elsif ($2 eq 'no') { + if ($cond eq '') { + $evar{$1} = "( \%\{$1\} )"; + } else { + $evar{$1} = "( %\{$1\} && ! ( $cond ) )"; + } + } else { + warn "openpkg:index:WARNING: logic too complex for '$1' (boolean expressions allowed only):\n< $l\n> $v"; + } + } else { + $var{$1} = $2; + } + } + elsif ($v =~ /^\#(?:undefine)\s*(\S+)\s*$/) { + # undefine conditional variables + # undefine internal variables + if (exists($evar{$1})) { + $evar{$1} = "\%\{$1\}"; + } else { + delete($var{$1}); + } + } + elsif ($v =~ /^\#(?:provides)\s*(\S+)\s*(.*?)\s*$/) { + # store option for current condition + if (exists($attr{'Name'}->{''})) { + push(@{$attr{'Provides'}->{$cond}}, { + resource => $attr{'Name'}->{''}->[0] . '::' . $1, + attrname => 'equ', + attrval => optesc($2) + }); + } else { + warn "openpkg:index:ERROR: no package name set for option \"$1 = $2\""; + } + } + elsif ($v =~ /^\#NoSource\s*(.*?)\s*$/) { + # store conditional NoSource attribute + push(@{$attr{'NoSource'}->{$cond}}, commasep('NoSource', $1)); + + } + elsif ($v =~ /^\s*([^\#]\S*)\s*:\s*(.*?)\s*$/) { + # store "attribute: value" headers for current condition + push(@{$attr{$1}->{$cond}}, commasep($1,$2)); + $avar{lc($1)} = $2 if ($cond eq ''); + } + } + + # return all header "attributes" + return \%attr; +} + +# split spec file into sections starting with a %word +# - concatenate extended lines +# - strip comment lines +# - map %command to #command +# - split sections +# - return package2data() from default section (before first %xxx section) +sub spec2data ($) { + my ($s) = @_; + my (%map); + my ($a, $o); + my $spec = $s; + + # remove comments + $s =~ s/^\s*#.*?\n//mg; + + # map commands + $s =~ s/^%(ifdef|ifndef|if|NoSource|option|undefine|define|else|endif|\{)/#$1/mg; + + # split sections + foreach (split(m/^(?=%\w+\s*\n)/m, $s)) { + if (m/^%(\w+)\s*\n/) { + $map{$1} .= $'; + } else { + $map{'*'} .= $_; + } + } + + # translate package information into "data" + if (exists($map{'description'})) { + # backward compatibility (options are in description) + $o = find_options($map{'description'}); + $a = package2data($map{'*'}, $o ); + $a->{'Description'} = { '' => [ $map{'description'} ] }; + } else { + # standard case + $a = package2data($map{'*'}, {}); + } + return $a; +} + +############################################################################# +## +## XML/RDF Generation +## +############################################################################# + +# start of XML file +sub xml_head ($$) { + my ($fh, $res) = @_; + print $fh < + + +EOFEOF +} + +# end of XML file, corresponds with start tags +sub xml_foot ($) { + my($fh) = @_; + print $fh < + +EOFEOF +} + +# conditional expansion of attribute +sub n ($$) { + my ($a, $k) = @_; + return if (not $a->{$k}); + return if (not $a->{$k}->{''}); + return ($a->{$k}->{''}->[0]); +} + +# send out $a->{$k} as text-style tag +sub xml_text ($$$;$) { + my ($i, $a, $k, $tag) = @_; + my ($out); + return "" if (not exists($a->{$k})); + $tag = $k if (not defined($tag)); + $i = ' ' x $i; + $out = e(n($a, $k)); + return if $out eq ''; + return "$i<$tag>\n$out\n$i\n"; +} + +# send out @{$a->{$k}} as body of an XML tag +# $k is the name of the tag unless overridden by $tag +# $i denotes the depth of indentation to form nicely +# looking files. +# all data from the list is flattened into a single +# body, separated by LF and escaped for XML metachars. +sub xml_tag ($$$;$) { + my ($i, $a, $k, $tag) = @_; + my ($out, $cond, $upn); + return "" if (not exists($a->{$k})); + $tag = $k if (not defined($tag)); + $out = ''; + $i = ' ' x $i; + foreach $cond (sort keys(%{$a->{$k}})) { + $upn = e(upn($cond)); + $out .= $i . + ($cond ne '' ? "<$tag cond=\"$upn\">" : "<$tag>") . + join("\n", map { e($_) } @{$a->{$k}->{$cond}}) . + "\n"; + } + return $out; +} + +# send out @{$a->{$k}} as a rdf:bag +# $k is the name of the outer tag unless overriden by $tag +# $i denotes the depth of indentation, inner tags are indented +# 2 or 4 more character positions. +# each element of the bag is listed +sub xml_bag ($$$;$) { + my ($i, $a, $k, $tag) = @_; + my ($out, $cond, $upn); + return "" if (not exists($a->{$k})); + $tag = $k if (not defined($tag)); + $out = ''; + $i = ' ' x $i; + foreach $cond (sort keys %{$a->{$k}}) { + next if (not @{$a->{$k}->{$cond}}); + $upn = e(upn($cond)); + $out .= $i . + ($cond ne '' ? "<$tag cond=\"$upn\">\n" : "<$tag>\n") . + "$i \n" . + join("", + map { + ref $_ + ? "$i {attrname} + ? " $_->{attrname}=\"".e($_->{attrval})."\"" + : "" + ) . + ">".e($_->{resource})."\n" + : "$i ".e($_)."\n" + } + @{$a->{$k}->{$cond}}) . + "$i \n" . + "$i\n"; + } + return $out; +} + +# send out reference to another RDF +sub xml_reference ($$$$$$) { + my($fh, $res, $href, $S, $T, $D) = @_; + print $fh " \n"; +} + +# send out reference to other resources +sub xml_other ($$$$$$) { + my($fh, $about, $href, $S, $T, $D) = @_; + print $fh " \n"; + print $fh " \n"; +} + +# translate attributes from %$a as generated by package2data +# into XML and write to file $fh +sub xml_record ($$$$$$) { + my ($fh, $a, $href, $S, $T, $D) = @_; + my ($maj, $min, $rel, $about); + + $about = + n($a, 'Name') . '-' . + n($a, 'Version') . '-' . + n($a, 'Release'); + if (not defined($href)) { + # guess location from Information in Specfile + if (exists($a->{'NoSource'})) { + $href = "$about.nosrc.rpm"; + } else { + $href = "$about.src.rpm"; + } + ($maj, $min, $rel) = (n($a, 'Release') =~ m/^(\d+)\.(\d+)\.(\d+)/); + if (defined($min)) { + if ($maj > 1 || ($maj == 1 && $min > 0)) { + # OpenPKG-1.1-RELEASE or later + if (n($a, 'Distribution') =~ /\[PLUS\]/) { + $href = 'PLUS/'.$href; + } + } + if ($maj > 1 || ($maj == 1 && $min >= 0)) { + # OpenPKG-1.0-RELEASE or later + if ($rel > 0) { + $href = 'UPD/'.$href; + } + } + } else { + # OpenPKG-CURRENT + } + } + + print $fh " \n"; + + # fake Source attribute from Source\d attribtutes + # XXX only default conditional + $a->{'Source'} = { '' => [ + map { + s/\Q%{name}\E/n($a, 'Name')/esg; + s/\Q%{version}\E/n($a, 'Version')/esg; + s/\Q%{release}\E/n($a, 'Release')/esg; + $_; + } + map { + $a->{$_}->{''} ? @{$a->{$_}->{''}} : () + } + sort { + my ($x) = ($a =~ /^(\d*)$/); + my ($y) = ($b =~ /^(\d*)$/); + return $x <=> $y; + } + grep { + /^Source\d*$/ + } keys(%$a) + ]}; + delete($a->{'Source'}) if (not @{$a->{'Source'}->{''}}); + + print $fh + xml_tag(6, $a, 'Name'), + xml_tag(6, $a, 'Version'), + xml_tag(6, $a, 'Release'), + xml_tag(6, $a, 'Distribution'), + xml_tag(6, $a, 'Class'), + xml_tag(6, $a, 'Group'), + xml_tag(6, $a, 'License'), + xml_tag(6, $a, 'Packager'), + xml_tag(6, $a, 'Summary'), + xml_tag(6, $a, 'URL'), + xml_tag(6, $a, 'Vendor'), + xml_tag(6, $a, 'SourceRPM'), + xml_tag(6, $a, 'Arch'), + xml_tag(6, $a, 'Os'), + xml_tag(6, $a, 'BuildHost'), + xml_tag(6, $a, 'BuildSystem'), + xml_tag(6, $a, 'BuildTime'), + xml_tag(6, $a, 'Relocations'), + xml_tag(6, $a, 'Size'), + xml_tag(6, $a, 'Prefixes'), + xml_tag(6, $a, 'Platform'), + xml_tag(6, $a, 'SigSize'), + xml_tag(6, $a, 'SigMD5'), + xml_tag(6, $a, 'SigPGP'), + xml_tag(6, $a, 'SigGPG'), + xml_bag(6, $a, 'BuildPreReq'), + xml_bag(6, $a, 'PreReq'), + xml_bag(6, $a, 'Provides'), + xml_bag(6, $a, 'Conflicts'), + xml_bag(6, $a, 'Source'), + xml_bag(6, $a, 'NoSource'), + xml_bag(6, $a, 'Filenames'), + xml_text(6, $a, 'Description'); + + print $fh " \n"; +} + +############################################################################# +## +## OpenPKG RPM Package Payload Extraction +## +############################################################################# + +# extract foo.spec from foo-V-R.src.rpm file +sub rpm2spec ($) { + my ($fn) = @_; + local($SIG{'PIPE'}) = 'IGNORE'; + local(*PIPE); + open(PIPE, "$R2C '$fn' |") + or die "openpkg:index:FATAL: cannot read '$fn' ($!)\n"; + my ($buf, @hdr, $n, $m, $name, $step); + my ($spec); + while (read(PIPE, $buf, 110) == 110) { + @hdr = unpack('a6a8a8a8a8a8a8a8a8a8a8a8a8a8', $buf); + $n = hex($hdr[12]); # filename length + $m = int(($n+5)/4)*4-2; # filename size (padded) + last if (not (read(PIPE,$buf,$m) == $m)); + $name = substr($buf, 0, $n-1); + $n = hex($hdr[7]); # file length + $m = int(($n+3)/4)*4; # file size (padded) + if ($name !~ m/.spec$/) { + while ($m > 0) { + $step = $m > 8192 ? 8192 : $m; + last if (not read(PIPE,$buf,$step)); + $m -= length($buf); + } + } else { + if (read(PIPE,$buf,$n) == $n) { + $spec = $buf; + } + last; + } + } + close(PIPE); + return $spec; +} + +############################################################################# +## +## OpenPKG RPM Package Header Extraction +## +############################################################################# + +# extract header information from foo-V-R.src.rpm +sub rpm2data ($$) { + my ($fn, $platform) = @_; + my ($q, %a); + my ($t, $v); + local(*PIPE); + + if (not defined($platform)) { + die "openpkg:index:FATAL: indexing binary package '$fn' requires -p option\n"; + } + + $q = <) { + if (/^(\S+)\s+(.*?)\s*$/) { + $t = $1; + $v = $2; + } elsif (/^(\s+.+?)\s*$/) { + next if (not defined($t)); + $v = $1; + } else { + $t = undef; + next; + } + if (exists($a{$t})) { + $a{$t} .= "\n$v"; + } else { + $a{$t} = $v; + } + } + close(PIPE); + + %a = map { $_ => $a{$_} } + grep { $a{$_} ne '(none)' } + keys(%a); + if ($a{'Relocations'} eq '(non relocatable)') { + delete($a{'Relocations'}); + } + if ($a{'SigMD5'} eq '(unknown type)') { + delete($a{'SigMD5'}); + } + if (defined($platform)) { + $a{'Platform'} = $platform; + } + $a{'Description'} = [ $a{'Description'} ]; + + foreach ('Conflicts', 'PreReq', 'Provides') { + $a{$_} = [ + map { &$make_resource($_) } + grep { !/^rpmlib\(/ } + split(/\n+/, $a{$_}) + ]; + } + + return { map { + $_ => { '' => (ref $a{$_} ? $a{$_} : [ split(/\n+/, $a{$_}) ]) } + } keys(%a) }; +} + +############################################################################# +## +## OpenPKG XML/RDF Index Locating +## +############################################################################# + +# detect index files +sub getindex ($) { + my ($dir) = @_; + my (@idx) = + sort { -M $a <=> -M $b; } + grep { -f $_ } + ( <$dir/00INDEX.rdf>, <$dir/00INDEX.rdf.*> ); + return if (not @idx); + return $idx[0]; +} + +# list RPM directories of unpacked .spec files +sub list_specdir ($) { + my ($dir) = @_; + my ($d, $path); + my (@list); + + local(*DH); + opendir(DH, $dir); + while ($d = readdir(DH)) { + next if ($d =~ m/^\./); + $path = "$dir/$d/$d.spec"; + push(@list, $path) if (-f $path); + } + closedir(DH); + return \@list; +} + +# list index or RPM file directories +sub list_rpmdir ($) { + my ($dir) = @_; + my ($d, $path); + my (@list, $idx, $sub); + + local(*DH); + opendir(DH, $dir); + while ($d = readdir(DH)) { + next if ($d =~ m/^\./); + $path = "$dir/$d"; + if (-d $path) { + $idx = getindex($path); + if (defined($idx)) { + push(@list, $idx); + } else { + $sub = list_rpmdir($path); + push(@list, @$sub); + undef $sub; + } + } else { + next if (not ($d =~ m/\.(?:rpm|sh)$/ && -f $path)); + push(@list, $path); + } + } + closedir(DH); + return \@list; +} + +############################################################################# +## +## OpenPKG XML/RDF Index Reading +## +############################################################################# + +# fetch a whole file +sub readfile ($) { + my ($fn) = @_; + local(*FH); + open(FH, "< $fn") + or die "FATAL: cannot read '$fn' ($!)\n"; + my $l; { local $/; $l = ; } + close(FH); + return $l; +} + +# create relative path by stripping instance prefix +sub relpath ($$) { + my ($prefix, $path) = @_; + $path =~ s/^\Q$prefix\E\///s; + return $path; +} + +# create directory path with trailing slash +sub dirname ($) { + my ($path) = @_; + $path =~ s/\/[^\/]*$//s; + return $path.'/'; +} + +# peek at resource identifier of index file +sub getresource ($) { + my ($fn) = @_; + my ($fh, $buf); + + local(*FH); + if ($fn =~ /\.bz2$/) { + open(FH, "$BZ -dc $fn |") + or die "FATAL: cannot read '$fn' ($!)\n"; + } else { + open(FH, "< $fn") + or die "FATAL: cannot read '$fn' ($!)\n"; + } + read(FH, $buf, 1024); + close(FH); + if ($buf =~ //dev/null || true`; + if ($output =~ m/MD5\(.+?\)=\s*([0-9a-fA-F]+)/s) { + $digest = uc($1); + } + return $digest; +} + +sub write_index ($$$$$$) { + my ($fh, $prefix, $resource, $platform, $list, $cache) = @_; + my ($a, $h, $r, $spec, $T, $D); + + foreach (@$list) { + $a = undef; + $h = undef; + $r = undef; + $S = undef; + $T = undef; + $D = undef; + $o = undef; + + # determine information + if (m/\.spec$/) { + $spec = readfile($_); + $a = spec2data($spec); + ($S, $T) = sizetime($_) if ($opt_S or $opt_T); + $D = digest($_) if ($opt_D); + } elsif (m/([^\/]+\.(?:no)?src\.rpm)$/) { + $h = relpath($prefix, $_); + ($S, $T) = sizetime($_) if ($opt_S or $opt_T or $cache); + if ($cache) { + if ( exists($cache->{"T$_"}) + && $cache->{"T$_"} == $T + && exists($cache->{"s$_"}) + && $cache->{"s$_"} ne "" + && (!$opt_S || ($opt_S && exists($cache->{"S$_"}) && $cache->{"S$_"} ne "")) + && (!$opt_D || ($opt_D && exists($cache->{"D$_"}) && $cache->{"D$_"} ne ""))) { + # found in cache + $spec = $cache->{"s$_"}; + $S = $cache->{"S$_"} if ($opt_S); + $D = $cache->{"D$_"} if ($opt_D); + } else { + # not found in cache + $spec = rpm2spec($_); + $cache->{"s$_"} = $spec; + $cache->{"S$_"} = $S; + $cache->{"T$_"} = $T; + $D = digest($_) if ($opt_D); + $cache->{"D$_"} = $D if ($opt_D); + } + } else { + # no cache at all + $spec = rpm2spec($_); + $D = digest($_) if ($opt_D); + } + $a = spec2data($spec); + } elsif (m/([^\/]+\.rpm)$/) { + $h = relpath($prefix, $_); + $a = rpm2data($_, $platform); + ($S, $T) = sizetime($_) if ($opt_S or $opt_T); + $D = digest($_) if ($opt_D); + } elsif (m/(([^\/]+)\.(?:no)?src\.sh)$/) { + $h = relpath($prefix, $_); + ($S, $T) = sizetime($_) if ($opt_S or $opt_T); + $D = digest($_) if ($opt_D); + $o = "$2:bootstrap"; + } elsif (m/([^\/]+\.rdf[^\/]*)$/) { + $h = relpath($prefix, $_); + $r = getresource($_) || $resource.dirname($h); + ($S, $T) = sizetime($_) if ($opt_S or $opt_T); + $D = digest($_) if ($opt_D); + } + + # process information + if ($a) { + xml_record($fh, $a, $h, $S, $T, $D); + } elsif ($o) { + xml_other($fh, $o, $h, $S, $T, $D); + } elsif ($r) { + xml_reference($fh, $r, $h, $S, $T, $D); + } else { + warn "openpkg:index:ERROR: cannot process $_"; + } + } +} + diff -r 71503088f51b -r f880f219c566 openpkg/index.pod --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/index.pod Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,133 @@ +## +## index.pod -- OpenPKG Package Indexing +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +=pod + +=head1 NAME + +B - B Package Indexing + +=head1 SYNOPSIS + +B +B +[B<-r> I] +[B<-p> I] +[B<-S>] +[B<-T>] +[B<-D>] +[B<-C> I] +[B<-o> I] +[B<-c>] +[B<-i>] +I ... + +=head1 DESCRIPTION + +The B tool is a frontend for indexing of RPM files. It +creates an XML/RDF based resource index for RPM F<.spec> files in a +source tree or from an RPM package repository. The index holds enough +information to support an automated build process by B. + +=head1 OPTIONS + +The following command line options exist: + +=over 4 + +=item B<-r> I + +The name of the resource stored in the index. The default is +"C". + +=item B<-p> I + +B adds a platform attribute for binary RPMs. This +must be unique to correctly identify a specific architecture, OS +and build environment. + +=item B<-S> + +Optionally determines and stores the size (in bytes) of each indexed file. +This is not required for the correct operation of the B command, but +the B command requires it. + +=item B<-T> + +Optionally determines and stores the modification time (C) of each indexed file. +This is not required for the correct operation of the B command, but +the B command requires it. + +=item B<-D> + +Optionally determines and stores the message digest (C) of each indexed file. +This is not required for the correct operation of the B command, but +the B command requires it. + +=item B<-C> I + +Cache all F<.spec> files into this Berkeley-DB file when indexing source +RPMs. The cache is refreshed automatically when the source RPMs are more +recent than the cache entry. The B<-C> option requires an installed +DB_File perl module. + +=item B<-o> I + +Name of the output XML/RDF file, default is to write to F. + +=item B<-c> + +Compress output with C. Use the B<-o> option to specify a F<.bz2> +suffix. + +=item B<-i> + +The specified directories are RPM repositories. Build index over +all F<.rpm> files in these directories and all subdirectories. +If a subdirectory already contains a C<00INDEX.rdf> or C<00INDEX.rdf.*> +file then skip scanning the subdirectory, instead add a reference +to the index file into the new index. + +Without this option the directories are source trees with a subdirectory +per package and a IC<.spec> file inside each subdirectory. + +=back + +=head1 SEE ALSO + +rpm(8). + +=head1 HISTORY + +The B command was invented in November 2002 by I Emlelstv@serpens.deE under contract with I Ehttp://www.cw.com/E for use inside the B +project Ehttp://www.openpkg.org/E. + +=head1 AUTHORS + + Michael van Elst + mlelstv@serpens.de + +=cut + diff -r 71503088f51b -r f880f219c566 openpkg/libarchive.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/libarchive.patch Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,33 @@ +Index: Makefile.in +--- Makefile.in.orig 2011-12-24 19:05:17.000000000 +0100 ++++ Makefile.in 2011-12-26 08:30:54.000000000 +0100 +@@ -1091,7 +1091,7 @@ + lib_LTLIBRARIES = libarchive.la + noinst_LTLIBRARIES = libarchive_fe.la + man_MANS = $(libarchive_man_MANS) $(bsdtar_man_MANS) $(bsdcpio_man_MANS) +-BUILT_SOURCES = libarchive/test/list.h tar/test/list.h cpio/test/list.h ++BUILT_SOURCES = + TESTS_ENVIRONMENT = $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) + # Always build and test both bsdtar and bsdcpio as part of 'distcheck' + DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio +Index: cpio/cmdline.c +--- cpio/cmdline.c.orig 2011-12-24 18:56:24.000000000 +0100 ++++ cpio/cmdline.c 2011-12-26 08:29:08.000000000 +0100 +@@ -56,7 +56,7 @@ + /* + * Long options for cpio. Please keep this sorted. + */ +-static const struct option { ++static const struct libarchive_option { + const char *name; + int required; /* 1 if this option requires an argument */ + int equivalent; /* Equivalent short option. */ +@@ -104,7 +104,7 @@ + static int state = state_start; + static char *opt_word; + +- const struct option *popt, *match = NULL, *match2 = NULL; ++ const struct libarchive_option *popt, *match = NULL, *match2 = NULL; + const char *p, *long_prefix = "--"; + size_t optlength; + int opt = '?'; diff -r 71503088f51b -r f880f219c566 openpkg/license-BOOT.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license-BOOT.txt Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,271 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Id: BOOT +Name: OpenPKG Framework Bootstrap License +Version: 1.0.0 +Issuer: OpenPKG GmbH +Issued: 2010-01-01 + +Licensee: arbitrary deployer of OpenPKG Framework + with this run-time license activated + +Description: + + OPENPKG FRAMEWORK BOOTSTRAP LICENSE + =================================== + + This license agreement constitutes a valid and binding agreement + between the OpenPKG GmbH, jurisdiction identification "DE MUC HRB + 160208", postal address "Weblinger Weg 28, 85221 Dachau, GERMANY", + digital signature name "OpenPKG GmbH " and + digital signature fingerprint "7D12 1A8F C05D C18A 4329 E9EF 6704 + 2EC9 61B7 AE34", represented by the two managing directors Ralf S. + Engelschall and Thomas Lotterer, and you, the licensee. + + "You" means the natural person or the entity that is agreeing to be + bound by this agreement. You shall be liable for any failure by your + employees and third party contractors that provide services to you + to comply with the terms and conditions of this agreement. + + AGREEMENT + --------- + + By using, copying, modifying or distributing the Product you agree + to be bound by the terms and conditions of this agreement. If you + are accepting these terms on behalf of another person or a company + or other legal entity, you represent and warrant that you have full + authority to bind that person, company, or legal entity to these + terms. If you do not agree to the terms and conditions of this + agreement, you may not use, copy, modify or distribute the Product. + You may return the unused Product to the supplier from which you + acquired it within 30 days and request a refund of the license fee, + if any, already paid upon showing proof of payment. + + TERMINOLOGY + ----------- + + OpenPKG is a solution to build software stacks consisting of OpenPKG + Packages and an OpenPKG Framework to operate them. + + For your information, OpenPKG Packages are available from the + OpenPKG Foundation e.V., which licenses and distributes them as Open + Source Software. These OpenPKG Packages are in no way subject of + this agreement. + + The OpenPKG Framework is a property of the OpenPKG GmbH with all + rights reserved. Licenses, like this one, which grant limited + permission to use, copy, modify and distribute this software are + exclusively issued by the OpenPKG GmbH. + + Licensing as described in this agreement covers the OpenPKG + Framework code copyrighted by the OpenPKG GmbH and the OpenPKG + Framework as a compound work. The OpenPKG Framework is distributed + in source code form and also contains pristine third-party sources + where each comes with its own licensing model. These licenses are + in no way altered by this agreement, but passed through to you + verbatim. You are responsible for obtaining and obeying any such + vendor license. + + This license describes how you appropriately use, copy, modify + and distribute the OpenPKG Framework source code and the binaries + resulting from the build process. This license does not include any + entitlement for you to receive service or support from the OpenPKG + GmbH, there are no warranties beyond the minimum implied warranty, + and there are no promises with respect to the future of the Product + or any derived works. + + GRANT OF RIGHTS GENERAL TERMS + ----------------------------- + + The OpenPKG Framework is licensed, not sold. Subject to the terms + and conditions of this agreement, the OpenPKG GmbH hereby grants + you a non-exclusive, non-sub-licensable and non-transferable right + to use the Product. You may not lease or rent the OpenPKG Framework + license. + + You may sell or otherwise transfer unused licenses if you ensure + the recipient receives these terms and conditions with the same + transaction and acknowledges to take over your responsibilities from + this agreement. + + You may not remove any titles, trademarks or trade names, copyright + notices, legends, or other proprietary markings on the Product. You + are not granted any rights to any trademarks or service marks of the + OpenPKG GmbH. All rights not expressly granted by this license are + reserved. + + You may use the Product as long as you own this license issued by + the OpenPKG GmbH, install it and obey the terms and conditions + listed below. This license, issued by the OpenPKG GmbH, ships + as a digitally signed text file which carries the exact license + conditions both in human readable plain text and attached in a + machine readable format. The latter may be used by the OpenPKG + Framework to programmatically validate the license compliance. If + programmatic license validation within the OpenPKG Framework detects + a compliance failure, the OpenPKG Framework might cease operation. + It is your responsibility to ensure compliance with these terms and + conditions. + + GRANT OF RIGHTS TO USE THE OPENPKG FRAMEWORK + -------------------------------------------- + + This "bootstrap" license ships free of charge with every OpenPKG + Framework and allows restricted use of the OpenPKG Framework. The + constraint is a run-time limitation of the RPM database to contain + only the "openpkg" package and GPG keys, a situation typical during + and immediately after bootstrapping. The license does not impose + any life-time limitation. + + GRANT OF RIGHTS TO COPY THE OPENPKG FRAMEWORK + --------------------------------------------- + + You may create an unlimited number of copies of the Product. + + GRANT OF RIGHTS TO MODIFY THE OPENPKG FRAMEWORK + ----------------------------------------------- + + You may modify most parts of the Product and adjust it to your + needs, creating derivative works. You may not remove license + validation code, and you must ensure the preservation of the OpenPKG + GmbH fingerprint data. The copyright notice, the license excerpt and + the reference to this terms and conditions must be kept verbatim. + You must make clear to the recipient of the derived works that the + version he is receiving has been modified and by whom. + + These terms and conditions stay if force for derivative works. To + keep modifications your property you must not distribute them, in + source or binary form, beyond your organizational scope. In cases + of extended distribution or publication you agree to contribute + your modifications automatically, free of charge and without any + royalty claims, to the OpenPKG GmbH, transfer the source code of + your modifications to the OpenPKG GmbH and irrevocably transfer + all rights of your modifications to the OpenPKG GmbH which will + grant you unlimited use rights to your contribution. There is no + promise the OpenPKG GmbH includes your contribution into the OpenPKG + Framework. + + GRANT OF RIGHTS TO DISTRIBUTE THE OPENPKG FRAMEWORK + --------------------------------------------------- + + You may distribute the Product, or derivative works thereof created + under adherence of the "rights to modify" grant, if you ensure + the recipient receives these terms and conditions with the same + transaction. + + ONLINE ACCESS + ------------- + + The OpenPKG Framework collects information about the OpenPKG + Framework, OpenPKG Framework License and OpenPKG Packages for use + by the OpenPKG Project, the OpenPKG Foundation e.V. and the OpenPKG + GmbH. The programmatic license validation might and the information + upload process does require online access to the Internet. You agree + to grant the OpenPKG Framework permission for this use case and you + assume all costs related to the online access. + + TERMINATION + ----------- + + You may not use the OpenPKG Framework except as expressly + provided under the license. Any attempt to otherwise use, copy, + modify, distribute or sub-license the Product is void, and will + automatically terminate your rights under this license. + + CHANGE + ------ + + The OpenPKG GmbH reserves the right to subsequently modify or amend + details of these terms and conditions where this seems applicable, + as long as you are, in good faith, not disadvantaged thereby. + + Those changes or amendments of the terms and conditions will be + proclaimed to you by a written document, delivered to you in + electronic format or paper mail as chosen by the OpenPKG GmbH. + Anonymous and unknown users cannot be contacted by the OpenPKG GmbH. + They must review the terms and conditions regularly at the same time + they obtain or use an updated OpenPKG Framework. You cannot rise an + objection against the proclaimed changes or amendments. However, you + can terminate the license agreement without prior notice. + + DISCLAIMER + ---------- + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR + 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. + + LIMITED WARRANTY AND LIMITATION OF LIABILITY + -------------------------------------------- + + The OpenPKG GmbH is only liable for damages if the OpenPKG GmbH + or one of its vicarious agents has violated a major contractual + (cardinal) obligation or jeopardized the intention of the agreement + or the damage was done by gross negligence or intention of the + OpenPKG GmbH or one of its vicarious agents. + + In case the violation of a cardinal obligation is not caused by + gross negligence or intention of the OpenPKG GmbH or one of its + vicarious agents the liability of the OpenPKG GmbH is limited to the + predictable damage characteristical for the contract. + + The preceding liability limitations apply for contractual and + non-contractual claims. The liability of the OpenPKG GmbH due to + warranties, personal injury and due to the German Product Liability + Act remains unaffected from the preceding liability limitations. + + GENERAL + ------- + + This agreement sets forth the OpenPKG GmbH's entire liability and + your exclusive remedy with respect to the Product and supersedes + the terms of any purchase orders and any other communications or + advertising with respect to the Product. You acknowledge that this + agreement is a complete statement of the agreement between you + and the OpenPKG GmbH with respect to the Product, and that there + are no other prior or contemporaneous understandings, promises, + representations, or descriptions with respect to the Product. + + Headings under this agreement are intended only for convenience and + shall not affect the interpretation of this agreement. + + No failure of either party to exercise or enforce any of its rights + under this agreement will act as a waiver of those rights. This + agreement may only be modified, or any rights under it waived, by a + written document executed by the party against which it is asserted. + + If any provision of this agreement is found illegal or + unenforceable, it will be enforced to the maximum extent + permissible, and the legality and enforceability of the other + provisions of this agreement will not be affected. + + This agreement is governed by German law. + + If you have any questions about this agreement please contact the + OpenPKG GmbH. Direct all traditional paper correspondence to the + official company address as listed in the very first paragraph of + this document. You find the most recent contact information on our + website http://openpkg.com/ + + You can find the most recent version of this document on our website + http://openpkg.com/go/framework-license + +Assertion-MinProcVersion: 0.9.0 +Assertion-PackageNames: .*:^(openpkg|gpg-pubkey)$ + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAktAcNsACgkQZwQuyWG3rjSDIwCgzD8svM5KrsKGPLhOq08f2JLb +WlsAoNBKLE86nU3K78PY9k3ZHl1+CME0 +=1xzZ +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license-COMMUNITY.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license-COMMUNITY.txt Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,1063 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Id: COMMUNITY +Name: OpenPKG Framework Community License +Version: 1.0.0 +Issuer: OpenPKG GmbH +Issued: 2012-05-12 + +Licensee: arbitrary deployer of OpenPKG Framework + with this run-time license activated + +Description: + + OPENPKG FRAMEWORK COMMUNITY LICENSE + =================================== + + This license agreement constitutes a valid and binding agreement + between the OpenPKG GmbH, jurisdiction identification "DE MUC HRB + 160208", postal address "Weblinger Weg 28, 85221 Dachau, GERMANY", + digital signature name "OpenPKG GmbH " and + digital signature fingerprint "7D12 1A8F C05D C18A 4329 E9EF 6704 + 2EC9 61B7 AE34", represented by the two managing directors Ralf S. + Engelschall and Thomas Lotterer, and you, the licensee. + + "You" means the natural person or the entity that is agreeing to be + bound by this agreement. You shall be liable for any failure by your + employees and third party contractors that provide services to you + to comply with the terms and conditions of this agreement. + + AGREEMENT + --------- + + By using, copying, modifying or distributing the Product you agree + to be bound by the terms and conditions of this agreement. If you + are accepting these terms on behalf of another person or a company + or other legal entity, you represent and warrant that you have full + authority to bind that person, company, or legal entity to these + terms. If you do not agree to the terms and conditions of this + agreement, you may not use, copy, modify or distribute the Product. + You may return the unused Product to the supplier from which you + acquired it within 30 days and request a refund of the license fee, + if any, already paid upon showing proof of payment. + + TERMINOLOGY + ----------- + + OpenPKG is a solution to build software stacks consisting of OpenPKG + Packages and an OpenPKG Framework to operate them. + + For your information, OpenPKG Packages are available from the + OpenPKG Foundation e.V., which licenses and distributes them as Open + Source Software. These OpenPKG Packages are in no way subject of + this agreement. + + The OpenPKG Framework is a property of the OpenPKG GmbH with all + rights reserved. Licenses, like this one, which grant limited + permission to use, copy, modify and distribute this software are + exclusively issued by the OpenPKG GmbH. + + Licensing as described in this agreement covers the OpenPKG + Framework code copyrighted by the OpenPKG GmbH and the OpenPKG + Framework as a compound work. The OpenPKG Framework is distributed + in source code form and also contains pristine third-party sources + where each comes with its own licensing model. These licenses are + in no way altered by this agreement, but passed through to you + verbatim. You are responsible for obtaining and obeying any such + vendor license. + + This license describes how you appropriately use, copy, modify + and distribute the OpenPKG Framework source code and the binaries + resulting from the build process. This license does not include any + entitlement for you to receive service or support from the OpenPKG + GmbH, there are no warranties beyond the minimum implied warranty, + and there are no promises with respect to the future of the Product + or any derived works. + + GRANT OF RIGHTS GENERAL TERMS + ----------------------------- + + The OpenPKG Framework is licensed, not sold. Subject to the terms + and conditions of this agreement, the OpenPKG GmbH hereby grants + you a non-exclusive, non-sub-licensable and non-transferable right + to use the Product. You may not lease or rent the OpenPKG Framework + license. + + You may sell or otherwise transfer unused licenses if you ensure + the recipient receives these terms and conditions with the same + transaction and acknowledges to take over your responsibilities from + this agreement. + + You may not remove any titles, trademarks or trade names, copyright + notices, legends, or other proprietary markings on the Product. You + are not granted any rights to any trademarks or service marks of the + OpenPKG GmbH. All rights not expressly granted by this license are + reserved. + + You may use the Product as long as you own this license issued by + the OpenPKG GmbH, install it and obey the terms and conditions + listed below. This license, issued by the OpenPKG GmbH, ships + as a digitally signed text file which carries the exact license + conditions both in human readable plain text and attached in a + machine readable format. The latter may be used by the OpenPKG + Framework to programmatically validate the license compliance. If + programmatic license validation within the OpenPKG Framework detects + a compliance failure, the OpenPKG Framework might cease operation. + It is your responsibility to ensure compliance with these terms and + conditions. + + GRANT OF RIGHTS TO USE THE OPENPKG FRAMEWORK + -------------------------------------------- + + This "community" license ships free of charge with every OpenPKG + Framework and allows restricted use of the OpenPKG Framework. The + constraints are run-time limitations of the OpenPKG Framework to + enforce regular updates. The packages must have been built on the + target host, inhibiting "build on one host, deploy on other host" + scenarios. Online reporting is enabled. A large amount of + packgages being installed must be known by name and release, + preventing use of large amounts of outdated or modified packages. + This is effectively a "force source" and "bleeding edge" license. + + GRANT OF RIGHTS TO COPY THE OPENPKG FRAMEWORK + --------------------------------------------- + + You may create an unlimited number of copies of the Product. + + GRANT OF RIGHTS TO MODIFY THE OPENPKG FRAMEWORK + ----------------------------------------------- + + You may modify most parts of the Product and adjust it to your + needs, creating derivative works. You may not remove license + validation code, and you must ensure the preservation of the OpenPKG + GmbH fingerprint data. The copyright notice, the license excerpt and + the reference to this terms and conditions must be kept verbatim. + You must make clear to the recipient of the derived works that the + version he is receiving has been modified and by whom. + + These terms and conditions stay if force for derivative works. To + keep modifications your property you must not distribute them, in + source or binary form, beyond your organizational scope. In cases + of extended distribution or publication you agree to contribute + your modifications automatically, free of charge and without any + royalty claims, to the OpenPKG GmbH, transfer the source code of + your modifications to the OpenPKG GmbH and irrevocably transfer + all rights of your modifications to the OpenPKG GmbH which will + grant you unlimited use rights to your contribution. There is no + promise the OpenPKG GmbH includes your contribution into the OpenPKG + Framework. + + GRANT OF RIGHTS TO DISTRIBUTE THE OPENPKG FRAMEWORK + --------------------------------------------------- + + You may distribute the Product, or derivative works thereof created + under adherence of the "rights to modify" grant, if you ensure + the recipient receives these terms and conditions with the same + transaction. + + ONLINE ACCESS + ------------- + + The OpenPKG Framework collects information about the OpenPKG + Framework, OpenPKG Framework License and OpenPKG Packages for use + by the OpenPKG Project, the OpenPKG Foundation e.V. and the OpenPKG + GmbH. The programmatic license validation might and the information + upload process does require online access to the Internet. You agree + to grant the OpenPKG Framework permission for this use case and you + assume all costs related to the online access. + + TERMINATION + ----------- + + You may not use the OpenPKG Framework except as expressly + provided under the license. Any attempt to otherwise use, copy, + modify, distribute or sub-license the Product is void, and will + automatically terminate your rights under this license. + + CHANGE + ------ + + The OpenPKG GmbH reserves the right to subsequently modify or amend + details of these terms and conditions where this seems applicable, + as long as you are, in good faith, not disadvantaged thereby. + + Those changes or amendments of the terms and conditions will be + proclaimed to you by a written document, delivered to you in + electronic format or paper mail as chosen by the OpenPKG GmbH. + Anonymous and unknown users cannot be contacted by the OpenPKG GmbH. + They must review the terms and conditions regularly at the same time + they obtain or use an updated OpenPKG Framework. You cannot rise an + objection against the proclaimed changes or amendments. However, you + can terminate the license agreement without prior notice. + + DISCLAIMER + ---------- + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR + 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. + + LIMITED WARRANTY AND LIMITATION OF LIABILITY + -------------------------------------------- + + The OpenPKG GmbH is only liable for damages if the OpenPKG GmbH + or one of its vicarious agents has violated a major contractual + (cardinal) obligation or jeopardized the intention of the agreement + or the damage was done by gross negligence or intention of the + OpenPKG GmbH or one of its vicarious agents. + + In case the violation of a cardinal obligation is not caused by + gross negligence or intention of the OpenPKG GmbH or one of its + vicarious agents the liability of the OpenPKG GmbH is limited to the + predictable damage characteristical for the contract. + + The preceding liability limitations apply for contractual and + non-contractual claims. The liability of the OpenPKG GmbH due to + warranties, personal injury and due to the German Product Liability + Act remains unaffected from the preceding liability limitations. + + GENERAL + ------- + + This agreement sets forth the OpenPKG GmbH's entire liability and + your exclusive remedy with respect to the Product and supersedes + the terms of any purchase orders and any other communications or + advertising with respect to the Product. You acknowledge that this + agreement is a complete statement of the agreement between you + and the OpenPKG GmbH with respect to the Product, and that there + are no other prior or contemporaneous understandings, promises, + representations, or descriptions with respect to the Product. + + Headings under this agreement are intended only for convenience and + shall not affect the interpretation of this agreement. + + No failure of either party to exercise or enforce any of its rights + under this agreement will act as a waiver of those rights. This + agreement may only be modified, or any rights under it waived, by a + written document executed by the party against which it is asserted. + + If any provision of this agreement is found illegal or + unenforceable, it will be enforced to the maximum extent + permissible, and the legality and enforceability of the other + provisions of this agreement will not be affected. + + This agreement is governed by German law. + + If you have any questions about this agreement please contact the + OpenPKG GmbH. Direct all traditional paper correspondence to the + official company address as listed in the very first paragraph of + this document. You find the most recent contact information on our + website http://openpkg.com/ + + You can find the most recent version of this document on our website + http://openpkg.com/go/framework-license + +Assertion-MinProcVersion: 0.9.0 +Assertion-LifeTime: 2009-01-01:2012-09-01 +Assertion-GrantTime: 2009-01-01:2012-09-01 +Assertion-FromSourceOnTarget: yes +Assertion-OnlineReporting: http://openpkg.com/go/framework-license-reporting +Assertion-PackageReleaseAge: 90%:90d:^OpenPKG.*$ + *:20120624 lzma:20090830 + openpkg:20120701 lzo:20110827 + a2ps:20080101 lzop:20110924 + aalib:20100227 m4:20110303 + accent:20080101 maatkit:20110610 + ack:20120616 mailgrep:20080101 + activemq:20120509 mailman:20090327 + adns:20080101 mailsync:20080101 + adobeflex:20111217 majordomo:20110208 + aegis:20080808 make:20100729 + afio:20101219 makepp:20090206 + aft:20100911 mapson:20100225 + aica:20100227 maradns:20120312 + aide:20100911 markdown:20120414 + akka:20120606 mathomatic:20120630 + al:20080101 matrixssl:20100310 + alpine:20080827 maven:20120121 + altermime:20081116 max:20120623 + amanda:20101006 mbuffer:20110726 + amavisd:20110520 mc:20120423 + amd:20090418 mcpp:20081130 + analog:20080101 mcrypt:20090130 + anchor:20120319 md5deep:20120612 + ansifilter:20110402 md5sha1sum:20080101 + ant:20120524 mdbtools:20080102 + antiword:20080101 mdocml:20111009 + antlr:20110809 mediaproxy:20080112 + anubis:20081223 mediawiki:20100529 + apache-apreq:20101219 memcached:20120524 + apache-authext:20110219 memphis:20080101 + apache-authremote:20081228 mercurial:20120603 + apache-cloudflare:20120606 meta-antivirus:20080101 + apache-define:20081228 meta-archiver:20080101 + apache-extfwd:20080102 meta-core:20080101 + apache-fastcgi:20080101 meta-devel:20120627 + apache-flvx:20090301 meta-ldap:20120627 + apache-geoip:20110827 meta-pgp:20120627 + apache-icpquery:20081114 meta-rdbms:20120627 + apache-kerberos:20090326 metalink:20090327 + apache-layout:20080107 mhash:20090327 + apache-macro:20100911 mhonarc:20110109 + apache-openid:20100110 microemacs:20100110 + apache-perl:20120606 microregex:20100110 + apache-php:20120627 milter-backscatter:20100221 + apache-proxyhtml:20081219 milter-bogom:20080626 + apache-pubtkt:20120628 milter-dk:20090327 + apache-python:20101212 milter-dkim:20090826 + apache-roaming:20081230 milter-greylist:20100902 + apache-ruby:20081214 milter-header:20090707 + apache-sasl:20111022 milter-regex:20111122 + apache-security:20100206 milter-sa:20110924 + apache-sendmail:20110409 milter-sid:20080608 + apache-suphp:20100402 milter-smc:20080705 + apache-timedout:20100105 milter:20110731 + apache-tomcat:20120601 mimedefang:20100819 + apache-uid:20090412 minicom:20111229 + apache-wsgi:20101212 mirror:20080208 + apache-xslt:20080906 mixmaster:20100109 + apache-zeus:20080101 mk:20080101 + apache:20120205 mkisofs:20101219 + apacheds:20100410 mksh:20120407 + apachetop:20080101 mktemp:20100426 + apg:20080101 mldonkey:20100816 + apr:20120214 mm:20091121 + apt:20080101 mng:20080101 + aqbanking:20080101 modsurvey:20091122 + aqmoney:20120515 mongodb:20120630 + arc:20100808 monit:20120507 + ares:20120619 mono:20110106 + argp:20080921 monotone:20100417 + argtable:20110111 mozldap:20090410 + aria2:20120528 mp3c:20080101 + arj:20080101 mp3imagetagextr:20100129 + arpalert:20080401 mp3info:20080101 + arpd:20080101 mp3nema:20090409 + arpoison:20080101 mpack:20080101 + arptools:20080101 mpc:20110222 + arx:20100930 mpfr:20120508 + ascii:20110317 mpg123:20120512 + ascii2binary:20100830 mpop:20120502 + asciidoc:20120318 mrtg:20111202 + asmifier:20110912 msmtp:20120502 + asn1c:20080101 msntp:20080101 + aspell:20110731 msort:20100111 + asterisk-conference:20080320 mtasc:20100126 + asterisk-espeak:20080322 mtools:20110629 + asterisk-festival:20080321 mtr:20120623 + asterisk-flite:20080322 mtx:20080821 + asterisk-ldap:20080323 multisort:20080101 + asterisk-libiax:20080320 multitail:20111231 + asterisk-utils:20080324 mutt:20110123 + asterisk:20101019 mxml:20111221 + asymptote:20120602 mybatis:20120523 + atool:20120403 myjit:20120126 + audiofile:20100322 myodbc:20091110 + augeas:20110416 mysql:20120630 + autoconf-archive:20120409 mysql55:20100920 + autoconf:20120426 mysqlproxy:20111211 + autogen:20101120 nagios:20120628 + autojar:20110731 nail:20100418 + automake:20120603 nano:20110511 + autossh:20111013 nant:20120610 + autotrace:20101219 nasm:20090722 + avahi:20110404 ncftp:20110120 + avis:20091216 ncompress:20080101 + awk:20080101 ncurses:20120529 + axkit:20100415 ndb:20120630 + axl:20120105 ne:20120419 + babl:20120603 neko:20100107 + bacula:20120629 neo4j:20120421 + bar:20110322 neon:20110504 + bash:20120603 netatalk:20120523 + bashdb:20110731 netcat:20080101 + bazaar:20120531 netcdf:20100403 + bbe:20080101 netpbm:20100202 + bc:20080829 netrik:20090620 + bdc:20080101 nettle:20111114 + bdec:20110711 newlib:20101217 + beecrypt:20120124 newlisp:20120508 + bind:20120603 newsyslog:20090718 + binutils:20111122 newt:20101112 + bird:20120329 nexus:20111223 + bison:20120606 nfdump:20120314 + bitflu:20120502 nfs-ganesha:20110720 + bittorrent:20081029 nginx:20120627 + blosxom:20080101 ngircd:20120304 + bnd:20110731 ngrep:20080101 + boa:20080101 njmc:20080101 + bogofilter:20101219 nmake:20120109 + bonnie:20080101 nmap:20120617 + boost:20120623 nn:20080101 + botan:20120618 nntpcache:20080101 + botan18:20110711 node-redis:20120312 + boxes:20080101 node-underscore:20120410 + bs:20080101 node:20120630 + bsdiff:20080101 noexec:20080101 + btar:20120610 noweb:20100130 + btyacc:20080101 nqp:20120611 + bup:20120217 ns4:20100110 + burp:20120608 nsd:20120217 + byacc:20120527 nsis:20091207 + bzip2:20100920 nslint:20100912 + c2man:20080101 nspr:20111211 + cabextract:20110924 nss:20080802 + cacti-spine:20120501 ntp:20111226 + cacti:20120501 nwcc:20090305 + cadaver:20120530 nxlog:20120605 + cairo:20120623 ocaml:20110705 + cairomm:20110509 ocrad:20110111 + calamaris:20080101 ocspd:20110212 + calc:20081229 odoc:20080101 + calcurse:20100529 odt2txt:20091016 + calltree:20080101 offlineimap:20100109 + captivednsd:20081102 oidentd:20080101 + ccache:20120108 omake:20080101 + ccfe:20120513 omnisync:20090104 + ccide:20101009 ondir:20120310 + ccrypt:20090829 onig:20100108 + cdb:20110406 op:20080101 + cdk:20120329 opencdk:20080806 + cdpr:20100217 openclipart:20080101 + cdrecord:20080101 opendbx:20100421 + cego:20120527 opendkim:20120625 + cencode:20091121 openfire:20090503 + centericq:20080101 openjade:20090327 + cfengine:20120211 openjpeg:20100110 + cfg:20080101 openldap:20120301 + cflow:20080101 openmpi:20120515 + cftp:20080101 openpkg-darwin:20100329 + cfv:20090608 openpkg-external:20111126 + cgdb:20110917 openrdate:20081123 + cgiirc:20101219 opensips:20101221 + cgilib:20100109 openslp:20080101 + cgit:20120319 opensp:20080101 + cgstmad:20100105 openssh:20120627 + chaiscript:20100119 openssl:20120606 + check:20090923 openssl10:20100226 + checkbot:20081015 openvpn:20111223 + cherokee:20111020 opie:20080101 + chilon:20110320 optipng:20120321 + chkrootkit:20090804 oracle:20080101 + cint:20080101 orbit:20080101 + cinvoke:20080101 orbit2:20100929 + citadel:20080304 orc:20111004 + clamav:20120617 orientdb:20120515 + clamshell:20090705 orpie:20100110 + classgen:20080101 ortp:20120223 + clearsilver:20080101 osip:20120412 + clex:20090926 ots:20080101 + cli:20091219 owncloud:20120629 + cloc:20120410 p0f:20120512 + clojure:20110414 p11kit:20120310 + closurecompiler:20120501 p7zip:20100530 + closurelinter:20120301 pam:20110219 + closurestylesheets:20111231 pango:20120623 + cloudvpn:20110731 pangoxsl:20080101 + cmake:20120419 paperkey:20091015 + cmph:20120603 papyrus:20080101 + cocom:20080101 paq:20080829 + cocor:20080101 par:20080101 + coffeescript:20120410 par2cmdline:20080806 + commons:20120617 parallel:20120623 + compass:20120303 pari:20120207 + config:20120627 parrot:20120528 + conman:20110423 patch:20091230 + cook:20100926 patchutils:20110211 + coreutils:20120603 path:20120310 + couchdb:20120407 pax:20120109 + cparser:20100416 pb4sd:20080101 + cpio:20100311 pcal:20080101 + cppcheck:20100110 pccts:20080101 + cppi:20120603 pcre:20120528 + cppunit:20120505 pdcurses:20080909 + cproto:20110103 pdf2djvu:20120605 + cpu:20080101 pdf2svg:20100506 + cracklib:20120519 pdflib:20100804 + crm114:20100111 pdfresurrect:20120531 + cronolog:20080515 pdfsam:20101122 + crossroads:20080519 pdftk:20080721 + crush:20091228 pdksh:20080101 + cryptlib:20110731 pdnsd:20120318 + cscope:20120616 pecomato:20080101 + csp:20080101 peep:20080101 + css2xslfo:20100824 peg:20120501 + cssc:20110515 pegdown:20111217 + csync:20120522 pegtl:20110227 + ctags:20091018 perftools:20110827 + ctalk:20100401 perl-aop:20120531 + ctorrent:20080101 perl-apache:20120531 + ctrlproxy:20090503 perl-asterisk:20120531 + cttl:20090824 perl-biz:20120531 + cufon-fonts:20100313 perl-bytecode:20120605 + cufon:20120414 perl-cache:20120531 + cup:20080101 perl-comp:20120531 + cups:20120516 perl-conv:20120610 + curl:20120525 perl-crypto:20120608 + cutils:20080101 perl-curses:20120603 + cvs:20100106 perl-db:20120531 + cvs2cl:20100105 perl-dbi:20120626 + cvsd:20120603 perl-dbix:20120531 + cvsgraph:20080522 perl-devel:20120531 + cvsps:20080402 perl-dns:20120531 + cvstrac:20110203 perl-ds:20120629 + cvsweb:20080101 perl-font:20120531 + cvsync:20080101 perl-gd:20120531 + cwc:20091015 perl-gfx:20120531 + daemon:20100613 perl-inline:20120531 + daemontools:20081007 perl-kerberos:20120531 + dailystrips:20080101 perl-ldap:20120531 + dante:20120603 perl-locale:20120602 + dar:20110907 perl-mail:20120621 + darcs:20080101 perl-math:20120622 + dash:20100227 perl-module:20120621 + data-charset:20080530 perl-net:20120621 + data-iana:20080306 perl-ole:20120531 + data-isocodes:20120630 perl-openpkg:20120531 + data-timezone:20110731 perl-par:20120531 + dateutils:20120115 perl-parse:20120622 + davical:20120618 perl-poe:20120531 + db:20091002 perl-regex:20120607 + db45:20080502 perl-sip:20120626 + dbmail:20120120 perl-ssh:20120531 + dbtool:20090625 perl-ssl:20120618 + dbus:20120628 perl-stats:20120531 + dcc:20090112 perl-sys:20120616 + dchk:20100805 perl-template:20120531 + dcron:20080424 perl-term:20120531 + ddrescue:20120612 perl-text:20120531 + deco:20100608 perl-time:20120602 + deheader:20110211 perl-tm:20120531 + delegate:20100401 perl-util:20120616 + devtodo:20080101 perl-vcs:20120621 + dhcp-agent:20080101 perl-www:20120628 + dhcpd:20111211 perl-wx:20120531 + dhcpdump:20080625 perl-xml:20120626 + dhcping:20080101 perl:20120531 + dhrystone:20080101 perlbal:20110123 + dhtml:20120623 perltidy:20120621 + di:20111121 petidomo:20080101 + dialog:20120603 pgautodoc:20120109 + diction:20080101 pgfouine:20100225 + diffstat:20120103 pgp:20080101 + diffutils:20120512 pgp2:20080101 + dim:20091123 pgpdump:20080101 + diogene87:20120623 pgpool:20120527 + dirac:20120123 pgscript:20080908 + discount:20120120 phc:20090216 + distcache:20080101 php-apc:20120608 + distcc:20120623 php-couchdb:20120608 + ditaa:20090411 php-fpm:20120616 + djbdns:20080101 php-imagemagick:20120608 + djvulibre:20110307 php-memcached:20120608 + dlint:20080101 php-mongodb:20120608 + dmake:20080101 php-sabre:20120613 + dmalloc:20080101 php-slim:20120608 + dnstracer:20080210 php-xcache:20120608 + docbook:20101102 php-xdebug:20120423 + docbook2x:20080726 php-zf:20120623 + doclifter:20120625 php:20120616 + docutils:20120503 phpbb:20100715 + doodle:20101219 pine:20080101 + dos2unix:20120507 pinentry:20120623 + dovecot:20120531 pinfo:20080101 + doxygen:20120603 pisa:20100617 + dparser:20101221 pkgconfig:20110530 + dpkg:20120320 pks:20080101 + drac:20120521 pktstat:20120306 + dragon:20100816 ploticus:20120623 + drizzle:20100915 plotutils:20100507 + drupal-module-misc:20120625 pmake:20080101 + drupal-theme-misc:20120531 pmk:20080325 + drupal:20110526 pnet:20080101 + dsh:20080101 pnetlib:20080101 + dsniff:20080101 png:20110707 + dspam:20120424 png2ico:20080101 + dss:20080101 pngrewrite:20100609 + duff:20120129 pngslice:20081018 + dumpasn1:20110218 pod2pdf:20090717 + dvdauthor:20101023 polarssl:20110223 + dvdrw-tools:20080305 poppler-data:20110901 + dvipng:20101215 poppler:20120611 + dwarf:20110123 popt:20100508 + dwdiff:20120613 portablesigner:20100110 + dynamips:20080101 portfwd:20080101 + dyncall:20120103 portsentry:20080101 + easysoap:20080101 poster:20080101 + ecartis:20080101 postfix-mailgraph:20080101 + echoping:20080101 postfix:20120627 + ecj:20111207 postgresql:20120623 + ecl:20111211 postgrey:20110505 + ed:20120103 pound:20111229 + editline:20100813 poweradmin:20080101 + ee:20100604 powerdns:20090126 + ejs:20090517 precc:20080101 + eli:20080101 premake:20101117 + elinks:20090708 prest:20101209 + elm:20110526 prince:20120122 + emacs:20120623 prince7:20111001 + email:20101101 privoxy:20111227 + enscript:20080101 prngd:20080101 + envstore:20100626 procmail:20090727 + eotutils:20120103 proftpd:20120328 + epic4:20090906 proguard:20120528 + epm:20080101 protobuf:20110501 + eps2png:20090529 proxytunnel:20080304 + epstool:20080101 prwd:20091212 + epub2pdf:20100516 psh:20080101 + equinox:20111207 pstoedit:20110828 + erlang:20120404 pstreams:20100513 + esmtp:20091224 psutils:20080101 + espeak:20120109 pth:20080101 + ettercap:20080101 punbb-ext-standard:20110305 + ex-vi:20080101 punbb:20110922 + ex:20080211 pureftpd:20111208 + exif:20101219 pv:20080306 + exim:20100123 pwauth:20111009 + expat:20120325 pwmd:20101122 + expect:20080419 python-crypto:20120128 + ez-ipupdate:20080101 python-db:20111013 + faac:20090301 python-gfx:20100705 + faad:20090228 python-google:20120421 + fann:20090327 python-json:20120626 + fastjar:20090925 python-ldap:20120618 + festival:20080323 python-math:20120520 + fetchmail:20110827 python-net:20120606 + ffe:20110411 python-paste:20111110 + ffmpeg:20120608 python-pdf:20101205 + fftw:20120507 python-setup:20100724 + fido:20120605 python-text:20120311 + fig2pstricks:20090222 python-www:20111126 + figlet:20120609 python-xml:20111126 + file:20120603 python:20120412 + fileschanged:20120610 python3:20100322 + findutils:20110515 qdbm:20080101 + flac:20090228 qore:20091212 + flashpolicyd:20090919 qpopper:20110701 + flawfinder:20080101 qrencode:20120419 + flex:20100913 quagga:20120502 + flite:20091230 quilt:20120301 + flow2rrd:20110209 r:20120623 + flowd:20100110 rabbitmq:20120622 + flowscan:20080101 radius:20081217 + flowtools:20080101 radiusclient:20080317 + flvtool:20090307 ragel:20110524 + flvtoolxx:20090619 rakudo:20120501 + fly:20090617 ratbox:20100423 + fm-submit:20080101 rats:20110722 + fntsample:20100806 rbldnsd:20080329 + font-optimizer:20100405 rc:20090509 + fontconfig:20120625 rcs:20120606 + fontface:20120108 rdiff-backup:20090317 + fontforge:20120618 rdist:20080101 + fonts-free:20120614 rdp:20080101 + fonttools:20100405 rdup:20120219 + fop:20100721 re2:20110305 + fossil:20111214 re2c:20080526 + fourstore-java:20100331 readline:20120406 + fourstore:20110923 recode:20110731 + fpdns:20080101 recutils:20120114 + fping:20120529 redis-libs:20120629 + fprobe:20080101 redis-tools:20110225 + fprot:20080101 redis:20120622 + freeradius:20100929 redland-raptor:20120625 + freetds:20120603 redland-rasqal:20120515 + freetype:20120616 redland:20111204 + fribidi:20090328 regexp9:20080906 + frink:20110218 regina:20100106 + fsharp:20090620 remind:20120124 + fsl:20100418 reposurgeon:20111116 + gale:20080101 rfc:20100214 + gamin:20120610 rhino:20110730 + ganttproject:20090327 rhodecode:20111211 + gated:20080101 rie:20080101 + gawk:20120331 ripe-asused:20120424 + gc:20120626 ripe-dbase:20080101 + gcal:20120603 ripe-ipadm:20080101 + gcc:20120321 ripe-whois:20080101 + gcc47:20120603 rlwrap:20100505 + gcflow:20111014 roadrunner:20080101 + gconf:20100805 roff:20080408 + gcrypt:20100714 rolo:20080101 + gd:20120623 rpl:20080425 + gdb:20120603 rrdtool:20120308 + gdbm:20120605 rspamd:20110227 + gdk-pixbuf:20120623 rsstail:20110310 + gecode:20111011 rsstool:20100312 + gengen:20091001 rst2pdf:20120602 + gengetopt:20091224 rsync:20110924 + gentle:20080101 rsyslog:20120605 + geoip:20110827 rt:20120525 + getopt:20080101 ruby-gems:20120428 + gettext:20100607 ruby-gfx:20120303 + ghc-zlib:20120122 ruby-spec:20120504 + ghc:20090503 ruby:20120414 + ghostscript:20120623 ruby18:20110731 + gif2png:20120309 ruli:20080101 + giflib:20120620 rush:20100708 + gift-ares:20080101 rvm:20101001 + gift-fasttrack:20080101 rwhoisd:20080101 + gift-gnutella:20080101 rxspencer:20080906 + gift-openft:20080101 rzip:20080101 + gift:20080101 sa:20080101 + giftcurs:20080101 sablecc:20120627 + git:20120622 sablotron:20080101 + gjdoc:20120603 sam2p:20091123 + gjrand:20110701 samba:20120626 + glark:20101219 samhain:20120503 + glassfish:20120623 sasl:20101020 + gle:20120623 sass:20120303 + glib:20080101 sav:20080101 + glib2:20120610 saxon:20111004 + glibmm:20100107 sbt:20110925 + glimpse:20081220 scala:20120414 + global:20120603 scanssh:20080101 + glpk:20111211 sccs:20110428 + gmime:20120614 scli:20100220 + gmime22:20120410 scons:20110910 + gmime24:20120219 scponly:20101209 + gmp:20120511 screen:20110217 + gnats:20080101 sec:20120124 + gnet:20100220 sed:20090628 + gntp:20100505 see:20090428 + gnuchess:20120603 seed7:20120623 + gnuit:20090224 sendfile:20080526 + gnupg:20120329 sendmail:20120521 + gnupg1:20120201 serf:20120321 + gnuplot:20120623 sfio:20080101 + gnutls:20120609 sgml:20080101 + go:20120414 sgmlfmt:20080101 + goaccess:20110103 sgrep:20080101 + gocr:20120623 sh:20100306 + googlecl:20110402 shared-mime-info:20101205 + gperf:20090206 sharutils:20120605 + gpg-error:20101027 shellinabox:20111101 + gpgme:20110731 shiela:20080207 + gpp:20080322 shishi:20120605 + gprolog:20110731 shrinksafe:20081225 + gradle:20120612 shsql:20080101 + grammatica:20090309 shtool:20080718 + graphite:20100108 shush:20090721 + graphviz:20120623 sid:20100110 + grep:20120425 siege:20100809 + grepcidr:20080101 sio:20080101 + grepmail:20080101 sipcalc:20090721 + groff:20101231 siproxd:20091012 + groovy:20120628 sipsak:20080101 + grzip:20080101 sitecopy:20110731 + gsasl:20120529 skey:20080101 + gsl:20110731 skill:20080101 + gsm:20090406 sks:20080101 + gsnmp:20100220 slang:20110731 + gsoap:20100406 sleuthkit:20111009 + gss:20120603 smalltalk:20120605 + guile:20120201 smbc:20080101 + gup:20080405 smbget:20080101 + gyp:20120515 smlnj:20120623 + gzip:20120618 smokeping:20080725 + h2:20120523 smtpfeed:20080101 + hadoop:20120517 snappy:20120225 + haildb:20111211 sng:20110717 + haml:20120304 snmp:20111211 + hamsterdb:20120123 snmpdx:20080101 + haproxy:20120521 snort:20100427 + haxe:20110131 snownews:20090919 + hclnfsd:20080101 soapbox:20120406 + hdf:20120603 soapjr:20090326 + heartbeat:20080101 socat:20120515 + heimdal:20100914 softflowd:20080101 + heise:20110205 solarium:20120417 + hevea:20080101 solr:20120412 + hexcurse:20080101 solrflux:20110730 + hexdump:20101021 soot:20120123 + hexer:20110831 sophie:20080101 + highlight:20120105 source-highlight:20120701 + hlfl:20100110 sox:20110228 + honeyd:20080101 spamassassin:20110526 + hping:20080101 spambouncer:20080101 + htdig:20080101 spandsp:20100108 + html2latex:20080101 spdylay:20120612 + html2ps:20100508 speex:20080724 + html2text:20080101 spegla:20080101 + httptunnel:20080101 spin:20120623 + httrack:20100105 splint:20080101 + hugs:20080101 spread:20091003 + hungrycat:20120310 spring:20110731 + hypermail:20080101 sqlite:20120625 + iat:20090825 sqlitedbms:20080101 + iburg:20080101 sqlshell:20120523 + icecast:20120612 sqlsync:20080508 + ices:20091202 squid:20120609 + icmake:20090430 squidguard:20100910 + icns:20090627 squirrelmail:20100723 + icon-theme:20101109 srp:20081223 + icon:20100414 ss5:20120525 + icoutils:20090817 sshfp:20111211 + icu:20110526 ssldump:20080101 + id3lib:20080101 sslh:20120519 + idutils:20120603 ssmtp:20110731 + ifile:20080101 ssss:20080325 + iftop:20111005 sswf:20090308 + iksemel:20090726 star:20080523 + imagemagick:20120623 statsvn:20100105 + imap:20120603 steghide:20080101 + imap2mbox:20091102 stlport:20100111 + imapd:20120603 stonevpn:20120128 + imapfilter:20100124 str:20080101 + imapsync:20101027 strace:20091022 + imaputils:20080101 stuffit:20080101 + imlib:20120623 stun:20080101 + indent:20090614 stunnel:20111211 + inetutils:20120603 styx:20101230 + infozip:20080101 subgit:20120313 + iniparser:20080401 subversion-apache:20120518 + inn:20090309 subversion-cvs:20100725 + instant:20100105 subversion-perl:20110602 + integrit:20080101 subversion-python:20110602 + interceptty:20080101 subversion:20120518 + intltool:20090315 suck:20080101 + io:20100110 sudo:20120531 + iodbc:20120329 sudosh:20100710 + iozone:20120511 sugarcrm:20120701 + ipaudit:20080101 super:20120310 + ircd:20080101 supervisord:20111126 + ircii:20110731 supose:20100612 + ironout:20080924 surl:20120309 + irssi:20100403 svk:20111103 + iselect:20080101 svnauthcheck:20111113 + ispell:20120607 svnnotify:20111030 + its4:20080101 svntree2files:20090410 + jabberd:20110602 svnweb:20100725 + jam:20100323 svrcore:20090410 + jargon:20080101 svs:20091018 + jarjar:20120504 swaks:20120321 + jarprocessor:20111207 swatch:20080704 + jasmin:20100508 swfmill:20111107 + jasper:20080101 swftools:20120409 + java-gcj:20080101 swhoisd:20080101 + java-jdk15:20080709 swig:20120526 + java-jdk16:20100111 sympa:20090418 + java-jdkfake:20090922 synctool:20100729 + java:20091207 syslog-ng:20120527 + javacc:20090717 sysmon:20080101 + jboss:20080101 t1lib:20120623 + jclazz:20090430 tacacs:20080101 + jenkins:20120625 tailor:20120606 + jflex:20090131 talkfilters:20080101 + jidgen:20081017 tar:20110731 + jikes:20080101 tardy:20100522 + jitterbug:20080101 tcl:20120623 + jode:20080101 tcpdump:20120613 + joe:20090327 tcpreplay:20100405 + john:20111124 tcptrace:20080101 + joomla:20111211 tcptraceroute:20080101 + jpeg:20120116 tcptrack:20080207 + jrst:20090223 tcpwrappers:20080101 + js:20111103 tcsh:20081010 + js2coffee:20120410 teapop:20080101 + jsdoc:20080726 tecla:20120613 + jslim:20120117 termutils:20080101 + jslint:20120122 tetex:20120623 + json:20110522 tex4ht:20080101 + jsqsh:20120523 texinfo:20080923 + jxplorer:20100503 texlive:20120623 + kaffe:20080101 tftp:20110624 + kcd:20090327 the:20111211 + kelbt:20120123 theora:20091003 + kerberos:20100227 thrift:20111130 + kermit:20080101 throttle:20080305 + keychain:20080101 thttpd:20080101 + kimwitu:20080101 tidy:20110313 + klish:20120630 tiff:20120219 + knot:20120421 tika:20111111 + kotlin:20120217 tin:20111226 + kouprey:20091012 tinyap:20080512 + ksh:20120109 tinyproxy:20080101 + kwiki:20090823 tla:20080101 + l2:20090710 tmake:20110320 + lame:20120301 tmpp:20080806 + lasem:20100216 tmux:20120124 + latex2html:20080924 tokyocabinet:20120411 + lcal:20080101 tomcat:20120629 + lcdf-typetools:20120414 top:20090522 + lcms:20111216 tor:20120427 + ldapdiff:20081214 trac-plugins:20110619 + ldapuseradd:20111122 trac:20120207 + ldapvi:20080101 traceroute:20080101 + ldns:20120523 trafficserver:20120622 + lemon:20090718 trang:20080815 + leo:20080504 transcode:20091101 + less:20120627 tre:20090920 + lessjs:20120618 tree:20091126 + leveldb:20110730 treecc:20080101 + lex:20080101 tripwire:20080101 + lft:20080516 ts:20120527 + lftp:20120531 tsocks:20080101 + lha:20080101 ttf2eot:20120102 + libarchive:20120113 ttfautohint:20120617 + libart:20100402 ttmkfdir:20100405 + libassuan:20120603 tw:20120109 + libbls:20091116 twiki:20080101 + libcli:20100313 txr:20120421 + libcroco:20111116 txt2html:20080508 + libdaemon:20100813 txt2man:20110317 + libdbi:20080607 txt2pdf:20100106 + libdnet:20080101 txt2regex:20080101 + libdrizzle:20100319 txt2tags:20080727 + libdvdcss:20120312 typo3:20120523 + libdvdread:20090329 ucarp:20100201 + libecap:20110219 ucblogo:20100111 + libedit:20120602 ucl:20080101 + libee:20120417 ucspi-tcp:20080101 + libeio:20100812 udns:20111230 + libelf:20091101 uglifyjs:20120528 + libelvin:20080101 umlspeed:20080101 + libemf:20120526 unarj:20080101 + libesmtp:20100810 unfsd:20090106 + libestr:20110803 unhash:20100220 + libev:20110216 uni2ascii:20110515 + libevent:20120504 unifdef:20110223 + libexecinfo:20100328 unison:20110418 + libexif:20101216 units:20120629 + libexplain:20110827 uniutils:20090219 + libextractor:20111211 unix-essentials:20100329 + libfa:20111203 unixodbc:20111126 + libffi:20120603 unrar:20120614 + libfirm:20111223 upx:20111213 + libflaim:20080101 uriparser:20090305 + libgda:20080101 urpmi:20100111 + libgdome:20080101 usemod:20080101 + libghttp:20080101 ustl:20120219 + libgit2:20120612 uucp:20080101 + libgnomeprint:20100929 uudeview:20080101 + libgsasl:20120603 uuid:20080717 + libgsf:20110521 uvscan:20101229 + libhx:20091012 uxdstools:20101126 + libical:20111214 v8:20120625 + libiconv:20110807 vacation:20080216 + libidl:20100331 val:20080101 + libidn:20120529 vala-gee:20090721 + libjio:20110228 vala:20110918 + libjit:20081210 valgrind:20111107 + libjudy:20110227 var:20080101 + libksba:20110303 varnish:20120521 + liblogging:20080506 vbindiff:20080727 + liblqr:20090725 vcdiff:20120404 + liblzf:20110208 vcheck:20110311 + libmcrypt:20080101 vd:20090510 + libmicrohttpd:20120605 vfu:20120609 + libmikmod:20080101 viewmtn:20080101 + libming:20100207 viewvc:20120623 + libmpeg2:20090329 vifm:20120625 + libmrss:20080823 vile:20120627 + libmsgque:20101201 vilistextum:20080101 + libnatpmp:20110809 vim-plugin-misc:20110708 + libnet:20080416 vim-plugin-shell:20110731 + libnetdude:20100317 vim:20120623 + libnfsidmap:20111207 visitors:20080101 + libnids:20100314 vorbis-libs:20120204 + libntlm:20091106 vorbis-tools:20080101 + libnut:20090314 vortex:20120105 + libnxml:20080823 vpnc:20091104 + libodbcplus:20120623 vrl:20090509 + liboil:20100205 vstr:20080101 + liboop:20080101 w3m:20110115 + liboping:20120201 waf:20120415 + libopkele:20091223 wcd:20120301 + libparsifal:20090725 wdg-validator:20110303 + libpcap:20120613 wdiff:20120603 + libpcapnav:20080101 weaveserver:20100131 + libpipeline:20120303 webalizer:20110110 + libpixman:20120630 webdis:20110223 + libpki:20110615 webmin:20110805 + libpst:20111226 webp:20111118 + libptytty:20090504 wget:20111018 + libradius:20080101 whatmask:20080101 + libraw:20120628 whetstone:20080101 + librelp:20091213 which:20080807 + librmath:20120622 whois:20111226 + librsvg:20120623 whoson:20090711 + librsync:20080101 wipe:20101219 + libsamplerate:20110827 wireshark:20120622 + libshout:20120516 wml:20110213 + libsieve:20081116 woff:20120103 + libsigcxx:20120603 wordpress:20120629 + libsigsegv:20110403 wput:20100110 + libsmbclient:20120626 wv:20120623 + libsndfile:20110715 x264:20120414 + libsoup:20111122 x509:20120315 + libspf2:20081105 xalan:20080101 + libsrs2:20080101 xar:20080105 + libssh2:20120519 xbase:20080101 + libtasn1:20120603 xdelta:20100803 + libtelnet:20100110 xds:20080101 + libtool:20111211 xerces-c:20100620 + libtpl:20100206 xfpt:20120520 + libunistring:20110216 xinetd:20080101 + liburcu:20120421 xjobs:20120413 + libutf8:20100105 xmake:20080101 + libutf8proc:20100110 xml-coreutils:20110731 + libuuid:20101223 xml2rfc:20110327 + libvncserver:20120623 xmlcatmgr:20080101 + libvpx:20110403 xmldiff:20081001 + libwmf:20120623 xmlpatch:20111211 + libxdiff:20081113 xmlroff:20120623 + libxml:20101106 xmlrpcpp:20080101 + libxmlpatch:20111126 xmlsec:20110512 + libxr:20090223 xmlstarlet:20120115 + libxslt:20090925 xmlto:20100105 + libzdb:20120620 xmlvm:20100328 + libzip:20120321 xnm:20090130 + lighttpd:20120601 xpdf:20120623 + limesurvey:20120623 xplain2sql:20080819 + limo:20080101 xsugar:20090130 + linc:20080101 xtermcontrol:20120630 + linkchecker:20090608 xvid:20110602 + linklint:20080101 xz:20120627 + links:20120626 yacc:20080101 + llgen:20080101 yamdi:20110227 + lljvm:20100125 yaml:20120420 + llnextgen:20120102 yasm:20111031 + llvm:20111203 yassl:20100127 + lmtp2nntp:20080101 yml:20111230 + log4c:20080921 yodl:20080101 + log4net:20080204 youtrack:20120630 + logsurfer:20080101 ypanything:20080101 + logtools:20080608 ytree:20110110 + lout:20100922 yuicompressor:20110430 + lpsolve:20100813 yum:20080101 + lrzip:20110928 zebra:20080101 + lrzsz:20080101 zile:20111222 + lsh:20080101 zimg:20080101 + lsof:20120603 ziproxy:20100909 + lua-cjson:20120302 zlex:20080101 + lua-curl:20100208 zlib:20120503 + lua-posix:20080719 zmq:20111004 + lua-rdbms:20080608 zoem:20110617 + lua-regex:20101216 zoo:20080101 + lua-socket:20080608 zope-cmf:20080106 + lua-std:20110227 zope-plone:20080101 + lua:20120616 zope:20080510 + luit:20120623 zsh:20120603 + lwc:20080101 zsync:20100920 + lynx:20090707 zyacc:20080101 + lzip:20120313 zziplib:20120311 + lzlib:20120408 + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAk/wbhYACgkQZwQuyWG3rjQkjACfUNFTGwKIiCEhQrOSi3P4BWTu +tf4AoLdAZtAXzDeduf6bKpzR1fM0jFAE +=YgE4 +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license-EVAL.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license-EVAL.txt Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,272 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Id: EVAL +Name: OpenPKG Framework Evaluation License +Version: 1.0.0 +Issuer: OpenPKG GmbH +Issued: 2010-01-01 + +Licensee: arbitrary deployer of OpenPKG Framework + with this run-time license activated + +Description: + + OPENPKG FRAMEWORK EVALUATION LICENSE + ==================================== + + This license agreement constitutes a valid and binding agreement + between the OpenPKG GmbH, jurisdiction identification "DE MUC HRB + 160208", postal address "Weblinger Weg 28, 85221 Dachau, GERMANY", + digital signature name "OpenPKG GmbH " and + digital signature fingerprint "7D12 1A8F C05D C18A 4329 E9EF 6704 + 2EC9 61B7 AE34", represented by the two managing directors Ralf S. + Engelschall and Thomas Lotterer, and you, the licensee. + + "You" means the natural person or the entity that is agreeing to be + bound by this agreement. You shall be liable for any failure by your + employees and third party contractors that provide services to you + to comply with the terms and conditions of this agreement. + + AGREEMENT + --------- + + By using, copying, modifying or distributing the Product you agree + to be bound by the terms and conditions of this agreement. If you + are accepting these terms on behalf of another person or a company + or other legal entity, you represent and warrant that you have full + authority to bind that person, company, or legal entity to these + terms. If you do not agree to the terms and conditions of this + agreement, you may not use, copy, modify or distribute the Product. + You may return the unused Product to the supplier from which you + acquired it within 30 days and request a refund of the license fee, + if any, already paid upon showing proof of payment. + + TERMINOLOGY + ----------- + + OpenPKG is a solution to build software stacks consisting of OpenPKG + Packages and an OpenPKG Framework to operate them. + + For your information, OpenPKG Packages are available from the + OpenPKG Foundation e.V., which licenses and distributes them as Open + Source Software. These OpenPKG Packages are in no way subject of + this agreement. + + The OpenPKG Framework is a property of the OpenPKG GmbH with all + rights reserved. Licenses, like this one, which grant limited + permission to use, copy, modify and distribute this software are + exclusively issued by the OpenPKG GmbH. + + Licensing as described in this agreement covers the OpenPKG + Framework code copyrighted by the OpenPKG GmbH and the OpenPKG + Framework as a compound work. The OpenPKG Framework is distributed + in source code form and also contains pristine third-party sources + where each comes with its own licensing model. These licenses are + in no way altered by this agreement, but passed through to you + verbatim. You are responsible for obtaining and obeying any such + vendor license. + + This license describes how you appropriately use, copy, modify + and distribute the OpenPKG Framework source code and the binaries + resulting from the build process. This license does not include any + entitlement for you to receive service or support from the OpenPKG + GmbH, there are no warranties beyond the minimum implied warranty, + and there are no promises with respect to the future of the Product + or any derived works. + + GRANT OF RIGHTS GENERAL TERMS + ----------------------------- + + The OpenPKG Framework is licensed, not sold. Subject to the terms + and conditions of this agreement, the OpenPKG GmbH hereby grants + you a non-exclusive, non-sub-licensable and non-transferable right + to use the Product. You may not lease or rent the OpenPKG Framework + license. + + You may sell or otherwise transfer unused licenses if you ensure + the recipient receives these terms and conditions with the same + transaction and acknowledges to take over your responsibilities from + this agreement. + + You may not remove any titles, trademarks or trade names, copyright + notices, legends, or other proprietary markings on the Product. You + are not granted any rights to any trademarks or service marks of the + OpenPKG GmbH. All rights not expressly granted by this license are + reserved. + + You may use the Product as long as you own this license issued by + the OpenPKG GmbH, install it and obey the terms and conditions + listed below. This license, issued by the OpenPKG GmbH, ships + as a digitally signed text file which carries the exact license + conditions both in human readable plain text and attached in a + machine readable format. The latter may be used by the OpenPKG + Framework to programmatically validate the license compliance. If + programmatic license validation within the OpenPKG Framework detects + a compliance failure, the OpenPKG Framework might cease operation. + It is your responsibility to ensure compliance with these terms and + conditions. + + GRANT OF RIGHTS TO USE THE OPENPKG FRAMEWORK + -------------------------------------------- + + This "evaluation" license ships free of charge with every OpenPKG + Framework and allows restricted use of the OpenPKG Framework. The + constraint is a run-time limitation after initial installation, + see "Assertion-InstanceAge" at the bottom of this document. After + that period the evaluation license is void and either must be + replaced by another license or use of the OpenPKG Framework must be + discontinued. + + GRANT OF RIGHTS TO COPY THE OPENPKG FRAMEWORK + --------------------------------------------- + + You may create an unlimited number of copies of the Product. + + GRANT OF RIGHTS TO MODIFY THE OPENPKG FRAMEWORK + ----------------------------------------------- + + You may modify most parts of the Product and adjust it to your + needs, creating derivative works. You may not remove license + validation code, and you must ensure the preservation of the OpenPKG + GmbH fingerprint data. The copyright notice, the license excerpt and + the reference to this terms and conditions must be kept verbatim. + You must make clear to the recipient of the derived works that the + version he is receiving has been modified and by whom. + + These terms and conditions stay if force for derivative works. To + keep modifications your property you must not distribute them, in + source or binary form, beyond your organizational scope. In cases + of extended distribution or publication you agree to contribute + your modifications automatically, free of charge and without any + royalty claims, to the OpenPKG GmbH, transfer the source code of + your modifications to the OpenPKG GmbH and irrevocably transfer + all rights of your modifications to the OpenPKG GmbH which will + grant you unlimited use rights to your contribution. There is no + promise the OpenPKG GmbH includes your contribution into the OpenPKG + Framework. + + GRANT OF RIGHTS TO DISTRIBUTE THE OPENPKG FRAMEWORK + --------------------------------------------------- + + You may distribute the Product, or derivative works thereof created + under adherence of the "rights to modify" grant, if you ensure + the recipient receives these terms and conditions with the same + transaction. + + ONLINE ACCESS + ------------- + + The OpenPKG Framework collects information about the OpenPKG + Framework, OpenPKG Framework License and OpenPKG Packages for use + by the OpenPKG Project, the OpenPKG Foundation e.V. and the OpenPKG + GmbH. The programmatic license validation might and the information + upload process does require online access to the Internet. You agree + to grant the OpenPKG Framework permission for this use case and you + assume all costs related to the online access. + + TERMINATION + ----------- + + You may not use the OpenPKG Framework except as expressly + provided under the license. Any attempt to otherwise use, copy, + modify, distribute or sub-license the Product is void, and will + automatically terminate your rights under this license. + + CHANGE + ------ + + The OpenPKG GmbH reserves the right to subsequently modify or amend + details of these terms and conditions where this seems applicable, + as long as you are, in good faith, not disadvantaged thereby. + + Those changes or amendments of the terms and conditions will be + proclaimed to you by a written document, delivered to you in + electronic format or paper mail as chosen by the OpenPKG GmbH. + Anonymous and unknown users cannot be contacted by the OpenPKG GmbH. + They must review the terms and conditions regularly at the same time + they obtain or use an updated OpenPKG Framework. You cannot rise an + objection against the proclaimed changes or amendments. However, you + can terminate the license agreement without prior notice. + + DISCLAIMER + ---------- + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR + 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. + + LIMITED WARRANTY AND LIMITATION OF LIABILITY + -------------------------------------------- + + The OpenPKG GmbH is only liable for damages if the OpenPKG GmbH + or one of its vicarious agents has violated a major contractual + (cardinal) obligation or jeopardized the intention of the agreement + or the damage was done by gross negligence or intention of the + OpenPKG GmbH or one of its vicarious agents. + + In case the violation of a cardinal obligation is not caused by + gross negligence or intention of the OpenPKG GmbH or one of its + vicarious agents the liability of the OpenPKG GmbH is limited to the + predictable damage characteristical for the contract. + + The preceding liability limitations apply for contractual and + non-contractual claims. The liability of the OpenPKG GmbH due to + warranties, personal injury and due to the German Product Liability + Act remains unaffected from the preceding liability limitations. + + GENERAL + ------- + + This agreement sets forth the OpenPKG GmbH's entire liability and + your exclusive remedy with respect to the Product and supersedes + the terms of any purchase orders and any other communications or + advertising with respect to the Product. You acknowledge that this + agreement is a complete statement of the agreement between you + and the OpenPKG GmbH with respect to the Product, and that there + are no other prior or contemporaneous understandings, promises, + representations, or descriptions with respect to the Product. + + Headings under this agreement are intended only for convenience and + shall not affect the interpretation of this agreement. + + No failure of either party to exercise or enforce any of its rights + under this agreement will act as a waiver of those rights. This + agreement may only be modified, or any rights under it waived, by a + written document executed by the party against which it is asserted. + + If any provision of this agreement is found illegal or + unenforceable, it will be enforced to the maximum extent + permissible, and the legality and enforceability of the other + provisions of this agreement will not be affected. + + This agreement is governed by German law. + + If you have any questions about this agreement please contact the + OpenPKG GmbH. Direct all traditional paper correspondence to the + official company address as listed in the very first paragraph of + this document. You find the most recent contact information on our + website http://openpkg.com/ + + You can find the most recent version of this document on our website + http://openpkg.com/go/framework-license + +Assertion-MinProcVersion: 0.9.0 +Assertion-InstanceAge: 90d + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAktAcOAACgkQZwQuyWG3rjTH+gCfXyfm2xzMoGqsYthehkbLh+8x +mooAnA6O7bygggM8RaHjRZs2YZ1oQAqa +=zsbV +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license-EXAMPLE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license-EXAMPLE.txt Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,275 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Id: EXAMPLE +Name: OpenPKG Framework Example License +Version: 1.0.0 +Issuer: OpenPKG GmbH +Issued: 2010-01-01 + +Licensee: arbitrary deployer of OpenPKG Framework + with this run-time license activated + +Description: + + OPENPKG FRAMEWORK EXAMPLE LICENSE + ================================= + + This license agreement constitutes a valid and binding agreement + between the OpenPKG GmbH, jurisdiction identification "DE MUC HRB + 160208", postal address "Weblinger Weg 28, 85221 Dachau, GERMANY", + digital signature name "OpenPKG GmbH " and + digital signature fingerprint "7D12 1A8F C05D C18A 4329 E9EF 6704 + 2EC9 61B7 AE34", represented by the two managing directors Ralf S. + Engelschall and Thomas Lotterer, and you, the licensee. + + "You" means the natural person or the entity that is agreeing to be + bound by this agreement. You shall be liable for any failure by your + employees and third party contractors that provide services to you + to comply with the terms and conditions of this agreement. + + AGREEMENT + --------- + + By using, copying, modifying or distributing the Product you agree + to be bound by the terms and conditions of this agreement. If you + are accepting these terms on behalf of another person or a company + or other legal entity, you represent and warrant that you have full + authority to bind that person, company, or legal entity to these + terms. If you do not agree to the terms and conditions of this + agreement, you may not use, copy, modify or distribute the Product. + You may return the unused Product to the supplier from which you + acquired it within 30 days and request a refund of the license fee, + if any, already paid upon showing proof of payment. + + TERMINOLOGY + ----------- + + OpenPKG is a solution to build software stacks consisting of OpenPKG + Packages and an OpenPKG Framework to operate them. + + For your information, OpenPKG Packages are available from the + OpenPKG Foundation e.V., which licenses and distributes them as Open + Source Software. These OpenPKG Packages are in no way subject of + this agreement. + + The OpenPKG Framework is a property of the OpenPKG GmbH with all + rights reserved. Licenses, like this one, which grant limited + permission to use, copy, modify and distribute this software are + exclusively issued by the OpenPKG GmbH. + + Licensing as described in this agreement covers the OpenPKG + Framework code copyrighted by the OpenPKG GmbH and the OpenPKG + Framework as a compound work. The OpenPKG Framework is distributed + in source code form and also contains pristine third-party sources + where each comes with its own licensing model. These licenses are + in no way altered by this agreement, but passed through to you + verbatim. You are responsible for obtaining and obeying any such + vendor license. + + This license describes how you appropriately use, copy, modify + and distribute the OpenPKG Framework source code and the binaries + resulting from the build process. This license does not include any + entitlement for you to receive service or support from the OpenPKG + GmbH, there are no warranties beyond the minimum implied warranty, + and there are no promises with respect to the future of the Product + or any derived works. + + GRANT OF RIGHTS GENERAL TERMS + ----------------------------- + + The OpenPKG Framework is licensed, not sold. Subject to the terms + and conditions of this agreement, the OpenPKG GmbH hereby grants + you a non-exclusive, non-sub-licensable and non-transferable right + to use the Product. You may not lease or rent the OpenPKG Framework + license. + + You may sell or otherwise transfer unused licenses if you ensure + the recipient receives these terms and conditions with the same + transaction and acknowledges to take over your responsibilities from + this agreement. + + You may not remove any titles, trademarks or trade names, copyright + notices, legends, or other proprietary markings on the Product. You + are not granted any rights to any trademarks or service marks of the + OpenPKG GmbH. All rights not expressly granted by this license are + reserved. + + You may use the Product as long as you own this license issued by + the OpenPKG GmbH, install it and obey the terms and conditions + listed below. This license, issued by the OpenPKG GmbH, ships + as a digitally signed text file which carries the exact license + conditions both in human readable plain text and attached in a + machine readable format. The latter may be used by the OpenPKG + Framework to programmatically validate the license compliance. If + programmatic license validation within the OpenPKG Framework detects + a compliance failure, the OpenPKG Framework might cease operation. + It is your responsibility to ensure compliance with these terms and + conditions. + + GRANT OF RIGHTS TO USE THE OPENPKG FRAMEWORK + -------------------------------------------- + + This "example" license ships free of charge with every OpenPKG + Framework and allows restricted use of the OpenPKG Framework. The + constraints are the use in documentation, demonstration and training + material only and the filesystem prefix, user and group + parameters being locked to certain paramenters, see + "Assertion-Prefix", "Assertion-User" and "Assertion-Group" at the + bottom of this document. The license does not impose any life-time + limitation. + + GRANT OF RIGHTS TO COPY THE OPENPKG FRAMEWORK + --------------------------------------------- + + You may create an unlimited number of copies of the Product. + + GRANT OF RIGHTS TO MODIFY THE OPENPKG FRAMEWORK + ----------------------------------------------- + + You may modify most parts of the Product and adjust it to your + needs, creating derivative works. You may not remove license + validation code, and you must ensure the preservation of the OpenPKG + GmbH fingerprint data. The copyright notice, the license excerpt and + the reference to this terms and conditions must be kept verbatim. + You must make clear to the recipient of the derived works that the + version he is receiving has been modified and by whom. + + These terms and conditions stay if force for derivative works. To + keep modifications your property you must not distribute them, in + source or binary form, beyond your organizational scope. In cases + of extended distribution or publication you agree to contribute + your modifications automatically, free of charge and without any + royalty claims, to the OpenPKG GmbH, transfer the source code of + your modifications to the OpenPKG GmbH and irrevocably transfer + all rights of your modifications to the OpenPKG GmbH which will + grant you unlimited use rights to your contribution. There is no + promise the OpenPKG GmbH includes your contribution into the OpenPKG + Framework. + + GRANT OF RIGHTS TO DISTRIBUTE THE OPENPKG FRAMEWORK + --------------------------------------------------- + + You may distribute the Product, or derivative works thereof created + under adherence of the "rights to modify" grant, if you ensure + the recipient receives these terms and conditions with the same + transaction. + + ONLINE ACCESS + ------------- + + The OpenPKG Framework collects information about the OpenPKG + Framework, OpenPKG Framework License and OpenPKG Packages for use + by the OpenPKG Project, the OpenPKG Foundation e.V. and the OpenPKG + GmbH. The programmatic license validation might and the information + upload process does require online access to the Internet. You agree + to grant the OpenPKG Framework permission for this use case and you + assume all costs related to the online access. + + TERMINATION + ----------- + + You may not use the OpenPKG Framework except as expressly + provided under the license. Any attempt to otherwise use, copy, + modify, distribute or sub-license the Product is void, and will + automatically terminate your rights under this license. + + CHANGE + ------ + + The OpenPKG GmbH reserves the right to subsequently modify or amend + details of these terms and conditions where this seems applicable, + as long as you are, in good faith, not disadvantaged thereby. + + Those changes or amendments of the terms and conditions will be + proclaimed to you by a written document, delivered to you in + electronic format or paper mail as chosen by the OpenPKG GmbH. + Anonymous and unknown users cannot be contacted by the OpenPKG GmbH. + They must review the terms and conditions regularly at the same time + they obtain or use an updated OpenPKG Framework. You cannot rise an + objection against the proclaimed changes or amendments. However, you + can terminate the license agreement without prior notice. + + DISCLAIMER + ---------- + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR + 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. + + LIMITED WARRANTY AND LIMITATION OF LIABILITY + -------------------------------------------- + + The OpenPKG GmbH is only liable for damages if the OpenPKG GmbH + or one of its vicarious agents has violated a major contractual + (cardinal) obligation or jeopardized the intention of the agreement + or the damage was done by gross negligence or intention of the + OpenPKG GmbH or one of its vicarious agents. + + In case the violation of a cardinal obligation is not caused by + gross negligence or intention of the OpenPKG GmbH or one of its + vicarious agents the liability of the OpenPKG GmbH is limited to the + predictable damage characteristical for the contract. + + The preceding liability limitations apply for contractual and + non-contractual claims. The liability of the OpenPKG GmbH due to + warranties, personal injury and due to the German Product Liability + Act remains unaffected from the preceding liability limitations. + + GENERAL + ------- + + This agreement sets forth the OpenPKG GmbH's entire liability and + your exclusive remedy with respect to the Product and supersedes + the terms of any purchase orders and any other communications or + advertising with respect to the Product. You acknowledge that this + agreement is a complete statement of the agreement between you + and the OpenPKG GmbH with respect to the Product, and that there + are no other prior or contemporaneous understandings, promises, + representations, or descriptions with respect to the Product. + + Headings under this agreement are intended only for convenience and + shall not affect the interpretation of this agreement. + + No failure of either party to exercise or enforce any of its rights + under this agreement will act as a waiver of those rights. This + agreement may only be modified, or any rights under it waived, by a + written document executed by the party against which it is asserted. + + If any provision of this agreement is found illegal or + unenforceable, it will be enforced to the maximum extent + permissible, and the legality and enforceability of the other + provisions of this agreement will not be affected. + + This agreement is governed by German law. + + If you have any questions about this agreement please contact the + OpenPKG GmbH. Direct all traditional paper correspondence to the + official company address as listed in the very first paragraph of + this document. You find the most recent contact information on our + website http://openpkg.com/ + + You can find the most recent version of this document on our website + http://openpkg.com/go/framework-license + +Assertion-MinProcVersion: 0.9.0 +Assertion-Prefix: /example +Assertion-User: example +Assertion-Group: example + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAktAcOIACgkQZwQuyWG3rjSTnACgpJQfhIGbGVd5z7XsM2F+aC8y +nT8AoNrkoEU9ChUQVDse4q9liDfeJayN +=aCvW +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license-PROMO.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license-PROMO.txt Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,272 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Id: PROMO +Name: OpenPKG Framework Promotion License +Version: 1.0.0 +Issuer: OpenPKG GmbH +Issued: 2010-01-30 + +Licensee: arbitrary deployer of OpenPKG Framework + with this run-time license activated + +Description: + + OPENPKG FRAMEWORK PROMOTION LICENSE + =================================== + + This license agreement constitutes a valid and binding agreement + between the OpenPKG GmbH, jurisdiction identification "DE MUC HRB + 160208", postal address "Weblinger Weg 28, 85221 Dachau, GERMANY", + digital signature name "OpenPKG GmbH " and + digital signature fingerprint "7D12 1A8F C05D C18A 4329 E9EF 6704 + 2EC9 61B7 AE34", represented by the two managing directors Ralf S. + Engelschall and Thomas Lotterer, and you, the licensee. + + "You" means the natural person or the entity that is agreeing to be + bound by this agreement. You shall be liable for any failure by your + employees and third party contractors that provide services to you + to comply with the terms and conditions of this agreement. + + AGREEMENT + --------- + + By using, copying, modifying or distributing the Product you agree + to be bound by the terms and conditions of this agreement. If you + are accepting these terms on behalf of another person or a company + or other legal entity, you represent and warrant that you have full + authority to bind that person, company, or legal entity to these + terms. If you do not agree to the terms and conditions of this + agreement, you may not use, copy, modify or distribute the Product. + You may return the unused Product to the supplier from which you + acquired it within 30 days and request a refund of the license fee, + if any, already paid upon showing proof of payment. + + TERMINOLOGY + ----------- + + OpenPKG is a solution to build software stacks consisting of OpenPKG + Packages and an OpenPKG Framework to operate them. + + For your information, OpenPKG Packages are available from the + OpenPKG Foundation e.V., which licenses and distributes them as Open + Source Software. These OpenPKG Packages are in no way subject of + this agreement. + + The OpenPKG Framework is a property of the OpenPKG GmbH with all + rights reserved. Licenses, like this one, which grant limited + permission to use, copy, modify and distribute this software are + exclusively issued by the OpenPKG GmbH. + + Licensing as described in this agreement covers the OpenPKG + Framework code copyrighted by the OpenPKG GmbH and the OpenPKG + Framework as a compound work. The OpenPKG Framework is distributed + in source code form and also contains pristine third-party sources + where each comes with its own licensing model. These licenses are + in no way altered by this agreement, but passed through to you + verbatim. You are responsible for obtaining and obeying any such + vendor license. + + This license describes how you appropriately use, copy, modify + and distribute the OpenPKG Framework source code and the binaries + resulting from the build process. This license does not include any + entitlement for you to receive service or support from the OpenPKG + GmbH, there are no warranties beyond the minimum implied warranty, + and there are no promises with respect to the future of the Product + or any derived works. + + GRANT OF RIGHTS GENERAL TERMS + ----------------------------- + + The OpenPKG Framework is licensed, not sold. Subject to the terms + and conditions of this agreement, the OpenPKG GmbH hereby grants + you a non-exclusive, non-sub-licensable and non-transferable right + to use the Product. You may not lease or rent the OpenPKG Framework + license. + + You may sell or otherwise transfer unused licenses if you ensure + the recipient receives these terms and conditions with the same + transaction and acknowledges to take over your responsibilities from + this agreement. + + You may not remove any titles, trademarks or trade names, copyright + notices, legends, or other proprietary markings on the Product. You + are not granted any rights to any trademarks or service marks of the + OpenPKG GmbH. All rights not expressly granted by this license are + reserved. + + You may use the Product as long as you own this license issued by + the OpenPKG GmbH, install it and obey the terms and conditions + listed below. This license, issued by the OpenPKG GmbH, ships + as a digitally signed text file which carries the exact license + conditions both in human readable plain text and attached in a + machine readable format. The latter may be used by the OpenPKG + Framework to programmatically validate the license compliance. If + programmatic license validation within the OpenPKG Framework detects + a compliance failure, the OpenPKG Framework might cease operation. + It is your responsibility to ensure compliance with these terms and + conditions. + + GRANT OF RIGHTS TO USE THE OPENPKG FRAMEWORK + -------------------------------------------- + + This "promotion" license can be obtained from the OpenPKG GmbH + and allows restricted use of the OpenPKG Framework. The constraints + are the use of the OpenPKG Framework in a specified real-time frame, + see "Assertion-LifeTime" at the bottom of this document, and use of + the OpenPKG Framework released in a specified time frame, see + "Assertion-GrantTime" at the bottom of this document. + + GRANT OF RIGHTS TO COPY THE OPENPKG FRAMEWORK + --------------------------------------------- + + You may create an unlimited number of copies of the Product. + + GRANT OF RIGHTS TO MODIFY THE OPENPKG FRAMEWORK + ----------------------------------------------- + + You may modify most parts of the Product and adjust it to your + needs, creating derivative works. You may not remove license + validation code, and you must ensure the preservation of the OpenPKG + GmbH fingerprint data. The copyright notice, the license excerpt and + the reference to this terms and conditions must be kept verbatim. + You must make clear to the recipient of the derived works that the + version he is receiving has been modified and by whom. + + These terms and conditions stay if force for derivative works. To + keep modifications your property you must not distribute them, in + source or binary form, beyond your organizational scope. In cases + of extended distribution or publication you agree to contribute + your modifications automatically, free of charge and without any + royalty claims, to the OpenPKG GmbH, transfer the source code of + your modifications to the OpenPKG GmbH and irrevocably transfer + all rights of your modifications to the OpenPKG GmbH which will + grant you unlimited use rights to your contribution. There is no + promise the OpenPKG GmbH includes your contribution into the OpenPKG + Framework. + + GRANT OF RIGHTS TO DISTRIBUTE THE OPENPKG FRAMEWORK + --------------------------------------------------- + + You may distribute the Product, or derivative works thereof created + under adherence of the "rights to modify" grant, if you ensure + the recipient receives these terms and conditions with the same + transaction. + + ONLINE ACCESS + ------------- + + The OpenPKG Framework collects information about the OpenPKG + Framework, OpenPKG Framework License and OpenPKG Packages for use + by the OpenPKG Project, the OpenPKG Foundation e.V. and the OpenPKG + GmbH. The programmatic license validation might and the information + upload process does require online access to the Internet. You agree + to grant the OpenPKG Framework permission for this use case and you + assume all costs related to the online access. + + TERMINATION + ----------- + + You may not use the OpenPKG Framework except as expressly + provided under the license. Any attempt to otherwise use, copy, + modify, distribute or sub-license the Product is void, and will + automatically terminate your rights under this license. + + CHANGE + ------ + + The OpenPKG GmbH reserves the right to subsequently modify or amend + details of these terms and conditions where this seems applicable, + as long as you are, in good faith, not disadvantaged thereby. + + Those changes or amendments of the terms and conditions will be + proclaimed to you by a written document, delivered to you in + electronic format or paper mail as chosen by the OpenPKG GmbH. + Anonymous and unknown users cannot be contacted by the OpenPKG GmbH. + They must review the terms and conditions regularly at the same time + they obtain or use an updated OpenPKG Framework. You cannot rise an + objection against the proclaimed changes or amendments. However, you + can terminate the license agreement without prior notice. + + DISCLAIMER + ---------- + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR + 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. + + LIMITED WARRANTY AND LIMITATION OF LIABILITY + -------------------------------------------- + + The OpenPKG GmbH is only liable for damages if the OpenPKG GmbH + or one of its vicarious agents has violated a major contractual + (cardinal) obligation or jeopardized the intention of the agreement + or the damage was done by gross negligence or intention of the + OpenPKG GmbH or one of its vicarious agents. + + In case the violation of a cardinal obligation is not caused by + gross negligence or intention of the OpenPKG GmbH or one of its + vicarious agents the liability of the OpenPKG GmbH is limited to the + predictable damage characteristical for the contract. + + The preceding liability limitations apply for contractual and + non-contractual claims. The liability of the OpenPKG GmbH due to + warranties, personal injury and due to the German Product Liability + Act remains unaffected from the preceding liability limitations. + + GENERAL + ------- + + This agreement sets forth the OpenPKG GmbH's entire liability and + your exclusive remedy with respect to the Product and supersedes + the terms of any purchase orders and any other communications or + advertising with respect to the Product. You acknowledge that this + agreement is a complete statement of the agreement between you + and the OpenPKG GmbH with respect to the Product, and that there + are no other prior or contemporaneous understandings, promises, + representations, or descriptions with respect to the Product. + + Headings under this agreement are intended only for convenience and + shall not affect the interpretation of this agreement. + + No failure of either party to exercise or enforce any of its rights + under this agreement will act as a waiver of those rights. This + agreement may only be modified, or any rights under it waived, by a + written document executed by the party against which it is asserted. + + If any provision of this agreement is found illegal or + unenforceable, it will be enforced to the maximum extent + permissible, and the legality and enforceability of the other + provisions of this agreement will not be affected. + + This agreement is governed by German law. + + If you have any questions about this agreement please contact the + OpenPKG GmbH. Direct all traditional paper correspondence to the + official company address as listed in the very first paragraph of + this document. You find the most recent contact information on our + website http://openpkg.com/ + + You can find the most recent version of this document on our website + http://openpkg.com/go/framework-license + +Assertion-MinProcVersion: 0.9.0 +Assertion-LifeTime: 2008-01-01:2010-04-01 +Assertion-GrantTime: 2008-01-01:2010-04-01 + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAktlqB8ACgkQZwQuyWG3rjSHwgCgrBoJ8HMeOGPiylwb3QbTKTis +kHIAoISMlvKP/DpIv86yDSjWpn6kPB0c +=ik+2 +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license-RECOVERY.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license-RECOVERY.txt Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,270 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +Id: RECOVERY +Name: OpenPKG Framework Recovery License +Version: 1.0.0 +Issuer: OpenPKG GmbH +Issued: 2010-01-01 + +Licensee: arbitrary deployer of OpenPKG Framework + with this run-time license activated + +Description: + + OPENPKG FRAMEWORK RECOVERY LICENSE + ================================== + + This license agreement constitutes a valid and binding agreement + between the OpenPKG GmbH, jurisdiction identification "DE MUC HRB + 160208", postal address "Weblinger Weg 28, 85221 Dachau, GERMANY", + digital signature name "OpenPKG GmbH " and + digital signature fingerprint "7D12 1A8F C05D C18A 4329 E9EF 6704 + 2EC9 61B7 AE34", represented by the two managing directors Ralf S. + Engelschall and Thomas Lotterer, and you, the licensee. + + "You" means the natural person or the entity that is agreeing to be + bound by this agreement. You shall be liable for any failure by your + employees and third party contractors that provide services to you + to comply with the terms and conditions of this agreement. + + AGREEMENT + --------- + + By using, copying, modifying or distributing the Product you agree + to be bound by the terms and conditions of this agreement. If you + are accepting these terms on behalf of another person or a company + or other legal entity, you represent and warrant that you have full + authority to bind that person, company, or legal entity to these + terms. If you do not agree to the terms and conditions of this + agreement, you may not use, copy, modify or distribute the Product. + You may return the unused Product to the supplier from which you + acquired it within 30 days and request a refund of the license fee, + if any, already paid upon showing proof of payment. + + TERMINOLOGY + ----------- + + OpenPKG is a solution to build software stacks consisting of OpenPKG + Packages and an OpenPKG Framework to operate them. + + For your information, OpenPKG Packages are available from the + OpenPKG Foundation e.V., which licenses and distributes them as Open + Source Software. These OpenPKG Packages are in no way subject of + this agreement. + + The OpenPKG Framework is a property of the OpenPKG GmbH with all + rights reserved. Licenses, like this one, which grant limited + permission to use, copy, modify and distribute this software are + exclusively issued by the OpenPKG GmbH. + + Licensing as described in this agreement covers the OpenPKG + Framework code copyrighted by the OpenPKG GmbH and the OpenPKG + Framework as a compound work. The OpenPKG Framework is distributed + in source code form and also contains pristine third-party sources + where each comes with its own licensing model. These licenses are + in no way altered by this agreement, but passed through to you + verbatim. You are responsible for obtaining and obeying any such + vendor license. + + This license describes how you appropriately use, copy, modify + and distribute the OpenPKG Framework source code and the binaries + resulting from the build process. This license does not include any + entitlement for you to receive service or support from the OpenPKG + GmbH, there are no warranties beyond the minimum implied warranty, + and there are no promises with respect to the future of the Product + or any derived works. + + GRANT OF RIGHTS GENERAL TERMS + ----------------------------- + + The OpenPKG Framework is licensed, not sold. Subject to the terms + and conditions of this agreement, the OpenPKG GmbH hereby grants + you a non-exclusive, non-sub-licensable and non-transferable right + to use the Product. You may not lease or rent the OpenPKG Framework + license. + + You may sell or otherwise transfer unused licenses if you ensure + the recipient receives these terms and conditions with the same + transaction and acknowledges to take over your responsibilities from + this agreement. + + You may not remove any titles, trademarks or trade names, copyright + notices, legends, or other proprietary markings on the Product. You + are not granted any rights to any trademarks or service marks of the + OpenPKG GmbH. All rights not expressly granted by this license are + reserved. + + You may use the Product as long as you own this license issued by + the OpenPKG GmbH, install it and obey the terms and conditions + listed below. This license, issued by the OpenPKG GmbH, ships + as a digitally signed text file which carries the exact license + conditions both in human readable plain text and attached in a + machine readable format. The latter may be used by the OpenPKG + Framework to programmatically validate the license compliance. If + programmatic license validation within the OpenPKG Framework detects + a compliance failure, the OpenPKG Framework might cease operation. + It is your responsibility to ensure compliance with these terms and + conditions. + + GRANT OF RIGHTS TO USE THE OPENPKG FRAMEWORK + -------------------------------------------- + + This "recovery" license ships free of charge with every OpenPKG + Framework and allows temporary recovery from licensing issues. + It requires online access to license clearing services from the + OpenPKG GmbH which are not guaranteed to be available. + + GRANT OF RIGHTS TO COPY THE OPENPKG FRAMEWORK + --------------------------------------------- + + You may create an unlimited number of copies of the Product. + + GRANT OF RIGHTS TO MODIFY THE OPENPKG FRAMEWORK + ----------------------------------------------- + + You may modify most parts of the Product and adjust it to your + needs, creating derivative works. You may not remove license + validation code, and you must ensure the preservation of the OpenPKG + GmbH fingerprint data. The copyright notice, the license excerpt and + the reference to this terms and conditions must be kept verbatim. + You must make clear to the recipient of the derived works that the + version he is receiving has been modified and by whom. + + These terms and conditions stay if force for derivative works. To + keep modifications your property you must not distribute them, in + source or binary form, beyond your organizational scope. In cases + of extended distribution or publication you agree to contribute + your modifications automatically, free of charge and without any + royalty claims, to the OpenPKG GmbH, transfer the source code of + your modifications to the OpenPKG GmbH and irrevocably transfer + all rights of your modifications to the OpenPKG GmbH which will + grant you unlimited use rights to your contribution. There is no + promise the OpenPKG GmbH includes your contribution into the OpenPKG + Framework. + + GRANT OF RIGHTS TO DISTRIBUTE THE OPENPKG FRAMEWORK + --------------------------------------------------- + + You may distribute the Product, or derivative works thereof created + under adherence of the "rights to modify" grant, if you ensure + the recipient receives these terms and conditions with the same + transaction. + + ONLINE ACCESS + ------------- + + The OpenPKG Framework collects information about the OpenPKG + Framework, OpenPKG Framework License and OpenPKG Packages for use + by the OpenPKG Project, the OpenPKG Foundation e.V. and the OpenPKG + GmbH. The programmatic license validation might and the information + upload process does require online access to the Internet. You agree + to grant the OpenPKG Framework permission for this use case and you + assume all costs related to the online access. + + TERMINATION + ----------- + + You may not use the OpenPKG Framework except as expressly + provided under the license. Any attempt to otherwise use, copy, + modify, distribute or sub-license the Product is void, and will + automatically terminate your rights under this license. + + CHANGE + ------ + + The OpenPKG GmbH reserves the right to subsequently modify or amend + details of these terms and conditions where this seems applicable, + as long as you are, in good faith, not disadvantaged thereby. + + Those changes or amendments of the terms and conditions will be + proclaimed to you by a written document, delivered to you in + electronic format or paper mail as chosen by the OpenPKG GmbH. + Anonymous and unknown users cannot be contacted by the OpenPKG GmbH. + They must review the terms and conditions regularly at the same time + they obtain or use an updated OpenPKG Framework. You cannot rise an + objection against the proclaimed changes or amendments. However, you + can terminate the license agreement without prior notice. + + DISCLAIMER + ---------- + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR + 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. + + LIMITED WARRANTY AND LIMITATION OF LIABILITY + -------------------------------------------- + + The OpenPKG GmbH is only liable for damages if the OpenPKG GmbH + or one of its vicarious agents has violated a major contractual + (cardinal) obligation or jeopardized the intention of the agreement + or the damage was done by gross negligence or intention of the + OpenPKG GmbH or one of its vicarious agents. + + In case the violation of a cardinal obligation is not caused by + gross negligence or intention of the OpenPKG GmbH or one of its + vicarious agents the liability of the OpenPKG GmbH is limited to the + predictable damage characteristical for the contract. + + The preceding liability limitations apply for contractual and + non-contractual claims. The liability of the OpenPKG GmbH due to + warranties, personal injury and due to the German Product Liability + Act remains unaffected from the preceding liability limitations. + + GENERAL + ------- + + This agreement sets forth the OpenPKG GmbH's entire liability and + your exclusive remedy with respect to the Product and supersedes + the terms of any purchase orders and any other communications or + advertising with respect to the Product. You acknowledge that this + agreement is a complete statement of the agreement between you + and the OpenPKG GmbH with respect to the Product, and that there + are no other prior or contemporaneous understandings, promises, + representations, or descriptions with respect to the Product. + + Headings under this agreement are intended only for convenience and + shall not affect the interpretation of this agreement. + + No failure of either party to exercise or enforce any of its rights + under this agreement will act as a waiver of those rights. This + agreement may only be modified, or any rights under it waived, by a + written document executed by the party against which it is asserted. + + If any provision of this agreement is found illegal or + unenforceable, it will be enforced to the maximum extent + permissible, and the legality and enforceability of the other + provisions of this agreement will not be affected. + + This agreement is governed by German law. + + If you have any questions about this agreement please contact the + OpenPKG GmbH. Direct all traditional paper correspondence to the + official company address as listed in the very first paragraph of + this document. You find the most recent contact information on our + website http://openpkg.com/ + + You can find the most recent version of this document on our website + http://openpkg.com/go/framework-license + +Assertion-MinProcVersion: 0.9.0 +Assertion-OnlineApproval: http://openpkg.com/go/framework-license-exception +Assertion-ErrorToWarning: yes + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAktAcOcACgkQZwQuyWG3rjSeagCfcFS91ucreRtRxxK1rRoODgLI +mmAAnim+i0THJLMrm/ha1FfOGroa30ve +=VAb/ +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license.8 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license.8 Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,210 @@ +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.22) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "LICENSE 8" +.TH LICENSE 8 "OpenPKG" "LICENSE(8)" "OpenPKG" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +openpkg license \- OpenPKG License Utility +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBopenpkg license\fR \fBhelp\fR +.PP +\&\fBopenpkg license\fR \fBinstall\fR \fIid\fR \fIfile\fR|\fIurl\fR|\f(CW\*(C`\-\*(C'\fR +.PP +\&\fBopenpkg license\fR \fBupdate\fR \fIid\fR \fIfile\fR|\fIurl\fR|\f(CW\*(C`\-\*(C'\fR +.PP +\&\fBopenpkg license\fR \fBuninstall\fR \fIid\fR +.PP +\&\fBopenpkg license\fR \fBactivate\fR \fIid\fR +.PP +\&\fBopenpkg license\fR \fBview\fR \fIid\fR +.PP +\&\fBopenpkg license\fR \fBlist\fR +.PP +\&\fBopenpkg license\fR \fBactive\fR +.PP +\&\fBopenpkg license\fR \fBsanity\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fBopenpkg license\fR command is the maintenance utility for OpenPKG +Framework licenses. +.SH "COMMANDS" +.IX Header "COMMANDS" +.IP "\fBopenpkg license\fR \fBhelp\fR" 4 +.IX Item "openpkg license help" +This command just displays a short usage help information. +.ie n .IP "\fBopenpkg license\fR \fBinstall\fR \fIid\fR \fIfile\fR|\fIurl\fR|\*(C`\-\*(C'" 4 +.el .IP "\fBopenpkg license\fR \fBinstall\fR \fIid\fR \fIfile\fR|\fIurl\fR|\f(CW\*(C`\-\*(C'\fR" 4 +.IX Item "openpkg license install id file|url|-" +This command installs the license contained in \fIfile\fR or at \fIurl\fR or +provided on \fIstdin\fR under the identifier \fIid\fR. The \fIid\fR can be an +arbitrary string, but the convention is that \fIid\fR is a short upper-case +identifier. +.ie n .IP "\fBopenpkg license\fR \fBupdate\fR \fIid\fR \fIfile\fR|\fIurl\fR|\*(C`\-\*(C'" 4 +.el .IP "\fBopenpkg license\fR \fBupdate\fR \fIid\fR \fIfile\fR|\fIurl\fR|\f(CW\*(C`\-\*(C'\fR" 4 +.IX Item "openpkg license update id file|url|-" +This command updates an already installed license with the license +contained in \fIfile\fR or at \fIurl\fR or provided on \fIstdin\fR under the +identifier \fIid\fR. +.IP "\fBopenpkg license\fR \fBuninstall\fR \fIid\fR" 4 +.IX Item "openpkg license uninstall id" +This command uninstalls the license which is installed under \fIid\fR. +A license can be uninstalled only if it is not currently activated (see +\&\fBopenpkg license activate\fR command). +.IP "\fBopenpkg license\fR \fBactivate\fR \fIid\fR" 4 +.IX Item "openpkg license activate id" +This command activates the license which is installed under \fIid\fR. +Only one installed license can be active at any time, so this command +implicitly deactivates the currently activate license. +.IP "\fBopenpkg license\fR \fBview\fR \fIid\fR" 4 +.IX Item "openpkg license view id" +This command shows the license which is installed under \fIid\fR. +.IP "\fBopenpkg license\fR \fBlist\fR" 4 +.IX Item "openpkg license list" +This command lists the identifiers of all installed licenses. +.IP "\fBopenpkg license\fR \fBactive\fR" 4 +.IX Item "openpkg license active" +This command outputs the identifier of the currently activated license. +.IP "\fBopenpkg license\fR \fBsanity\fR" 4 +.IX Item "openpkg license sanity" +This command sanity checks the current license configuration. +.SH "FILES" +.IX Header "FILES" +.ie n .IP "\fI\fI@l_prefix\fI@/etc/license\fR" 4 +.el .IP "\fI\f(CI@l_prefix\fI@/etc/license\fR" 4 +.IX Item "@l_prefix@/etc/license" +The name of the currently activated license file under +\&\fI\f(CI@l_prefix\fI@/etc/license.d/\fR. +.ie n .IP "\fI\fI@l_prefix\fI@/etc/license.d/*\fR" 4 +.el .IP "\fI\f(CI@l_prefix\fI@/etc/license.d/*\fR" 4 +.IX Item "@l_prefix@/etc/license.d/*" +The directory containing all installed license files. +.SH "HISTORY" +.IX Header "HISTORY" +The \fBopenpkg license\fR command first appeared in \fBOpenPKG 4.0\fR. diff -r 71503088f51b -r f880f219c566 openpkg/license.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license.lua Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,808 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +- -- +- -- OpenPKG Framework License Processor +- -- Copyright (c) 2000-2012 OpenPKG GmbH +- -- +- -- This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +- -- All rights reserved. Licenses which grant limited permission to use, +- -- copy, modify and distribute this software are available from the +- -- OpenPKG GmbH. +- -- +- -- THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +- -- 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. +- -- + +- -- This is the RPM run-time integrity processor of the OpenPKG +- -- Framework. It currently checks the OpenPKG Framework run-time +- -- license only. The following grammar specifies and documents all +- -- currently supported license parameters. +- -- +- -- license ::= "Assertion-MinProcVersion:" version +- -- # require a minimum version of the license integrity processor +- -- +- -- | "Assertion-ErrorToWarning:" yes-no +- -- # allow all fatal integrity checking errors to be +- -- # converted to non-fatal warnings +- -- +- -- | "Assertion-OnlineApproval:" url +- -- # require an online approval by receiving an "OK" from +- -- # specified remote service +- -- +- -- | "Assertion-OnlineReporting:" url +- -- # perform an asynchronous online reporting to +- -- # specified remote service +- -- +- -- | "Assertion-Prefix:" path +- -- # require %{l_prefix} to match specified path +- -- +- -- | "Assertion-User:" user +- -- # require %{l_musr} to match specified username +- -- +- -- | "Assertion-Group:" group +- -- # require %{l_mgrp} to match specified groupname +- -- +- -- | "Assertion-Domain:" domain +- -- # require domain of host to match specified domain name +- -- +- -- | "Assertion-LifeTime:" iso-date.":".iso-date +- -- # require current real-time to be within specified +- -- # begin and end date +- -- +- -- | "Assertion-GrantTime:" iso-date.":".iso-date +- -- # require current OpenPKG Framework %{RELEASE} +- -- # (release time) to be within specified begin and end +- -- # date +- -- +- -- | "Assertion-InstanceAge:" duration +- -- # require current OpenPKG Framework %{ORIGINTIME} +- -- # (first install time) to be within specified begin +- -- # and end date +- -- +- -- | "Assertion-FromSourceOnTarget:" yes-no +- -- # require either (if "yes") that all package +- -- # %{BUILDHOST} are equal the host name or (if "no") +- -- # that all package %{BUILDHOST} are not equal the host +- -- # name +- -- +- -- | "Assertion-PackageNames:" +- -- ("!"?.mode-regex.":"."!"?.package-regex)+ +- -- # require all package %{NAME} to (not) match the +- -- # specified regex while the current RPM run-time mode +- -- # has to (not) match the specified regex. RPM run-time +- -- # modes are: query, verify, checksig, resign, install, +- -- # erase, build rebuild, recompile, tarbuild, initdb, +- -- # rebuilddb and verifydb. +- -- +- -- | "Assertion-PackageReleaseAge:" +- -- percent.":".duration.":".dist-regex ((package-name|"*").":".release)+ +- -- # require that for at least the specified amount (in +- -- # percent) of packages, which %{DISTRIBUTION} matches +- -- # the specified regex, the %{RELEASE} is at least as +- -- # old as the specified release or at least not older +- -- # than the specified duration. +- -- +- -- | "Assertion-Expression:" expression +- -- # evaluates the Lua boolean expression after expanding +- -- # RPM macros %{VARNAME} and expanding the construct +- -- # "" ~~ // into the corresponding PCRE +- -- # based regular expression match. +- -- +- -- version ::= /^\d+\.\d+\.\d+$/ +- -- yes-no ::= /^yes|no$/ +- -- url ::= /^https?:\/\/.+$/ +- -- path ::= /^\/.+$/ +- -- user ::= /^[a-z][a-zA-Z0-9_]*$/ +- -- group ::= /^[a-z][a-zA-Z0-9_]*$/ +- -- domain ::= /^(?:[^.]+\.)+[^.]+$/ +- -- mode-regex ::= /^.+$/ +- -- package-regex ::= /^.+$/ +- -- package-name ::= /^[a-z][a-zA-Z0-9-]*$/ +- -- percent ::= /^\d+%$/ +- -- duration ::= /^\d+[smhdw]?$/ +- -- release ::= /^\d{8}$/ +- -- iso-date ::= /^\d{4}-\d{2}-\d{2}$/ +- -- expression ::= /^.+$/ + +- -- integrity processor version +integrity.version = "1.0.0" + +- -- integrity processor validation callback function +function integrity.validate(ctx, cfg) + integrity.util.debug(1, "OpenPKG run-time license integrity validation") + integrity.util.debug(4, function (ctx) return "dump: ctx = " .. util.dump(ctx) end, ctx) + integrity.util.debug(4, function (cfg) return "dump: cfg = " .. util.dump(cfg) end, cfg) + + -- process "Assertion-OnlineApproval" constraint + if os.getenv("OPENPKG_LICENSE_EXCEPTION") ~= nil then + -- support explicitly requested license exception + cfg["Assertion-OnlineApproval"] = "http://openpkg.com/go/framework-license-exception" + end + if cfg["Assertion-OnlineApproval"] ~= nil then + integrity.util.debug(2, "checking: Assertion-OnlineApproval: \"%s\"", cfg["Assertion-OnlineApproval"]) + local uuids = integrity.util.uuids() + if uuids["UUID_REGISTRY"] == "" then + uuids["UUID_REGISTRY"] = "unknown" + end + if uuids["UUID_INSTANCE"] == "" then + uuids["UUID_INSTANCE"] = "unknown" + end + if uuids["UUID_PLATFORM"] == "" then + uuids["UUID_PLATFORM"] = "unknown" + end + local request = cfg["Assertion-OnlineApproval"] + request = request .. "?UUID_REGISTRY=" .. uuids["UUID_REGISTRY"] + request = request .. "&UUID_INSTANCE=" .. uuids["UUID_INSTANCE"] + request = request .. "&UUID_PLATFORM=" .. uuids["UUID_PLATFORM"] + integrity.util.debug(3, "info: remote request \"%s\"", request) + local response = rpm.expand("%(%{l_prefix}/bin/openpkg curl -s -L -R '" .. request .. "')") + integrity.util.debug(3, "info: remote response \"%s\"", response) + if util.rmatch(response, "(?s)^\\s*OK\\s*$") then + -- approved + if os.getenv("OPENPKG_LICENSE_EXCEPTION") ~= nil then + -- support explicitly requested license exception + cfg["Assertion-ErrorToWarning"] = "yes" + end + else + -- rejected + cfg["Assertion-ErrorToWarning"] = "no" + return integrity.util.error(ctx, cfg, + "license requires online approval but we failed to get " .. + "an \"OK\" response from the online service") + end + end + + -- process "Assertion-MinProcVersion" constraint + integrity.util.debug(2, "checking: Assertion-MinProcVersion: \"%s\"", cfg["Assertion-MinProcVersion"]) + if cfg["Assertion-MinProcVersion"] == nil then + return integrity.util.error(ctx, cfg, + "license configuration is missing required \"Assertion-MinProcVersion\" parameter") + end + integrity.util.debug(3, "require: %s <= %s", cfg["Assertion-MinProcVersion"], integrity.version) + if rpm.vercmp(cfg["Assertion-MinProcVersion"], integrity.version) > 0 then + return integrity.util.error(ctx, cfg, + "license configuration requires a license processor of " .. + "at least version \"" .. cfg["Assertion-MinProcVersion"] .. "\"") + end + + -- process "Assertion-OnlineReporting" constraint + if cfg["Assertion-OnlineReporting"] ~= nil then + integrity.util.debug(2, "checking: Assertion-OnlineReporting: \"%s\"", cfg["Assertion-OnlineReporting"]) + local uuids = integrity.util.uuids() + if uuids["UUID_REGISTRY"] == "" then + uuids["UUID_REGISTRY"] = "unknown" + end + if uuids["UUID_INSTANCE"] == "" then + uuids["UUID_INSTANCE"] = "unknown" + end + if uuids["UUID_PLATFORM"] == "" then + uuids["UUID_PLATFORM"] = "unknown" + end + local request = cfg["Assertion-OnlineReporting"] + request = request .. "?UUID_REGISTRY=" .. uuids["UUID_REGISTRY"] + request = request .. "&UUID_INSTANCE=" .. uuids["UUID_INSTANCE"] + request = request .. "&UUID_PLATFORM=" .. uuids["UUID_PLATFORM"] + integrity.util.debug(3, "info: remote request \"%s\"", request) + rpm.expand("%(nohup %{l_prefix}/bin/openpkg curl -s -L -R '" .. request .. "' >/dev/null 2>&1 &)") + integrity.util.debug(3, "response: (ignored, because asynchronous operation)") + end + + -- process "Assertion-Prefix" constraint + if cfg["Assertion-Prefix"] ~= nil then + integrity.util.debug(2, "checking: Assertion-Prefix: \"%s\"", cfg["Assertion-Prefix"]) + local prefix = rpm.expand("%{l_prefix}") + integrity.util.debug(3, "require: \"%s\" == \"%s\"", cfg["Assertion-Prefix"], prefix) + if cfg["Assertion-Prefix"] ~= prefix then + return integrity.util.error(ctx, cfg, + "instance prefix \"" .. prefix .. "\" " .. + "does not match value \"" .. cfg["Assertion-Prefix"] .. "\" of " .. + "license configuration parameter \"Assertion-Prefix\"") + end + end + + -- process "Assertion-User" constraint + if cfg["Assertion-User"] ~= nil then + integrity.util.debug(2, "checking: Assertion-User: \"%s\"", cfg["Assertion-User"]) + local user = rpm.expand("%{l_musr}") + integrity.util.debug(3, "require: \"%s\" == \"%s\"", cfg["Assertion-User"], user) + if cfg["Assertion-User"] ~= user then + return integrity.util.error(ctx, cfg, + "instance management user \"" .. user .. "\" " .. + "does not match value \"" .. cfg["Assertion-User"] .. "\" of " .. + "license configuration parameter \"Assertion-User\"") + end + end + + -- process "Assertion-Group" constraint + if cfg["Assertion-Group"] ~= nil then + integrity.util.debug(2, "checking: Assertion-Group: \"%s\"", cfg["Assertion-Group"]) + local group = rpm.expand("%{l_mgrp}") + integrity.util.debug(3, "require: \"%s\" == \"%s\"", cfg["Assertion-Group"], group) + if cfg["Assertion-Group"] ~= group then + return integrity.util.error(ctx, cfg, + "instance management group \"" .. group .. "\" " .. + "does not match value \"" .. cfg["Assertion-Group"] .. "\" of " .. + "license configuration parameter \"Assertion-Group\"") + end + end + + -- process "Assertion-Domain" constraint + if cfg["Assertion-Domain"] ~= nil then + integrity.util.debug(2, "checking: Assertion-Domain: \"%s\"", cfg["Assertion-Domain"]) + local domain = rpm.expand("%(%{l_shtool} echo -n -e '%d')") + integrity.util.debug(3, "require: \"%s\" ~~ /(?s)^.*%s$/", domain, cfg["Assertion-Domain"]) + local s, _, m = util.rmatch(domain, "(?s)^.*" .. cfg["Assertion-Domain"] .. "$") + if s == nil then + return integrity.util.error(ctx, cfg, + "host domain \"" .. domain .. "\" " .. + "does not end in pattern \"" .. cfg["Assertion-Domain"] .. "\") " .. + "of license configuration parameter \"Assertion-Domain\"") + end + end + + -- process "Assertion-LifeTime" constraint + if cfg["Assertion-LifeTime"] ~= nil then + integrity.util.debug(2, "checking: Assertion-LifeTime: \"%s\"", cfg["Assertion-LifeTime"]) + + -- determine lifetime begin and end + local lifetime = cfg["Assertion-LifeTime"] + local s, _, m = util.rmatch(lifetime, "^(?s)(\\d{4})-(\\d{2})-(\\d{2})\\s*:\\s*(\\d{4})-(\\d{2})-(\\d{2})$") + if s == nil then + return integrity.util.error(ctx, cfg, + "failed to extract time information from " .. + "license configuration parameter \"Assertion-LifeTime\"") + end + local lifetime_begin = os.time({ + year = tonumber(m[1]), + month = tonumber(m[2]), + day = tonumber(m[3]), + hour = 0, + min = 0, + sec = 0 + }) + local lifetime_end = os.time({ + year = tonumber(m[4]), + month = tonumber(m[5]), + day = tonumber(m[6]), + hour = 23, + min = 59, + sec = 59 + }) + + -- check whether current run-time is within lifetime + local t_now = os.time() + integrity.util.debug(3, "require: %d <= %d <= %d", lifetime_begin, t_now, lifetime_end) + if not (lifetime_begin <= t_now and t_now <= lifetime_end) then + return integrity.util.error(ctx, cfg, + "current time \"" .. os.date("!%Y-%m-%d %H:%M:%S UTC", t_now) .. "\" " .. + "is not within the timerange \"" .. cfg["Assertion-LifeTime"] .. "\" " .. + "of license configuration parameter \"Assertion-LifeTime\"") + end + end + + -- process "Assertion-GrantTime" constraint + if cfg["Assertion-GrantTime"] ~= nil then + integrity.util.debug(2, "checking: Assertion-GrantTime: \"%s\"", cfg["Assertion-GrantTime"]) + + -- determine granttime begin and end + local granttime = cfg["Assertion-GrantTime"] + local s, _, m = util.rmatch(granttime, "^(?s)(\\d{4})-(\\d{2})-(\\d{2})\\s*:\\s*(\\d{4})-(\\d{2})-(\\d{2})$") + if s == nil then + return integrity.util.error(ctx, cfg, + "failed to extract time information from " .. + "license configuration parameter \"Assertion-GrantTime\"") + end + local granttime_begin = os.time({ + year = tonumber(m[1]), + month = tonumber(m[2]), + day = tonumber(m[3]), + hour = 0, + min = 0, + sec = 0 + }) + local granttime_end = os.time({ + year = tonumber(m[4]), + month = tonumber(m[5]), + day = tonumber(m[6]), + hour = 23, + min = 59, + sec = 59 + }) + + -- determine OpenPKG Framework release time + -- (allow openpkg.spec:%pre to override with a higher value for pre-checking) + local t_release = 0 + local result = {} + for _, line in ipairs(rpm.query("Q:%{RELEASE}", false, "openpkg")) do + local s, _, m = util.rmatch(line, "(?s)^Q:(.+)$") + if s ~= nil then + table.insert(result, m[1]) + end + end + if result[1] ~= nil then + local s, _, m = util.rmatch(result[1], "^(?s)(\\d{4})(\\d{2})(\\d{2})$") + if s ~= nil then + t_release = os.time({ + year = tonumber(m[1]), + month = tonumber(m[2]), + day = tonumber(m[3]), + hour = 0, + min = 0, + sec = 0 + }) + end + end + if t_release == 0 then + return integrity.util.error(ctx, cfg, + "failed to determine OpenPKG Framework release time") + end + local override = os.getenv("OPENPKG_FRAMEWORK_RELEASE") + if override ~= nil then + local s, _, m = util.rmatch(override, "^(?s)(\\d{4})(\\d{2})(\\d{2})$") + if s ~= nil then + local t_override = os.time({ + year = tonumber(m[1]), + month = tonumber(m[2]), + day = tonumber(m[3]), + hour = 0, + min = 0, + sec = 0 + }) + if t_release < t_override then + t_release = t_override + end + end + end + + -- check whether current OpenPKG Framework release time is within granttime + integrity.util.debug(3, "require: %d <= %d <= %d", granttime_begin, t_release, granttime_end) + if not (granttime_begin <= t_release and t_release <= granttime_end) then + return integrity.util.error(ctx, cfg, + "current OpenPKG Framework release time \"" .. os.date("%Y-%m-%d", t_release) .. "\" " .. + "is not within the timerange \"" .. cfg["Assertion-GrantTime"] .. "\" " .. + "of license configuration parameter \"Assertion-GrantTime\"") + end + end + + -- process "Assertion-InstanceAge" constraint + if cfg["Assertion-InstanceAge"] ~= nil then + integrity.util.debug(2, "checking: Assertion-InstanceAge: \"%s\"", cfg["Assertion-InstanceAge"]) + + -- determine maximum instance age in seconds + local t_diff_max = cfg["Assertion-InstanceAge"] + t_diff_max = 0 + util.rsubst(t_diff_max, "^(\\d+)([smhdw])$", function (t, unit) + if unit == "s" then t = t * 1 + elseif unit == "m" then t = t * 60 + elseif unit == "h" then t = t * 60 * 60 + elseif unit == "d" then t = t * 60 * 60 * 24 + elseif unit == "w" then t = t * 60 * 60 * 24 * 7 + end + return t + end) + + -- approach 1: determine install time via timestamp of UUID_REGISTRY + local uuids = integrity.util.uuids() + if uuids["UUID_REGISTRY"] == "" then + return integrity.util.error(ctx, cfg, + "failed to load UUID_REGISTRY") + end + txt = uuid.describe(uuids["UUID_REGISTRY"]) + if txt == nil then + return integrity.util.error(ctx, cfg, + "failed to parse extracted UUID_REGISTRY string \"" .. uuids["UUID_REGISTRY"] .. "\" as an UUID") + end + local s, _, m = util.rmatch(txt, "(?s)^.*time:\\s+(\\d{4})-(\\d{2})-(\\d{2})\\s+(\\d{2}):(\\d{2}):(\\d{2}).*$") + if s == nil then + return integrity.util.error(ctx, cfg, + "failed to extract timestamp from UUID_REGISTRY \"" .. uuids["UUID_REGISTRY"] .. "\"") + end + local t_install = os.time({ + year = tonumber(m[1]), + month = tonumber(m[2]), + day = tonumber(m[3]), + hour = tonumber(m[4]), + min = tonumber(m[5]), + sec = tonumber(m[6]) + }) + + -- approach 2: determine install time via first install time of "openpkg" package + local result = {} + for _, line in ipairs(rpm.query( + "Q:%|ORIGINTIME?{" .. + "%{ORIGINTIME}" .. -- regular case: RPM 5 installed/updated with RPM 5 + "}:{" .. + "%|INSTALLTIME?{" .. + "%{INSTALLTIME}" .. -- special case: RPM 5 installed initially with RPM 4 + "}:{" .. + "}|" .. + "}|", false, "openpkg" + )) do + local s, _, m = util.rmatch(line, "(?s)^Q:(.+)$") + if s ~= nil then + table.insert(result, m[1]) + end + end + if result[1] ~= nil then + local n = tonumber(result[1]) + if n > 0 then + t_install = n + end + end + + -- check time difference + local t_now = os.time() + local t_diff = os.difftime(t_now, t_install) + integrity.util.debug(3, "calc: %d - %d = %d", t_now, t_install, t_diff) + if t_diff < 0 then + return integrity.util.error(ctx, cfg, + "current system time \"" .. t_now .. "\" is lower than " .. + "instance installation time \"" .. t_install .. "\"") + end + integrity.util.debug(3, "require: %d <= %d", t_diff, t_diff_max) + if t_diff > t_diff_max then + return integrity.util.error(ctx, cfg, + "instance age \"" .. t_diff .. "\" " .. + "is greater than value \"" .. t_diff_max .. "\" (\"" .. cfg["Assertion-InstanceAge"] .. "\") " .. + "of license configuration parameter \"Assertion-InstanceAge\"") + end + end + + -- process "Assertion-FromSourceOnTarget" constraint + if cfg["Assertion-FromSourceOnTarget"] ~= nil then + integrity.util.debug(2, "checking: Assertion-FromSourceOnTarget: \"%s\"", cfg["Assertion-FromSourceOnTarget"]) + local hostname = rpm.hostname() + for _, line in ipairs(rpm.query("Q:%{NAME}:%{BUILDHOST}", true, "*")) do + local s, _, m = util.rmatch(line, "(?s)^Q:([^:]+):(.+)$") + if s ~= nil then + local name = m[1] + local buildhost = m[2] + integrity.util.debug(4, "info: name \"%s\", buildhost \"%s\"", name, buildhost) + if not util.rmatch(name, "(?s)^gpg-.+$") and buildhost ~= "localhost" then + if cfg["Assertion-FromSourceOnTarget"] == "yes" and buildhost ~= hostname then + return integrity.util.error(ctx, cfg, + "license-required \"build from source on target system only\" situation not met because " .. + "package build host \"" .. buildhost .. "\" is not(!) equal to the package install host \"" .. hostname .. "\".") + end + if cfg["Assertion-FromSourceOnTarget"] == "no" and buildhost == hostname then + return integrity.util.error(ctx, cfg, + "license-required \"build binaries on separate build-host only\" situation not met because " .. + "package build host \"" .. buildhost .. "\" is equal to the package install host \"" .. hostname .. "\".") + end + end + end + end + end + + -- process "Assertion-PackageNames" constraints + if cfg["Assertion-PackageNames"] ~= nil then + integrity.util.debug(2, "checking: Assertion-PackageNames: \"%s\"", cfg["Assertion-PackageNames"]) + + -- query RPMDB for names of all installed packages + local packages = {} + for _, line in ipairs(rpm.query("Q:%{NAME}", true, "*")) do + local s, _, m = util.rmatch(line, "(?s)^Q:(.+)$") + if s ~= nil then + table.insert(packages, m[1]) + end + end + + -- iterate over all constraints + for _, constraint in + ipairs( + util.rsplit( + util.rsubst( + cfg["Assertion-PackageNames"], + "(?s)^\\s*(.+?)\\s*$", "%1" + ), + "(?s)\\s+" + ) + ) do + -- parse constraint + local s, _, m = util.rmatch(constraint, "(?s)^(!?)([^:]+):(!?)(.+)$") + if s == nil then + return integrity.util.error(ctx, cfg, + "invalid syntax in license configuration \"Assertion-PackageNames\" " .. + "parameter: \"" .. constraint .. "\"") + end + local mode_negate = m[1] ~= "" + local mode_regex = m[2] + local package_negate = m[3] ~= "" + local package_regex = m[4] + -- apply the mode filter + local mode_matches, _, _ = util.rmatch(ctx.rpm.mode, mode_regex); + if (not mode_negate and mode_matches ~= nil) + or ( mode_negate and mode_matches == nil) then + -- apply the package filter to names of all installed packages + for _, package in ipairs(packages) do + if package_negate then + integrity.util.debug(3, "require: \"%s\" !~ /%s/", package, package_regex) + else + integrity.util.debug(3, "require: \"%s\" ~~ /%s/", package, package_regex) + end + local package_matches, _, _ = util.rmatch(package, package_regex) + if not ( (not package_negate and package_matches ~= nil) + or ( package_negate and package_matches == nil)) then + -- indicate integrity validation error + return integrity.util.error(ctx, cfg, + "installed package \"" .. package .. "\" " .. + "under RPM run-time mode \"" .. ctx.rpm.mode .. "\" " .. + "not covered by pattern \"" .. package_regex .. "\" " .. + "of license configuration parameter \"Assertion-PackageNames\"") + end + end + end + end + end + + -- process "Assertion-PackageReleaseAge" + if cfg["Assertion-PackageReleaseAge"] ~= nil then + integrity.util.debug(2, "checking: Assertion-PackageReleaseAge: \"%s[...]\"", string.sub(cfg["Assertion-PackageReleaseAge"], 1, 20)) + + -- parse constraint + local constraint = cfg["Assertion-PackageReleaseAge"] + local s, _, m = util.rmatch(constraint, "(?s)^([^:]+)%:([^:]+):([^\\s]+)\\s+(.+)$") + if s == nil then + return integrity.util.error(ctx, cfg, + "invalid syntax in license configuration \"Assertion-PackageReleaseAge\" parameter") + end + local percent = m[1] / 100 + local offset = m[2] + local distregex = m[3] + local spec = m[4] + + -- determine maximum release time difference (in seconds) + local t_diff_max = 0 + util.rsubst(offset, "^(\\d+)([smhdw])$", function (t, unit) + if unit == "s" then t = t * 1 + elseif unit == "m" then t = t * 60 + elseif unit == "h" then t = t * 60 * 60 + elseif unit == "d" then t = t * 60 * 60 * 24 + elseif unit == "w" then t = t * 60 * 60 * 24 * 7 + end + return t + end) + + -- iterate over all package specifications to build release map + local releases = {} + for _, constraint in + ipairs( + util.rsplit( + util.rsubst( + spec, + "(?s)^\\s*(.+?)\\s*$", "%1" + ), + "(?s)\\s+" + ) + ) do + + -- parse specification into package name and release constraint + local s, _, m = util.rmatch(constraint, "(?s)^([^:]+):(.+)$") + if s == nil then + return integrity.util.error(ctx, cfg, + "invalid syntax in license configuration \"Assertion-PackageReleaseAge\" " .. + "parameter: \"" .. constraint .. "\"") + end + + -- store result into release map + releases[m[1]] = m[2] + end + + -- query RPMDB for releases of all installed packages and decide + -- whether the release time is inside or outside our constraint window + local release_window_inside = 0 + local release_window_outside = 0 + local release_window_foreign = 0 + local release_window_unknown = 0 + for _, line in ipairs(rpm.query("Q:%{NAME}:%{RELEASE}:%{DISTRIBUTION}", true, "*")) do + local s, _, m = util.rmatch(line, "(?s)^Q:([^:]+):(\\d\\d\\d\\d)(\\d\\d)(\\d\\d):(.+)$") + if s ~= nil then + -- parse query results + local name = m[1] + local t_release = os.time({ + year = tonumber(m[2]), + month = tonumber(m[3]), + day = tonumber(m[4]), + hour = 23, + min = 59, + sec = 59 + }) + local dist = m[5] + + -- only check files of the constrained distribution(s) + if util.rmatch(dist, "(?s)" .. distregex) then + + -- determine minimum release constraint + local t_release_min = releases[name] + if t_release_min == nil then + t_release_min = releases["*"] + end + if t_release_min == nil then + t_release_min = os.time() + else + local s, _, m = util.rmatch(t_release_min, "^(?s)(\\d{4})(\\d{2})(\\d{2})$") + t_release_min = os.time({ + year = tonumber(m[1]), + month = tonumber(m[2]), + day = tonumber(m[3]), + hour = 0, + min = 0, + sec = 0 + }) + end + + -- check time difference of package release + local t_diff = os.difftime(t_release_min, t_release) + integrity.util.debug(4, "calc: %d - %d = %d", t_release_min, t_release, t_diff) + integrity.util.debug(4, "require: %d <= 0 or (%d > 0 and %d < %d)", t_diff, t_diff, t_diff, t_diff_max) + if t_diff <= 0 or (t_diff > 0 and t_diff < t_diff_max) then + release_window_inside = release_window_inside + 1 + else + release_window_outside = release_window_outside + 1 + end + else + release_window_foreign = release_window_foreign + 1 + end + else + release_window_unknown = release_window_unknown + 1 + end + end + integrity.util.debug(3, "info: inside %d, outside %d, foreign %d, unknown %d", + release_window_inside, release_window_outside, release_window_foreign, release_window_unknown) + + -- check validity of overall constraint + local percent_inside = + (release_window_inside / (release_window_inside + release_window_outside)) + integrity.util.debug(3, "require: %d >= %d", percent_inside, percent) + if percent_inside < percent then + return integrity.util.error(ctx, cfg, + "there are only " .. math.floor(percent_inside * 100) .. "% " .. + "packages inside the release date constraint " .. + "(expected a minimum of " .. math.floor(percent * 100) .. "%)") + end + end + + -- process "Assertion-Expression" constraint + if cfg["Assertion-Expression"] ~= nil then + integrity.util.debug(2, "checking: Assertion-Expression: \"%s\"", cfg["Assertion-Expression"]) + + -- expand special consytructs in expression + local expr = cfg["Assertion-Expression"] + expr = util.rsubst(expr, "(%\{[a-zA-Z_][a-zA-Z0-9_]+\})", function (str) + return rpm.expand(str) + end) + expr = util.rsubst(expr, "\"((?:\\\\.|[^\"])+)\"\\s*~~\\s*/((?:\\\\.|[^/])+)/", function (str, regex) + if util.rmatch(str, "(?s)" .. regex) ~= nil then + return "true" + else + return "false" + end + end) + + -- evaluate expression + integrity.util.debug(3, "evaluate: %s", expr) + result = assert(loadstring(expr))() + if type(result) ~= "boolean" then + result = false + end + if not result then + return integrity.util.error(ctx, cfg, + "expression \"" .. cfg["Assertion-Expression"] .. "\" " .. + "of license configuration parameter \"Assertion-Expression\"" .. + "evaluated to false") + end + end + + -- indicate license integrity validation success + return "OK" +end + +- -- integrity processor utilities namespace +integrity.util = {} + +- -- write debug information to stderr +function integrity.util.debug(level_this, msg, ...) + local level_min = os.getenv("OPENPKG_LICENSE_DEBUG") + if level_min ~= nil then + if type(level_min) == "string" then + level_min = tonumber(level_min) + end + if type(level_min) ~= "number" then + level_min = 0 + end + if level_this <= level_min then + local output + if type(msg) == "function" then + output = msg(...) + else + output = string.format(msg, ...) + end + local prefix = "" + local i = 1 + while (i < level_this) do + prefix = prefix .. " " + i = i + 1 + end + io.stderr:write("rpm: DEBUG: " .. prefix .. output .. "\n") + end + end +end + +- -- load OpenPKG instance UUIDs +function integrity.util.uuids() + local uuids = { + UUID_REGISTRY = "", + UUID_INSTANCE = "", + UUID_PLATFORM = "" + } + local filename = rpm.expand("%{l_prefix}/etc/openpkg/uuid") + local txt = rpm.slurp(filename) + if txt ~= nil then + for name, _ in pairs(uuids) do + local s, _, m = util.rmatch(txt, "(?s)^.*" .. name .. "=\"([^\"\"]+)\".*$") + if s ~= nil then + uuids[name] = m[1] + end + end + end + return uuids +end + +- -- report validation warning +function integrity.util.warning(ctx, cfg, warning) + -- return prominent warning message + return + "WARNING: OpenPKG run-time license check failed -- continue processing\n" .. + "+-----------------------------------------------------------------------------+\n" .. + "| Attention, the OpenPKG RPM run-time integrity checking facility encountered a\n" .. + "| non-fatal problem during license checking, but allows processing to continue.\n" .. + "| The particular warning reported by the OpenPKG license processor is:\n" .. + "|\n" .. + util.textwrap("| ", warning, 60, 70) .. + "|\n" .. + "| Notice: Operation of the OpenPKG Framework requires a valid license.\n" .. + "| Go to http://openpkg.com/go/framework-license for more details, please.\n" .. + "+-----------------------------------------------------------------------------+" +end + +- -- report validation error +function integrity.util.error(ctx, cfg, error) + -- support conversion of errors into warnings + if cfg["Assertion-ErrorToWarning"] ~= nil then + if cfg["Assertion-ErrorToWarning"] == "yes" then + return integrity.util.warning(ctx, cfg, error) + end + end + + -- return prominent error message + return + "ERROR: OpenPKG run-time license check failed -- stopping processing\n" .. + "+-----------------------------------------------------------------------------+\n" .. + "| Sorry, the OpenPKG RPM run-time integrity checking facility encountered a\n" .. + "| fatal problem during license checking and stops processing immediately.\n" .. + "| The particular error reported by the OpenPKG license processor is:\n" .. + "|\n" .. + util.textwrap("| ", error, 60, 70) .. + "|\n" .. + "| Notice: Operation of the OpenPKG Framework requires a valid license.\n" .. + "| Go to http://openpkg.com/go/framework-license for more details, please.\n" .. + "| Run \"openpkg man license\" for details about local license management.\n" .. + "+-----------------------------------------------------------------------------+" +end + +-----BEGIN PGP SIGNATURE----- +Comment: OpenPKG GmbH + +iEYEARECAAYFAk8BelcACgkQZwQuyWG3rjTL6QCeLTLVj4PTnd/E7mf+Sv4mgbZj +5J0AoMXrO4EimPSSCZSJ1TLW8f8GP+B5 +=AVpf +-----END PGP SIGNATURE----- diff -r 71503088f51b -r f880f219c566 openpkg/license.pod --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license.pod Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,126 @@ +## +## OpenPKG License Utility +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +=pod + +=head1 NAME + +B - OpenPKG License Utility + +=head1 SYNOPSIS + +B B + +B B I I|I|C<-> + +B B I I|I|C<-> + +B B I + +B B I + +B B I + +B B + +B B + +B B + +=head1 DESCRIPTION + +The B command is the maintenance utility for OpenPKG +Framework licenses. + +=head1 COMMANDS + +=over 4 + +=item B B + +This command just displays a short usage help information. + +=item B B I I|I|C<-> + +This command installs the license contained in I or at I or +provided on F under the identifier I. The I can be an +arbitrary string, but the convention is that I is a short upper-case +identifier. + +=item B B I I|I|C<-> + +This command updates an already installed license with the license +contained in I or at I or provided on F under the +identifier I. + +=item B B I + +This command uninstalls the license which is installed under I. +A license can be uninstalled only if it is not currently activated (see +B command). + +=item B B I + +This command activates the license which is installed under I. +Only one installed license can be active at any time, so this command +implicitly deactivates the currently activate license. + +=item B B I + +This command shows the license which is installed under I. + +=item B B + +This command lists the identifiers of all installed licenses. + +=item B B + +This command outputs the identifier of the currently activated license. + +=item B B + +This command sanity checks the current license configuration. + +=back + +=head1 FILES + +=over 4 + +=item F<@l_prefix@/etc/license> + +The name of the currently activated license file under +F<@l_prefix@/etc/license.d/>. + +=item F<@l_prefix@/etc/license.d/*> + +The directory containing all installed license files. + +=back + +=head1 HISTORY + +The B command first appeared in B. + +=cut + diff -r 71503088f51b -r f880f219c566 openpkg/license.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/license.sh Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,281 @@ +#!@l_prefix@/lib/openpkg/bash +## +## uuid -- OpenPKG UUID Update Utility +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# configuration +prefix="@l_prefix@" +musr="@l_musr@" +mgrp="@l_mgrp@" + +# minimum command line parsing +opt_v=no +while [ 1 ]; do + case "$1" in + -v | --verbose ) opt_v=yes; shift ;; + * ) break ;; + esac +done + +# determine temporary directory +tmpdir="${TMPDIR-/tmp}" + +# helper function for checking the signature +valid_signature () { + script="%{lua: print(rpm.signature(\"$1\", nil," + script="$script \"$prefix/etc/openpkg/openpkg.com.pgp\"," + script="$script \"7D121A8FC05DC18A4329E9EF67042EC961B7AE34\")) }" + result=`$prefix/bin/openpkg rpm --eval "$script" 2>/dev/null || true` + if [ ".$result" == .true ]; then + return 0 + else + return 1 + fi +} + +# display usage help +do_help () { + echo "openpkg license help .......................... show usage help (this text)" + echo "openpkg license install ||- ... install a new license" + echo "openpkg license update ||- .... update an installed license" + echo "openpkg license uninstall ................ uninstall an installed license" + echo "openpkg license activate ................. activate an installed license" + echo "openpkg license view ..................... view an installed license" + echo "openpkg license list .......................... list all installed licenses" + echo "openpkg license active ........................ list the currently activated license" + echo "openpkg license sanity ........................ sanity check installed license" +} + +# install license +do_install () { + if [ $# -ne 2 ]; then + echo "openpkg:license:USAGE: openpkg license install |-" 1>&2 + exit 1 + fi + id="$1" + src="$2" + case "$src" in + http:* | https:* | ftp:* ) + tmp="$tmpdir/openpkg.license.txt" + ( rm -f $tmp >/dev/null 2>&1 || true + set -o noclobber + $prefix/lib/openpkg/curl -s -q -f -L $src >$tmp + ) || exit $? + src="$tmp" + ;; + "-" ) + src="$tmpdir/openpkg.license.txt" + ( rm -f $src >/dev/null 2>&1 || true + set -o noclobber + cat >$src + ) || exit $? + ;; + esac + if [ -f $prefix/etc/openpkg/license.d/$id ]; then + echo "openpkg:license:ERROR: license with id \"$id\" already exists -- uninstall first" 1>&2 + exit 1 + fi + if ! valid_signature $src; then + echo "openpkg:license:ERROR: invalid signature on license file" 1>&2 + exit 1 + fi + if [ ! -w $prefix/etc/openpkg/license.d ]; then + echo "openpkg:license:ERROR: unable to store signature -- permission problems?" 1>&2 + exit 1 + fi + cat $src >$prefix/etc/openpkg/license.d/$id || exit $? + chown $musr:$mgrp $prefix/etc/openpkg/license.d/$id >/dev/null 2>&1 || true +} + +# update license +do_update () { + if [ $# -ne 2 ]; then + echo "openpkg:license:USAGE: openpkg license update |-" 1>&2 + exit 1 + fi + id="$1" + src="$2" + case "$src" in + http:* | https:* | ftp:* ) + tmp="$tmpdir/openpkg.license.txt" + ( rm -f $tmp >/dev/null 2>&1 || true + set -o noclobber + $prefix/lib/openpkg/curl -s -q -f -L $src >$tmp + ) || exit $? + src="$tmp" + ;; + "-" ) + src="$tmpdir/openpkg.license.txt" + ( rm -f $src >/dev/null 2>&1 || true + set -o noclobber + cat >$src + ) || exit $? + ;; + esac + if [ ! -f $prefix/etc/openpkg/license.d/$id ]; then + echo "openpkg:license:ERROR: license with id \"$id\" does not exist -- install first to update" 1>&2 + exit 1 + fi + if ! valid_signature $src; then + echo "openpkg:license:ERROR: invalid signature on license file" 1>&2 + exit 1 + fi + if [ ! -w $prefix/etc/openpkg/license.d ]; then + echo "openpkg:license:ERROR: unable to store signature -- permission problems?" 1>&2 + exit 1 + fi + cat $src >$prefix/etc/openpkg/license.d/$id || exit $? + chown $musr:$mgrp $prefix/etc/openpkg/license.d/$id >/dev/null 2>&1 || true +} + +# uninstall license +do_uninstall () { + if [ $# -ne 1 ]; then + echo "openpkg:license:USAGE: openpkg license uninstall " 1>&2 + exit 1 + fi + id="$1" + if [ ! -f $prefix/etc/openpkg/license.d/$id ]; then + echo "openpkg:license:ERROR: no license under id \"$id\" installed" 1>&2 + exit 1 + fi + id_active="`cat $prefix/etc/openpkg/license`" + if [ ".$id" = ".$id_active" ]; then + echo "openpkg:license:ERROR: license under id \"$id\" still activated -- activate a different one first" 1>&2 + exit 1 + fi + rm -f $prefix/etc/openpkg/license.d/$id + if [ $? -ne 0 ]; then + echo "openpkg:license:ERROR: failed to uninstall license" 1>&2 + exit 1 + fi +} + +# activate license +do_activate () { + if [ $# -ne 1 ]; then + echo "openpkg:license:USAGE: openpkg license activate " 1>&2 + exit 1 + fi + id="$1" + if [ ! -f $prefix/etc/openpkg/license.d/$id ]; then + echo "openpkg:license:ERROR: no license under id \"$id\" installed" 1>&2 + exit 1 + fi + id_active="`cat $prefix/etc/openpkg/license`" + if [ ".$id" = ".$id_active" ]; then + echo "openpkg:license:ERROR: license id \"$id\" is already activated" 1>&2 + exit 1 + fi + echo "$id" >$prefix/etc/openpkg/license + if [ $? -ne 0 ]; then + echo "openpkg:license:ERROR: failed to activate license under id \"$id\"" 1>&2 + exit 1 + fi +} + +# view license +do_view () { + if [ $# -ne 1 ]; then + echo "openpkg:license:USAGE: openpkg license view " 1>&2 + exit 1 + fi + id="$1" + if [ ! -f $prefix/etc/openpkg/license.d/$id ]; then + echo "openpkg:license:ERROR: no license under id \"$id\" installed" 1>&2 + exit 1 + fi + viewer="" + for name in less more cat; do + for dir in `echo $PATH | sed -e 's;:; ;g'`; do + if [ -x $dir/$name ]; then + viewer="$dir/$name" + break + fi + done + if [ ".$viewer" != . ]; then + break + fi + done + eval $viewer $prefix/etc/openpkg/license.d/$id +} + +# list license +do_list () { + if [ $# -ne 0 ]; then + echo "openpkg:license:USAGE: openpkg license list" 1>&2 + exit 1 + fi + id_active="`cat $prefix/etc/openpkg/license`" + for file in `cd / && find $prefix/etc/openpkg/license.d -type f -print | sort`; do + id=`echo $file | sed -e "s;^$prefix/etc/openpkg/license.d/;;"` + status="-" + if [ ".$id" = ".$id_active" ]; then + status="+" + fi + echo . | awk '{ printf("%s %s\n", status, id); }' id="$id" status="$status" + done +} + +# list currently activate license +do_active () { + if [ $# -ne 0 ]; then + echo "openpkg:license:USAGE: openpkg license active" 1>&2 + exit 1 + fi + cat $prefix/etc/openpkg/license +} + +# sanity-check license +do_sanity () { + if [ $# -ne 0 ]; then + echo "openpkg:license:USAGE: openpkg license sanity" 1>&2 + exit 1 + fi + id="`cat $prefix/etc/openpkg/license`" + if [ ! -f $prefix/etc/openpkg/license.d/$id ]; then + echo "openpkg:license:ERROR: active license with id \"$id\" does not exist" 1>&2 + exit 1 + fi + if ! valid_signature $prefix/etc/openpkg/license.d/$id; then + echo "openpkg:license:ERROR: invalid signature on active license" 1>&2 + exit 1 + fi +} + +# Command Line Dispatching +cmd="$1" +shift +case "$cmd" in + help ) do_help ${1+"$@"} ;; + install ) do_install ${1+"$@"} ;; + update ) do_update ${1+"$@"} ;; + uninstall ) do_uninstall ${1+"$@"} ;; + activate ) do_activate ${1+"$@"} ;; + view ) do_view ${1+"$@"} ;; + list ) do_list ${1+"$@"} ;; + active ) do_active ${1+"$@"} ;; + sanity ) do_sanity ${1+"$@"} ;; + "" ) echo "openpkg:license:ERROR: no command given (use \"help\" for usage)" 1>&2; exit 1 ;; + * ) echo "openpkg:license:ERROR: invalid command \"$cmd\" (use \"help\" for usage)" 1>&2; exit 1 ;; +esac + diff -r 71503088f51b -r f880f219c566 openpkg/lint-fsl.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/lint-fsl.pl Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,502 @@ +## +## lint-fsl.pl -- OpenPKG fsl.* File Checker +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# Perl run-time requirement +require 5; +BEGIN { + eval "use Getopt::Long; use IO;"; + if ($@) { + print STDERR + "lint-fsl: ERROR: This command requires a full-size Perl installation!\n" . + "lint-fsl: HINT: Install OpenPKG \"perl\" package to use this command.\n"; + exit(1); + } +} + +# OpenPKG instance prefix +my $my_prefix = $ENV{'OPENPKG_PREFIX'}; +delete $ENV{'OPENPKG_PREFIX'}; + +# program information +my $progname = "lint-fsl"; +my $progvers = "1.0.0"; + +# parameters (defaults) +my $version = 0; +my $verbose = 0; +my $help = 0; +my $check = 'all'; +my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname"; +my $rpm = "$my_prefix/bin/openpkg rpm"; + +# exception handling support +$SIG{__DIE__} = sub { + my ($err) = @_; + $err =~ s|\s+at\s+.*||s if (not $verbose); + print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n"; + exit(1); +}; + +# command line parsing +Getopt::Long::Configure("bundling"); +my $result = GetOptions( + 'V|version' => \$version, + 'v|verbose' => \$verbose, + 'h|help' => \$help, + 'c|check=s' => \$check, + 't|tmpdir=s' => \$tmpdir, + 'r|rpm=s' => \$rpm, +) || die "option parsing failed"; +if ($help) { + print "Usage: $progname [options] [RPMFILE ...]\n" . + "Available options:\n" . + " -v,--verbose enable verbose run-time mode\n" . + " -h,--help print out this usage page\n" . + " -c,--check=CHECKS select checks to perform (default='all')\n" . + " -r,--rpm=FILE filesystem path to RPM program\n" . + " -t,--tmpdir=PATH filesystem path to temporary directory\n" . + " -V,--version print program version\n"; + exit(0); +} +if ($version) { + print "OpenPKG $progname $progvers\n"; + exit(0); +} + +# verbose message printing +sub msg_verbose { + my ($msg) = @_; + print STDERR "$msg\n" if ($verbose); +} + +# warning message printing +sub msg_warning { + my ($msg) = @_; + print STDERR "$progname:WARNING: $msg\n"; +} + +# error message printing +sub msg_error { + my ($msg) = @_; + print STDERR "$progname:ERROR: $msg\n"; +} + +# determine check list +my @check_list = (qw( + blank + comment + ident +)); +my @checks = (); +if ($check eq 'all') { + @checks = @check_list; +} +else { + foreach my $c (split(/,/, $check)) { + if (not grep(/^$c$/, @check_list)) { + die "invalid check \"$c\""; + } + push(@checks, $c); + } +} + +# global return code +$main::GRC = 0; + +# environment preparation +system("rm -rf $tmpdir"); +system("mkdir -p $tmpdir"); + +# iterate over all fsl. files +foreach my $filename (@ARGV) { + my $io = new IO::File "<$filename" + or die "unable to open file \"$filename\" for reading"; + my $spec; { local $/ = undef; $spec = <$io>; } + $io->close; + foreach my $check (@checks) { + eval "\&check_$check(\$filename, \$spec);"; + } +} + +# environment cleanup +system("rm -rf $tmpdir"); + +# die gracefully +exit($main::GRC); + +## _________________________________________________________________ +## +## COMMON SUBROUTINES +## _________________________________________________________________ +## + +sub lines { + my ($txt) = @_; + my $l = 0; + $txt =~ s|\n|$l++, ''|sge; + return $l; +} + +sub lint_message { + my ($type, $file, $done, $this, $msg) = @_; + if (defined($done) and defined($this)) { + my $start = &lines($done) + 1; + my $end = $start + &lines($this); + my $pos = $start; + $pos .= "-". $end if ($end > $start); + printf("%s:%s: %s:%s: %s\n", $progname, $type, $file, $pos, $msg); + } + else { + printf("%s:%s: %s: %s\n", $progname, $type, $file, $msg); + } +} + +sub lint_warning { + my ($file, $done, $this, $msg) = @_; + &lint_message("WARNING", $file, $done, $this, $msg); + $main::GRC = 1 if ($main::GRC < 1); +} + +sub lint_error { + my ($file, $done, $this, $msg) = @_; + &lint_message("ERROR", $file, $done, $this, $msg); + $main::GRC = 2 if ($main::GRC < 2); +} + +## _________________________________________________________________ +## +## CHECK "blank": whitespace and blank lines +## _________________________________________________________________ +## + +sub check_blank { + my ($file, $spec) = @_; + + # check for CR-LF combination + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/\r\n/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "carriage-return (CR, 0x0d) line-feed (NL, 0x0a) combination (expected just line-feed)"); + $done .= $this; + } + + # check for multiple blank lines + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/(\r?\n[ \t]*){3,}/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "multiple subsequent blank lines (expected single blank line)"); + $done .= $this; + } + + # check for trailing whitespaces + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/[ \t]+\r?\n/s) { + $done .= $`; $this = $&; $todo = $'; + if ($done eq '' or $done =~ m|\n$|s) { + &lint_warning($file, $done, $this, "whitespace on empty line (expected none)"); + } + else { + &lint_warning($file, $done, $this, "trailing whitespace (expected none)"); + } + $done .= $this; + } + + # check for bogus line continuations + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/\\[ \t]*\r?\n(?=[ \t]*\r?\n)/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "bogus line continuation for following empty line (expect no line continuation)"); + $done .= $this; + } + + # check for leading whitespaces before line continuations + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/[ \t]{2,}\\[ \t]*\r?\n/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "multiple leading whitespace before line continuation (expected just a single space)"); + $done .= $this; + } + + # check for leading tabs + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/^ *\t+ *[^ \t]/m) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "leading tabs (expected spaces)"); + $done .= $this; + } + + # check for mandatory/wished trailing blank line + if ($spec !~ m|\n\n$|) { + &lint_warning($file, $done, "", "mandatory/wished trailing blank line missing (expected one)"); + } +} + +## _________________________________________________________________ +## +## CHECK "comment": sharp-comments +## _________________________________________________________________ +## + +sub check_comment { + my ($file, $spec) = @_; + my ($pkg); + + # determine package name + $pkg = $file; + $pkg =~ s|^.+/||; + $pkg =~ s|^fsl\.||; + + # check comment header + my $re = ""; + $re .= "##\\n## fsl.$pkg -- OSSP fsl configuration\\n##\\n\\n"; + if ($spec !~ m|^$re|os) { + &lint_warning($file, "", "", "invalid comment header (expected $re)"); + } + + # check for comment indentation + my $done .= $`; my $this = $&; my $todo = $'; + while ($todo =~ m/^([ \t]*)(#+)([ \t]*)(.*?)$/m) { + $done .= $`; $this = $&; $todo = $'; + my ($lead, $sharp, $pad, $text) = ($1, $2, $3, $4); + if (length($lead) % 2 != 0) { + &lint_warning($file, $done, $this, "incorrect comment indentation (expected a multiple of 2 spaces)"); + } + if (length($lead) > 1 && length($sharp) > 1) { + &lint_warning($file, $done, $this, "indented comment has introduced with multiple sharps (expected single sharp character)"); + } + if (length($pad.$text) > 0 && length($sharp.$pad) % 4 != 0) { + &lint_warning($file, $done, $this, "incorrect comment text padding (expected a multiple of 4 sharps or spaces)"); + } + if (length($pad) == 0 && length($text) > 0) { + &lint_warning($file, $done, $this, "missing leading space before comment text (expected padding spaces)"); + } + if (length($pad) > 0 && length($text) == 0) { + &lint_warning($file, $done, $this, "empty comment text (expected a reasonable text)"); + } + $done .= $this; + } +} + +## _________________________________________________________________ +## +## CHECK "ident" +## _________________________________________________________________ +## + +sub check_ident { + my ($file, $spec) = @_; + my ($pkg, $section); + + # determine package name + $pkg = $file; + $pkg =~ s|^.+/||; + $pkg =~ s|^fsl\.||; + + # check sections with ident/facility regex + my $done .= ""; my $this = ""; my $todo = $spec; + while ($todo =~ m:\n(\w+)(\s+)(\S+)/(\S+)(\s+)q\{(.*?)\};:s) { + $done .= $`; $this = $&; $todo = $'; + my ($section, $ws1, $ident, $facility, $ws2, $body) = ($1, $2, $3, $4, $5, $6); + + if ($pkg eq "fsl") { + # enforce default section for fsl + if ($section ne "default") { + &lint_warning($file, "", "", "section \"$section\" not allowed for package $pkg (expected default)"); + } + } + else { + # enforce ident section for any package othen than fsl + if ($section ne "ident") { + &lint_warning($file, "", "", "section \"$section\" not allowed for package $pkg (expected ident)"); + } + + # ident and facility wildcard-only would be a catch-all + if ($ident =~ m/^[(]?\.[\+\*][)]?$/ and $facility =~ m/^[(]?\.[\+\*][)]?$/) { + &lint_warning($file, "", "", "wildcard not allowed for both ident and facility (found $ident/$facility"); + } + } + + # enforce a single space + if (length($ws1) != 1) { + &lint_warning($file, "", "", "whitespace count wrong between section ($section) and ident ($ident)"); + } + + # enforce a single space + if (length($ws2) != 1) { + &lint_warning($file, "", "", "whitespace count wrong between facility ($facility) and end of line"); + } + + # ident same as facility is likely to be a typo + if ($ident eq $facility) { + &lint_warning($file, "", "", "unusual constellation ident equal to facility (found $ident/$facility"); + } + + # FIXME MTAs hardcoded here for /mail + if ($facility eq "mail" and $pkg !~ m/^(sendmail|ssmtp|postfix|exim)$/) { + &lint_warning($file, "", "", "only MTAs may match facility mail"); + } + + # FIXME inn hardcoded here for /news + if ($facility eq "news" and $pkg !~ m/^(inn)$/) { + &lint_warning($file, "", "", "only inn may match facility news"); + } + + # check prefix channel + if ($body =~ m/\n([ ]*)prefix(\s*?)\((.*?)\)/s) { + my ($ws1, $ws2, $options) = ($1, $2, $3); + + # enforce eight spaces + if (length($ws1) != 4) { + &lint_warning($file, "", "", "prefix channel whitespace count at start of line"); + } + + # enforce zero spaces + if (length($ws2) != 0) { + &lint_warning($file, "", "", "whitespace not allowed between prefix channel and round open bracket"); + } + + # enforce prefix options in prefix channel + if ($options !~ m/\sprefix="%b %d %H:%M:%S %N (<%L> )?\$1(\[%P\])?: "/) { + &lint_warning($file, "", "", "prefix option in prefix channel invalid or missing"); + } + $options = $'; + $options =~ s/,//; + + # detect superflous options in prefix channel + if ($options =~ m/\S+/s) { + $options =~ s/\n/\\n/; + &lint_warning($file, "", "", "superflous option in prefix channel unseparated line detected: $options"); + } + } + else { + &lint_warning($file, "", "", "prefix channel missing"); + } + + # check path branch + if ($body !~ m/\n([ ]*)->(\s*?)\{(.*)\}\n/s) { + &lint_warning($file, "", "", "no path branch found"); + return; + } + my ($ws1, $ws2, $body) = ($1, $2, $3); #FIXME check ws1/ws2 + + # check path channel + while ($body =~ m/\n([ ]*)(\w+):(\s+?)file(\s*?)\((.*?)\);/s) { + my ($ws1, $level, $ws2, $ws3, $options) = ($1, $2, $3, $4, $5); + $body = $'; + + # enforce eight spaces + if (length($ws1) != 8) { + &lint_warning($file, "", "", "path channel whitespace count at start of line"); + } + + # enforce spaces + if (length($ws2) < 1) { + &lint_warning($file, "", "", "whitespace required between level and file"); + } + + # enforce zero spaces + if (length($ws3) != 0) { + &lint_warning($file, "", "", "path channel whitespace not allowed between file channel and round open bracket"); + } + + # check for legal l2 level + if ($level !~ m/^(panic|critical|error|warning|notice|info|trace|debug)$/) { + &lint_warning($file, "", "", "illegal l2 level $level detected"); + } + + # enforce file option in file channel + if ($options !~ m;path="\@l_prefix\@/var/$pkg/(log\S+|$pkg\.log)";) { + &lint_warning($file, "", "", "path option in file channel invalid or missing"); + } + $options = $'; + $options =~ s/,//; + + # enforce perm option in file channel + if ($options !~ m;perm=0[0-7]{3};) { + &lint_warning($file, "", "", "perm option in file channel invalid or missing"); + } + $options = $'; + $options =~ s/,//; + + # detect superflous options in file channel + if ($options =~ m/\S+/s) { + $options =~ s/\n/\\n/; + &lint_warning($file, "", "", "superflous option in prefix channel detected: $options"); + } + } + + # check path channel + if ($body =~ m/\n([ ]*)(\w+):(\s*?)file(\s*?)\((.*?)\)/s) { + my ($ws1, $level, $ws2, $ws3, $options) = ($1, $2, $3, $4, $5); + + # enforce eight spaces + if (length($ws1) != 8) { + &lint_warning($file, "", "", "path channel whitespace count at start of unseparated line"); + } + + # enforce spaces + if (length($ws2) < 1) { + &lint_warning($file, "", "", "path channel whitespace required between level and file of unseparated line"); + } + + # enforce zero spaces + if (length($ws3) != 0) { + &lint_warning($file, "", "", "whitespace not allowed between file channel and round open bracket"); + } + + # check for legal l2 level + if ($level !~ m/^(panic|critical|error|warning|notice|info|trace|debug)$/) { + &lint_warning($file, "", "", "illegal l2 level $level detected on unseparated line"); + } + + # enforce file option in file channel + if ($options !~ m;path="\@l_prefix\@/var/$pkg/(log\S+|$pkg\.log)";) { + &lint_warning($file, "", "", "XXX path option in file channel invalid or missing on unseparated line"); + } + $options = $'; + $options =~ s/,//; + + # enforce perm option in file channel + if ($options !~ m;perm=0[0-7]{3};) { + &lint_warning($file, "", "", "perm option in file channel invalid or missing on unseparated line"); + } + + $options = $'; + $options =~ s/, jitter=[0-9]+//; + $options =~ s/, monitor=[0-9]+//; + $options =~ s/,//; + + # detect superflous options in file channel + if ($options =~ m/\S+/s) { + $options =~ s/\n/\\n/; + &lint_warning($file, "", "", "superflous option in file channel unseparated line detected: $options"); + } + } + else { + &lint_warning($file, "", "", "file channel missing"); + } + + $done .= $this; + } + return; +} diff -r 71503088f51b -r f880f219c566 openpkg/lint-rc.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/lint-rc.pl Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,517 @@ +## +## lint-rc.pl -- OpenPKG rc.* File Checker +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# Perl run-time requirement +require 5; +BEGIN { + eval "use Getopt::Long; use IO;"; + if ($@) { + print STDERR + "lint-rc: ERROR: This command requires a full-size Perl installation!\n" . + "lint-rc: HINT: Install OpenPKG \"perl\" package to use this command.\n"; + exit(1); + } +} + +# OpenPKG instance prefix +my $my_prefix = $ENV{'OPENPKG_PREFIX'}; +delete $ENV{'OPENPKG_PREFIX'}; + +# program information +my $progname = "lint-rc"; +my $progvers = "1.0.0"; + +# parameters (defaults) +my $version = 0; +my $verbose = 0; +my $help = 0; +my $check = 'all'; +my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname"; +my $rpm = "$my_prefix/bin/openpkg rpm"; + +# exception handling support +$SIG{__DIE__} = sub { + my ($err) = @_; + $err =~ s|\s+at\s+.*||s if (not $verbose); + print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n"; + exit(1); +}; + +# command line parsing +Getopt::Long::Configure("bundling"); +my $result = GetOptions( + 'V|version' => \$version, + 'v|verbose' => \$verbose, + 'h|help' => \$help, + 'c|check=s' => \$check, + 't|tmpdir=s' => \$tmpdir, + 'r|rpm=s' => \$rpm, +) || die "option parsing failed"; +if ($help) { + print "Usage: $progname [options] [RPMFILE ...]\n" . + "Available options:\n" . + " -v,--verbose enable verbose run-time mode\n" . + " -h,--help print out this usage page\n" . + " -c,--check=CHECKS select checks to perform (default='all')\n" . + " -r,--rpm=FILE filesystem path to RPM program\n" . + " -t,--tmpdir=PATH filesystem path to temporary directory\n" . + " -V,--version print program version\n"; + exit(0); +} +if ($version) { + print "OpenPKG $progname $progvers\n"; + exit(0); +} + +# verbose message printing +sub msg_verbose { + my ($msg) = @_; + print STDERR "$msg\n" if ($verbose); +} + +# warning message printing +sub msg_warning { + my ($msg) = @_; + print STDERR "$progname:WARNING: $msg\n"; +} + +# error message printing +sub msg_error { + my ($msg) = @_; + print STDERR "$progname:ERROR: $msg\n"; +} + +# determine check list +my @check_list = (qw( + blank + comment + section + script + global +)); +my @checks = (); +if ($check eq 'all') { + @checks = @check_list; +} +else { + foreach my $c (split(/,/, $check)) { + if (not grep(/^$c$/, @check_list)) { + die "invalid check \"$c\""; + } + push(@checks, $c); + } +} + +# global return code +$main::GRC = 0; + +# environment preparation +system("rm -rf $tmpdir"); +system("mkdir -p $tmpdir"); + +# iterate over all rc. files +foreach my $filename (@ARGV) { + my $io = new IO::File "<$filename" + or die "unable to open file \"$filename\" for reading"; + my $spec; { local $/ = undef; $spec = <$io>; } + $io->close; + foreach my $check (@checks) { + &msg_verbose("$check in $filename"); + eval "\&check_$check(\$filename, \$spec);"; + } +} + +# environment cleanup +system("rm -rf $tmpdir"); + +# die gracefully +exit($main::GRC); + +## _________________________________________________________________ +## +## COMMON SUBROUTINES +## _________________________________________________________________ +## + +sub lines { + my ($txt) = @_; + my $l = 0; + $txt =~ s|\n|$l++, ''|sge; + return $l; +} + +sub lint_message { + my ($type, $file, $done, $this, $msg) = @_; + if (defined($done) and defined($this)) { + my $start = &lines($done) + 1; + my $end = $start + &lines($this); + my $pos = $start; + $pos .= "-". $end if ($end > $start); + printf("%s:%s: %s:%s: %s\n", $progname, $type, $file, $pos, $msg); + } + else { + printf("%s:%s: %s: %s\n", $progname, $type, $file, $msg); + } +} + +sub lint_warning { + my ($file, $done, $this, $msg) = @_; + &lint_message("WARNING", $file, $done, $this, $msg); + $main::GRC = 1 if ($main::GRC < 1); +} + +sub lint_error { + my ($file, $done, $this, $msg) = @_; + &lint_message("ERROR", $file, $done, $this, $msg); + $main::GRC = 2 if ($main::GRC < 2); +} + +## _________________________________________________________________ +## +## CHECK "blank": whitespace and blank lines +## _________________________________________________________________ +## + +sub check_blank { + my ($file, $spec) = @_; + + # check for CR-LF combination + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/\r\n/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "carriage-return (CR, 0x0d) line-feed (NL, 0x0a) combination (expected just line-feed)"); + $done .= $this; + } + + # check for multiple blank lines + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/(\r?\n[ \t]*){3,}/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "multiple subsequent blank lines (expected single blank line)"); + $done .= $this; + } + + # check for trailing whitespaces + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/[ \t]+\r?\n/s) { + $done .= $`; $this = $&; $todo = $'; + if ($done eq '' or $done =~ m|\n$|s) { + &lint_warning($file, $done, $this, "whitespace on empty line (expected none)"); + } + else { + &lint_warning($file, $done, $this, "trailing whitespace (expected none)"); + } + $done .= $this; + } + + # check for bogus line continuations + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/\\[ \t]*\r?\n(?=[ \t]*\r?\n)/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "bogus line continuation for following empty line (expect no line continuation)"); + $done .= $this; + } + + # check for leading whitespaces before line continuations + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/[ \t]{2,}\\[ \t]*\r?\n/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "multiple leading whitespace before line continuation (expected just a single space)"); + $done .= $this; + } + + # check for leading tabs + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/^ *\t+ *[^ \t]/m) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "leading tabs (expected spaces)"); + $done .= $this; + } + + # check for mandatory/wished trailing blank line + if ($spec !~ m|\n\n$|s) { + &lint_warning($file, $done, "", "mandatory/wished trailing blank line at end of file missing (expected one)"); + } +} + +## _________________________________________________________________ +## +## CHECK "comment": sharp-comments +## _________________________________________________________________ +## + +sub check_comment { + my ($file, $spec) = @_; + my ($pkg); + + # determine package name + $pkg = $file; + $pkg =~ s|^.+/||; + $pkg =~ s|^rc\.||; + + # check "shebang" header + my $re = ""; + $re .= "#!\@l_prefix\@/bin/openpkg rc\\n"; + if ($spec !~ m|^$re|s) { + &lint_warning($file, "", "", "invalid shebang header (expected $re)"); + } + + # check comment header + my $re = ""; + $re .= ".*?\\n##\\n## rc.$pkg -- Run-Commands\\n##\\n\\n"; + if ($pkg ne "openpkg" and $spec !~ m|^$re|s) { + &lint_warning($file, "", "", "invalid comment header (expected $re)"); + } + + # check for comment indentation + my $done .= $`; my $this = $&; my $todo = $'; + while ($todo =~ m/^([ \t]*)(#+)([ \t]*)(.*?)$/m) { + $done .= $`; $this = $&; $todo = $'; + my ($lead, $sharp, $pad, $text) = ($1, $2, $3, $4); + if (length($lead) % 2 != 0) { + &lint_warning($file, $done, $this, "incorrect comment indentation (expected a multiple of 2 spaces)"); + } + if (length($lead) > 1 && length($sharp) > 1) { + &lint_warning($file, $done, $this, "indented comment has introduced with multiple sharps (expected single sharp character)"); + } + if (length($pad.$text) > 0 && length($sharp.$pad) % 4 != 0) { + &lint_warning($file, $done, $this, "incorrect comment text padding (expected a multiple of 4 sharps or spaces)"); + } + if (length($pad) == 0 && length($text) > 0) { + &lint_warning($file, $done, $this, "missing leading space before comment text (expected padding spaces)"); + } + if (length($pad) > 0 && length($text) == 0) { + &lint_warning($file, $done, $this, "empty comment text (expected a reasonable text)"); + } + $done .= $this; + } +} + +## _________________________________________________________________ +## +## CHECK "section": run command sections +## _________________________________________________________________ +## + +sub check_section { + my ($file, $spec) = @_; + + my $require = qq{ + (%config,)? + (%common,)? + (%status,)? + (%info,)? + (%start,)? + (%stop,)? + (%restart,)? + (%reload,)? + (%quarterly,)? + (%hourly,)? + (%daily,)? + (%weekly,)? + (%monthly,)? + (%env,)? + }; + + # check for order of headers + my $sections = ""; + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/^(\S+:|%\S+).*$/m) { + $done .= $`; $this = $&; $todo = $'; + my $section = $1; + $sections .= "$section,"; + $done .= $this; + } + my $regex = $require; + $regex =~ s|\s+||sg; + if ($sections !~ m/^$regex$/s) { + $regex =~ s|,| |sg; + &lint_error($file, undef, undef, "invalid run command section order (expected \"$regex\")"); + } +} + +## _________________________________________________________________ +## +## CHECK "script": shell scripts +## _________________________________________________________________ +## + +sub check_script { + my ($file, $spec) = @_; + + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/(\%(?:config|info|common|status|start|stop|restart|reload|quarterly|hourly|daily|weekly|env))([^\n]*)\n(.*?\n)(?=\%(?:config|info|common|status|start|stop|restart|reload|quarterly|hourly|daily|weekly|env)|$)/s) { + $done .= $`; $this = $&; $todo = $'; + my ($section, $args, $script) = ($1, $2, $3); + + # perform checks for a single script section + &check_script_section($file, $done, $this, $section, $args, $script); + + $done .= $this; + } +} + +sub check_script_section { + my ($file, $outer_done, $outer_this, $section, $args, $script) = @_; + my ($done, $this, $todo); + my ($pkg, $pkgu); + + # determine package name + $pkg = $file; + $pkg =~ s|^.+/||; + $pkg =~ s|^rc\.||; + + # determine package name, dash becomes underscore + $pkgu = $pkg; + $pkgu =~ s|-|_|; + + # remove comment contents + $outer_this =~ s|^[ \t]*#[^\n]*\n||mg; + + # check config + if ($section =~ m/^%(config)$/) { + + # check for badly prefixed variables + $done = $outer_done; $this = ''; $todo = $outer_this; + while ($todo =~ m/ [^=]+=[^\n]+/s) { + $done .= $`; $this = $&; $todo = $'; + if ($this !~ m/ ([A-Z]+|$pkgu)_[a-z_][a-z0-9_]*=/) { + &lint_warning($file, $done, $this, "section $section: badly prefixed variable"); + } + $done .= $this; + } + + # enforce _enable to default to openpkg_rc_def + $done = $outer_done; $this = ''; $todo = $outer_this; + if ( $todo =~ m/ [^=]+_enable=[^\n]+/s and $todo !~ m/ [^=]+_enable="\$openpkg_rc_def"\n+/s) { + &lint_warning($file, $done, $this, "section $section: wrong default for ${pkgu}_enable"); + } + + if ($pkg eq "openpkg") { + # openpkg_rc before _enable, if used, must be the first variable + $done = $outer_done; $this = ''; $todo = $outer_this; + if ( $todo !~ m/%config\n( [A-Z]+_[a-z_]+=[^\n]*\n)* openpkg_rc_def=[^\n]+?\n openpkg_rc_all=[^\n]+?\n [^=]+_enable=[^\n]+/s) { + &lint_warning($file, $done, $this, "section $section: openpkg_rc_def, openpkg_rc_all and ${pkgu}_enable must be the first lowercase variable"); + } + } + else { + # _enable, if used, must be the first variable + $done = $outer_done; $this = ''; $todo = $outer_this; + if ( $todo =~ m/ [^=]+_enable=[^\n]+/s and $todo !~ m/%config\n( [A-Z]+_[a-z_]+=[^\n]*\n)* [^=]+_enable=[^\n]+/s) { + &lint_warning($file, $done, $this, "section $section: ${pkgu}_enable must be the first lowercase variable"); + } + } + } + + if ($section =~ m/^%(config|info|status)$/) { + # check illegal use of return/exit + $done = $outer_done; $this = ''; $todo = $outer_this; + if ( $todo =~ m/[^a-zA-Z0-9_](return|exit)\s/s ) { + &lint_warning($file, $done, $this, "section $section: return or exit not allowed here"); + } + return; + } + + # check rcService only used for enable|usable|active PR#232 + $done = $outer_done; $this = ''; $todo = $outer_this; + while ( $todo =~ m/rcService\s+\w+\s+(\w+)/s ) { + $done .= $`; $this = $&; $todo = $'; + if ( $1 !~ m/^(enable|usable|active)$/ ) { + &lint_warning($file, $done, $this, "section $section: rcService must check for (enable|usable|active) only, found check for \"$1\""); + } + $done .= $this; + } + + # check rcService short circuit + if ($section !~ m/^%(config|common|info)$/) { + $done = $outer_done; $this = ''; $todo = $outer_this; + if ( $todo !~ m/^[^\n]+\n rcService $pkg enable yes \|\| exit 0\n/s ) { + &lint_warning($file, $done, $this, "section $section: \"rcService ... enable yes\" short circuit missing"); + } + else { + # check rcService package reference + $done = $outer_done; $this = ''; $todo = $outer_this; + if ( $todo !~ m/\brcService\s+$pkg\s+/s ) { + &lint_warning($file, $done, $this, "section $section: rcService referencing wrong package"); + } + } + } + + # check shell redirections + $done = $outer_done; $this = ''; $todo = $outer_this; + while ( $todo =~ m/[ \t]+(\d+)?[><][ \t]+\S+/s + or $todo =~ m/[ \t]+[><](\&\d+)?[ \t]+\S+/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "section $section: whitespace after shell redirection (expected none)"); + $done .= $this; + } +} + +## _________________________________________________________________ +## +## CHECK "global": globals +## _________________________________________________________________ +## + +sub check_global { + my ($file, $spec) = @_; + + # utility function: extract a single shell command + sub command_extract { + my ($script) = @_; + my $cmd = ''; + while ($script ne '') { + $script =~ s/^([ \t]*'[^']*')/ $cmd .= $1, ''/se && next; + $script =~ s/^([ \t]*"[^"]*")/ $cmd .= $1, ''/se && next; + $script =~ s/^([ \t]*[^ \t;\)\\\r\n]+)/$cmd .= $1, ''/se && next; + $script =~ s/^([ \t]*\\[ \t]*\r?\n)/ $cmd .= $1, ''/se && next; + last; + } + return ($cmd, $script); + } + + # check for deprecated use of opServiceEnabled function + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/\bopServiceEnabled\b/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "deprecated usage of opServiceEnabled macro (expected rcService ... enable yes)"); + $done .= $this; + } + + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/shtool\s+/s) { + $done .= $`; $this = $&; $todo = $'; + ($this, $todo) = &command_extract($this . $todo); + + # check for shtool options with no space before argument + my $subthis = $this; + $subthis =~ s/%{[^}]*?}//sg; + $subthis =~ s/'[^']*'//sg; + $subthis =~ s/"[^"]*"//sg; + $subthis =~ s/[;|&].*$//s; # catch command termination by semicolon, pipe, or, and; + if ($subthis =~ m/\s-[a-zA-Z]\S/) { + &lint_warning($file, $done, $this, "found use of shtool option with space omitted before argument"); + } + $done .= $this; + } +} diff -r 71503088f51b -r f880f219c566 openpkg/lint-rpm.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/lint-rpm.pl Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,447 @@ +## +## lint-rpm.pl -- OpenPKG *.rpm File Checker +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# Perl run-time requirement +require 5; +BEGIN { + eval "use Getopt::Long; use IO;"; + if ($@) { + print STDERR + "lint-rpm: ERROR: This command requires a full-size Perl installation!\n" . + "lint-rpm: HINT: Install OpenPKG \"perl\" package to use this command.\n"; + exit(1); + } +} + +# OpenPKG instance prefix +my $my_prefix = $ENV{'OPENPKG_PREFIX'}; +delete $ENV{'OPENPKG_PREFIX'}; + +# program information +my $progname = "lint-rpm"; +my $progvers = "1.0.0"; + +# parameters (defaults) +my $version = 0; +my $verbose = 0; +my $help = 0; +my $check = 'all'; +my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname"; +my $rpm = "$my_prefix/bin/openpkg rpm"; +my $rpm2cpio = "$my_prefix/bin/openpkg rpm2cpio"; + +# exception handling support +$SIG{__DIE__} = sub { + my ($err) = @_; + $err =~ s|\s+at\s+.*||s if (not $verbose); + print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n"; + exit(1); +}; + +# command line parsing +Getopt::Long::Configure("bundling"); +my $result = GetOptions( + 'V|version' => \$version, + 'v|verbose' => \$verbose, + 'h|help' => \$help, + 'c|check=s' => \$check, + 't|tmpdir=s' => \$tmpdir, + 'r|rpm=s' => \$rpm, +) || die "option parsing failed"; +if ($help) { + print "Usage: $progname [options] [RPMFILE ...]\n" . + "Available options:\n" . + " -v,--verbose enable verbose run-time mode\n" . + " -h,--help print out this usage page\n" . + " -c,--check=CHECKS select checks to perform (default='all')\n" . + " -r,--rpm=FILE filesystem path to RPM program\n" . + " -t,--tmpdir=PATH filesystem path to temporary directory\n" . + " -V,--version print program version\n"; + exit(0); +} +if ($version) { + print "OpenPKG $progname $progvers\n"; + exit(0); +} + +# verbose message printing +sub msg_verbose { + my ($msg) = @_; + print STDERR "$msg\n" if ($verbose); +} + +# warning message printing +sub msg_warning { + my ($msg) = @_; + print STDERR "$progname:WARNING: $msg\n"; +} + +# error message printing +sub msg_error { + my ($msg) = @_; + print STDERR "$progname:ERROR: $msg\n"; +} + +# determine check list +my @check_list = (qw( + layout + attrib + content +)); +my @checks = (); +if ($check eq 'all') { + @checks = @check_list; +} +else { + foreach my $c (split(/,/, $check)) { + if (not grep(/^$c$/, @check_list)) { + die "invalid check \"$c\""; + } + push(@checks, $c); + } +} + +# global return code +$main::GRC = 0; + +# environment preparation +system("rm -rf $tmpdir"); +system("mkdir -p $tmpdir"); + +# iterate over all .rpm files +foreach my $filename (@ARGV) { + die "unable to open file \"$filename\" for reading" + if (not -f $filename); + my $info = &rpm_info($filename, \@checks); + foreach my $check (@checks) { + eval "\&check_$check(\$filename, \$info);"; + } + &rpm_info_cleanup($filename, \@checks, $info); +} + +# environment cleanup +system("rm -rf $tmpdir"); + +# die gracefully +exit($main::GRC); + +## _________________________________________________________________ +## +## COMMON SUBROUTINES +## _________________________________________________________________ +## + +sub lint_message { + my ($type, $file, $msg) = @_; + $file =~ s|^.+?/([^/]+)$|$1|s; + printf(STDERR "%s:%s: %s: %s\n", $progname, $type, $file, $msg); +} + +sub lint_warning { + my ($file, $msg) = @_; + &lint_message("WARNING", $file, $msg); + $main::GRC = 1 if ($main::GRC < 1); +} + +sub lint_error { + my ($file, $msg) = @_; + &lint_message("ERROR", $file, $msg); + $main::GRC = 2 if ($main::GRC < 2); +} + +## _________________________________________________________________ +## +## RPM INFORMATION GATHERING +## _________________________________________________________________ +## + +sub rpm_info { + my ($filename, $checks) = @_; + my $info = {}; + + # query package name + &msg_verbose("++ querying RPM package name"); + $info->{name} = `$rpm -qp --qf '%{NAME}' $filename`; + + # query prefix + &msg_verbose("++ querying RPM package installation prefix"); + $info->{prefix} = `$rpm -qp --qf '%{PREFIXES}' $filename`; + + # query file listing + &msg_verbose("++ querying RPM package file listing"); + my @list = `$rpm -qplv $filename`; + my @config = `$rpm -qplc $filename`; + + # process file listing + $info->{ls} = {}; + foreach my $entry (@list) { + if ($entry =~ m|^\(contains no files\)\s*$|s) { + next; + } + elsif ($entry =~ m|^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(.{12})\s+(.+)\s*$|s) { + my ($perm, $links, $owner, $group, $size, $mtime, $path) = ($1, $2, $3, $4, $5, $6, $7); + my $symlink = ""; + if ($path =~ m|^(\S+)\s+->\s+(\S+)$|) { + ($path, $symlink) = ($1, $2); + } + $path =~ s|\s+$||s; + my $config = 0; + if (grep(m|^$path$|, @config)) { + $config = 1; + } + $info->{ls}->{$path} = { + 'perm' => $perm, + 'links' => $links, + 'owner' => $owner, + 'group' => $group, + 'size' => $size, + 'time' => $mtime, + 'path' => $path, + 'symlink' => $symlink, + 'config' => $config, + }; + } + else { + &lint_error($filename, "invalid file listing entry: \"$entry\""); + } + } + + # unpacking files + if (grep(/^content$/, @{$checks})) { + &msg_verbose("++ unpacking RPM package files"); + $info->{root} = "$tmpdir/root"; + system("mkdir -p ".$info->{root}); + system("$rpm2cpio $filename | (cd ".$info->{root}." && cpio -idmu 2>/dev/null)"); + } + + return $info; +} + +sub rpm_info_cleanup { + my ($filename, $checks, $info) = @_; + + if (grep(/^content$/, @{$checks})) { + system("rm -rf ".$info->{root}) if ($info->{root} =~ m/^\/.+/ and -d $info->{root}); + } +} + +## _________________________________________________________________ +## +## CHECK "layout": file path layout +## _________________________________________________________________ +## + +sub check_layout { + my ($rpm, $info) = @_; + + # no need to check 'openpkg' package because it + # has a hard-coded file list! + return if ($rpm =~ m|^(.+?/)?openpkg-\d[^/]+$|); + + # check prefix + if ($info->{prefix} !~ m|^/.+$|) { + &lint_error($rpm, "invalid installation prefix ".$info->{prefix}. + " (expected to match \"^/.+\$\")"); + return; + } + + # check top-level path (all-in-one) + my @topdirs = (qw( + bin cgi etc include info lib libexec + local man pub sbin share usr var + )); + my $topdirs = "{".join(",", @topdirs)."}"; + if (not keys(%{$info->{ls}})) { + &lint_error($rpm, "invalid empty package (expected at least one file)"); + return; + } + foreach my $path (keys(%{$info->{ls}})) { + my $ok = 0; + foreach my $topdir (@topdirs) { + my $prefix = quotemeta($info->{prefix} . "/" . $topdir); + if ($path =~ m/^$prefix$/ && $rpm !~ m|^openpkg-\d+|) { + &lint_error($rpm, "top-level directory \"$topdir\" provided" . + " (expected none except for 'openpkg' package)"); + } + if ($path =~ m/^$prefix/) { + $ok = 1; + last; + } + } + if (not $ok) { + &lint_error($rpm, "invalid top-level directory in path \"$path\"". + " (expected one of $topdirs)"); + } + } + + # check for second-level path (all-in-one) + my @topdirs_subdir_no = (qw(bin cgi info sbin)); + my @topdirs_subdir_yes = (qw(etc libexec share var)); + foreach my $path (keys(%{$info->{ls}})) { + foreach my $topdir (@topdirs_subdir_yes) { + my $prefix = quotemeta($info->{prefix} . "/" . $topdir); + if ($path =~ m/^$prefix\/[^\/]+$/) { + if ($info->{ls}->{$path}->{perm} !~ m|^d|) { + &lint_error($rpm, "invalid positioned file \"$path\" under topdir \"$topdir\" (expected directory)"); + } + } + } + foreach my $topdir (@topdirs_subdir_no) { + my $prefix = quotemeta($info->{prefix} . "/" . $topdir); + if ($path =~ m/^$prefix\/[^\/]+$/) { + if ($info->{ls}->{$path}->{perm} =~ m|^d|) { + &lint_error($rpm, "invalid positioned directory \"$path\" under topdir \"$topdir\" (expected file)"); + } + } + } + } + + # check "bin" and "sbin" directories + foreach my $path (keys(%{$info->{ls}})) { + foreach my $topdir (qw(bin sbin)) { + my $prefix = quotemeta($info->{prefix} . "/" . $topdir); + if ($path =~ m/^$prefix\/(.+)$/) { + my $file = $1; + if ($file =~ m|^[^/]+\.[^/.]+$|) { + &lint_warning($rpm, "strange executable filename \"$path\" containing an extension (expected no extension)"); + } + my $perm = $info->{ls}->{$path}->{'perm'}; + if ($perm =~ m|^-| && $perm !~ m|^-[-r][-w][sx][-r][-w][-sx][-r][-w][-tx]$|) { + &lint_error($rpm, "non-executable file \"$path\" (with permissions \"$perm\" under topdir \"$topdir\" (expected to be executable)"); + } + } + } + } + + # check for symbolic link targets (outside absolute, dangling) + foreach my $path (keys(%{$info->{ls}})) { + my $symlink = $info->{ls}->{$path}->{'symlink'}; + if ($symlink ne '') { + # check for outside absolute target + my $prefix = quotemeta($info->{prefix}); + if ($symlink =~ m|^/.*| and $symlink !~ m|^$prefix|s) { + &lint_warning($rpm, "symbolic link \"$path\" points to absolute path \"$symlink\" outside prefix \"$info->{prefix}\" (expected it to be under prefix only)"); + } + # check for dangling target + my $resolved = &resolve($info, $path); + sub resolve { + my ($info, $path) = @_; + if (not defined($info->{ls}->{$path})) { + return $path; + } + my $symlink = $info->{ls}->{$path}->{'symlink'}; + if ($symlink eq '') { + return $path; + } + else { + my $resolved; + if ($symlink =~ m|^/|) { + $resolved = $symlink; + } + else { + $resolved = $path; + $resolved =~ s|/[^/]+$||s; + $resolved .= "/" . $symlink; + $resolved =~ s|/{2,}|/|sg; + $resolved =~ s|/\.(?=/)||sg; + $resolved =~ s|/\.$||sg; + 1 while ($resolved =~ s|/[^/]+/\.\./|/|s); + $resolved =~ s|/[^/]+/\.\.$||s; + $resolved =~ s|(.)/$|$1|s; + } + return &resolve($info, $resolved); + } + } + if (not defined($info->{ls}->{$resolved})) { + &lint_error($rpm, "symbolic link \"$path\" points to not existing target path \"$resolved\" (expected existing target path)"); + } + } + } +} + +## _________________________________________________________________ +## +## CHECK "attrib": file attributes +## _________________________________________________________________ +## + +sub check_attrib { + my ($rpm, $info) = @_; + + # check for empty files + foreach my $path (keys(%{$info->{ls}})) { + if ( $info->{ls}->{$path}->{'size'} == 0 + and $info->{ls}->{$path}->{'perm'} !~ m|^d| + and $path !~ m/^.*\/lib\/perl\/.+\.bs$/ + and $rpm !~ m/\bopenpkg-[0-9]+/) { + &lint_warning($rpm, "empty file \"$path\" found (expected no empty files)"); + } + } + + # check for %config flagged files + my $prefix = quotemeta($info->{'prefix'}); + my $name = quotemeta($info->{'name'}); + foreach my $path (keys(%{$info->{ls}})) { + my $config = $info->{ls}->{$path}->{'config'}; + my $path = $info->{ls}->{$path}->{'path'}; + if ($rpm !~ m/\bopenpkg-[0-9]+/ and $config and $path !~ m/^$prefix\/etc\/($name\d*|fsl)\/.+/) { + &lint_warning($rpm, "non-config file \"$path\" flagged as \%config (expected only \"$prefix/etc/$name/*\" files to be \%config files)"); + } + if ($config and $path =~ m/^$prefix\/s?bin\/[^\/]+$/) { + &lint_error($rpm, "executable file \"$path\" flagged as \%config"); + } + if ($config and $path =~ m/^$prefix\/etc\/rc\.d\/rc\.$name$/) { + &lint_error($rpm, "run-command file \"$path\" flagged as \%config"); + } + } + + # check for permissions + foreach my $path (keys(%{$info->{ls}})) { + my $perm = $info->{ls}->{$path}->{'perm'}; + if ($path =~ m/^$prefix\/(bin|sbin)\/[^\/]+$/) { + if ($perm !~ m|^[^d]..[xs]..[xs]..[xt]$|) { + &lint_warning($rpm, "executable file \"$path\" has permissions \"$perm\" only (expected it to be executable by everyone)"); + } + } + } + + # TODO: user/group? +} + +## _________________________________________________________________ +## +## CHECK "content": file content +## _________________________________________________________________ +## + +sub check_content { + my ($rpm, $info) = @_; + + # TODO: stripped (file) + # TODO: syslibs (ldd) + # TODO: hard-coded paths pointing outside instance + # TODO: sanity check for shebang-lines + # TODO: contained temporary path + # TODO: bad-files: .po +} + diff -r 71503088f51b -r f880f219c566 openpkg/lint-spec.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openpkg/lint-spec.pl Tue Jul 31 12:23:42 2012 +0200 @@ -0,0 +1,1388 @@ +## +## lint-spec.pl -- OpenPKG *.spec File Checker +## Copyright (c) 2000-2012 OpenPKG GmbH +## +## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. +## All rights reserved. Licenses which grant limited permission to use, +## copy, modify and distribute this software are available from the +## OpenPKG GmbH. +## +## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +## 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. +## + +# Perl run-time requirement +require 5; +BEGIN { + eval "use Getopt::Long; use IO;"; + if ($@) { + print STDERR + "lint-spec: ERROR: This command requires a full-size Perl installation!\n" . + "lint-spec: HINT: Install OpenPKG \"perl\" package to use this command.\n"; + exit(1); + } +} + +# OpenPKG instance prefix +my $my_prefix = $ENV{'OPENPKG_PREFIX'}; +delete $ENV{'OPENPKG_PREFIX'}; + +# program information +my $progname = "lint-spec"; +my $progvers = "1.0.0"; + +# parameters (defaults) +my $version = 0; +my $verbose = 0; +my $help = 0; +my $check = 'all'; +my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname"; +my $rpm = "$my_prefix/bin/openpkg rpm"; + +# exception handling support +$SIG{__DIE__} = sub { + my ($err) = @_; + $err =~ s|\s+at\s+.*||s if (not $verbose); + print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n"; + exit(1); +}; + +# command line parsing +Getopt::Long::Configure("bundling"); +my $result = GetOptions( + 'V|version' => \$version, + 'v|verbose' => \$verbose, + 'h|help' => \$help, + 'c|check=s' => \$check, + 't|tmpdir=s' => \$tmpdir, + 'r|rpm=s' => \$rpm, +) || die "option parsing failed"; +if ($help) { + print "Usage: $progname [options] [SPECFILE ...]\n" . + "Available options:\n" . + " -v,--verbose enable verbose run-time mode\n" . + " -h,--help print out this usage page\n" . + " -c,--check=CHECKS select checks to perform (default='all')\n" . + " -r,--rpm=FILE filesystem path to RPM program\n" . + " -t,--tmpdir=PATH filesystem path to temporary directory\n" . + " -V,--version print program version\n"; + exit(0); +} +if ($version) { + print "OpenPKG $progname $progvers\n"; + exit(0); +} + +# verbose message printing +sub msg_verbose { + my ($msg) = @_; + print STDERR "$msg\n" if ($verbose); +} + +# warning message printing +sub msg_warning { + my ($msg) = @_; + print STDERR "$progname:WARNING: $msg\n"; +} + +# error message printing +sub msg_error { + my ($msg) = @_; + print STDERR "$progname:ERROR: $msg\n"; +} + +# determine check list +my @check_list = (qw( + blank + comment + license + header + section + preproc + script + global + sources + digest +)); +my @checks = (); +if ($check eq 'all') { + @checks = @check_list; +} +else { + foreach my $c (split(/,/, $check)) { + if (not grep($c, @check_list)) { + die "invalid check \"$c\""; + } + push(@checks, $c); + } +} + +# global return code +$main::GRC = 0; + +# iterate over all .spec files +foreach my $filename (@ARGV) { + my $io = new IO::File "<$filename" + or die "unable to open file \"$filename\" for reading"; + my $spec; { local $/ = undef; $spec = <$io>; } + $io->close; + foreach my $check (@checks) { + eval "\&check_$check(\$filename, \$spec);"; + } +} + +# die gracefully +exit($main::GRC); + +## _________________________________________________________________ +## +## COMMON SUBROUTINES +## _________________________________________________________________ +## + +sub lines { + my ($txt) = @_; + my $l = 0; + $txt =~ s|\n|$l++, ''|sge; + return $l; +} + +sub lint_message { + my ($type, $file, $done, $this, $msg) = @_; + if (defined($done) and defined($this)) { + my $start = &lines($done) + 1; + my $end = $start + &lines($this); + my $pos = $start; + $pos .= "-". $end if ($end > $start); + printf("%s:%s: %s:%s: %s\n", $progname, $type, $file, $pos, $msg); + } + else { + printf("%s:%s: %s: %s\n", $progname, $type, $file, $msg); + } +} + +sub lint_warning { + my ($file, $done, $this, $msg) = @_; + &lint_message("WARNING", $file, $done, $this, $msg); + $main::GRC = 1 if ($main::GRC < 1); +} + +sub lint_error { + my ($file, $done, $this, $msg) = @_; + &lint_message("ERROR", $file, $done, $this, $msg); + $main::GRC = 2 if ($main::GRC < 2); +} + +## _________________________________________________________________ +## +## CHECK "blank": whitespace and blank lines +## _________________________________________________________________ +## + +sub check_blank { + my ($file, $spec) = @_; + + # check for CR-LF combination + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/\r\n/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "carriage-return (CR, 0x0d) line-feed (NL, 0x0a) combination (expected just line-feed)"); + $done .= $this; + } + + # check for multiple blank lines + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/(\r?\n[ \t]*){3,}/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "multiple subsequent blank lines (expected single blank line)"); + $done .= $this; + } + + # check for trailing whitespaces + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/[ \t]+\r?\n/s) { + $done .= $`; $this = $&; $todo = $'; + if ($done eq '' or $done =~ m|\n$|s) { + &lint_warning($file, $done, $this, "whitespace on empty line (expected none)"); + } + else { + &lint_warning($file, $done, $this, "trailing whitespace (expected none)"); + } + $done .= $this; + } + + # check for bogus line continuations + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/\\[ \t]*\r?\n(?=[ \t]*\r?\n)/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "bogus line continuation for following empty line (expect no line continuation)"); + $done .= $this; + } + + # check for leading whitespaces before line continuations + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/[ \t]{2,}\\[ \t]*\r?\n/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "multiple leading whitespace before line continuation (expected just a single space)"); + $done .= $this; + } + + # check for leading tabs + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/^ *\t+ *[^ \t]/m) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "leading tabs (expected spaces)"); + $done .= $this; + } + + # check for mandatory/wished trailing blank line + if ($spec !~ m|\n\n$|) { + &lint_warning($file, $spec, "", "mandatory/wished trailing blank line missing (expected one)"); + } +} + +## _________________________________________________________________ +## +## CHECK "comment": sharp-comments +## _________________________________________________________________ +## + +sub check_comment { + my ($file, $spec) = @_; + + # check for comment indentation and contents + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/^([ \t]*)(#+)([ \t]*)(.*?)$/m) { + $done .= $`; $this = $&; $todo = $'; + my ($lead, $sharp, $pad, $text) = ($1, $2, $3, $4); + if (length($lead) % 2 != 0) { + &lint_warning($file, $done, $this, "incorrect comment indentation (expected a multiple of 2 spaces)"); + } + if (length($lead) > 1 && length($sharp) > 1) { + &lint_warning($file, $done, $this, "indented comment has introduced with multiple sharps (expected single sharp character)"); + } + if (length($pad.$text) > 0 && length($sharp.$pad) % 4 != 0) { + &lint_warning($file, $done, $this, "incorrect comment text padding (expected a multiple of 4 sharps or spaces)"); + } + if (length($pad) == 0 && length($text) > 0) { + &lint_warning($file, $done, $this, "missing leading space before comment text (expected padding spaces)"); + } + if (length($pad) > 0 && length($text) == 0) { + &lint_warning($file, $done, $this, "empty comment text (expected a reasonable text)"); + } + $done .= $this; + } + + # check for comment contents only + if ($file !~ m|openpkg\.spec$|) { + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/\n\n[ \t]*#[ \t]+([^\n]+)(?!\n([ \t]*#))/s) { + $done .= $`; $this = $&; $todo = $'; + my $text = $1; + if (length($text) > 0 and $text =~ m|^[A-Z][^A-Z]|) { + &lint_warning($file, $done, $this, "comment text starts with upper-case letter (expected lower-case letter)"); + } + $done .= $this; + } + } +} + +## _________________________________________________________________ +## +## CHECK "license": license header +## _________________________________________________________________ +## + +sub check_license { + my ($file, $spec) = @_; + + my $name = "[a-z][a-z0-9-]*"; + if ($file =~ m|^.*/([a-z][a-z0-9-]*)\.spec$|) { + $name = $1; + } + elsif ($file =~ m|^([a-z][a-z0-9-]*)\.spec$|) { + $name = $1; + } + my $re = ""; + $re .= "##\\n"; + $re .= "## $name\\.spec -- OpenPKG RPM Package Specification\\n"; + $re .= "## Copyright \\(c\\) 200[0-9]-2012 OpenPKG Foundation e\.V\. \\n"; + $re .= "##\\n"; + $re .= "## Permission to use, copy, modify, and distribute this software for\\n"; + $re .= "## any purpose with or without fee is hereby granted, provided that\\n"; + $re .= "## the above copyright notice and this permission notice appear in all\\n"; + $re .= "## copies\\.\\n"; + $re .= "##\\n"; + $re .= "## THIS SOFTWARE IS PROVIDED \\`\\`AS IS'' AND ANY EXPRESSED OR IMPLIED\\n"; + $re .= "## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\\n"; + $re .= "## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED\\.\\n"; + $re .= "## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR\\n"; + $re .= "## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\\n"; + $re .= "## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \\(INCLUDING, BUT NOT\\n"; + $re .= "## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\\n"; + $re .= "## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION\\) HOWEVER CAUSED AND\\n"; + $re .= "## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\\n"; + $re .= "## OR TORT \\(INCLUDING NEGLIGENCE OR OTHERWISE\\) ARISING IN ANY WAY OUT\\n"; + $re .= "## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\\n"; + $re .= "## SUCH DAMAGE\\.\\n"; + $re .= "##\\n"; + if ($name ne "openpkg" and $spec !~ m|^$re|os) { + &lint_warning($file, "", "", "invalid license header"); + } +} + +## _________________________________________________________________ +## +## CHECK "header": RPM headers +## _________________________________________________________________ +## + +sub check_header { + my ($file, $spec) = @_; + + my @headers = (qw( + m:Name:^[a-z][a-z0-9-]*$ + m:Summary:^[A-Z]\S*(\s+([A-Z]\S*|of|for|from|in|at|on|\(\S+\)))* + m:URL:^((https?|ftp)://.+|-)$ + m:Vendor:.+ + m:Packager:^(OpenPKG\sFoundation\se\.V\.|OpenPKG\sGmbH)$ + m:Distribution:^(OpenPKG|OpenPKG\sCommunity|OpenPKG\sEnterprise)$ + m:Class:^(BOOT|CORE|BASE|PLUS|EVAL|JUNK|PRIV)$ + m:Group:^[A-Z][a-zA-Z0-9]+$ + m:License:.+ + m:Version:^[^-]+$ + m:Release:^(E?([1-9]\.)?20[0-9][0-9](0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])|E?[1-9]\.[0-9]\.\d+|%\{[^\}]+\})$ + o:Source\d+:^((https?|ftp)://.+|[^/]+)$ + o:Patch\d+:^((https?|ftp)://.+|[^/]+)$ + o:Prefix:^%{l_prefix}$ + o:BuildRoot:^%{l_buildroot}$ + m:BuildPreReq:^(((,\s+)?digest\\(sha1:\%\{(SOURCE|PATCH)\d+\}\\)\s+=\s+[0-9a-fA-F]+)+|(OpenPKG,\sopenpkg\s>=\s\S+)?((,\s)?([a-z][a-z0-9-]*(\:\:with_[a-z][a-z0-9_]+)?|[A-Z][A-Z0-9-]*)(\s(>=?|==?|<=?|!=)\s\S+)?)+)$ + m:PreReq:^(OpenPKG,\sopenpkg\s>=\s\S+)?((,\s)?([a-z][a-z0-9-]*(\:\:with_[a-z][a-z0-9_]+)?|[A-Z][A-Z0-9-]*)(\s(>=?|==?|<=?|!=)\s\S+)?)+$ + o:AutoReq:^no$ + o:AutoReqProv:^no$ + o:Provides:^((,\s)?([a-z][a-z0-9-]*(\:\:with_[a-z][a-z0-9_]+)?|[A-Z][A-Z0-9-]*)(\s==?\s\S+)?)+$ + o:Conflicts:^((,\s)?([a-z][a-z0-9-]*(\:\:with_[a-z][a-z0-9_]+)?|[A-Z][A-Z0-9-]*)(\s(>=?|==?|<=?|!=)\s\S+)?)+$ + )); + my @headers_def = (qw( + Summary:^Badly\sPackaged\sProgram$ + Vendor:^John\sDoe$ + Group:^Unknown$ + License:^DoePL$ + )); + my @headers_mult = (qw( + BuildPreReq PreReq Provides Conflicts + )); + + my @seen = (); + my %count = (); + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/^(\S+):([ \t]*)(.*?)$/m) { + $done .= $`; $this = $&; $todo = $'; + my ($header, $pad, $value) = ($1, $2, $3); + + # check for layouting + if (length($value) == 0) { + &lint_error($file, $done, $this, "empty RPM header value"); + } + if (length($header.":".$pad) != 14) { + &lint_warning($file, $done, $this, "invalid RPM header name/value padding (expected value at column 15)"); + } + + # check for valid header name and value + if (not grep { $header =~ m|^$_$|s } map { m/^[^:]:([^:]+):/, $1 } @headers) { + &lint_error($file, $done, $this, "invalid RPM header name \"$header\""); + } + else { + my $hn = quotemeta((grep { $header =~ m|^$_$|s } map { m/^[^:]+:([^:]+):/, $1 } @headers)[0]); + my $re = (map { m/^[^:]+:${hn}:(.+)$/s } @headers)[0]; + my $re_match = $re; + $re_match =~ s|^\(|(?:|sg; + $re_match =~ s|([^\\])\(|\1(?:|sg; + if ( not ($file =~ m|openpkg\.spec$| and $header eq 'Provides' and $value eq '%{l_prefix}') + and $value !~ m|${re_match}|s) { + &lint_warning($file, $done, $this, "RPM header \"$header\": " . + "invalid value \"$value\" (expected to match \"$re\")"); + } + my $re_def = (map { m/^${hn}:(.+)$/s } @headers_def)[0]; + if (defined($re_def)) { + my $re_def_match = $re_def; + $re_def_match =~ s|^\(|(?:|sg; + $re_def_match =~ s|([^\\])\(|\1(?:|sg; + if ($value =~ m|${re_def_match}|s) { + &lint_warning($file, $done, $this, "RPM header \"$header\": " . + "default value \"$value\" (expected to match \"$re\", except for this)"); + } + } + if ($header =~ m/^Vendor/ and $value =~ m/et\sal/ and $value !~ m/et\sal\./) { + &lint_warning($file, $done, $this, "RPM header \"$header\": " . + "has value \"$value\" (expected \"et al.\" with dot)"); + } + } + push(@seen, $header); + $count{$header}++; + $done .= $this; + } + + # check for existence of mandatory headers + foreach my $header (@headers) { + my ($type, $name, $regex) = split(/:/, $header, 3); + if ($type eq 'm') { + if ($file =~ m|openpkg\.spec$| and + ($name eq "BuildPreReq" or $name eq "PreReq")) { + # the bootstrap package is an obvious exception + next; + } + if (not grep(/^$name$/, @seen)) { + &lint_warning($file, undef, undef, "mandatory RPM header \"$name\" not found"); + } + } + } + + # check for multiple occurrence headers + foreach my $seen (@seen) { + if ($count{$seen} > 1 and not (grep { $_ eq $seen } @headers_mult)) { + &lint_error($file, undef, undef, "RPM header \"$seen\" occurs multiple times (expected just once)"); + } + } +} + +## _________________________________________________________________ +## +## CHECK "section": RPM sections +## _________________________________________________________________ +## + +sub check_section { + my ($file, $spec) = @_; + + my $require = qq{ + (%define,)* + Name:, + Summary:, + URL:, + Vendor:, + Packager:, + Distribution:, + Class:, + Group:, + License:, + Version:, + Release:, + (%option,)* + (%define,|%undefine,)* + (Source\\d+:,)* + (Patch\\d+:,)* + (%NoSource,)* + (%NoPatch,)* + (Prefix:,)? + (BuildRoot:,)? + ((BuildPreReq:,) + |(PreReq:,))* + (AutoReq:,)? + (AutoReqProv:,)? + (Provides:,)* + (Conflicts:,)* + %description, + (%track,)? + %prep, + %build, + %install, + (%check,)? + %files, + %clean, + (%pre,)? + (%post,)? + (%preun,)? + (%postun,)? + (%trigger,)? + (%triggerin,)? + (%triggerun,)? + (%triggerpostun,)? + (%verifyscript,)? + }; + + # check for order of headers + my $sections = ""; + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/^(\S+:|%\S+).*$/m) { + $done .= $`; $this = $&; $todo = $'; + my $section = $1; + next if ($section =~ m/^%(if|else|endif)/); + $sections .= "$section,"; + $done .= $this; + } + my $regex = $require; + $regex =~ s|\s+||sg; + if ($sections !~ m/^$regex$/s) { + $regex =~ s|,| |sg; + &lint_error($file, undef, undef, "invalid RPM section order: $sections (expected \"$regex\")"); + } +} + +## _________________________________________________________________ +## +## CHECK "preproc": RPM macro pre-processor +## _________________________________________________________________ +## + +sub check_preproc { + my ($file, $spec) = @_; + + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/^(%(?:if|else|endif|define|undefine|option))(.*)$/m) { + $done .= $`; $this = $&; $todo = $'; + my ($cmd, $args) = ($1, $2); + if ($cmd eq '%if') { + # FIXME: either try to really parse the boolean expression + # FIXME: or at least try to guess its correct syntax + } + elsif ($cmd eq '%else' or $cmd eq '%endif') { + if (length($args) > 0) { + &lint_warning($file, $done, $this, "garbage after pre-processor directive " . + "\"$cmd\" (expected no arguments)"); + } + } + elsif ($cmd eq '%undefine') { + if ($args =~ m|^\s+(\S+)\s*$|) { + my $var = $1; + if ($var !~ m/^(V|with)_[a-z][a-zA-Z0-9_]*$/) { + &lint_warning($file, $done, $this, "unusually named macro: \"$var\" " . + "(expected \"(V|with)_[a-z][a-zA-Z0-9_]*\")"); + next; + } + } + else { + &lint_error($file, $done, $this, "invalid number of arguments to pre-processor " . + "directive \"$cmd\" (expected exactly 1 argument)"); + } + } + elsif ($cmd eq '%define' or $cmd eq '%option') { + if ($args =~ m|^\s+(\S+)\s+(.*)$|) { + my ($var, $val) = ($1, $2); + if ($var !~ m/^(V|with)_[a-z][a-zA-Z0-9_]*$/) { + &lint_warning($file, $done, $this, "unusually named macro: \"$var\" " . + "(expected \"(V|with)_[a-z][a-zA-Z0-9_]*\")"); + next; + } + if (length($val) == 0) { + &lint_error($file, $done, $this, "empty macro value"); + } + } + else { + &lint_error($file, $done, $this, "invalid number of arguments to pre-processor " . + "directive \"$cmd\" (expected exactly 2 arguments)"); + } + } + $done .= $this; + } + + # check correct if/endif nesting + my @stack = (); + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/^(%(?:if|else|endif|define|undefine|option)).*$/m) { + $done .= $`; $this = $&; $todo = $'; + my $directive = $1; + if ($directive eq '%if') { + push(@stack, &lines($done . $this)); + } + elsif ($directive eq '%endif') { + if (@stack == 0) { + &lint_error($file, $done, $this, "found \%endif without corresponding opening \%if"); + last; + } + pop(@stack); + } + $done .= $this; + } + my $line; + while (defined($line = pop(@stack))) { + &lint_error($file, undef, undef, "\%if at line $line never closed by \%endif"); + } + + # check for indented preprocessor constructs + $done = ''; $this = ''; $todo = $spec; + while ($todo =~ m/^[ \t]+(%(?:if|else|endif|define|undefine|option)).*$/m) { + $done .= $`; $this = $&; $todo = $'; + my $directive = $1; + &lint_error($file, $done, $this, "found indented \"$directive\" preprocessor directive (expected no indentation)"); + $done .= $this; + } +} + +## _________________________________________________________________ +## +## CHECK "script": shell scripts +## _________________________________________________________________ +## + +sub check_script { + my ($file, $spec) = @_; + + my $done = ''; my $this = ''; my $todo = $spec; + while ($todo =~ m/(\%(?:description|prep|build|install|check|files|clean|pre|post|preun|postun|trigger|triggerin|triggerun|triggerpostun|verifyscript))([^\n]*)\n(.*?\n)(?=\%(?:description|prep|build|install|check|files|clean|pre|post|preun|postun|trigger|triggerin|triggerun|triggerpostun|verifyscript)|$)/s) { + $done .= $`; $this = $&; $todo = $'; + my ($section, $args, $script) = ($1, $2, $3); + + # perform checks for a single script section + &check_script_section($file, $done, $this, $section, $args, $script); + + $done .= $this; + } +} + +sub check_script_section { + my ($file, $outer_done, $outer_this, $section, $args, $script) = @_; + + # skip plain-text/non-scripting section %description + return if ($section eq '%description'); + + # remove comment contents + $outer_this =~ s|^[ \t]*#[^\n]*||mg; + + # check shell redirections + my $done = $outer_done; my $this = ''; my $todo = $outer_this; + while ( $todo =~ m/[ \t]+(\d+)?[><][ \t]+\S+/s + or $todo =~ m/[ \t]+[><](\&\d+)?[ \t]+\S+/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "section $section: whitespace after shell redirection (expected none)"); + $done .= $this; + } + + # utility function: extract a single shell command + sub command_extract { + my ($script) = @_; + my $cmd = ''; + while ($script ne '') { + $script =~ s/^([ \t]*'[^']*')/ $cmd .= $1, ''/se && next; + $script =~ s/^([ \t]*"[^"]*")/ $cmd .= $1, ''/se && next; + $script =~ s/^([ \t]*[^ \t;\)\\\r\n]+)/$cmd .= $1, ''/se && next; + $script =~ s/^([ \t]*\\[ \t]*\r?\n)/ $cmd .= $1, ''/se && next; + last; + } + return ($cmd, $script); + } + + # utility function: join a multi-line command + sub multiline_join { + my ($cmd) = @_; + $cmd =~ s/([ \t]*\\[ \t]*\r?\n[ \t]*)/ /sg; + return $cmd; + } + + # utility function: split command into arguments + sub shell_tokenize { + my ($cmd) = @_; + my @cmd = (); + while ($cmd ne '') { + $cmd =~ s/^\s*('[^']*')/push(@cmd, $1), ''/se && next; + $cmd =~ s/^\s*("[^"]*")/push(@cmd, $1), ''/se && next; + $cmd =~ s/^\s*(\S+)/ push(@cmd, $1), ''/se && next; + $cmd =~ s/^\s*$/ ''/se && last; + } + return @cmd; + } + + # check filesystem path style + $done = $outer_done; $this = ''; $todo = $outer_this; + while ($todo =~ m/\%\{l_shtool\}\s+(\w+)\s+/s) { + $done .= $`; $this = $&; $todo = $'; + ($this, $todo) = &command_extract($this . $todo); + + # check for shtool options with no space before argument + my $subthis = $this; + $subthis =~ s/\%{[A-Za-z][A-Za-z0-9_]*}//sg; + $subthis =~ s/\%{[A-Za-z][A-Za-z0-9_]*(?:\s+[^}]+?)?}//sg; + # remove content of quoted arguments as they might contain unrelated things to catch + $subthis =~ s/'[^']*'/ARG/sg; + $subthis =~ s/"[^"]*"/ARG/sg; + $subthis =~ s/`[^`]*`/ARG/sg; + # remove us completely if line ends with a quote as this indicates we are a quoted argument to ourselfs + $subthis =~ s/[^']*'$//s; + $subthis =~ s/[^"]*"$//s; + $subthis =~ s/[^`]*`$//s; + $subthis =~ s/[^']*' \\\n//s; + $subthis =~ s/[^"]*" \\\n//s; + $subthis =~ s/[^`]*` \\\n//s; + # catch command termination by semicolon, pipe, or, and; + $subthis =~ s/[;|&].*$//s; + if ($subthis =~ m/\s-[a-zA-Z]\S/) { + &lint_warning($file, $done, $this, "found use of shtool option with space omitted before argument"); + } + + # openpkg-rc is special because does bootstrap things + last if ($file =~ m|openpkg-rc\.spec$|); + + my @cmd = &shell_tokenize(&multiline_join($this)); + if ($cmd[1] eq 'mkdir') { + # join flags with their arguments + for (my $i = 2; $i <= $#cmd; $i++) { + if ($cmd[$i] eq '-m') { + splice(@cmd, $i, 2, $cmd[$i].$cmd[$i+1]); + } + } + # check paths + for (my $i = $#cmd; $i > 1 and $cmd[$i] !~ m|^-| and $cmd[$i] !~ m|^\d+$|; $i--) { + if ($cmd[$i] =~ m|/$|) { + &lint_warning($file, $done, $this, "section $section: superfluous trailing slash on " . + "created path in \"shtool mkdir\" command (expected none)"); + } + } + } + elsif ($cmd[1] eq 'install') { + # join flags with their arguments + for (my $i = 2; $i <= $#cmd; $i++) { + if ($cmd[$i] =~ m/-(e|m|o|g)$/) { + splice(@cmd, $i, 2, $cmd[$i].$cmd[$i+1]); + } + elsif ($cmd[$i] eq '%{SOURCE') { + splice(@cmd, $i, 2, $cmd[$i].$cmd[$i+1]); + } + elsif ($cmd[$i] eq '%{l_value') { + while ($i < $#cmd and $cmd[$i+1] !~ m|\}$|s) { + splice(@cmd, $i, 2, $cmd[$i].$cmd[$i+1]); + } + splice(@cmd, $i, 2); + $i--; + } + } + + # determine last path argument + my $i = $#cmd; $i-- while ($i > 1 and $cmd[$i] !~ m|^-| and $cmd[$i] !~ m|^\d+$|); + + # check paths + if (($#cmd - $i) > 2 and $cmd[-1] !~ m|/$|) { + # simple case: multiple sources require target to be a directory + &lint_warning($file, $done, $this, "section $section: missing trailing slash on " . + "destination path in \"shtool install\" command (expected one) 1"); + } + elsif (($#cmd - $i) == 2 and $cmd[-1] !~ m|/$|) { + # complex case: single source, so we can check only known destination paths + if ( $cmd[-1] =~ m/\%\{l_prefix\}\/(bin|cgi|include|info|lib|pub|sbin)$/ + or $cmd[-1] =~ m/\%\{l_prefix\}\/(etc|libexec|man|share|var)(\/[^\/]+)?$/) { + &lint_warning($file, $done, $this, "section $section: missing trailing slash on " . + "destination path in \"shtool install\" command (expected one) 2"); + } + } + else { + # special case: if any path contains '*', then globbing might occur + for (my $i = 2; $i <= $#cmd; $i++) { + if ($cmd[$i] =~ m/\*/ and $cmd[-1] !~ m|/$|) { + &lint_warning($file, $done, $this, "section $section: missing trailing slash on " . + "destination path in \"shtool install\" command (expected one) 3"); + last; + } + } + } + } + $done .= $this; + } + + # check for redundant 'export PATH' statements + #$done = $outer_done; $this = ''; $todo = $outer_this; + #while ($todo =~ m/\bexport[ \t]+([a-zA-Z_][a-zA-Z0-9_]*[ \t]+)*PATH\b/s) { + # $done .= $`; $this = $&; $todo = $'; + # &lint_warning($file, $done, $this, "section $section: redundant \"export PATH\" statement (expected none)"); + # $done .= $this; + #} + + # check for obsolete cpp build flags + $done = $outer_done; $this = ''; $todo = $outer_this; + while ($todo =~ m/-I\%\{l_prefix\}\/include(\/([^ \t"';]+?))?[ \t"';]/s) { + $done .= $`; $this = $&; $todo = $'; + my ($subdir) = $2; + &lint_warning($file, $done, $this, "section $section: hard-coded C pre-processor path option " . + "(use \"%{l_cppflags".($subdir ? " $subdir" : "")."}\" instead)"); + $done .= $this; + } + + # check for obsolete ld build flags + $done = $outer_done; $this = ''; $todo = $outer_this; + while ($todo =~ m/-L\%\{l_prefix\}\/lib(\/([^ \t"';]+?))?[ \t"';]/s) { + $done .= $`; $this = $&; $todo = $'; + my ($subdir) = $2; + &lint_warning($file, $done, $this, "section $section: hard-coded linker path option " . + "(use \"%{l_ldflags".($subdir ? " $subdir" : "")."}\" instead)"); + $done .= $this; + } + + # check for "raw" tool usage + if ($section ne '%description' and $file !~ m|openpkg\.spec$|) { + foreach my $token (&shell_tokenize($outer_this)) { + if ($token =~ m/^(rpmtool|shtool|curl|bash|gzip|bzip2|tar|cc|cxx|make|patch)$/s) { + &lint_warning($file, undef, undef, "section $section: raw usage of standard tool \"$token\"" . + " (use \"%{l_${token}}\" instead)"); + } + } + } + + # check for setup and patch macro usage + if ($section eq '%prep') { + $done = $outer_done; $this = ''; $todo = $outer_this; + my @tokens = &shell_tokenize($outer_this); + while ($todo =~ m/([^\n]*)\n/s) { + $done .= $`; $this = $&; $todo = $'; + if ($this =~ m/^ *%setup.* .*$/) { + &lint_warning($file, undef, undef, "section $section: multiple spaces in \"\%setup\" macro" . + " (reduce to single space)"); + } + if ($this =~ m/^ *%setup.*-[ab]$/ and grep(/^\%setup+$/, @tokens) == 1) { + &lint_warning($file, undef, undef, "section $section: -[ab] option superflous for single \"\%setup\" macro" . + " (remove it)"); + } + if ($this =~ m/^ *%patch.* .*$/) { + &lint_warning($file, undef, undef, "section $section: multiple spaces in \"\%patch\" macro" . + " (reduce to single space)"); + } + if ($this =~ m/^ *%patch.*-p +[01]/) { + &lint_warning($file, undef, undef, "section $section: syntactically wrong space in \"\%patch\" macro" . + " (use -pN)"); + } + if ($this =~ m/^ *%patch.*-P 0\s*$/ and grep(/^\%patch+$/, @tokens) == 1) { + &lint_warning($file, undef, undef, "section $section: syntactically wrong space in \"\%patch\" macro" . + " (omit -P 0 for single patch)"); + } + if ($this =~ m/^ *%patch.*-P [^0-9]/ and grep(/^\%patch+$/, @tokens) > 1) { + &lint_warning($file, undef, undef, "section $section: syntactically wrong space in \"\%patch\" macro" . + " (use -P for multiple patches)"); + } + $done .= $this; + } + if (grep(/^\%setup\d+$/, @tokens)) { + &lint_warning($file, undef, undef, "section $section: numbered \"\%setup\" macro" . + " (do not use %setup directly followed by a number, replace with %setup ... -[ab])"); + } + if (grep(/^\%patch\d+$/, @tokens)) { + &lint_warning($file, undef, undef, "section $section: numbered \"\%patch\" macro" . + " (do not use %patch directly followed by a number, replace with %patch ... -P)"); + } + } + + # check for hard-coded prefix in %pre[un],%post[un] scripts + if ($section =~ m/^\%(preun|postun|pre|post)$/s and $file !~ m|openpkg\.spec$|) { + $done = $outer_done; $this = ''; $todo = $outer_this; + while ($todo =~ m/\%\{l_prefix\}/s) { + $done .= $`; $this = $&; $todo = $'; + &lint_warning($file, $done, $this, "section $section: hard-coded prefix (\%{l_prefix}) found " . + "(use \"\$RPM_INSTALL_PREFIX\" to allow relocation)"); + $done .= $this; + } + } + + # check for sub-shell parenthesis style + # (this is such complicated because the Bourne Shell has a + # construct "case in )