From 8b8d4d39aaf7f2a943220c539c1a01fca6300f2c Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Mon, 25 Mar 2002 20:37:46 +0000 Subject: [PATCH] sync with rpm4 branch: added new files --- README.ALT | 89 +++ autodeps/linux.prov.in | 174 +++++ autodeps/linux.req.in | 245 +++++++ lib/closeall.c | 33 + scripts/brp-adjust_libraries | 37 + scripts/brp-alt.in | 50 ++ scripts/brp-bytecompile_python | 37 + scripts/brp-cleanup | 64 ++ scripts/brp-compress.in | 134 ++++ scripts/brp-fix-perms | 48 ++ scripts/brp-strip.in | 240 +++++++ scripts/compress_files.in | 45 ++ scripts/delayed_rebuilddb | 4 + scripts/find-lang | 174 +++++ scripts/find-package | 67 ++ scripts/javadeps.c | 1217 ++++++++++++++++++++++++++++++++ scripts/pam.prov | 28 + scripts/pam.req | 30 + scripts/shell.req.in | 64 ++ scripts/strip_files | 74 ++ tools/filesize.c | 68 ++ tools/pdeath_execute.c | 95 +++ tools/relative.c | 150 ++++ update-alternatives | 571 +++++++++++++++ update-alternatives.8 | 362 ++++++++++ 25 files changed, 4100 insertions(+) create mode 100644 README.ALT create mode 100755 autodeps/linux.prov.in create mode 100755 autodeps/linux.req.in create mode 100644 lib/closeall.c create mode 100755 scripts/brp-adjust_libraries create mode 100755 scripts/brp-alt.in create mode 100755 scripts/brp-bytecompile_python create mode 100755 scripts/brp-cleanup create mode 100755 scripts/brp-compress.in create mode 100755 scripts/brp-fix-perms create mode 100755 scripts/brp-strip.in create mode 100755 scripts/compress_files.in create mode 100755 scripts/delayed_rebuilddb create mode 100755 scripts/find-lang create mode 100755 scripts/find-package create mode 100755 scripts/javadeps.c create mode 100755 scripts/pam.prov create mode 100755 scripts/pam.req create mode 100755 scripts/shell.req.in create mode 100755 scripts/strip_files create mode 100644 tools/filesize.c create mode 100644 tools/pdeath_execute.c create mode 100644 tools/relative.c create mode 100755 update-alternatives create mode 100644 update-alternatives.8 diff --git a/README.ALT b/README.ALT new file mode 100644 index 0000000..7101aa0 --- /dev/null +++ b/README.ALT @@ -0,0 +1,89 @@ +There are few noticeable for packager differences of this version +of the RPM from ALT Linux Team from the version from MandrakeSoft on which +this one is based upon: + +Features and incompatibilities: +0. Many bug fixes still missing in public release of rpm-3.0.6. +1. Advanced and enhanced macros designed to simplify work of packager, including + + add_optflags, remove_optflags, and many others (for easy compilation + tuning); + + make_compile, make_install, make (aliases for make in %build and %install + sections); + + install_info, uninstall_info (advanced variants of _install_info and + _remove_install_info from MDK for work with info pages); + + various macros aliasing well-known directories; +2. Automatic lookup for dependencies in shell scripts (use "Autoreq: no" to + disable). +3. By default, info and man pages are compressed with either "gzip -9n" or + "bzip2 -9", depending on result size; it means that numerous ".bz2"s in + %files section should be replaced with "*"; same changes should be done in + other sections of spec file. + This behavior of rpm is handled by %_compress_method macro; currently defined + methods are: + + auto: compression as described above; + + bzip2: compression with "bzip2 -9" program; + + gzip: compression with "gzip -9n" program; + + none: all pages will be uncompressed; + + skip: just skip this phase, do not (un)compress at all, only check links. +4. At the post-install stage, ELF binaries are stripped, depending on file type. + This behavior of rpm is handled by %_strip_method macro which is set of + recognizable ELF file types: + + executable (ELF executable); + + relocatable (ELF relocatable); + + shared (ELF shared object); + + static (current ar archive); + + no, none, off, false - designates no stripping at all. + Value of %_strip_method macro can be set by %set_strip_method macro or + defined directly. + By default, only ELF executables and ELF shared objects will be stripped. + Also, there are 4 macros designed for manual stripping from .spec file: + %strip_executable, %strip_relocatable, %strip_shared, %strip_static. + Syntax of these macros described in '/usr/lib/rpm/brp-strip --help'. +5. At the post-install stage, RPM performs lookup for dependencies. + This behavior of rpm is handled by standard tags: AutoReq, AutoProv, + AutoReqProv. Unlike original yes/no rule, these tags now define set of + methods to be used for lookup. Currently, following methods are recognized: + + files - enable lookup for external files dependencies; + + nofiles - disable lookup for external files dependencies; + + lib - enable lookup for shared library dependencies; + + nolib - disable lookup for shared library dependencies; + + pam - enable lookup for pam dependencies; + + nopam - disable lookup for pam dependencies; + + perl - enable lookup for dependencies found in perl scripts; + + noperl - disable lookup for dependencies found in perl scripts; + + shell - enable lookup for dependencies found in Bourne shell scripts; + + noshell - disable lookup for dependencies found in Bourne shell scripts; + + default, yes, true - enable lookup using default methods (see rcfiles for details). + + all - enable lookup using all known methods (files, lib, pam, perl, shell). + + no, none, off, false - disable lookup; + By default, both AutoReq and AutoProv defined to "yes" - it means that + values of %_findreq_default_method and %_findprov_default_method macros will + be used to define lookup methods. + In addition, macro _perl_lib_path can be defined to customize + RPM_PERL_LIB_PATH variable used to find perl provides/requires. +6. At the post-install stage, RPM performs recompilation of python modules + if found in BuildRoot, using value of __python macro as python compiler. + By default, it's equal to /usr/bin/python; to bypass the procedure, just + undefine this macro. + Rationale: if not compiled properly, compiled python modules will be useless + after package installation. +7. BuildRoot now defined in /usr/lib/rpm/macros; that is, BuildRoot tag + defined in specfile will have no effect and may be omitted. More even, + building packages without proper defined BuildRoot is impossible. + %buildroot macro can be redefined in any rcfile. +8. Before executing %install and after executing %clean sections, BuildRoot will + be automatically purged; that is, you don't need to specify this pesky + "rpm -rf" any more. Note, however, that any activity in BuildRoot before + %install section will be lost. + If you need to keep BuildRoot before %install section, you should use + %buildmulti macro instead of %build. In this case, BuildRoot will be purged + right before %build section. +9. Default %defattr value in all %files sections is %{_defattr}. + This macro have been defined to %defattr(-,root,root,755) by default. + That is, most of %defattr entries in spec file may be omitted. +10.POPT library now distributed in separate package; also, files required only + for packaging have been moved to rpm-build subpackage. +11.By default, rpm now blocks if package database lock cannot be obtained. + This wait-for-lock behavior can be disabled with --nowait-lock option. +12.By default, root no longer allowed to build packages. This behavior can be + changed by _allow_root_build macro. diff --git a/autodeps/linux.prov.in b/autodeps/linux.prov.in new file mode 100755 index 0000000..46adea2 --- /dev/null +++ b/autodeps/linux.prov.in @@ -0,0 +1,174 @@ +#!/bin/sh -e +# +# find-provides - generate list of linux-specific package provides. +# Inspired by tool with same name from RPM distribution. +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +FIND_LIBS= +FIND_PAM= +FIND_PERL= + +ParseMethod() +{ + local t + for t in "$@"; do + case "${t/%,}" in + no|none|off|false) + FIND_LIBS= + FIND_PAM= + FIND_PERL= + ;; + lib) + FIND_LIBS=1 + ;; + nolib) + FIND_LIBS= + ;; + pam) + FIND_PAM=1 + ;; + nopam) + FIND_PAM= + ;; + perl) + FIND_PERL=1 + ;; + noperl) + FIND_PERL= + ;; + all) + FIND_LIBS=1 + FIND_PAM=1 + FIND_PERL=1 + ;; + default|yes|true) + ParseMethod $RPM_FINDPROV_DEFAULT_METHOD + ;; + *) + echo "Unrecognized find-provides method: $t" >&2 + exit 1 + ;; + esac + done +} +ParseMethod $RPM_FINDPROV_METHOD + +if [ -z "$FIND_LIBS" -a -z "$FIND_PAM" -a -z "$FIND_PERL" ]; then + # Nothing to do + cat &>/dev/null + exit 0 +fi + +ulimit -c 0 + +case "$LD_PRELOAD" in + *libfakeroot*) + unset LD_PRELOAD + ;; + *libbuildreq.so*) + unset LD_PRELOAD + ;; +esac + +FOUND_PROVS= +LIST_PERL= + +ListScriptProvs() +{ + local f="$1" + local t="$2" + if [ -z "${t##ASCII *text*}" -a -z "${f%%$RPM_BUILD_ROOT/etc/pam.d/*}" ]; then + if [ -n "$FIND_PAM" ]; then + local r="$(@RPMCONFIGDIR@/pam.prov "$f")" + [ -z "$FOUND_PROVS" ] && FOUND_PROVS="$r" || FOUND_PROVS="$FOUND_PROVS +$r" + fi + elif [ -z "${t##perl script text*}" -o -z "${f%%*.p[lmh]}" ]; then + if [ -n "$FIND_PERL" ]; then + [ -z "$LIST_PERL" ] && LIST_PERL="$f" || LIST_PERL="$LIST_PERL +$f" + fi + fi +} + +FindPerlProvs() +{ + if [ -n "$LIST_PERL" ]; then + local r="$(echo "$LIST_PERL" |@RPMCONFIGDIR@/perl.prov)" + [ -z "$FOUND_PROVS" ] && FOUND_PROVS="$r" || FOUND_PROVS="$FOUND_PROVS +$r" + fi +} + +# Note this works for both a.out and ELF executables. +# It also auto-generates provides for scripts. + +FindLibProvs() +{ + [ -n "$FIND_LIBS" ] || return 0 + local f="$1" + local d + if d="$(objdump -p "$f")"; then + local soname="$(echo -E "$d" |awk '/SONAME/ {print $2}')" + if [ -n "$soname" ]; then + if [ ! -L "$f" ]; then + # name + echo "$soname" + + # version definitions + echo -E "$d" | awk "-vsoname=$soname" ' + BEGIN {START=0;} + /^Version definitions:$/ {START=1;} + /^[0-9]/ && (START==1) && ($4!=soname) {printf("%s(%s)\n",soname,$4);} + /^$/ { START=0; } + ' + fi + else + echo "${f##*/}" + fi + fi +} + +while IFS= read -r f; do + if t="$(file -bL "$f")"; then + if [ -z "${t##* text*}" ]; then + ListScriptProvs "$f" "$t" + elif [ -z "${t##* shared object*}" ]; then + r="$(FindLibProvs "$f")" + [ -z "$FOUND_PROVS" ] && FOUND_PROVS="$r" || FOUND_PROVS="$FOUND_PROVS +$r" + fi + else + echo "Not found: $f" >&2 + fi +done + +# Find provides in listed perl scripts, if any +FindPerlProvs + +# Finally sort and print them. +echo "$FOUND_PROVS" |sort -u diff --git a/autodeps/linux.req.in b/autodeps/linux.req.in new file mode 100755 index 0000000..a8a866f --- /dev/null +++ b/autodeps/linux.req.in @@ -0,0 +1,245 @@ +#!/bin/sh -e +# +# find-requires - generate list of linux-specific package requires. +# Inspired by tool with same name from RPM distribution. +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +Exit() +{ + RETVAL=$? + trap '' EXIT + cat &>/dev/null + exit $RETVAL +} + +trap "Exit " EXIT + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +FIND_FILES= +FIND_LIBS= +FIND_PAM= +FIND_PERL= +FIND_SHELL= + +ParseMethod() +{ + local t + for t in "$@"; do + case "${t/%,}" in + no|none|off|false) + FIND_FILES= + FIND_LIBS= + FIND_PAM= + FIND_PERL= + FIND_SHELL= + ;; + lib|library) + FIND_LIBS=1 + ;; + nolib|nolibrary) + FIND_LIBS= + ;; + files) + FIND_FILES=1 + ;; + nofiles) + FIND_FILES= + ;; + pam) + FIND_PAM=1 + ;; + nopam) + FIND_PAM= + ;; + perl) + FIND_PERL=1 + ;; + noperl) + FIND_PERL= + ;; + sh|shell) + FIND_SHELL=1 + ;; + nosh|noshell) + FIND_SHELL= + ;; + all) + FIND_FILES=1 + FIND_LIBS=1 + FIND_PAM=1 + FIND_PERL=1 + FIND_SHELL=1 + ;; + default|yes|true) + ParseMethod $RPM_FINDREQ_DEFAULT_METHOD + ;; + *) + echo "Unrecognized find-requires method: $t" >&2 + exit 1 + ;; + esac + done +} +ParseMethod $RPM_FINDREQ_METHOD + +FIND_SCRIPT= +if [ -n "$FIND_SHELL" -o -n "$FIND_PERL" -o -n "$FIND_PAM" ]; then + FIND_SCRIPT=1 +fi + +if [ -z "$FIND_LIBS" -a -z "$FIND_SCRIPT" -a -z "$FIND_FILES" ]; then + # Nothing to do + exit +fi + +if [ -n "$*" ]; then + # We do not handle arguments yet... + exit +fi + +. @RPMCONFIGDIR@/find-package + +ulimit -c 0 + +case "$LD_PRELOAD" in + *libfakeroot*) + unset LD_PRELOAD + ;; + *libbuildreq.so*) + unset LD_PRELOAD + ;; +esac + +FOUND_REQS= +LIST_PERL= + +ListScriptReqs() +{ + [ -n "$FIND_SCRIPT" ] || return 0 + local f="$1" + local t="$2" + if [ -x "$f" ]; then + local r="$(FindPackage "$f" "$(head -1 "$f" |sed -n 's|^#![ ]*\(/[^ ]\+\).*|\1|p')")" + [ -z "$FOUND_REQS" ] && FOUND_REQS="$r" || FOUND_REQS="$FOUND_REQS +$r" + fi + if [ -z "${t##Bourne* shell script text*}" ]; then + if [ -n "$FIND_SHELL" -a -x "$f" ]; then + local r="$(@RPMCONFIGDIR@/shell.req "$f")" + [ -z "$FOUND_REQS" ] && FOUND_REQS="$r" || FOUND_REQS="$FOUND_REQS +$r" + fi + elif [ -z "${t##ASCII *text*}" -a -z "${f%%$RPM_BUILD_ROOT/etc/pam.d/*}" ]; then + if [ -n "$FIND_PAM" ]; then + local r="$(@RPMCONFIGDIR@/pam.req "$f")" + [ -z "$FOUND_REQS" ] && FOUND_REQS="$r" || FOUND_REQS="$FOUND_REQS +$r" + fi + elif [ -z "${t##perl script text*}" -o -z "${f%%*.p[lmh]}" ]; then + if [ -n "$FIND_PERL" ]; then + [ -z "$LIST_PERL" ] && LIST_PERL="$f" || LIST_PERL="$LIST_PERL +$f" + fi + fi +} + +FindPerlReqs() +{ + if [ -n "$LIST_PERL" ]; then + local r="$(echo "$LIST_PERL" |@RPMCONFIGDIR@/perl.req)" + [ -z "$FOUND_REQS" ] && FOUND_REQS="$r" || FOUND_REQS="$FOUND_REQS +$r" + fi +} + +# Note this works for both a.out and ELF executables. +# It also auto-generates requirements for scripts. + +FindLibReqs() +{ + [ -n "$FIND_LIBS" ] || return 0 + local f="$1" + local d + + if d="$(objdump -p "$f")"; then + # Shared library dependencies, glibc version references. + echo -E "$d" |awk ' + BEGIN {start_shared=0; start_version=0; lib_name="";} + /^Dynamic Section:$/ {start_shared=1;} + /^Version References:$/ {start_version=1;} + (start_version==1) && /^ *required from/ {sub(/:/, "", $3); lib_name=$3;} + (start_shared==1) && /^ *NEEDED/ {print $2;} + (start_version==1) && (lib_name!="") && ($4!="") && ($4~/^(GLIBC|GCC|BZLIB)_*/) {print lib_name "(" $4 ")";} + /^$/ {start_shared=0; start_version=0;} + ' + fi +} + +FindExeReqs() +{ + if [ -x "$1" ]; then + FindLibReqs "$1" + fi +} + +while IFS= read -r f; do + if [ -n "$FIND_FILES" ]; then + if [ -z "${f%%$RPM_BUILD_ROOT/etc/xinetd.d/*}" ]; then + [ -z "$FOUND_REQS" ] && FOUND_REQS="xinetd" || FOUND_REQS="$FOUND_REQS +xinetd" + elif [ -z "${f%%$RPM_BUILD_ROOT/etc/logrotate.d/*}" ]; then + [ -z "$FOUND_REQS" ] && FOUND_REQS="logrotate" || FOUND_REQS="$FOUND_REQS +logrotate" + elif [ -z "${f%%$RPM_BUILD_ROOT/etc/cron.d/*}" ]; then + [ -z "$FOUND_REQS" ] && FOUND_REQS="vixie-cron" || FOUND_REQS="$FOUND_REQS +vixie-cron" + elif [ -z "${f%%$RPM_BUILD_ROOT/etc/chroot.d/*}" ]; then + [ -z "$FOUND_REQS" ] && FOUND_REQS="chrooted" || FOUND_REQS="$FOUND_REQS +chrooted" + elif [ -z "${f%%$RPM_BUILD_ROOT/etc/security/console.apps/*}" ]; then + [ -z "$FOUND_REQS" ] && FOUND_REQS="consolehelper" || FOUND_REQS="$FOUND_REQS +consolehelper" + fi + fi + t="$(file -b "$f")" + if [ -z "${t##* text*}" ]; then + ListScriptReqs "$f" "$t" + elif [ -z "${t##* executable*}" ]; then + r="$(FindExeReqs "$f")" + [ -z "$FOUND_REQS" ] && FOUND_REQS="$r" || FOUND_REQS="$FOUND_REQS +$r" + elif [ -z "${t##* shared object*}" ]; then + r="$(FindLibReqs "$f")" + [ -z "$FOUND_REQS" ] && FOUND_REQS="$r" || FOUND_REQS="$FOUND_REQS +$r" + fi +done + +# Find requires in listed perl scripts, if any +FindPerlReqs + +# Finally sort and print them. +echo "$FOUND_REQS" |sort -u diff --git a/lib/closeall.c b/lib/closeall.c new file mode 100644 index 0000000..04821a1 --- /dev/null +++ b/lib/closeall.c @@ -0,0 +1,33 @@ +#include +#include + +#ifdef __linux__ +#include +#endif + +int rpm_close_all( void ) +{ + int fd, max; + + max = sysconf(_SC_OPEN_MAX); + if ( max <= 0 ) + return -1; + +#ifdef __linux__ + if ( max < NR_OPEN ) + max = NR_OPEN; +#endif + + for ( fd = STDERR_FILENO + 1; fd < max; ++fd ) + { + if ( close(fd) && errno != EBADF ) + /* + * Possible errors are: + * EINTR: the close() call was interrupted by a signal; + * EIO: an I/O error occurred. + */ + return -1; + } + + return 0; +} diff --git a/scripts/brp-adjust_libraries b/scripts/brp-adjust_libraries new file mode 100755 index 0000000..2807007 --- /dev/null +++ b/scripts/brp-adjust_libraries @@ -0,0 +1,37 @@ +#!/bin/sh -e +# +# brp-adjust_libraries - update symbolic links to shared libraries. +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ \$RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +cd "$RPM_BUILD_ROOT" + +libs=`find -type d -name lib` + +if [ -n "$libs" ]; then + echo "Adjusting library links in $RPM_BUILD_ROOT" + /sbin/ldconfig -nv $libs +fi diff --git a/scripts/brp-alt.in b/scripts/brp-alt.in new file mode 100755 index 0000000..ec9728f --- /dev/null +++ b/scripts/brp-alt.in @@ -0,0 +1,50 @@ +#!/bin/sh -e +# +# brp-alt +# The ALT Linux build root policies invoked +# at the end of the %install scriptlet. +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ \$RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +cd "$RPM_BUILD_ROOT" + +# Cleanup files. +@RPMCONFIGDIR@/brp-cleanup + +# Fix file permissions. +@RPMCONFIGDIR@/brp-fix-perms + +# Compress info and man pages. +@RPMCONFIGDIR@/brp-compress + +# Strip ELF binaries. +@RPMCONFIGDIR@/brp-strip + +# Adjust library links. +@RPMCONFIGDIR@/brp-adjust_libraries + +# Re-bytecompile python modules. +@RPMCONFIGDIR@/brp-bytecompile_python diff --git a/scripts/brp-bytecompile_python b/scripts/brp-bytecompile_python new file mode 100755 index 0000000..67e4a56 --- /dev/null +++ b/scripts/brp-bytecompile_python @@ -0,0 +1,37 @@ +#!/bin/sh -e +# +# brp-bytecompile_python - compile python modules. +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ \$RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +cd "$RPM_BUILD_ROOT" + +if [ -n "$RPM_PYTHON" -a `find -type f -name \*.py |wc -l` -gt 0 ]; then + echo "Bytecompiling python modules in $PWD using $RPM_PYTHON" + $RPM_PYTHON -c "import compileall; compileall.compile_dir( '.', 10, '/', 1 );" + echo "Bytecompiling python modules with optimization in $PWD using $RPM_PYTHON -O" + $RPM_PYTHON -O -c "import compileall; compileall.compile_dir( '.', 10, '/', 1 );" +fi diff --git a/scripts/brp-cleanup b/scripts/brp-cleanup new file mode 100755 index 0000000..3215526 --- /dev/null +++ b/scripts/brp-cleanup @@ -0,0 +1,64 @@ +#!/bin/sh -e +# +# brp-cleanup - cleanup buildroot. +# +# Copyright (C) 2000, 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ \$RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +cd "$RPM_BUILD_ROOT" + +find -type f \( \ + -name '#*#' \ + -o -name '*~' \ + -o -name DEADJOE \ + -o -name '*.orig' \ + -o -name '*.rej' \ + -o -name '*.bak' \ + -o -name '.*.orig' \ + -o -name '.*.rej' \ + -o -name '.*.bak' \ + -o -name .SUMS \ + -o -name TAGS \ + -o -name core \ + -o \( -path '*/.deps/*' -a -name '*.P' \) \ + \) -print0 |xargs -r0 rm -vf + +find -type d -name CVS -print0 |xargs -r0 rm -vrf + +cd usr/lib/perl5 &>/dev/null || exit 0 + +echo "Cleaning in $PWD" + +find -type f -name .packlist -print0 |xargs -r0 rm -vf + +find -type f -name \*.bs -size 0 -print0 |xargs -r0 rm -vf + +f="$(find -type f -name \*.bs)" +if [ -n "$f" ]; then + echo "$PROG: non empty *.bs file(s) found:" + echo "$f" + echo "$PROG: please contact packager" + exit 1 +fi diff --git a/scripts/brp-compress.in b/scripts/brp-compress.in new file mode 100755 index 0000000..78f91ae --- /dev/null +++ b/scripts/brp-compress.in @@ -0,0 +1,134 @@ +#!/bin/sh +# +# brp-compress - compress info and manpages. +# Copyright (C) 2000, 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ \$RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +cd "$RPM_BUILD_ROOT" || exit + +StripSuffix() +{ + for s in gz bz2 Z; do + f="${1%.$s}" + if [ "$f" != "$1" ]; then + echo -nE "$f" + return + fi + done + echo -nE "$1" +} + +cd "$RPM_BUILD_ROOT" + +echo "Compressing files in $RPM_BUILD_ROOT ($RPM_COMPRESS_METHOD)" + +if [ "$RPM_COMPRESS_METHOD" = "skip" ]; then + exit 0 +fi + +for d in `find "$RPM_BUILD_ROOT" -type d -name info`; do + find "$d" -type f \( -name \*.gz -o -name \*.Z \) -print0 |xargs -r0 gunzip + find "$d" -type f -name \*.bz2 -print0 |xargs -r0 bunzip2 + find "$d" -type f -a \! -name dir -print0 |xargs -r0 @RPMCONFIGDIR@/compress_files +done + +for d in `find "$RPM_BUILD_ROOT" -type d -name man`; do + find "$d" -type f -size 0 -print0 |xargs -r0 rm -fv + find "$d" -type f -print0 |xargs -r0 chmod a-x + # Uncompress everything. + find "$d" -type f \( -name \*.gz -o -name \*.Z \) -print0 |xargs -r0 gunzip + find "$d" -type f -name \*.bz2 -print0 |xargs -r0 bunzip2 + # First, compress normal files. + for f in `find "$d" -type f -a \! -name whatis -print0 |xargs -r0 file |grep ':[^:]*troff or preprocessor input text' |sed -e 's/:[^:]*troff or preprocessor input text.*//g'`; do + [ -f "$f" ] || continue + if ! head -1 "$f" |grep -q '^.so '; then + @RPMCONFIGDIR@/compress_files "$f" + fi + done + # Second, convert .so links into symlinks. + for f in `find "$d" -type f -a \! -name whatis -print0 |xargs -r0 file |grep ':[^:]*troff or preprocessor input text' |sed -e 's/:[^:]*troff or preprocessor input text.*//g'`; do + [ -f "$f" ] || continue + if head -1 "$f" |grep -q '^.so '; then + f_dir="${f%/*}" + f_dir_name="${f_dir##*/}" + TARGET_orig="$(head -1 "$f" |sed -e 's/^.so\([[:space:]]\)\+//')" + TARGET="$TARGET_orig" + TARGET_base="${TARGET##*/}" + TARGET_dir="$(dirname "$TARGET")" + if [ "." = "$TARGET_dir" -o "$f_dir_name" = "$TARGET_dir" ]; then + TO="$(basename "$f_dir/$TARGET_base"*)" + else + if [ -z "${TARGET##/*}" ]; then + # TARGET starts with / + TARGET_root="/$(relative "$TARGET" "$RPM_BUILD_ROOT/")" + if [ -z "${TARGET_root##/../*}" ]; then + TARGET_root="$TARGET" + fi + f_root="/$(relative "$f" "$RPM_BUILD_ROOT/")" + TARGET="$(relative "$TARGET_root" "$f_root")" + TO="$(cd $f_dir; echo "$TARGET"*)" + else + TO="../$TARGET_dir/$(basename "$f_dir/../$TARGET"*)" + fi + fi + if [ ! -e "$f_dir/$TO" ]; then + # link to nothing + echo "$PROG: file $f points to non-existent file $TARGET_orig" + exit 1 + fi + FROM="$f${TO##*$TARGET_base}" + rm -fv "$f" + ln -sv "$TO" "$FROM" + fi + done + # Third, correct symlinks. + for f in `find "$d" -type l`; do + f_orig="$f" + TARGET_orig="$(StripSuffix "$(/bin/ls -l "$f" |awk '{print $11}')")" + f="$(StripSuffix "$f")" + if [ -z "${TARGET_orig##/*}" ]; then + # TARGET_orig starts with / + TARGET_root="/$(relative "$TARGET_orig" "$RPM_BUILD_ROOT/")" + if [ -z "${TARGET_root##/../*}" ]; then + TARGET_root="$TARGET_orig" + fi + else + TARGET_root="$TARGET_orig" + fi + f_root="/$(relative "$f" "$RPM_BUILD_ROOT/")" + TARGET="$(relative "$TARGET_root" "$f_root")" + DIR="$(dirname "$f")" + TO="$(relative "$(echo "$DIR/$TARGET"*)" "$f")" + if [ ! -e "$DIR/$TO" ]; then + # Found link to nothing. + echo "$PROG: file $f points to non-existent file $TARGET_orig" + exit 1 + fi + FROM="$f${TO#$TARGET}" + rm -fv "$f_orig" + ln -sv "$TO" "$FROM" + done +done +: diff --git a/scripts/brp-fix-perms b/scripts/brp-fix-perms new file mode 100755 index 0000000..19980b2 --- /dev/null +++ b/scripts/brp-fix-perms @@ -0,0 +1,48 @@ +#!/bin/sh -e +# +# brp-fix-permsp - try to fix permissions. +# +# Copyright (C) 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +# If using normal root, avoid changing anything. +if [ -z "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ]; then + echo "$PROG: non-/ \$RPM_BUILD_ROOT expected" >&2 + exit 1 +fi + +cd "$RPM_BUILD_ROOT" + +# Following objects should be world readable. +for d in usr/{share,include} usr/X11R6/{share,include,man}; do + [ ! -d "$d" ] || chmod -R a+rX "$d" +done + +# Following objects should not be group/world writable. +for d in usr/*; do + [ "$d" = "usr/src" -o -L "$d" -o ! -d "$d" ] || chmod -R go-w "$d" +done + +# Following files should not be group/world readable. +for d in bin sbin lib usr/{bin,sbin,lib} usr/X11R6/bin; do + if [ -d "$d" ]; then + find "$d" -type f -perm -4100 -print0 |xargs -r0 chmod -R go-rw + find "$d" -type f -perm -6100 -print0 |xargs -r0 chmod -R go-rw + fi +done diff --git a/scripts/brp-strip.in b/scripts/brp-strip.in new file mode 100755 index 0000000..34ddfe7 --- /dev/null +++ b/scripts/brp-strip.in @@ -0,0 +1,240 @@ +#!/bin/sh -e +# +# brp-strip - strip ELF binaries. +# Inspired by brp-strip script from RPM source code. +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +USAGE() +{ + cat <, --remove-section= + Remove the named section from files. This option may be given more than once. +-s, --strip-all + Remove all symbols. +-g, -S, --strip-debug + Remove all debugging symbols. +--strip-unneeded + Remove all symbols not needed by relocations. +-N, --strip-symbol + Do not copy named symbol. +-K, --keep-symbol + Only copy named symbol. +-x, --discard-all + Remove all non-global symbols. +-X, --discard-locals + Remove any compiler-generated symbols. +-v, --verbose + List all object files modified. +-T , --topdir= + Start file lookup at named directory, \$RPM_BUILD_ROOT by default. + +files is list of files or directory trees where files to be stripped. +By default, all files in TOPDIR, specified by \$RPM_STRIP_METHOD, will be stripped. +EOF + + [ -n "$1" ] && exit "$1" || exit +} + +TEMP=`getopt -n "$PROG" -o hpR:sgSN:K:xXvT: -l help,preserve-dates,remove-section:,strip-all,strip-symbol:,keep-symbol:,discard-all,discard-locals,verbose,topdir: -- "$@"` || USAGE +eval set -- "$TEMP" + +: ${TOPDIR:=$RPM_BUILD_ROOT} +export STRIP_FORCED= +export STRIP_FORCED_OPTS= + +AddForcedOpts() +{ + if [ -z "$STRIP_FORCED_OPTS" ]; then + STRIP_FORCED_OPTS="$*" + else + STRIP_FORCED_OPTS="$STRIP_FORCED_OPTS $*" + fi +} + +while :; do + case "$1" in + -h|--help) + USAGE 0 + ;; + -p|--preserve-dates) + AddForcedOpts -p + shift + ;; + -R|--remove-section) + shift + AddForcedOpts -R "$1" + shift + STRIP_FORCED=1 + ;; + -s|--strip-all) + AddForcedOpts -s + shift + STRIP_FORCED=1 + ;; + -g|-S|--strip-debug) + AddForcedOpts -g + shift + STRIP_FORCED=1 + ;; + --strip-unneeded) + AddForcedOpts --strip-unneeded + shift + STRIP_FORCED=1 + ;; + -N|--strip-symbol) + shift + AddForcedOpts -N "$1" + shift + STRIP_FORCED=1 + ;; + -K|--keep-symbol) + shift + AddForcedOpts -K "$1" + shift + STRIP_FORCED=1 + ;; + -x|--discard-all) + AddForcedOpts -x + shift + STRIP_FORCED=1 + ;; + -X|--discard-locals) + AddForcedOpts -X + shift + STRIP_FORCED=1 + ;; + -v|--verbose) + AddForcedOpts -v + shift + ;; + -T|--topdir) + shift + TOPDIR="$1" + shift + ;; + --) + shift + break + ;; + *) + echo "$PROG: unrecognized option: $1" >&2 + exit 1 + ;; + esac +done + +cd "$TOPDIR" +cd "$OLDPWD" + +TOPDIR="$(echo "$TOPDIR" |sed ' +s:/\(\./\)\+:/:g +s:/\+:/:g +s:/$:: +')" + +SHOW_METHODS= +AddShowMethods() +{ + if [ -z "$SHOW_METHODS" ]; then + SHOW_METHODS="$*" + else + SHOW_METHODS="$SHOW_METHODS,$*" + fi +} + +export STRIP_EXECUTABLE= +export STRIP_RELOCATABLE= +export STRIP_SHARED= +export STRIP_STATIC= +for t in $RPM_STRIP_METHOD; do + case "${t/%,}" in + no|none|off|false) + exit 0 + ;; + exec*) + STRIP_EXECUTABLE=executable + AddShowMethods executable + ;; + reloc*) + STRIP_RELOCATABLE=relocatable + AddShowMethods relocatable + ;; + share*) + STRIP_SHARED=shared + AddShowMethods shared + ;; + static*) + STRIP_STATIC=static + AddShowMethods static + ;; + *) + echo "Unrecognized strip method: $t" + exit 1 + ;; + esac +done + +if [ -z "$STRIP_EXECUTABLE" -a -z "$STRIP_RELOCATABLE" -a -z "$STRIP_SHARED" -a -z "$STRIP_STATIC" ]; then + # Nothing to do + exit 0 +fi + +PERMS= +if [ -z "$STRIP_RELOCATABLE" -a -z "$STRIP_STATIC" ]; then + PERMS='-perm +a=x' +elif [ -z "$STRIP_EXECUTABLE" -a -z "$STRIP_SHARED" ]; then + PERMS='-perm +a=r' +fi + +StripTree() +{ + echo "Stripping binaries in $1 ($SHOW_METHODS)" + find "$1" -type f $PERMS -print0 |xargs -r0 @RPMCONFIGDIR@/strip_files +} + +if [ -n "$*" ]; then + for d in "$@"; do + if [ -d "$d" ]; then + StripTree "$d" + else + @RPMCONFIGDIR@/strip_files "$d" + fi + done +else + if [ -z "$TOPDIR" ]; then + echo "$PROG: non-/ TOPDIR expected" >&2 + exit 1 + fi + + StripTree "$TOPDIR" +fi diff --git a/scripts/compress_files.in b/scripts/compress_files.in new file mode 100755 index 0000000..a3e0f7a --- /dev/null +++ b/scripts/compress_files.in @@ -0,0 +1,45 @@ +#!/bin/sh -e +# +# compress_files - compress files helper. +# Copyright (C) 2000, 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the te/bin/rms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +case "$RPM_COMPRESS_METHOD" in + no|none|plain) + exit 0 + ;; +esac + +for f in "$@"; do + case "$RPM_COMPRESS_METHOD" in + gz*) + /bin/gzip -9nf "$f" + ;; + bz*) + /bin/bzip2 -9f "$f" + ;; + *) + /bin/bzip2 -9kf "$f" + /bin/gzip -9nf "$f" + SIZE_BZIP2=`@RPMCONFIGDIR@/filesize "$f.bz2" 512` + SIZE_GZIP=`@RPMCONFIGDIR@/filesize "$f.gz" 512` + [ "$SIZE_GZIP" -gt "$SIZE_BZIP2" ] && /bin/rm -f "$f.gz" || /bin/rm -f "$f.bz2" + ;; + esac +done diff --git a/scripts/delayed_rebuilddb b/scripts/delayed_rebuilddb new file mode 100755 index 0000000..53e9917 --- /dev/null +++ b/scripts/delayed_rebuilddb @@ -0,0 +1,4 @@ +#!/bin/sh -e + +/usr/bin/rpmdb -v --rebuilddb && + /bin/rm -f /etc/rpm/macros.db1 diff --git a/scripts/find-lang b/scripts/find-lang new file mode 100755 index 0000000..95d5c48 --- /dev/null +++ b/scripts/find-lang @@ -0,0 +1,174 @@ +#!/bin/sh -e +# +# find-lang - generate list of language specific files. +# Inspired by tool with same name from W. L. Estes . +# +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +USAGE() +{ + cat <&2 + exit 1 + ;; + esac +done + +[ -n "$(echo "$@")" ] || USAGE + +cd "$TOPDIR" +cd "$OLDPWD" + +TOPDIR="$(echo "$TOPDIR" |sed ' +s:/\(\./\)\+:/:g +s:/\+:/:g +s:/$:: +')" + +if [ -z "$TOPDIR" ]; then + echo "$PROG: non-/ TOPDIR expected" >&2 + exit 1 +fi + +#export FIND_MO FIND_MAN FIND_GNOME APPEND OUTPUT NAME TOPDIR + +FindLang() +{ + # truncate if required + [ -n "$APPEND" ] || :>"$OUTFILE" + + echo '%defattr(644,root,root,755)' >>"$OUTFILE" + + if [ -n "$FIND_MO" ]; then + find "$TOPDIR" -type f |sed ' +s:'"$TOPDIR"':: +s:\(.*/share/locale/\)\([^/_]\+\)\(.*'"$NAME"'\.mo$\):%lang(\2) \1\2\3: +s:^\([^%].*\):: + ' |grep -v '^$' >> "$OUTFILE" ||: + fi + + if [ -n "$FIND_MAN" ]; then + find "$TOPDIR" -type f |sed ' +s:'"$TOPDIR"':: +s:\(.*/share/man/\)\([^/_]\+\)\(.*'"$NAME"'\..\)\(\.[^/]*\)\?$:%lang(\2) \1\2\3*: +s:^\([^%].*\):: +s:^%lang(man.*) .*:: + ' |grep -v '^$' >> "$OUTFILE" ||: + fi + + if [ -n "$FIND_GNOME" ]; then + find $TOPDIR -type d |sed ' +s:'"$TOPDIR"':: +s:\(.*/gnome/help/'"$NAME"'$\):%dir \1: +s:\(.*/gnome/help/'"$NAME"'/\)\([^/_]\+\):%dir %lang(\2) \1\2: +s:^\([^%].*\):: +s:%lang(C) :: + ' |grep -v '^$' >> "$OUTFILE" ||: + find "$TOPDIR" -type f |sed ' +s:'"$TOPDIR"':: +s:\(.*/gnome/help/'"$NAME"'/\)\([^/_]\+\):%lang(\2) \1\2: +s:^\([^%].*\):: +s:%lang(C) :: + ' |grep -v '^$' >> "$OUTFILE" ||: + fi + +} + +for NAME in "$@"; do + if [ -n "$OUTPUT" ]; then + OUTFILE="$OUTPUT" + [ "$NAME" = "$1" ] || APPEND=1 + else + OUTFILE="$NAME.lang" + fi + + FindLang +done diff --git a/scripts/find-package b/scripts/find-package new file mode 100755 index 0000000..95d964a --- /dev/null +++ b/scripts/find-package @@ -0,0 +1,67 @@ +#!/bin/sh -e +# +# find-package +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# If using normal root, avoid changing anything. +[ -n "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ] + +FindPackage() +{ + local f="$1" + shift + local r rep package deref + + for r in "$@"; do + [ -n "$r" ] || continue + if [ -z "${r##/*}" ]; then + if ! relative "$r" "$RPM_BUILD_ROOT" |grep -q "^../"; then + echo "$f: invalid dependence: $r" >&2 + return 1 + fi + rep="$r" + if [ -e "$RPM_BUILD_ROOT/$rep" ]; then + continue + fi + deref=`LC_TIME=C /bin/ls -l -- "$rep" |/bin/sed -ne 's,^lrwxrwxrwx \+1 .\+ \(/[^ ]\+\) -> /etc/alternatives/.\+$,\1,p'` + if [ "$deref" = "$rep" ]; then + echo -E "$rep" + else + if package="$(rpmquery --whatprovides --queryformat='%{NAME}\n' -- "$rep"|LC_COLLATE=C sort -u)"; then + echo -E "$package" + else + echo -E "$rep" + fi + fi + else + local RPATH="$(echo "$PATH" |sed -e "s|[^:]\+|$RPM_BUILD_ROOT&|g")" + if [ -n "$(PATH="$RPATH" /usr/bin/which -- "$r" 2>/dev/null)" ]; then + continue + fi + if ! rep="$(/usr/bin/which -- "$r" 2>/dev/null)"; then + continue + fi + if [ -e "$RPM_BUILD_ROOT/$rep" ]; then + continue + fi + if package="$(rpmquery --whatprovides --queryformat='%{NAME}\n' -- "$rep"|LC_COLLATE=C sort -u)"; then + echo -E "$package" + fi + fi + done +} diff --git a/scripts/javadeps.c b/scripts/javadeps.c new file mode 100755 index 0000000..6fc70f3 --- /dev/null +++ b/scripts/javadeps.c @@ -0,0 +1,1217 @@ +/* +RPM and it's source code are covered under two separate licenses. + +The entire code base may be distributed under the terms of the GNU General +Public License (GPL), which appears immediately below. Alternatively, +all of the source code in the lib subdirectory of the RPM source code +distribution as well as any code derived from that code may instead be +distributed under the GNU Library General Public License (LGPL), at the +choice of the distributor. The complete text of the LGPL appears +at the bottom of this file. + +This alternatively is allowed to enable applications to be linked against +the RPM library (commonly called librpm) without forcing such applications +to be distributed under the GPL. + +Any questions regarding the licensing of RPM should be addressed to +marc@redhat.com and ewt@redhat.com. +*/ + +/* + Simple progam for pullng all the referenced java classes out of a + class file. Java files are supposed to be platform independent, so + this program should work on all platforms. This code is based on + the information found in: + + "Java Virtual Machine" by Jon Meyer & Troy Downing. + O'Reilly & Associates, INC. (First Edition, March 1997) + ISBN: 1-56592-194-1 + + Jonathan Ross, Ken Estes + Mail.com + */ + + +/* + Remember that: + + JAR consists of a zip archive, as defined by PKWARE, containing + a manifest file and potentially signature files, as defined in + the Manifest and Signature specification. So we use infozip's + 'unzip -p' found at http://www.cdrom.com/pub/infozip/. + + Additional documentation, about this fact, at: + + http://java.sun.com/products/jdk/1.1/docs/guide/jar/jarGuide.html + http://java.sun.com/products/jdk/1.2/docs/guide/jar/jarGuide.html + + http://java.sun.com/products/jdk/1.1/docs/guide/jar/manifest.html + http://java.sun.com/products/jdk/1.2/docs/guide/jar/manifest.html + +*/ + +#include "system.h" + +/* + these includes are for my use, rpm will use #include "system.h"* +*/ + +/* +#include +#include +#include +#include +*/ + +#include + +/*---------typedefs---------*/ + + +/* The symbol table is a waste of memory.. + but it's easy to code! */ + +typedef struct { + short poolSize; + char **stringList; + short *classRef; + short *typeRef; +} symbolTable_t; + + +/*---------Global Variables, in all caps---------*/ + +/*name of this program*/ +char *PROGRAM_NAME=0; + +/*name of the current class file*/ +char *FILE_NAME=0; + +/*the name of the last class file seen*/ +char *CLASS_NAME=0; + +/*arguments chosen*/ +int ARG_PROVIDES=0; +int ARG_REQUIRES=0; +int ARG_RPMFORMAT=0; +int ARG_KEYWORDS=0; +int ARG_STARPROV=0; + +/*keywords found in class file*/ +char *KEYWORD_VERSION=0; +char *KEYWORD_REVISION=0; +char *KEYWORD_EPOCH=0; + +/* + + Quantify says over 80 percent of the time of the program is spent + in printf (and the functions it calls) AND I verified that only + about a quarter of the classes found in the dependency analysis are + unique. After the change no function used more then 26% of the over + all time. + + I implement a simple mechanism to remove most duplicate dependencies. + The print_table is a table of string which are to be printed. Just + before the program exists it is sorted and all unique entries are + printed. If it fills up during then it is flushed using the same + technique as above. + + The functions which manipulate the table are: + void print_table_flush(void) + void print_table_add(char *str) + +*/ + + +#define MAX_PRINT_TABLE 10000 +char *PRINT_TABLE[MAX_PRINT_TABLE]; +int SIZE_PRINT_TABLE; + +/*--------- declare all functions ---------*/ + +void usage (void); +void outofmemory(void); +void die(char *format, ...); +size_t my_fread(void *ptr, size_t size, size_t nitems, FILE *stream); +void check_range(short value, short poolSize); +char *is_lower_equal (char *string, char *pattern); +int findJavaMagic (FILE *fileHandle); +int my_strcmp (const void *a, const void *b); +void print_table_flush(void); +void print_table_add(char *str); +char *formatClassName(char *pSomeString, char terminator, char print_star); +void dumpRefType(char *pSomeString); +void dumpRequires(symbolTable_t *symbolTable); +void genSymbolTable (FILE *fileHandle, symbolTable_t *symbolTable); +void findClassName (FILE *fileHandle, symbolTable_t *symbolTable); +void freeSymbolTable (symbolTable_t *symbolTable); +void processJavaFile (FILE *fileHandle); + +/*--------- functions ---------*/ + +void +usage (void) +{ + printf("NAME:\n\tjavadeps - Examine Java class files and\n" + "\t\t\treturn information about their dependencies.\n\n"); + printf("USAGE:\n"); + printf("\t javadeps { --provides | --requires } \n" + "\t\t [--rpmformat] [--keywords] \n" + "\t\t [--] classfile-name ... \n\n" + "\t javadeps [--help]\n\n"); + printf("\n\n"); + printf("DESCRIPTION:\n\n"); + printf("List the dependencies or the fully qualified class names, of the \n" + "classfiles listed on the command line. \n\n"); + printf("OPTIONS:\n\n"); + printf("--requires For each class files listed in the arguments,\n" + " -r print the list of class files that would be\n" + " required to run these java programs. This does not \n" + " include anyting instantiated by reflection.\n\n"); + printf("--provides For each class files listed in the arguments, \n" + " -p Print the fully qualified java classes,\n" + " that they provide.\n\n"); + printf("--rpmformat format the output to match that used by RPM's \n" + " -F (Red Hat Package Manager) dependency analysis \n" + " database. The default is not --rpmformat.\n\n"); + printf("--keywords Make use of any keywords embeded in the classfile.\n" + " -k The default is not --keyword.\n\n"); + printf("--starprov Add the star notation provides to the provides list.\n" + " -s The default is not --starprov. This is only for use\n" + " with (Sun) jhtml dependencies, and since jhtml is \n" + " deprecated so is this option.\n\n"); + printf("--help Display this page and exit.\n\n"); + printf("-- This stops the processing of arguments, making it \n" + " easier for users to have filenames like '--keywords',\n" + " without the command line parser getting confused.\n\n"); + printf("\n\n"); + printf("If any of the class file names in the argument list is '-' then\n" + " will be read instead of reading from a file. The\n" + "contents of should be the contents of a class file and \n" + "not a list of class files to read. It is assumed that when run \n" + "with '-', this program is in a pipeline preceeded by the \n" + "command 'unzip -p filename.jar' so that may contain\n" + "the contents of several classfiles concatenated together.\n"); + printf("\n\n"); + printf("If --keywords is specified then the following strings are \n" + "searched for (case insensitive) in the class file string table\n" + "and, if a string is found with a prefix matching the keyword then \n" + "the dependencies are changed accordingly. There may be multiple \n" + "string tables entries prefixed with RPM_Provides and RPM_Requires. \n" + "This would indicate that the dependency is the union\n" + "of all entries.\n" + "\n\n" + "Keyword List:\n\n" + "'$Revision: ' This RCS/CVS compatible keyword is assumed to \n" + " contain the version number of the class file \n" + " it is found in. Care should be taken with this\n" + " option as RPM's notion of which version is later\n" + " may not corrispond with your own, especially\n" + " if you use branches. This keyword\n" + " only effects the output of --provides and only\n" + " when RPM_Version is not defined.\n\n" + "'RPM_Version: ' This is an alternative method of specifing the\n" + " version number of the class. It will override\n" + " $Revision if set. This keyword only effects\n" + " the output of --provides \n\n" + "'RPM_Epoch: ' This string contains the epoch to use with the \n" + " version number stored in Revision. If not \n" + " specified, the epoch is assumed to be zero.\n" + " This keyword only effects the output of\n " + " --provides and only when $Revision number is\n" + " used.\n\n" + "'RPM_Provides: ' This string lists additional capabilites\n" + " provided by the java class. The string should\n" + " be a white space ([\\t\\v\\n\\r\\f\\ ])\n" + " separated list of dependency strings. Each\n" + " dependency string must be of the same format as\n" + " would be valid in the Requires or Provides line\n" + " of the specfile. This keyword only effects the\n" + " output of --provides.\n\n" + "'RPM_Requires: ' This string lists additional requirements of\n" + " the java class. The string should be a white \n" + " space ([\\t \v\\n\\r\\f\\ ]) separated list of \n" + " dependency strings. Each dependency string must\n" + " be of the same format as would be valid in the \n" + " Requires or Provides line of the specfile. This\n" + " keyword only effects the output of --requires.\n " + " \n\n" + "Note that there is no means of setting the release number. This\n" + "is necessary because release numbers are incremented when the\n" + "source does not change but the package needs to be rebuilt. So\n" + "relase numbers can not be stored in the source. The release is\n" + "assumed to be zero. \n\n" + ""); + printf("EXAMPLES (Java Keywords): \n\n" + "\t public static final String REVISION = \"$Revision$\";\n" + "\t public static final String EPOCH = \"4\";\n" + "\t public static final String REQUIRES = \"RPM_Requires: " + "java(gnu.regexp.RE) java(com.ibm.site.util.Options)>=1.5\";\n" + ""); + printf("\n\n"); + printf("EXAMPLES (Arguments): \n\n" + "\tjavadeps --requires -- filename.class\n\n" + "\tjavadeps --provides -- filename.class\n\n" + "\tjavadeps --help\n\n" + "\n" + "\tjavadeps --requires --rpmformat --keywords -- filename.class\n\n" + "\tjavadeps --requires -- filename1.class filename2.class\n\n" + "\tcat filename2.class | javadeps --requires -- filename1.class -\n\n" + "\tunzip -p filename.jar | javadeps --requires -- - \n\n" + ""); + printf("This program is distributed with RPM the Redhat Package \n" + "Managment system. Further information about RPM can be found at \n" + "\thttp://www.rpm.org/\n\n"); + printf("\n\n"); + exit(-1); +} + + +void outofmemory(void) { + + /* Its doubtful we could do a printf if there is really a memory + issue but at least halt the program */ + + fprintf(stderr, "Could not allocate memory"); + exit(-1); +} + + +void die(char *format, ...) { + /* Most errors are fatal. + This function throws a fatal error and + accepts arguments like printf does*/ + + char *newformat = NULL, *newmsg = NULL; + va_list ap; + + if ( !(newformat = malloc(1024)) || !(newmsg = malloc(1024)) ) + outofmemory(); + + /* Rewrite format line, to include additional information. The + format line we chose depends on how much information is availible + at the time of the error. Display the maximum ammount of + information. */ + + /* notice the FILE_NAME is useless for jar files. We would want to + print the name of the classfile which caused the error. That + is hard since we only know that name when we are done parsing + the file, and most errors will occur before that.*/ + + va_start(ap, format); + + if ( (!FILE_NAME) ) { + + sprintf (newformat, "\n%s: %s", + PROGRAM_NAME, format); + + } else if ( (FILE_NAME) && (!CLASS_NAME) ) { + + sprintf (newformat, "\n%s: Java classfile: %s, %s", + PROGRAM_NAME, FILE_NAME, format); + + } else if (CLASS_NAME) { + sprintf (newformat, "\n%s: Java classfile: %s, classname: %s, %s", + PROGRAM_NAME, FILE_NAME, CLASS_NAME, format); + } + + vsprintf (newmsg, newformat, ap); + + /* print error to where it needs to go: + stdout, stderr, or syslog + */ + + fprintf(stderr, newmsg); + + free(newformat); + free(newmsg); + + exit(-1); +} + + +/* wrap fread for safety. It is a fatal error to get an unexpected + EOF inside a class file. */ + +size_t my_fread(void *ptr, size_t size, size_t nitems, FILE *stream) { + size_t rc=0; + /*these variables are helpful in the debugger*/ + int eof=0; + int error=0; + + + rc = fread(ptr, size, nitems, stream); + if ( (size!=0) && (rc == 0) ) { + eof = feof(stream); + error = ferror(stream); + die("Error reading from file, or unexpected EOF\n"); + } + return rc; +} + + +void check_range(short value, short poolSize) { + + if (value > poolSize) { + die("Value: %d, is out of range of the constant pool\n", + value); + } + return ; +} + + + +/* If lower case conversion of string is equal to pattern return a + pointer into string, just after the match. If the string does not + patch the pattern the null pointer is returned. This does not + change string. + + This is similar to strcasecmp, but I expect my patterns to be a + prefix of my strings. */ + +char +*is_lower_equal (char *string, char *pattern) +{ + + while ( (tolower(*string) == *pattern) && + *string && *pattern ) { + string++; + pattern++; + } + + if ( *pattern == 0 ) { + return string; + } + + return NULL; +} + + +/* + Read fileHandle until we find the next instance of the Java + Classfile magic number indicating a java file or find EOF or + fileread error. Since we are reading from stdin which may contain + the concatination of many class files we can not be sure that the + magic number will be the first few bytes. + + Return 1 on success 0 on failure. */ + +#define mod4(num) ( (num) & 3 ) + + +int findJavaMagic (FILE *fileHandle) +{ + int offset=0; + int foundMagic = 0; + size_t rc; + + /* what were looking for */ + unsigned char magicInt[4] = {0xCA, 0xFE, 0xBA, 0xBE}; + /*the hex reads in decimal: 202 254 186 190 */ + + /* a circular buffer indicating the last few bytes we read */ + unsigned char buffer[4] = {0}; + + foundMagic = 0; + while( !foundMagic ) { + + rc = fread(&buffer[offset], 1, 1, fileHandle); + if ( !rc ) { + + /* Either this was not a java file or we were given a jar file + and have already found the last java file in it.*/ + + if ( feof(fileHandle) ) { + return 0; + } + + if ( ferror(fileHandle) ) { + die ("Error reading character from file.\n"); + }; + + } + + /* offset points to the most recent char we read so offest+1 + points to the oldest char we saved. */ + + foundMagic = ( + (magicInt[0] == buffer[mod4(offset+1)]) && + (magicInt[1] == buffer[mod4(offset+2)]) && + (magicInt[2] == buffer[mod4(offset+3)]) && + (magicInt[3] == buffer[mod4(offset+0)]) && + 1 + ); + + offset = mod4(offset+1); + + } /*end while*/ + + return foundMagic; +} + +#undef mod4 + + +int +my_strcmp (const void *a, const void *b) { +char **a1; char **b1; +int ret; + +a1 = (char **)a; +b1 = (char **)b; +ret = strcmp(*a1,*b1); + return ret; +} + +/* print the unique strings found in PRINT_TABLE and clear it out */ + +void +print_table_flush(void) { + int i; + char *last_string; + + if (!SIZE_PRINT_TABLE) { + return ; + } + + /* The qsort line gives a warning on some unicies who insist that + strcmp takes arguments of type pointers to void not the + traditional pointers to char. */ + + qsort( (void *) PRINT_TABLE, (size_t) SIZE_PRINT_TABLE, + sizeof(char *), &my_strcmp); + + printf("%s",PRINT_TABLE[0]); + last_string = PRINT_TABLE[0]; + PRINT_TABLE[0] = NULL; + + for (i = 1; i < SIZE_PRINT_TABLE; i++) { + if ( strcmp(last_string, PRINT_TABLE[i]) ){ + printf("%s",PRINT_TABLE[i]); + free(last_string); + last_string = PRINT_TABLE[i]; + } else { + free(PRINT_TABLE[i]); + } + PRINT_TABLE[i] = NULL; + } + + free(last_string); + SIZE_PRINT_TABLE = 0; + return ; +} + + +/* add an element to PRINT_TABLE for later printing to stdout. We do + not make a copy of the string so each string must be unique, + (different calls must pass pointers to different areas of memory) + and the string must not be freed anywhere else in the code and the + string must be from memory which can be freed.*/ + +void +print_table_add(char *str) { + + if (SIZE_PRINT_TABLE == MAX_PRINT_TABLE) { + print_table_flush(); + } + + PRINT_TABLE[SIZE_PRINT_TABLE] = str; + SIZE_PRINT_TABLE++; + return ; +} + + +void +print_list(char *in_string) { + + /* This function is no longer needed due to fixes in RPM's + processing of dependencies. Keep the code until I get a chance + to use RPM3.0 personally */ + + if (in_string) { + printf("%s\n", in_string); + } + +/* + Old function did: + + Given a list separated by whitespace, put each element in the print + table with an added "\n" */ + + /* + char *WhiteSpace_Set = "\t\v\n\r\f "; + char *newEnd, *out_string; + int copy_len; + + in_string += strspn(in_string, WhiteSpace_Set); + + while (*in_string) { + newEnd = strpbrk(in_string, WhiteSpace_Set); + + if (newEnd) { + copy_len = newEnd-in_string; + } else { + if (*in_string) { + copy_len = strlen(in_string); + } else { + copy_len = 0; + } + } + + out_string = malloc(copy_len+10); + if ( !out_string ) { + outofmemory(); + } + out_string[0]= '\0'; + + if (copy_len) { + strncat(out_string, in_string, copy_len); + in_string+=copy_len; + strcat(out_string, "\n"); + print_table_add(out_string); + } + + in_string += strspn(in_string+copy_len, WhiteSpace_Set); + } + + */ + return ; +} + + +/* Print a properly formatted java class name, and returns the length + of the class string . Do not print \n here as we may wish to + append the version number IFF we are printing the name of this classfile + + We also provide the class with the leaf node replaced with '*'. + This would not be necessary if we only had to worry about java + Class files. However our parsing of jhtml files depends on this + information. This is deprecated since jhtml is deprecated and + this method allows for very inaccurate dependencies. + + Also users may wish to refer to dependencies using star notation + (though this would be less accurate then explicit dependencies + since any leaf class will satify a star dependency). */ + +char +*formatClassName(char *in_string, char terminator, + char print_star) +{ + char *leaf_class=0, *out_string=0; + char *ClassName_Break_Set=0; + + + out_string = malloc(strlen(in_string) + 10); + if ( !out_string ) { + outofmemory(); + } + out_string[0]= '\0'; + + /*these characters end the current parse of the string in function + formatClassName.*/ + + ClassName_Break_Set = malloc(3); + if ( !ClassName_Break_Set ) { + outofmemory(); + } + ClassName_Break_Set[0] = '/'; + /*terminator can be '\0' this must go after '/'*/ + ClassName_Break_Set[1] = terminator; + ClassName_Break_Set[2] = '\0'; + + if(ARG_RPMFORMAT) { + strcat(out_string, "java("); + } + if (print_star) { + /* print the path to the leaf class but do not print the leaf + class, stop at the last '/' we fix this back below*/ + leaf_class = strrchr(in_string, '/'); + if (leaf_class) { + leaf_class[0] = terminator; + } + } + + while (*in_string != terminator) { + char *newEnd=0; + int copy_len; + + /* handle the break_set */ + + if (in_string[0] == '\0' ) { + die("Classname does not terminate with: '%c', '%s'\n", + terminator, in_string); + } else { + if (in_string[0] == '/' ) { + /* convert '/' to '.' */ + strcat(out_string, "."); + in_string++; + } + } + + newEnd = strpbrk(in_string, ClassName_Break_Set); + + if (newEnd) { + copy_len = newEnd-in_string; + } else { + if (terminator == '\0') { + copy_len = strlen(in_string); + } else { + copy_len = 0; + } + } + + /* handle upto but not including the break_set*/ + if (copy_len) { + strncat(out_string, in_string, copy_len); + in_string+=copy_len; + } + + } /*end while*/ + + if (leaf_class) { + /* print the star and fix the leaf class*/ + strcat(out_string, ".*"); + leaf_class[0] = '/'; + } + if(ARG_RPMFORMAT) { + strcat(out_string, ")"); + } + + strcat(out_string, "\n"); + free(ClassName_Break_Set); + return out_string; +} + + +/* Parse out just the class names from a java type and moves the string + pointer to the end of the string. */ + +void +dumpRefType(char *string) +{ + /* All class types start with a 'L' and and end with a ';'. We want + everyting in between. There might be more then one per string + like (params for a method call) */ + + string = strchr(string, 'L'); + while (string) { + string++; + print_table_add(formatClassName(string, ';', 0)); + string = strchr(string, ';'); + string = strchr(string, 'L'); + } + + return ; +} + + +/* Print out the classes referenced in the symbol table */ + +void +dumpRequires(symbolTable_t *symbolTable) { + int tem; + int ref = 0; + + for(tem=1; tem < symbolTable->poolSize; tem++ ) { + + /* dump all the classes in the const table. */ + ref = symbolTable->classRef[tem]; + if(ref) { + char *string = symbolTable->stringList[ref]; + if( !*string ) { + die("class num: %d, referenced string num: %d, " + "which is null.\n", + tem, ref); + } + if ( string[0] == '[' ) { + /* + This is an array. We need to ingore + strings like: + '[B' + '[[B' + '[[I' + + This hack leaves blank lines in the output + when a string not containing a class is + sent to dumpRefType. + */ + string = strchr(string, 'L'); + if (string) { + dumpRefType(string); + } + } else { + print_table_add(formatClassName(string, '\0', 0)); + } + } + + /* dump all the references */ + ref = symbolTable->typeRef[tem]; + if (ref) { + char *string = symbolTable->stringList[ref]; + if ( !*string ) { + die("type num: %d, referenced string num: %d, " + "which is null.\n", + tem, ref); + } + /* this is a java type... parse out the class names */ + dumpRefType(string); + } + + } /*end for*/ + + return ; +} + + +/* Read a java class files symbol table into memory. + - also - + Find the proper name of the current Java Class file. + Print it regardless of: --provides | --requires +*/ + + +void genSymbolTable (FILE *fileHandle, symbolTable_t *symbolTable) +{ + char ignore[10]; + int i=0; + + + /* We are called just after fileHandle saw the magic number, seek a + few bytes in to find the poolsize */ + + my_fread(&ignore, 4, 1, fileHandle); + + my_fread(&(symbolTable->poolSize), 2, 1, fileHandle); + + /* new the tables */ + + symbolTable->stringList = (char**) calloc(symbolTable->poolSize, + sizeof(char*)); + if(!symbolTable->stringList){ + outofmemory(); + } + + symbolTable->classRef = (short*) calloc(symbolTable->poolSize, + sizeof(short*)); + if(!symbolTable->classRef){ + outofmemory(); + } + + symbolTable->typeRef = (short*) calloc(symbolTable->poolSize, + sizeof(short*)); + if(!symbolTable->typeRef){ + outofmemory(); + } + + /* zero 'em all out. */ + for(i=0; i < symbolTable->poolSize; i++) { + symbolTable->stringList[i] = NULL; + symbolTable->classRef[i] = 0; + symbolTable->typeRef[i] = 0; + } + + + /* for the number of entries + (it starts at 1) + */ + + for(i=1; i < symbolTable->poolSize; i++) { + unsigned short type = 0; + unsigned short value = 0; + unsigned char tag = 0; + + /* read the type of this entry */ + + my_fread(&tag, 1, 1, fileHandle); + switch(tag) { + case 1: /* master string pool. */ + { + /* record all these strings */ + char *someString; + unsigned short length = 0; + + /* I am not sure if these strings must be null + terminated. I termiante them to be safe. */ + + my_fread(&length, 2, 1, fileHandle); + someString = (char*) malloc(length+1); + if(!someString){ + outofmemory(); + } + my_fread(someString, length, 1, fileHandle); + someString[length]=0; + symbolTable->stringList[i] = someString; + + if (ARG_KEYWORDS) { + char *ptr=0; + + /* Each keyword can appear multiple times. Don't + bother with datastructures to store these strings, + if we need to print it print it now. */ + + /* it would be better if instead of printing the + strings "raw" I turn the space separated list + into a "\n" separated list*/ + + if (ARG_REQUIRES) { + ptr = is_lower_equal(someString, "rpm_requires: "); + if(ptr){ + print_list(ptr); + } + } + if (ARG_PROVIDES) { + ptr = is_lower_equal(someString, "rpm_provides: "); + if(ptr){ + print_list(ptr); + } + } + /* I wish there was a good way to handle this + ptr = is_lower_equal(someString, "rpm_conflicts: "); + */ + ptr = is_lower_equal(someString, "$revision: "); + if(ptr){ + KEYWORD_REVISION=ptr; + /* terminate the string before " $" */ + ptr = strchr(KEYWORD_REVISION, ' '); + if (ptr) { + *ptr = 0; + } + } + ptr = is_lower_equal(someString, "rpm_version: "); + if(ptr){ + KEYWORD_VERSION=ptr; + /* terminate the string at first whitespace */ + ptr = strchr(KEYWORD_VERSION, ' '); + if (ptr) { + *ptr = 0; + } + } + ptr = is_lower_equal(someString, "rpm_epoch: "); + if(ptr){ + KEYWORD_EPOCH=ptr; + /* terminate the string at first whitespace */ + ptr = strchr(KEYWORD_EPOCH, ' '); + if (ptr) { + *ptr = 0; + } + } + } + break; + } + case 2: /* unknow type!! */ + die("Unknown type in constant table. " + "Entry: %d. \n", i); + break; + case 3: /* int */ + my_fread(&ignore, 4, 1, fileHandle); + break; + case 4: /* float */ + my_fread(&ignore, 4, 1, fileHandle); + break; + case 5: /* long (counts as 2) */ + my_fread(&ignore, 8, 1, fileHandle); + i++; + break; + case 6: /* double (counts as 2) */ + my_fread(&ignore, 8, 1, fileHandle); + i++; + break; + case 7: /* Class */ + my_fread(&value, 2, 1, fileHandle); + /* record which const it's referencing */ + check_range(value, symbolTable->poolSize); + symbolTable->classRef[i]=value; + break; + case 8: /* String */ + my_fread(&ignore, 2, 1, fileHandle); + break; + case 9: /* field reference */ + my_fread(&ignore, 4, 1, fileHandle); + break; + case 10: /* method reference */ + my_fread(&ignore, 4, 1, fileHandle); + break; + case 11: /* interface method reference */ + my_fread(&ignore, 4, 1, fileHandle); + break; + case 12: /* constant name/type */ + my_fread(&ignore, 2, 1, fileHandle); + my_fread(&type, 2, 1, fileHandle); + /* record the name, and the type it's referencing. */ + check_range(type, symbolTable->poolSize); + symbolTable->typeRef[i]=type; + break; + default: + die("Unknown tag type: %d.\n", + "Entry: %d. \n", tag, i); + break; + } + } + + return ; +} + + +/* + Find the proper name of the current Java Class file. + Print it regardless of: --provides | --requires +*/ + +void +findClassName (FILE *fileHandle, symbolTable_t *symbolTable) { + char ignore[10]; + unsigned short type = 0; + unsigned short class = 0; + char *out_string; + char *newline; + + /* seek a little past the end of the table */ + + my_fread(&ignore, 2, 1, fileHandle); + + /* read the name of this classfile */ + + my_fread(&type, 2, 1, fileHandle); + class = symbolTable->classRef[type]; + if( !class || + !symbolTable->stringList[class] ) { + die("Couln't find class: %d, provided by file.\n", class); + } + CLASS_NAME=symbolTable->stringList[class]; + + out_string = formatClassName(symbolTable->stringList[class], '\0', 0); + + { + int len = 10; + + if (out_string) { + len += strlen(out_string); + } + if (KEYWORD_EPOCH) { + len += strlen(KEYWORD_EPOCH); + } + if (KEYWORD_VERSION) { + len += strlen(KEYWORD_VERSION); + } + if (KEYWORD_REVISION) { + len += strlen(KEYWORD_REVISION); + } + + out_string = realloc(out_string, len ); + } + + if (!out_string){ + outofmemory(); + } + + if( KEYWORD_VERSION || KEYWORD_REVISION ){ + /* It is easier to remove the extra new line here in one place + then to try and add a newline every where that formatClassName + is called */ + char *newline; + + /* I am not using rpm 3.0 yet so I need both the dependencies with + and without the version numbers, when I upgrade I will remove + this block (with copy_string) and change the "=" to " = " ten + lines down.*/ + { + char *copy_string; + copy_string = (char*) malloc(strlen(out_string)); + if (!copy_string){ + outofmemory(); + } + copy_string = strcpy(copy_string, out_string); + print_table_add(copy_string); + } + + newline = strrchr(out_string, '\n'); + if (newline) { + newline[0] = '\0'; + } + strcat(out_string, " = "); + if(KEYWORD_EPOCH){ + strcat(out_string, KEYWORD_EPOCH); + strcat(out_string, ":"); + } + if(KEYWORD_VERSION){ + strcat(out_string, KEYWORD_VERSION); + } else { + strcat(out_string, KEYWORD_REVISION); + } + strcat(out_string, "\n"); + } + + print_table_add(out_string); + out_string=NULL; + + /* Provide the star version of this class for jhtml + dependencies. This option is deprecated since jhtml is + deprecated. */ + + if (ARG_STARPROV) { + out_string = formatClassName(symbolTable->stringList[class], '\0', 1); + print_table_add(out_string); + } + + return ; +} + + + + + +void freeSymbolTable (symbolTable_t *symbolTable) +{ + int i=0; + + for(i=1; i < symbolTable->poolSize; i++) { + if( symbolTable->stringList[i] ) { + free(symbolTable->stringList[i]); + symbolTable->stringList[i] = 0; + } + } + + free(symbolTable->stringList); + symbolTable->stringList=0; + + free(symbolTable->classRef); + symbolTable->classRef=0; + + free(symbolTable->typeRef); + symbolTable->typeRef=0; + + free(symbolTable); + symbolTable=0; + + return ; +} + + +/* process each file, + must be called directly after finding + the magic number. +*/ + +void processJavaFile (FILE *fileHandle) { + symbolTable_t symbolTable= {0}; + + genSymbolTable(fileHandle, &symbolTable); + findClassName(fileHandle, &symbolTable); + + if(ARG_REQUIRES) { + dumpRequires(&symbolTable); + } + + freeSymbolTable(&symbolTable); + + return ; + +} + + +int +main(int argc, char **argv) +{ + FILE *fileHandle; + int i = 0; + int rc = 0; + int foundMagic=0; + + PROGRAM_NAME=argv[0]; + + if(argv[1] == NULL) { + usage(); + } + + /* parse arguments which are not filenames*/ + + for (i = 1; argv[i] != NULL; i++) { + + if (0) { + /* + First entry a dummy to get the + other entries to align correctly + */ + ; + } else if ( !strcmp("-p",argv[i]) || !strcmp("--provides",argv[i]) ) { + ARG_PROVIDES = 1; + } else if ( !strcmp("-r",argv[i]) || !strcmp("--requires",argv[i]) ) { + ARG_REQUIRES = 1; + } else if ( !strcmp("-h",argv[i]) || !strcmp("--help",argv[i]) || + !strcmp("-?",argv[i]) ) { + + usage(); + } else if ( !strcmp("-F",argv[i]) || !strcmp("--rpmformat",argv[i]) ) { + ARG_RPMFORMAT=1; + } else if ( !strcmp("-k",argv[i]) || !strcmp("--keywords",argv[i]) ) { + ARG_KEYWORDS=1; + } else if ( !strcmp("-s",argv[i]) || !strcmp("--starprov",argv[i]) ) { + ARG_STARPROV=1; + } else if ( !strcmp("--",argv[i]) ) { + i++; + break; + } else { + /* we do not recognize the argument, must be a filename*/ + break; + } + } /*end for arguments which are not filenames*/ + + /* check arguments for consistancy */ + + if ( !ARG_PROVIDES && !ARG_REQUIRES ) { + die ("Must specify either --provides or --requires.\n"); + } + + if ( ARG_PROVIDES && ARG_REQUIRES ) { + die ("Can not specify both --provides and --requires.\n"); + } + + if ( ARG_REQUIRES && ARG_STARPROV) { + die ("Can not specify both --requires and --starpov.\n"); + } + + if(argv[i] == NULL) { + die ("Must specify Java class files.\n"); + } + + /* parse arguments which are filenames. */ + + for ( /*null initializer*/; argv[i] != NULL; i++) { + + /*open the correct file and process it*/ + + if ( !strcmp("-", argv[i]) ) { + /* use stdin, might be a jar file */ + fileHandle = stdin; + FILE_NAME = ""; + + foundMagic = findJavaMagic(fileHandle); + while (foundMagic) { + processJavaFile(fileHandle); + foundMagic = findJavaMagic(fileHandle); + } + } else { + /* Open a disk file*/ + fileHandle = fopen(argv[i], "r"); + if( fileHandle == 0 ) { + die ("Could not open file: %s.\n", argv[i]); + } + fileHandle = fileHandle; + FILE_NAME = argv[i]; + + foundMagic = findJavaMagic(fileHandle); + if (foundMagic) { + processJavaFile(fileHandle); + } + } + + rc = fclose(fileHandle); + if( rc ) { + die ("Could not close file: %s.\n", FILE_NAME); + } + CLASS_NAME=0; + } /*end parsing arguments which are filenames*/ + + print_table_flush(); + return 0; +} diff --git a/scripts/pam.prov b/scripts/pam.prov new file mode 100755 index 0000000..eef59ef --- /dev/null +++ b/scripts/pam.prov @@ -0,0 +1,28 @@ +#!/bin/sh -e +# +# pam.prov +# Copyright (C) 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# If using normal root, avoid changing anything. +[ -n "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ] + +file="$1" + +head -1 "$file" |grep -qs '^#%PAM' || exit 0 + +echo "pam(${file##$RPM_BUILD_ROOT/etc/pam.d/})" diff --git a/scripts/pam.req b/scripts/pam.req new file mode 100755 index 0000000..9c894da --- /dev/null +++ b/scripts/pam.req @@ -0,0 +1,30 @@ +#!/bin/sh -e +# +# pam.req +# Copyright (C) 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# If using normal root, avoid changing anything. +[ -n "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ] + +file="$1" + +head -1 "$file" |grep -qs '^#%PAM' || exit 0 + +sed -ne 's#^\(account\|auth\|password\|session\)[[:space:]]\+\(requisite\|required\|sufficient\|optional\)[[:space:]]\+\(/lib/security/\)\?\([^[:space:]]\+\).*#\4#pg' <"$file" |sort -u + +sed -ne 's#^\(account\|auth\|password\|session\)[[:space:]]\+\(requisite\|required\|sufficient\|optional\)[[:space:]]\+\(/lib/security/\)\?pam_stack\.so[[:space:]]\+service=\([^[:space:]]\+\).*#pam(\4)#pg' <"$file" |sort -u diff --git a/scripts/shell.req.in b/scripts/shell.req.in new file mode 100755 index 0000000..889e92a --- /dev/null +++ b/scripts/shell.req.in @@ -0,0 +1,64 @@ +#!/bin/sh -e +# +# shell.req +# Copyright (C) 2000 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# If using normal root, avoid changing anything. +[ -n "$(echo "$RPM_BUILD_ROOT" |tr -d ' /.')" ] + +. @RPMCONFIGDIR@/find-package + +FIND_REQ="/bin/sh --rpm-requires" + +# Make sure that this sh has the rpm-requires feature +$FIND_REQ /dev/null + +file="$1" +extra= + +if ! reqs="$($FIND_REQ "$file" 2>/dev/null)"; then + if egrep -vs '^(#|$)' "$file" 2>/dev/null |head -1 |grep -qs '^[ ]*exec '; then + reqs="$(echo "$reqs" |head -1)" + extra="$(echo "$reqs" |sed -e 's/^\(executable\)(\(.*\))$/\2/g')" + else + reqs="$($FIND_REQ "$file")" + fi +fi +reqs="$(echo "$reqs" |sed -e 's/^\(sh\|bash\|executable\)(\(.*\))$/\2/g' |sort -u)" +[ -n "$reqs" ] || exit 0 + +FindReqs() +{ + for r in "$@"; do + if [ -z "${r/*\$*}" ]; then + continue + fi + if [ "$(type -t -- "$r")" = "function" ]; then + continue + fi + FindPackage "$file" "$r" + done +} + +# Find requires +found="$(FindReqs $reqs)" + +# And print them. +echo "$found" |sort -u + +# TODO: more analysis based on $extra diff --git a/scripts/strip_files b/scripts/strip_files new file mode 100755 index 0000000..0cacf98 --- /dev/null +++ b/scripts/strip_files @@ -0,0 +1,74 @@ +#!/bin/sh -e +# +# strip_files - strip files helper. +# +# Copyright (C) 2000, 2001 Dmitry V. Levin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +PROG="${0##*/}" + +StripNote() +{ + if ! objdump -h "$1" |grep '^[ ]*[0-9]*[ ]*\.note[ ]' -A 1 |fgrep -q ALLOC; then + echo -n '-R .note' + fi +} + +DoStrip() +{ + f="$1" + shift + local opts= + if [ -z "$STRIP_FORCED" ]; then + opts="-p -R .comment $(StripNote "$f") $*" + fi + strip $opts $STRIP_FORCED_OPTS "$f" +} + +for f in "$@"; do + [ -f "$f" ] + + t="$(/usr/bin/file -b "$f")" + + if [ -z "${t/*ELF*executable,*/}" ]; then + if [ -n "$STRIP_EXECUTABLE" ]; then + DoStrip "$f" + fi + continue + fi + + if [ -z "${t/*ELF*relocatable,*/}" ]; then + if [ -n "$STRIP_RELOCATABLE" ]; then + DoStrip "$f" --strip-unneeded + fi + continue + fi + + if [ -z "${t/*ELF*shared object,*/}" ]; then + if [ -n "$STRIP_SHARED" ]; then + DoStrip "$f" --strip-unneeded + fi + continue + fi + + if [ -z "${t/*current ar archive/}" ]; then + if [ -n "$STRIP_STATIC" ]; then + DoStrip "$f" --strip-unneeded + fi + continue + fi +done diff --git a/tools/filesize.c b/tools/filesize.c new file mode 100644 index 0000000..eee57fc --- /dev/null +++ b/tools/filesize.c @@ -0,0 +1,68 @@ +/* + $Id$ + Copyright (C) 2001 Dmitry V. Levin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include + +extern const char *__progname; + +__attribute__ ((__noreturn__)) +static void usage( void ) +{ + fprintf( stderr, "usage: %s filename [blocksize]\n" + "\tfilename - stat this file\n" + "\tblocksize - set size of block to this value, overriding default\n", + __progname ); + exit( EXIT_FAILURE ); +} + +int main( int ac, const char *av[] ) +{ + const char *fname; + unsigned long bsize = 0; + struct stat stb; + + if ( (ac < 2) || (ac > 3) ) + usage(); + + fname = av[1]; + if ( ac > 2 ) + { + bsize = atol( av[2] ); + if ( bsize < 1 ) + usage(); + } + + if ( stat( fname, &stb ) < 0 ) + { + fprintf( stderr, "%s: %s: %s\n", __progname, fname, strerror(errno) ); + exit( EXIT_FAILURE ); + } + + if ( !bsize ) + bsize = stb.st_blksize; + + printf( "%lu\n", (bsize < 2) ? stb.st_size : ((bsize - 1 + stb.st_size)/bsize) ); + + return 0; +} diff --git a/tools/pdeath_execute.c b/tools/pdeath_execute.c new file mode 100644 index 0000000..3a48bbd --- /dev/null +++ b/tools/pdeath_execute.c @@ -0,0 +1,95 @@ +/* + $Id$ + Copyright (C) 2001 Dmitry V. Levin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include + +extern const char *__progname; + +static void +my_error_print_progname (void) +{ + fflush (stdout); + fprintf (stderr, "%s: ", __progname); +} + +__attribute__ ((__noreturn__)) +static void usage (void) +{ + fprintf (stderr, "usage: %s \n", __progname); + exit (EXIT_FAILURE); +} + +static void +wait_for_pdeath (pid_t pid) +{ + for (;;) + { + if (kill (pid, 0) < 0) + { + if (ESRCH == errno) + break; + else + error (EXIT_FAILURE, errno, "kill: %u", pid); + } + usleep (100000); + } +} + +int +main (int ac, char *const *av) +{ + pid_t pid; + + error_print_progname = my_error_print_progname; + + if (ac < 3) + usage (); + + pid = atoi (av[1]); + + /* + * Check arguments. + */ + + if (pid <= 1) + usage (); + + if (kill (pid, 0) < 0) + error (EXIT_FAILURE, errno, "kill: %u", pid); + + if (access (av[2], X_OK)) + error (EXIT_FAILURE, errno, "access: %s", av[2]); + + /* Lets parent go on. */ + if (daemon (1, 1) < 0) + error (EXIT_FAILURE, errno, "daemon"); + + /* Wait for parent completion. */ + wait_for_pdeath (pid); + + execv (av[2], av + 2); + error (EXIT_FAILURE, errno, "execv: %s", av[2]); + return EXIT_FAILURE; +} diff --git a/tools/relative.c b/tools/relative.c new file mode 100644 index 0000000..248676e --- /dev/null +++ b/tools/relative.c @@ -0,0 +1,150 @@ +/* + $Id$ + Copyright (C) 2001 Dmitry V. Levin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include + +static void result( const char *str ) __attribute__ ((noreturn)); + +static const char* normalize( char *str ) +{ + char *p; + size_t len = strlen( str ); + + for ( p = strstr( str, "//" ); p; p = strstr( str, "//" ) ) + memmove( p, p + 1, strlen( p ) ); + + for ( p = strstr( str, "/./" ); p; p = strstr( str, "/./" ) ) + memmove( p, p + 2, strlen( p + 1 ) ); + + if ( (len >= 2) && ('/' == str[len-2]) && ('.' == str[len-1]) ) + str[len-1] = '\0'; + + return str; +} + +static void result( const char *str ) +{ + puts( str ); + exit( 0 ); +} + +static void strip_trailing( char *str, const char sym ) +{ + char *p; + for ( p = strrchr( str, sym ); p && (p >= str) && (sym == *p); --p ) + *p = '\0'; +} + +static const char* base_name( const char *name ) +{ + const char* p = strrchr( name, '/' ); + if ( p ) + return p + 1; + else + return name; +} + +static char* lookup_back( const char *str, const char sym, const char *pos ) +{ + for ( ; pos >= str ; --pos ) + if ( sym == *pos ) + return (char *)pos; + + return 0; +} + +extern const char *__progname; + +int main( int ac, char *av[] ) +{ + if ( ac < 3 ) + { + fprintf( stderr, "Usage: %s \n", __progname ); + return 1; + } + else + { + const char *orig_what = normalize( av[1] ); + normalize( av[2] ); + + { + unsigned reslen; + char *what_p, *to_p; + + char what[ 1 + strlen( av[1] ) ], + to[ 1 + strlen( av[2] ) ]; + + memcpy( what, av[1], sizeof(what) ); + memcpy( to, av[2], sizeof(to) ); + + if ( '/' != *what ) + result( what ); + + if ( '/' != *to ) + { + fputs( "relative: must be absolute filename\n", stderr ); + return 1; + } + + reslen = PATH_MAX + strlen( what ) + strlen( to ); + + strip_trailing( what, '/' ); + strip_trailing( to, '/' ); + + for ( what_p = what, to_p = to; *what_p && *to_p ; ++what_p, ++to_p ) + if ( *what_p != *to_p ) + break; + + if ( !*what_p && !*to_p ) + result( base_name( orig_what ) ); + else + { + char res[ reslen ]; + memset( res, 0, sizeof(res) ); + + if ( ('/' == *what_p) && !*to_p ) + result( orig_what + (++what_p - what) ); + + if ( '/' != *to_p || *what_p ) + { + what_p = lookup_back( what, '/', what_p ); + strcpy( res, ".." ); + } + + for ( ; *to_p; ++to_p ) + { + if ( '/' == *to_p ) + { + if ( *res ) + strcat( res, "/.." ); + else + strcpy( res, ".." ); + } + } + + strcat( res, orig_what + (what_p - what) ); + result( res ); + } + } + } +} diff --git a/update-alternatives b/update-alternatives new file mode 100755 index 0000000..402e469 --- /dev/null +++ b/update-alternatives @@ -0,0 +1,571 @@ +#! /usr/bin/perl -- + +#use POSIX; &ENOENT; +sub ENOENT { 2; } +# Sorry about this, but the errno-part of POSIX.pm isn't in perl-*-base + +# Global variables: +# $alink Alternative we are managing (ie the symlink we're making/removing) (install only) +# $name Name of the alternative (the symlink) we are processing +# $apath Path of alternative we are offering +# $apriority Priority of link (only when we are installing an alternative) +# $mode action to perform (display / install / remove / display / auto / config) +# $manual update-mode for alternative (manual / auto) +# $state State of alternative: +# expected: alternative with highest priority is the active alternative +# expected-inprogress: busy selecting alternative with highest priority +# unexpected: alternative another alternative is active / error during readlink +# nonexistent: alternative-symlink does not exist +# $link Link we are working with +# @slavenames List with names of slavelinks +# %slavenum Map from name of slavelink to slave-index (into @slavelinks) +# @slavelinks List of slavelinks (indexed by slave-index) +# %versionnum Map from currently available versions into @versions and @priorities +# @versions List of available versions for alternative +# %priorities Map from @version-index to priority +# %slavepath Map from (@version-index,slavename) to slave-path + +$version="1.8.3"; # This line modified by Makefile +sub usageversion { + print(STDERR < + [--slave ] ... + update-alternatives --remove + update-alternatives --auto + update-alternatives --display + update-alternatives --config + is the name in /etc/alternatives. + is the name referred to. + is the link pointing to /etc/alternatives/. + is an integer; options with higher numbers are chosen. + +Options: --verbose|--quiet --test --help --version + --altdir --admindir +END + || &quit("failed to write usage: $!"); +} +sub quit { print STDERR "update-alternatives: @_\n"; exit(2); } +sub badusage { print STDERR "update-alternatives: @_\n\n"; &usageversion; exit(2); } + +$altdir= '/etc/alternatives'; +$admindir= '/var/lib/rpm/alternatives'; +$testmode= 0; +$verbosemode= 0; +$mode=''; +$manual= 'auto'; +$|=1; + +sub checkmanymodes { + return unless $mode; + &badusage("two modes specified: $_ and --$mode"); +} + +while (@ARGV) { + $_= shift(@ARGV); + last if m/^--$/; + if (!m/^--/) { + &quit("unknown argument \`$_'"); + } elsif (m/^--(help|version)$/) { + &usageversion; exit(0); + } elsif (m/^--test$/) { + $testmode= 1; + } elsif (m/^--verbose$/) { + $verbosemode= +1; + } elsif (m/^--quiet$/) { + $verbosemode= -1; + } elsif (m/^--install$/) { + &checkmanymodes; + @ARGV >= 4 || &badusage("--install needs "); + ($alink,$name,$apath,$apriority,@ARGV) = @ARGV; + $apriority =~ m/^[-+]?\d+/ || &badusage("priority must be an integer"); + $mode= 'install'; + } elsif (m/^--remove$/) { + &checkmanymodes; + @ARGV >= 2 || &badusage("--remove needs "); + ($name,$apath,@ARGV) = @ARGV; + $mode= 'remove'; + } elsif (m/^--(display|auto|config)$/) { + &checkmanymodes; + @ARGV || &badusage("--$1 needs "); + $mode= $1; + $name= shift(@ARGV); + } elsif (m/^--slave$/) { + @ARGV >= 3 || &badusage("--slave needs "); + ($slink,$sname,$spath,@ARGV) = @ARGV; + defined($aslavelink{$sname}) && &badusage("slave name $sname duplicated"); + $aslavelinkcount{$slink}++ && &badusage("slave link $slink duplicated"); + $aslavelink{$sname}= $slink; + $aslavepath{$sname}= $spath; + } elsif (m/^--altdir$/) { + @ARGV || &badusage("--altdir needs a argument"); + $altdir= shift(@ARGV); + } elsif (m/^--admindir$/) { + @ARGV || &badusage("--admindir needs a argument"); + $admindir= shift(@ARGV); + } else { + &badusage("unknown option \`$_'"); + } +} + +defined($aslavelink{$name}) && &badusage("name $name is both primary and slave"); +$aslavelinkcount{$alink} && &badusage("link $link is both primary and slave"); + +$mode || &badusage("need --display, --config, --install, --remove or --auto"); +$mode eq 'install' || !%slavelink || &badusage("--slave only allowed with --install"); + +if (open(AF,"$admindir/$name")) { + $manual= &gl("manflag"); + $manual eq 'auto' || $manual eq 'manual' || &badfmt("manflag"); + $link= &gl("link"); + while (($sname= &gl("sname")) ne '') { + push(@slavenames,$sname); + defined($slavenum{$sname}) && &badfmt("duplicate slave $tsname"); + $slavenum{$sname}= $#slavenames; + $slink= &gl("slink"); + $slink eq $link && &badfmt("slave link same as main link $link"); + $slavelinkcount{$slink}++ && &badfmt("duplicate slave link $slink"); + push(@slavelinks,$slink); + } + while (($version= &gl("version")) ne '') { + defined($versionnum{$version}) && &badfmt("duplicate path $tver"); + if ( -e $version ) { + push(@versions,$version); + $versionnum{$version}= $i= $#versions; + $priority= &gl("priority"); + $priority =~ m/^[-+]?\d+$/ || &badfmt("priority $version $priority"); + $priorities[$i]= $priority; + for ($j=0; $j<=$#slavenames; $j++) { + $slavepath{$i,$j}= &gl("spath"); + } + } else { + # File not found - remove + &pr("Alternative for $name points to $version - which wasn't found. Removing from list of alternatives.") + if $verbosemode > 0; + &gl("priority"); + for ($j=0; $j<=$#slavenames; $j++) { + &gl("spath"); + } + } + } + close(AF); + $dataread=1; +} elsif ($! != &ENOENT) { + &quit("failed to open $admindir/$name: $!"); +} + +if ($mode eq 'display') { + if (!$dataread) { + &pr("No alternatives for $name."); + } else { + &pr("$name - status is $manual."); + if (defined($linkname= readlink("$altdir/$name"))) { + &pr(" link currently points to $linkname"); + } elsif ($! == &ENOENT) { + &pr(" link currently absent"); + } else { + &pr(" link unreadable - $!"); + } + $best= ''; + for ($i=0; $i<=$#versions; $i++) { + if ($best eq '' || $priorities[$i] > $bestpri) { + $best= $versions[$i]; $bestpri= $priorities[$i]; + } + &pr("$versions[$i] - priority $priorities[$i]"); + for ($j=0; $j<=$#slavenames; $j++) { + next unless length($tspath= $slavepath{$i,$j}); + &pr(" slave $slavenames[$j]: $tspath"); + } + } + if ($best eq '') { + &pr("No versions available."); + } else { + &pr("Current \`best' version is $best."); + } + } + exit 0; +} + +$best= ''; +for ($i=0; $i<=$#versions; $i++) { + if ($best eq '' || $priorities[$i] > $bestpri) { + $best= $versions[$i]; $bestpri= $priorities[$i]; + } +} + +if ($mode eq 'config') { + if (!$dataread) { + &pr("No alternatives for $name."); + } else { + &config_alternatives($name); + } +} + +if (defined($linkname= readlink("$altdir/$name"))) { + if ($linkname eq $best) { + $state= 'expected'; + } elsif (defined($linkname2= readlink("$altdir/$name.rpm-tmp"))) { + $state= 'expected-inprogress'; + } else { + $state= 'unexpected'; + } +} elsif ($! == &ENOENT) { + $state= 'nonexistent'; +} else { + $state= 'unexpected'; +} + +# Possible values for: +# $manual manual, auto +# $state expected, expected-inprogress, unexpected, nonexistent +# $mode auto, install, remove +# all independent + +if ($mode eq 'auto') { + &pr("Setting up automatic selection of $name.") + if $verbosemode > 0; + unlink("$altdir/$name.rpm-tmp") || $! == &ENOENT || + &quit("unable to remove $altdir/$name.rpm-tmp: $!"); + unlink("$altdir/$name") || $! == &ENOENT || + &quit("unable to remove $altdir/$name.rpm-tmp: $!"); + $state= 'nonexistent'; + $manual= 'auto'; +} elsif ($state eq 'nonexistent') { + if ($manual eq 'manual') { + &pr("$altdir/$name has been deleted, returning to automatic selection.") + if $verbosemode > 0; + $manual= 'auto'; + } +} + +# $manual manual, auto +# $state expected, expected-inprogress, unexpected, nonexistent +# $mode auto, install, remove +# mode=auto <=> state=nonexistent + +if ($state eq 'unexpected' && $manual eq 'auto') { + &pr("$altdir/$name has been changed (manually or by a script).\n". + "Switching to manual updates only.") + if $verbosemode > 0; + $manual= 'manual'; +} + +# $manual manual, auto +# $state expected, expected-inprogress, unexpected, nonexistent +# $mode auto, install, remove +# mode=auto <=> state=nonexistent +# state=unexpected => manual=manual + +&pr("Checking available versions of $name, updating links in $altdir ...\n". + "(You may modify the symlinks there yourself if desired - see \`man ln'.)") + if $verbosemode > 0; + +if ($mode eq 'install') { + if ($link ne $alink && $link ne '') { + &pr("Renaming $name link from $link to $alink.") + if $verbosemode > 0; + rename_mv($link,$alink) || $! == &ENOENT || + &quit("unable to rename $link to $alink: $!"); + } + $link= $alink; + if (!defined($i= $versionnum{$apath})) { + push(@versions,$apath); + $versionnum{$apath}= $i= $#versions; + } + $priorities[$i]= $apriority; + for $sname (keys %aslavelink) { + if (!defined($j= $slavenum{$sname})) { + push(@slavenames,$sname); + $slavenum{$sname}= $j= $#slavenames; + } + $oldslavelink= $slavelinks[$j]; + $newslavelink= $aslavelink{$sname}; + $slavelinkcount{$oldslavelink}-- if $oldslavelink ne ''; + $slavelinkcount{$newslavelink}++ && + &quit("slave link name $newslavelink duplicated"); + if ($newslavelink ne $oldslavelink && $oldslavelink ne '') { + &pr("Renaming $sname slave link from $oldslavelink to $newslavelink.") + if $verbosemode > 0; + rename_mv($oldslavelink,$newslavelink) || $! == &ENOENT || + &quit("unable to rename $oldslavelink to $newslavelink: $!"); + } + $slavelinks[$j]= $newslavelink; + } + for ($j=0; $j<=$#slavenames; $j++) { + $slavepath{$i,$j}= $aslavepath{$slavenames[$j]}; + } +} + +if ($mode eq 'remove') { + if ($manual eq "manual" and $state eq "expected") { + &pr("Removing manually selected alternative - switching to auto mode"); + $manual= "auto"; + } + if (defined($i= $versionnum{$apath})) { + $k= $#versions; + $versionnum{$versions[$k]}= $i; + delete $versionnum{$versions[$i]}; + $versions[$i]= $versions[$k]; $#versions--; + $priorities[$i]= $priorities[$k]; $#priorities--; + for ($j=0; $j<=$#slavenames; $j++) { + $slavepath{$i,$j}= $slavepath{$k,$j}; + delete $slavepath{$k,$j}; + } + } else { + &pr("Alternative $apath for $name not registered, not removing.") + if $verbosemode > 0; + } +} + +for ($j=0; $j<=$#slavenames; $j++) { + for ($i=0; $i<=$#versions; $i++) { + last if $slavepath{$i,$j} ne ''; + } + if ($i > $#versions) { + &pr("Discarding obsolete slave link $slavenames[$j] ($slavelinks[$j]).") + if $verbosemode > 0; + unlink("$altdir/$slavenames[$j]") || $! == &ENOENT || + &quit("unable to remove $slavenames[$j]: $!"); + unlink($slavelinks[$j]) || $! == &ENOENT || + &quit("unable to remove $slavelinks[$j]: $!"); + $k= $#slavenames; + $slavenum{$slavenames[$k]}= $j; + delete $slavenum{$slavenames[$j]}; + $slavelinkcount{$slavelinks[$j]}--; + $slavenames[$j]= $slavenames[$k]; $#slavenames--; + $slavelinks[$j]= $slavelinks[$k]; $#slavelinks--; + for ($i=0; $i<=$#versions; $i++) { + $slavepath{$i,$j}= $slavepath{$i,$k}; + delete $slavepath{$i,$k}; + } + $j--; + } +} + +if ($manual eq 'manual') { + &pr("Automatic updates of $altdir/$name are disabled, leaving it alone.") + if $verbosemode > 0; + &pr("To return to automatic updates use \`update-alternatives --auto $name'.") + if $verbosemode > 0; +} else { + if ($state eq 'expected-inprogress') { + &pr("Recovering from previous failed update of $name ..."); + rename_mv("$altdir/$name.rpm-tmp","$altdir/$name") || + &quit("unable to rename $altdir/$name.rpm-tmp to $altdir/$name: $!"); + $state= 'expected'; + } +} + +# $manual manual, auto +# $state expected, expected-inprogress, unexpected, nonexistent +# $mode auto, install, remove +# mode=auto <=> state=nonexistent +# state=unexpected => manual=manual +# manual=auto => state!=expected-inprogress && state!=unexpected + +open(AF,">$admindir/$name.rpm-new") || + &quit("unable to open $admindir/$name.rpm-new for write: $!"); +&paf($manual); +&paf($link); +for ($j=0; $j<=$#slavenames; $j++) { + &paf($slavenames[$j]); + &paf($slavelinks[$j]); +} +&paf(''); +$best= ''; +for ($i=0; $i<=$#versions; $i++) { + if ($best eq '' || $priorities[$i] > $bestpri) { + $best= $versions[$i]; $bestpri= $priorities[$i]; $bestnum= $i; + } + &paf($versions[$i]); + &paf($priorities[$i]); + for ($j=0; $j<=$#slavenames; $j++) { + &paf($slavepath{$i,$j}); + } +} +&paf(''); +close(AF) || &quit("unable to close $admindir/$name.rpm-new: $!"); + +if ($manual eq 'auto') { + if ($best eq '') { + &pr("Last package providing $name ($link) removed, deleting it.") + if $verbosemode > 0; + unlink("$altdir/$name") || $! == &ENOENT || + &quit("unable to remove $altdir/$name: $!"); + unlink("$link") || $! == &ENOENT || + &quit("unable to remove $altdir/$name: $!"); + unlink("$admindir/$name.rpm-new") || + &quit("unable to remove $admindir/$name.rpm-new: $!"); + unlink("$admindir/$name") || $! == &ENOENT || + &quit("unable to remove $admindir/$name: $!"); + exit(0); + } else { + if (!defined($linkname= readlink($link)) && $! != &ENOENT) { + &pr("warning: $link is supposed to be a symlink to $altdir/$name\n". + " (or nonexistent); however, readlink failed: $!") + if $verbosemode > 0; + } elsif ($linkname ne "$altdir/$name") { + unlink("$link.rpm-tmp") || $! == &ENOENT || + &quit("unable to ensure $link.rpm-tmp nonexistent: $!"); + my_symlink("$altdir/$name","$link.rpm-tmp"); + rename_mv("$link.rpm-tmp",$link) || + &quit("unable to install $link.rpm-tmp as $link: $!"); + } + if (defined($linkname= readlink("$altdir/$name")) && $linkname eq $best) { + &pr("Leaving $name ($link) pointing to $best.") + if $verbosemode > 0; + } else { + &pr("Updating $name ($link) to point to $best.") + if $verbosemode > 0; + } + unlink("$altdir/$name.rpm-tmp") || $! == &ENOENT || + &quit("unable to ensure $altdir/$name.rpm-tmp nonexistent: $!"); + my_symlink($best,"$altdir/$name.rpm-tmp"); + } +} + +rename_mv("$admindir/$name.rpm-new","$admindir/$name") || + &quit("unable to rename $admindir/$name.rpm-new to $admindir/$name: $!"); + +if ($manual eq 'auto') { + rename_mv("$altdir/$name.rpm-tmp","$altdir/$name") || + &quit("unable to install $altdir/$name.rpm-tmp as $altdir/$name"); + for ($j=0; $j<=$#slavenames; $j++) { + $sname= $slavenames[$j]; + $slink= $slavelinks[$j]; + if (!defined($linkname= readlink($slink)) && $! != &ENOENT) { + &pr("warning: $slink is supposed to be a slave symlink to\n". + " $altdir/$sname, or nonexistent; however, readlink failed: $!") + if $verbosemode > 0; + } elsif ($linkname ne "$altdir/$sname") { + unlink("$slink.rpm-tmp") || $! == &ENOENT || + &quit("unable to ensure $slink.rpm-tmp nonexistent: $!"); + my_symlink("$altdir/$sname","$slink.rpm-tmp"); + rename_mv("$slink.rpm-tmp",$slink) || + &quit("unable to install $slink.rpm-tmp as $slink: $!"); + } + $spath= $slavepath{$bestnum,$j}; + unlink("$altdir/$sname.rpm-tmp") || $! == &ENOENT || + &quit("unable to ensure $altdir/$sname.rpm-tmp nonexistent: $!"); + if ($spath eq '') { + &pr("Removing $sname ($slink), not appropriate with $best.") + if $verbosemode > 0; + unlink("$altdir/$sname") || $! == &ENOENT || + &quit("unable to remove $altdir/$sname: $!"); + unlink("$slink") || $! == &ENOENT || + &quit("unable to remove $slink: $!"); + } else { + if (defined($linkname= readlink("$altdir/$sname")) && $linkname eq $spath) { + &pr("Leaving $sname ($slink) pointing to $spath.") + if $verbosemode > 0; + } else { + &pr("Updating $sname ($slink) to point to $spath.") + if $verbosemode > 0; + } + my_symlink("$spath","$altdir/$sname.rpm-tmp"); + rename_mv("$altdir/$sname.rpm-tmp","$altdir/$sname") || + &quit("unable to install $altdir/$sname.rpm-tmp as $altdir/$sname: $!"); + } + } +} + +sub config_message { + if ($#versions == 0) { + print "\nThere is only 1 program which provides $name\n"; + print "($versions[0]). Nothing to configure.\n"; + return; + } + printf(STDOUT "\nThere are %s programs which provide \`$name'.\n\n", $#versions+1); + printf(STDOUT " Selection Command\n"); + printf(STDOUT "-----------------------------------------------\n"); + for ($i=0; $i<=$#versions; $i++) { + printf(STDOUT "%s%s %s %s\n", + (readlink("$altdir/$name") eq $versions[$i]) ? '*' : ' ', + ($best eq $versions[$i]) ? '+' : ' ', + $i+1, $versions[$i]); + } + printf(STDOUT "\nEnter to keep the default[*], or type selection number: "); +} + +sub config_alternatives { + do { + &config_message; + if ($#versions == 0) { return; } + $preferred=; + chop($preferred); + } until $preferred eq '' || $preferred>=1 && $preferred<=$#versions+1 && + ($preferred =~ m/[0-9]*/); + if ($preferred ne '') { + $manual = "manual"; + $preferred--; + print STDOUT "Using \`$versions[$preferred]' to provide \`$name'.\n"; + my $spath = $versions[$preferred]; + my_symlink("$spath","$altdir/$name.rpm-tmp"); + rename_mv("$altdir/$name.rpm-tmp","$altdir/$name") || + &quit("unable to install $altdir/$name.rpm-tmp as $altdir/$name: $!"); + # Link slaves... + for( my $slnum = 0; $slnum < @slavenames; $slnum++ ) { + my $slave = $slavenames[$slnum]; + if ($slavepath{$preferred,$slnum} ne '') { + checked_symlink($slavepath{$preferred,$slnum}, + "$altdir/$slave.rpm-tmp"); + checked_mv("$altdir/$slave.rpm-tmp", "$altdir/$slave"); + } else { + &pr("Removing $slave ($slavelinks[$slnum]), not appropriate with $versions[$preferred].") + if $verbosemode > 0; + unlink("$altdir/$slave") || $! == &ENOENT || + &quit("unable to remove $altdir/$slave: $!"); + } + } + + } +} + +sub pr { print(STDOUT "@_\n") || &quit("error writing stdout: $!"); } +sub paf { + $_[0] =~ m/\n/ && &quit("newlines prohibited in update-alternatives files ($_[0])"); + print(AF "$_[0]\n") || &quit("error writing stdout: $!"); +} +sub gl { + $!=0; $_= ; + length($_) || &quit("error or eof reading $admindir/$name for $_[0] ($!)"); + s/\n$// || &badfmt("missing newline after $_[0]"); + $_; +} +sub badfmt { + &quit("internal error: $admindir/$name corrupt: $_[0]"); +} +sub rename_mv { + return (rename($_[0], $_[1]) || (system(("mv", $_[0], $_[1])) == 0)); +} +sub checked_symlink { + my ($filename, $linkname) = @_; + my_symlink($filename, $linkname); +} + +sub my_symlink { + my ($filename, $linkname) = @_; + local $_ = $linkname; + s|//|/|g; + if ( $_ == "/" ) { + my $relative = $_; + } + else { + my $relative = join('/', ("..") x (split(m|/|) - 2)); + } + symlink($relative.$filename,$linkname) || + &quit("unable to make $linkname a symlink to $relative.$filename: $!"); +} + +sub checked_mv { + my ($source, $dest) = @_; + rename_mv($source, $dest) || + &quit("unable to install $source as $dest: $!"); +} + +exit(0); + +# vim: nowrap ts=8 sw=4 diff --git a/update-alternatives.8 b/update-alternatives.8 new file mode 100644 index 0000000..08f2428 --- /dev/null +++ b/update-alternatives.8 @@ -0,0 +1,362 @@ +.\" update-alternatives.8 +.\" This man page is copyright 1997 Charles Briscoe-Smith +.\" This is free documentation; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published +.\" by the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. There is NO WARRANTY. +.TH UPDATE-ALTERNATIVES 8 "27 January 2001" "ALT Linux Team" "Linux-Mandrake RE" +.SH NAME +update-alternatives \- maintain symbolic links determining default commands +.SH SYNOPSIS +.B update-alternatives +.RI [ options ] +.B --install +.I link name path priority +.RB [ --slave +.I link name +.IR path ]... +.PP +.B update-alternatives +.RI [ options ] +.B --remove +.I name path +.PP +.B update-alternatives +.RI [ options ] +.B --auto +.I name +.PP +.B update-alternatives +.RI [ options ] +.B --display +.I name +.PP +.B update-alternatives +.RI [ options ] +.B --config +.I name +.SH DESCRIPTION +.B update-alternatives +creates, removes, maintains and displays information about the symbolic +links comprising the Linux-Mandrake RE alternatives system. +.PP +It is possible for several programs fulfilling the same or similar +functions to be installed on a single system at the same time. +For example, many systems have several text editors installed at once. +This gives choice to the users of a system, allowing each to use a +different editor, if desired, but makes it difficult for a program +to make a good choice of editor to invoke if the +user has not specified a particular preference. +.PP +The alternatives system aims to solve this problem. +A generic name in the filesystem is +shared by all files providing interchangeable functionality. +The alternatives system and the system administrator +together determine which actual file is referenced by this generic name. +For example, if the text editors +.BR ed (1) +and +.BR nvi (1) +are both installed on the system, the alternatives system will cause +the generic name +.I /usr/bin/editor +to refer to +.I /usr/bin/nvi +by default. The system administrator can override this and cause +it +to refer to +.I /usr/bin/ed +instead, +and the alternatives system will not alter this setting until explicitly +requested to do so. +.PP +The generic name is not a direct symbolic link to the selected alternative. +Instead, it is a symbolic link to a name in the +.I alternatives +.IR directory , +which in turn is a symbolic link to the actual file referenced. +This is done so that the system administrator's changes can be confined +within the +.I /etc +directory: the FHS (q.v.) gives reasons why this is a Good Thing. +.PP +When each package +providing a file with a particular functionality is +installed, changed or removed, +.B update-alternatives +is called to update information about that file in the alternatives system. +.B update-alternatives +is usually called from the +.B post-install +or +.B pre-uninstall +scripts in RPM packages. +.PP +It is often useful for a number of alternatives to be synchronised, +so that they are changed as a group; for example, when several versions +of the +.BR vi (1) +editor are installed, the man page referenced by +.I /usr/share/man/man1/vi.1 +should correspond to the executable referenced by +.IR /usr/bin/vi . +.B update-alternatives +handles this by means of +.I master +and +.I slave +links; when the master is changed, any associated slaves are changed +too. +A master link and its associated slaves make up a +.I link +.IR group . +.PP +Each link group is, at any given time, +in one of two modes: automatic or manual. +When a group is in automatic mode, the alternatives system will +automatically decide, as packages are installed and removed, +whether and how to update the links. +In manual mode, the alternatives system will not change the links; +it will leave all the decisions to the system administrator. +.PP +Link groups are in automatic mode when they are first introduced to +the system. +If the system administrator makes changes to the system's +automatic settings, +this will be noticed the next time +.B update-alternatives +is run on the changed link's group, +and the group will automatically be switched to manual mode. +.PP +Each alternative has a +.I priority +associated with it. +When a link group is in automatic mode, +the alternatives pointed to by members of the group +will be those which have the highest priority. +.PP +When using the +.I --config +option, +.B update-alternatives +will list all of the choices for the link group +of which given +.I name +is the master link. +You will then be prompted for which of the choices to use +for the link group. Once you make a change, the link group will no +longer be in +.I auto +mode. You will need to use the +.I --auto +option in order to return to the automatic state. +.SH TERMINOLOGY +Since the activities of +.B update-alternatives +are quite involved, some specific terms will help to explain its +operation. +.TP +generic name +A name, like +.IR /usr/bin/editor , +which refers, via the alternatives system, to one of a number of +files of similar function. +.TP +symlink +Without any further qualification, this means a symbolic link in the +alternatives directory: one which the system administrator is expected +to adjust. +.TP +alternative +The name of a specific file in the filesystem, which may be made +accessible via a generic name using the alternatives system. +.TP +alternatives directory +A directory, by default +.IR /etc/alternatives , +containing the symlinks. +.TP +administrative directory +A directory, by default +.IR /var/lib/rpm/alternatives , +containing +.BR update-alternatives ' +state information. +.TP +link group +A set of related symlinks, intended to be updated as a group. +.TP +master link +The link in a link group which determines how the other links in the +group are configured. +.TP +slave link +A link in a link group which is controlled by the setting of +the master link. +.TP +automatic mode +When a link group is in automatic mode, +the alternatives system ensures that the links in the group +point to the highest priority alternatives +appropriate for the group. +.TP +manual mode +When a link group is in manual mode, +the alternatives system will not make any changes +to the system administrator's settings. +.SH OPTIONS +Exactly one action must be specified if +.B update-alternatives +is to perform any meaningful task. +Any number of the common options may be specified together with any action. +.SS "COMMON OPTIONS" +.TP +.B --verbose +Generate more comments about what +.B update-alternatives +is doing. +.TP +.B --quiet +Don't generate any comments unless errors occur. +This option is not yet implemented. +.TP +.B --test +Don't actually do anything, just say what would be done. +This option is not yet implemented. +.TP +.B --help +Give some usage information (and say which version of +.B update-alternatives +this is). +.TP +.B --version +Tell which version of +.B update-alternatives +this is (and give some usage information). +.TP +\fB--altdir\fR \fIdirectory\fR +Specifies the alternatives directory, when this is to be +different from the default. +.TP +\fB--admindir\fR \fIdirectory\fR +Specifies the administrative directory, when this is to be +different from the default. +.SS ACTIONS +.\" The names of the arguments should be identical with the ones +.\" in SYNOPSIS section. +.TP +\fB--install\fR \fIlink gen path pri\fR [\fB--slave\fR \fIslink sgen spath\fR] ... +Add a group of alternatives to the system. +.I gen +is the generic name for the master link, +.I link +is the name of its symlink, and +.I path +is the alternative being introduced for the master link. +.IR sgen , +.I slink +and +.I spath +are the generic name, symlink name and alternative +for a slave link. +Zero or more +.B --slave +options, each followed by three arguments, +may be specified. +.IP +If the master symlink specified exists already +in the alternatives system's records, +the information supplied will be added as a new +set of alternatives for the group. +Otherwise, a new group, set to automatic mode, +will be added with this information. +If the group is in automatic mode, +and the newly added alternatives' priority is higher than +any other installed alternatives for this group, +the symlinks will be updated to point to the newly added alternatives. +.TP +\fB--remove\fR \fIname path\fR +Remove an alternative and all of its associated slave links. +.I name +is a name in the alternatives directory, and +.I path +is an absolute filename to which +.I name +could be linked. If +.I name +is indeed linked to +.IR path , +.I name +will be updated to point to another appropriate alternative, or +removed if there is no such alternative left. +Associated slave links will be updated or removed, correspondingly. +If the link is not currently pointing to +.IR path , +no links are changed; +only the information about the alternative is removed. +.TP +\fB--auto\fR \fIlink\fR +Switch the master symlink +.I link +to automatic mode. +In the process, this symlink and its slaves are updated +to point to the highest priority installed alternatives. +.TP +\fB--display\fR \fIlink\fR +Display information about the link group of which +.I link +is the master link. +Information displayed includes the group's mode +(auto or manual), +which alternative the symlink currently points to, +what other alternatives are available +(and their corresponding slave alternatives), +and the highest priority alternative currently installed. +.SH FILES +.TP +.I /etc/alternatives/ +The default alternatives directory. +Can be overridden by the +.B --altdir +option. +.TP +.I /var/lib/rpm/alternatives/ +The default administration directory. +Can be overridden by the +.B --admindir +option. +.SH "EXIT STATUS" +.IP 0 +The requested action was successfully performed. +.IP 2 +Problems were encountered whilst parsing the command line +or performing the action. +.SH DIAGNOSTICS +.B update-alternatives +chatters incessantly about its activities on its standard output channel. +If problems occur, +.B update-alternatives +outputs error messages on its standard error channel and +returns an exit status of 2. +These diagnostics should be self-explanatory; +if you do not find them so, please report this as a bug. +.SH BUGS +If you find a bug, please report it using the Linux-Mandrake RE bug-tracking system, +or, if that is not possible, email the author directly. +.PP +If you find any discrepancy between the operation of +.B update-alternatives +and this manual page, it is a bug, +either in the implementation or the documentation; please report it. +.SH AUTHOR +The update-alternatives system, based on Debian update-alternatives, +is copyright 1995 Ian Jackson. +It is free software; see the GNU General Public Licence +version 2 or later for copying conditions. There is NO warranty. +.PP +This manual page is copyright 1997/98 Charles Briscoe-Smith. +This is free documentation; see the GNU General Public Licence +version 2 or later for copying conditions. There is NO WARRANTY. +.SH "SEE ALSO" +.BR ln (1), +FHS, the Filesystem Hierarchy Standard.