You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1157 lines
39 KiB
1157 lines
39 KiB
#!/bin/sh |
|
## |
|
## rpmtool -- RPM Auxiliary Tool |
|
## Copyright (c) 2000-2001 Ralf S. Engelschall <rse@engelschall.com> |
|
## |
|
## Permission to use, copy, modify, and distribute this software for |
|
## any purpose with or without fee is hereby granted, provided that |
|
## the above copyright notice and this permission notice appear in all |
|
## copies. |
|
## |
|
## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
|
## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR |
|
## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
|
## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
## SUCH DAMAGE. |
|
## |
|
|
|
prog_name="rpmtool" |
|
prog_vers="1.0.2" |
|
prog_date="03-Aug-2001" |
|
|
|
if [ $# -eq 0 ]; then |
|
echo "$0:Error: invalid command line" 1>&2 |
|
echo "$0:Hint: run \`$0 -h' for usage" 1>&2 |
|
exit 1 |
|
fi |
|
if [ ".$1" = ".-h" -o ".$1" = ".--help" ]; then |
|
echo "This is $prog_name, version $prog_vers ($prog_date)" |
|
echo "Copyright (c) 2000-2001 Ralf S. Engelschall <rse@engelschall.com>" |
|
echo '' |
|
echo "Usage: $prog_name [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]" |
|
echo '' |
|
echo 'Available global <options>:' |
|
echo ' -d, --debug enable internal debugging' |
|
echo ' -v, --version display version information' |
|
echo ' -h, --help display usage help page (this one)' |
|
echo '' |
|
echo 'Available <cmd-name> [<cmd-options>] [<cmd-args>]:' |
|
echo ' platform' |
|
echo ' subst [-v] [-t] [-s] <sed-cmd> [...] -- <file> [...]' |
|
echo ' flags [-m] [-c] [-O] <tool>' |
|
echo ' files [-v] [-o <outfile>] [-r <buildroot>] [<filelist>]' |
|
echo ' user [-c] [-d] [-p <passwd>] [-n <realname>] [-d <homedir>]' |
|
echo ' [-s <shell>] [-u <min-uid>] <username>' |
|
echo ' group [-c] [-d] <groupname> <min-gid> [<username> ...]' |
|
echo ' signal [-v] [-t] [-n] [-c] [-d <delay>] [-p <pid>] [-m <pattern>] <sig> [<sig> ...]' |
|
echo ' config [-v] [-s] [-a] [-r] [-b <ext>] [-p <tagprefix>] [-t <tagname>] [-i <tagid>] <file>' |
|
echo '' |
|
exit 0 |
|
fi |
|
if [ ".$1" = ".-v" -o ".$1" = ."--version" ]; then |
|
echo "$prog_name $prog_vers ($prog_date)" |
|
exit 0 |
|
fi |
|
if [ ".$1" = ".-d" -o ".$1" = ."--debug" ]; then |
|
shift |
|
set -x |
|
fi |
|
|
|
tool="$1" |
|
shift |
|
arg_spec="" |
|
opt_spec="" |
|
gen_tmpfile=no |
|
|
|
# configure tool specific option parsing |
|
case $tool in |
|
platform ) |
|
str_usage="" |
|
arg_spec="0=" |
|
opt_spec="" |
|
;; |
|
subst ) |
|
str_usage="[-v] [-t] [-s] <sed-cmd> [...] -- <file> [...]" |
|
arg_spec="3+" |
|
opt_spec="v.t.s." |
|
opt_v=no |
|
opt_t=no |
|
opt_s=no |
|
gen_tmpfile=yes |
|
;; |
|
flags ) |
|
str_usage="[-m] [-c] [-O] <tool>" |
|
arg_spec="1=" |
|
opt_spec="m.c.O." |
|
opt_m=no |
|
opt_c=no |
|
opt_O=no |
|
;; |
|
files ) |
|
gen_tmpfile=yes |
|
str_usage="[-v] [-o <outfile>] [-r <buildroot>] [<filelist>]" |
|
arg_spec="0+" |
|
opt_spec="v.o:r:" |
|
opt_v=no |
|
opt_o='' |
|
opt_r='' |
|
;; |
|
user ) |
|
str_usage="[-a] [-r] [-p <passwd>] [-n <realname>] [-d <homedir>] [-s <shell>] [-u <min-uid>] <username>" |
|
arg_spec="1=" |
|
opt_spec="a.r.p:n:d:s:u:" |
|
opt_a=no |
|
opt_r=no |
|
opt_p='' |
|
opt_n='' |
|
opt_d='' |
|
opt_s='' |
|
opt_u=1000 |
|
;; |
|
group ) |
|
str_usage="[-a] [-r] [-g <min-gid>] <groupname> [<username> ...]" |
|
arg_spec="1+" |
|
opt_spec="a.r.g:" |
|
opt_a=no |
|
opt_r=no |
|
opt_g=1000 |
|
;; |
|
signal ) |
|
str_usage="[-v] [-t] [-n] [-c] [-d <delay>] [-p <pid>] [-m <pattern>] <sig> [<sig> ...]" |
|
arg_spec="1+" |
|
opt_spec="v.t.n.c.d:p:m:" |
|
opt_v=no |
|
opt_t=no |
|
opt_n=no |
|
opt_c=no |
|
opt_d=1 |
|
opt_p="" |
|
opt_m="" |
|
;; |
|
config ) |
|
str_usage="[-v] [-s] [-a] [-r] [-b <ext>] [-p <tagprefix>] [-t <tagname>] [-i <tagid>] <file>" |
|
arg_spec="1=" |
|
opt_spec="v.s.a.r.b:p:t:i:c:" |
|
opt_v=no |
|
opt_s=no |
|
opt_a=no |
|
opt_r=no |
|
opt_b="" |
|
opt_p="#" |
|
opt_t="OpenPKG" |
|
opt_i="" |
|
gen_tmpfile=yes |
|
;; |
|
|
|
-* ) |
|
echo "$prog_name:Error: unknown option \`$tool'" 2>&1 |
|
echo "$prog_name:Hint: run \`$0 -h' for usage" 2>&1 |
|
exit 1 |
|
;; |
|
* ) |
|
echo "$prog_name:Error: unknown command \`$tool'" 2>&1 |
|
echo "$prog_name:Hint: run \`$0 -h' for usage" 2>&1 |
|
exit 1 |
|
;; |
|
esac |
|
|
|
# tool information |
|
toolcmd="$0 $tool" |
|
toolcmdhelp="$prog_name $tool" |
|
msgprefix="$prog_name:$tool" |
|
|
|
# parse argument specification string |
|
eval `echo $arg_spec |\ |
|
sed -e 's/^\([0-9]*\)\([+=]\)/arg_NUMS=\1; arg_MODE=\2/'` |
|
|
|
# parse option specification string |
|
eval `echo h.$opt_spec |\ |
|
sed -e 's/\([a-zA-Z0-9]\)\([.:+]\)/opt_MODE_\1=\2;/g'` |
|
|
|
# interate over argument line |
|
opt_PREV='' |
|
while [ $# -gt 0 ]; do |
|
# special option stops processing |
|
if [ ".$1" = ".--" ]; then |
|
shift |
|
break |
|
fi |
|
|
|
# determine option and argument |
|
opt_ARG_OK=no |
|
if [ ".$opt_PREV" != . ]; then |
|
# merge previous seen option with argument |
|
opt_OPT="$opt_PREV" |
|
opt_ARG="$1" |
|
opt_ARG_OK=yes |
|
opt_PREV='' |
|
else |
|
# split argument into option and argument |
|
case "$1" in |
|
-[a-zA-Z0-9]*) |
|
eval `echo "x$1" |\ |
|
sed -e 's/^x-\([a-zA-Z0-9]\)/opt_OPT="\1";/' \ |
|
-e 's/";\(.*\)$/"; opt_ARG="\1"/'` |
|
;; |
|
-[a-zA-Z0-9]) |
|
opt_OPT=`echo "x$1" | cut -c3-` |
|
opt_ARG='' |
|
;; |
|
*) |
|
break |
|
;; |
|
esac |
|
fi |
|
|
|
# eat up option |
|
shift |
|
|
|
# determine whether option needs an argument |
|
eval "opt_MODE=\$opt_MODE_${opt_OPT}" |
|
if [ ".$opt_ARG" = . -a ".$opt_ARG_OK" != .yes ]; then |
|
if [ ".$opt_MODE" = ".:" -o ".$opt_MODE" = ".+" ]; then |
|
opt_PREV="$opt_OPT" |
|
continue |
|
fi |
|
fi |
|
|
|
# process option |
|
case $opt_MODE in |
|
'.' ) |
|
# boolean option |
|
eval "opt_${opt_OPT}=yes" |
|
;; |
|
':' ) |
|
# option with argument (multiple occurances override) |
|
eval "opt_${opt_OPT}=\"\$opt_ARG\"" |
|
;; |
|
'+' ) |
|
# option with argument (multiple occurances append) |
|
eval "opt_${opt_OPT}=\"\$opt_${opt_OPT} \$opt_ARG\"" |
|
;; |
|
* ) |
|
echo "$msgprefix:Error: unknown option: \`-$opt_OPT'" 1>&2 |
|
echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man $prog_name' for details" 1>&2 |
|
exit 1 |
|
;; |
|
esac |
|
done |
|
if [ ".$opt_PREV" != . ]; then |
|
echo "$msgprefix:Error: missing argument to option \`-$opt_PREV'" 1>&2 |
|
echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man $prog_name' for details" 1>&2 |
|
exit 1 |
|
fi |
|
|
|
# process help option |
|
if [ ".$opt_h" = .yes ]; then |
|
echo "Usage: $toolcmdhelp $str_usage" |
|
exit 0 |
|
fi |
|
|
|
# complain about incorrect number of arguments |
|
case $arg_MODE in |
|
'=' ) |
|
if [ $# -ne $arg_NUMS ]; then |
|
echo "$msgprefix:Error: invalid number of arguments (exactly $arg_NUMS expected)" 1>&2 |
|
echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man $prog_name' for details" 1>&2 |
|
exit 1 |
|
fi |
|
;; |
|
'+' ) |
|
if [ $# -lt $arg_NUMS ]; then |
|
echo "$msgprefix:Error: invalid number of arguments (at least $arg_NUMS expected)" 1>&2 |
|
echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man $prog_name' for details" 1>&2 |
|
exit 1 |
|
fi |
|
;; |
|
esac |
|
|
|
# establish a temporary file on request |
|
if [ ".$gen_tmpfile" = .yes ]; then |
|
if [ ".$TMPDIR" != . ]; then |
|
tmpdir="$TMPDIR" |
|
elif [ ".$TEMPDIR" != . ]; then |
|
tmpdir="$TEMPDIR" |
|
else |
|
tmpdir="/tmp" |
|
fi |
|
tmpfile="$tmpdir/.$prog_name.$$" |
|
rm -f $tmpfile >/dev/null 2>&1 |
|
touch $tmpfile |
|
fi |
|
|
|
# provide a few useful variables |
|
NL=" |
|
" |
|
TAB=" " |
|
DIFS=" ${TAB}${NL}" |
|
|
|
# determine platform information |
|
platform_machine=`(uname -m) 2>/dev/null` ||\ |
|
platform_machine=`(uname -p) 2>/dev/null` ||\ |
|
platform_machine='unknown' |
|
platform_release=`(uname -r) 2>/dev/null` ||\ |
|
platform_release='unknown' |
|
platform_system=`(uname -s) 2>/dev/null` ||\ |
|
platform_system='unknown' |
|
platform_version=`(uname -v) 2>/dev/null` ||\ |
|
platform_version='unknown' |
|
platform="${platform_machine}:${platform_system}:${platform_release}:${platform_version}" |
|
|
|
# dispatch into tools |
|
case $tool in |
|
platform ) |
|
# provide unique platform id |
|
m=`echo "$platform_machine" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` |
|
s=`echo "$platform_system" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` |
|
r=`echo "$platform_release" | sed -e 's;-.*$;;'` |
|
echo "${m}-${s}${r}" |
|
;; |
|
|
|
subst ) |
|
# substitute variables (in-place) |
|
ops="" |
|
files="" |
|
isop=1 |
|
for arg |
|
do |
|
if [ ".$arg" = ".--" ]; then |
|
isop=0 |
|
continue |
|
fi |
|
if [ ".$isop" = .1 ]; then |
|
ops="$ops%$arg" |
|
else |
|
files="$files%$arg" |
|
fi |
|
done |
|
cmd='sed' |
|
OIFS="$IFS"; IFS="%" |
|
for op in $ops; do |
|
test ".$op" = . && continue |
|
cmd="$cmd -e '$op'" |
|
done |
|
IFS="$OIFS" |
|
for file in `IFS="%"; echo $files`; do |
|
test ".$file" = . && continue |
|
if [ ! -f $file ]; then |
|
echo "$msgprefix:Warning: file \`$file' not found" 1>&2 |
|
continue |
|
fi |
|
if [ ".$opt_v" = .yes ]; then |
|
echo "patching file \`$file'" 1>&2 |
|
fi |
|
if [ ".$opt_t" = .yes ]; then |
|
echo "\$ cp -p $file $file.orig" |
|
echo "\$ $cmd <$file.orig >$file" |
|
fi |
|
cp -p $file $file.orig |
|
eval "$cmd <$file.orig >$file" |
|
if [ ".$opt_s" = .yes ]; then |
|
if [ ".$opt_t" = .yes ]; then |
|
echo "\$ touch -r $file.orig $file" |
|
fi |
|
touch -r $file.orig $file |
|
fi |
|
done |
|
;; |
|
|
|
flags ) |
|
tool="$1" |
|
if [ ".$opt_m" = .yes ]; then |
|
isgmake=no |
|
if [ ".`$tool -v 2>/dev/null | grep 'GNU Make'`" != . ]; then |
|
isgmake=yes |
|
fi |
|
mflags='' |
|
if [ ".$isgmake" = .yes ]; then |
|
mflags="--no-print-directory" |
|
fi |
|
if [ ".$opt_O" = .yes ]; then |
|
case $platform in |
|
*:SunOS:5.*:* | *:OSF1:*:* ) |
|
if [ ".$isgmake" = .yes ]; then |
|
n=`(/bin/uname -X) 2>/dev/null | grep -i NumCPU | awk '{ print $3; }'` |
|
if [ ".$n" != . ]; then |
|
if [ $n -gt 1 ]; then |
|
n=`expr $n \* 2` |
|
mflags="$mflags -j$n" |
|
fi |
|
fi |
|
fi |
|
;; |
|
*:FreeBSD:4.*:* ) |
|
n=`/sbin/sysctl hw.ncpu | awk '{ print $2; }'` |
|
if [ ".$n" != . ]; then |
|
if [ $n -gt 1 ]; then |
|
n=`expr $n \* 2` |
|
mflags="$mflags -j$n" |
|
if [ ".$isgmake" = .no ]; then |
|
mflags="$mflags -B" |
|
fi |
|
fi |
|
fi |
|
;; |
|
*:NetBSD:1.5*:* ) |
|
n=`/sbin/sysctl hw.ncpu | awk '{ print $3; }'` |
|
if [ ".$n" != . ]; then |
|
if [ $n -gt 1 ]; then |
|
n=`expr $n \* 2` |
|
mflags="$mflags -j$n" |
|
if [ ".$isgmake" = .no ]; then |
|
mflags="$mflags -B" |
|
fi |
|
fi |
|
fi |
|
;; |
|
*:Linux:*:* ) |
|
n=`cat /proc/cpuinfo | grep processor | wc -l | awk '{ print $1; }'` |
|
if [ ".$n" != . ]; then |
|
if [ $n -gt 1 ]; then |
|
n=`expr $n \* 2` |
|
mflags="$mflags -j$n" |
|
fi |
|
fi |
|
;; |
|
*:HP-UX:*:* ) |
|
n=1 # FIXME |
|
;; |
|
esac |
|
fi |
|
echo "$mflags" |
|
elif [ ".$opt_c" = .yes ]; then |
|
isgcc=no |
|
if [ ".`$tool --version 2>/dev/null | egrep '(2.[789]|3.[01])'`" != . ]; then |
|
isgcc=yes |
|
fi |
|
cflags='' |
|
if [ ".$opt_O" = .yes ]; then |
|
if [ ".$isgcc" = .yes ]; then |
|
cflags="-O2 -pipe" |
|
else |
|
cflags="-O" |
|
fi |
|
fi |
|
echo "$cflags" |
|
fi |
|
;; |
|
|
|
files ) |
|
# if a Perl interpreter is available, we perform the operation |
|
# with it because Perl is a magnitude (factor 10!) faster than |
|
# what we can do here in Bourne-Shell. |
|
perl='' |
|
for dir in `echo $PATH | sed -e 's/:/ /g'` .; do |
|
for tool in perl5 perl miniperl; do |
|
if [ -f "$dir/$tool" ]; then |
|
perl="$dir/$tool" |
|
break |
|
fi |
|
done |
|
if [ ".$perl" != . ]; then |
|
break |
|
fi |
|
done |
|
if [ ".$perl" != . ]; then |
|
cat >$tmpfile <<'EOT' |
|
## |
|
## PERL IMPLEMENTATION (FAST) |
|
## |
|
|
|
my $opt_v = 0; |
|
my $opt_o = ''; |
|
my $opt_r = ''; |
|
while ($ARGV[0] =~ m|^-(.)(.*)$|) { |
|
my ($opt, $arg) = ($1, $2); |
|
shift(@ARGV); |
|
unshift(@ARGV, $arg) if ($arg ne ''); |
|
$opt_v = 1 if ($opt eq 'v'); |
|
$opt_o = shift(@ARGV) if ($opt eq 'o'); |
|
$opt_r = shift(@ARGV) if ($opt eq 'r'); |
|
} |
|
|
|
# remember the build root in a reasonable short variable ;) |
|
my $br = "$opt_r"; |
|
|
|
# read input file list |
|
my @L = (); |
|
if ($#ARGV == -1 or ($#ARGV == 0 and $ARGV[0] eq "-")) { |
|
# read file list from stdin |
|
while (<STDIN>) { |
|
s/\n$//s; |
|
push(@L, $_); |
|
} |
|
} |
|
else { |
|
# read file list from argument line |
|
@L = @ARGV; |
|
} |
|
|
|
# PASS 1: PREPARATION AND SYNTACTICAL EXPANSION |
|
if ($opt_v == 1) { |
|
print STDERR "rpmtool:files: pass 1 (preparation and syntactical expansions)\n"; |
|
} |
|
my @T = (); |
|
my $l; |
|
foreach $l (@L) { |
|
# replace tabs with spaces, reduce multiple spaces to single |
|
# spaces, and remove leading and trailing spaces |
|
$l =~ s|[ \t\n]+| |sg; |
|
$l =~ s|^[ \t]+||sg; |
|
$l =~ s|[ \t]+$||sg; |
|
|
|
# move tags to end of entry for easier parsing |
|
1 while ($l =~ s|^(%\S+) (.+)|$2 $1|); |
|
|
|
# use `:' as a dummy path for tag-only entries (like `%defattr') |
|
# to avoid special cases in the later processing |
|
if ($l =~ m|^%.+|) { |
|
$l = ": $l"; |
|
} |
|
|
|
# split entry into path and optional tags |
|
my ($p, $t) = ($l =~ m|^(\S+)(.*)$|); |
|
|
|
# expand `{foo,bar,quux}' constructs in path (silent |
|
# assumtion to make life easier is that the constructs |
|
# occurs only once in a path!) |
|
if ($p =~ m|^(.*)\{([^\}]+)\}(.*)$|) { |
|
# split path into prolog, the set construct, and the epilog |
|
my ($pro, $set, $epi) = ($1, $2, $3); |
|
|
|
# repeat prolog and epilog for all elements in set |
|
my $x; |
|
foreach $x (split(/,/, $set)) { |
|
push(@T, "${pro}${x}${epi}${t}"); |
|
} |
|
} |
|
else { |
|
# else just take over the entry as is |
|
push(@T, $l); |
|
} |
|
} |
|
@L = @T; |
|
|
|
# PASS 2: FILESYSTEM-BASED EXPANSIONS |
|
if ($opt_v == 1) { |
|
print STDERR "rpmtool:files: pass 2 (filesystem-based expansions)\n"; |
|
} |
|
@T = (); |
|
foreach $l (@L) { |
|
# split entry into path and optional tags |
|
my ($p, $t) = ($l =~ m|^(\S*)(.*)$|); |
|
|
|
# expand... |
|
if (-d "$br$p" and $t !~ m|.*%dir.*|) { |
|
# expand path because it is not tagged with %dir |
|
my @X = `cd "$br$p" && find . -print`; |
|
my $x; |
|
foreach $x (@X) { |
|
$x =~ s|\n$||s; |
|
$x =~ s|^\.|$p|s; |
|
push(@T, "${x}${t}"); |
|
} |
|
} |
|
else { |
|
# expand path wildcards (`*' and `[..]') |
|
# (if not wildcards are present, this doesn't harm) |
|
my @X = glob("$br$p"); |
|
my $x; |
|
foreach $x (@X) { |
|
my $brqm = quotemeta($br); |
|
$x =~ s|^$brqm||s; |
|
push(@T, "${x}${t}"); |
|
} |
|
} |
|
} |
|
@L = @T; |
|
|
|
# PASS 3: DUPLICATION REMOVAL AND CLEANUP |
|
if ($opt_v == 1) { |
|
print STDERR "rpmtool:files: pass 3 (duplication removal and cleanup)\n"; |
|
} |
|
@T = (); |
|
foreach $l (@L) { |
|
# split entry into path and optional tags |
|
my ($p, $t) = ($l =~ m|^(\S*)(.*)$|); |
|
|
|
# add %dir tag if entry is a directory, but still not |
|
# tagged as such (else RPM would again expand it recursively) |
|
if (-d "$br$p") { |
|
if ($t !~ m|%dir|) { |
|
$t .= " %dir"; |
|
} |
|
} |
|
|
|
# remove duplicate entries in already processed part |
|
# (but make sure we keep the entries with the dummy tags) |
|
if ($p ne ":") { |
|
my @T2 = (); |
|
foreach $t (@T) { |
|
my $pqm = quotemeta($p); |
|
next if ($t =~ m|^$pqm | or $t eq $p); |
|
push(@T2, $t); |
|
} |
|
@T = @T2; |
|
} |
|
|
|
# keep entry only if no %not tag is present |
|
# (else all entries are removed) |
|
if ($t !~ m|.*%not.*|) { |
|
push(@T, "${p}${t}"); |
|
} |
|
} |
|
@L = @T; |
|
|
|
# write out new file list |
|
@T = (); |
|
foreach $l (@L) { |
|
$l =~ s|^(\S+) (.*)$|$2 $1|sg; |
|
$l =~ s|^\s+||s; |
|
$l =~ s|\s+$||s; |
|
$l =~ s|\s+:$||s; |
|
push(@T, $l); |
|
} |
|
@L = @T; |
|
if ($opt_o eq '' or $opt_o eq '-') { |
|
print STDOUT join("\n", @L)."\n"; |
|
} |
|
else { |
|
open(FP, ">$opt_o"); |
|
print FP join("\n", @L)."\n"; |
|
close(FP); |
|
} |
|
EOT |
|
cmd="$perl $tmpfile"; |
|
if [ ".$opt_v" = .yes ]; then |
|
cmd="$cmd -v" |
|
fi |
|
if [ ".$opt_o" != . ]; then |
|
cmd="$cmd -o \"$opt_o\"" |
|
fi |
|
if [ ".$opt_r" != . ]; then |
|
cmd="$cmd -r \"$opt_r\"" |
|
fi |
|
for arg |
|
do |
|
cmd="$cmd \"$arg\"" |
|
done |
|
eval $cmd |
|
else |
|
## |
|
## BOURNE-SHELL IMPLEMENTATION (PORTABLE) |
|
## |
|
|
|
# remember the build root in a reasonable short variable ;) |
|
br="$opt_r" |
|
|
|
# make sure filename expansion is disabled per default |
|
set -f |
|
|
|
# read input file list |
|
L='' |
|
if [ $# -eq 0 ] || [ $# -eq 1 -a ".$1" = ".-" ]; then |
|
# read file list from stdin |
|
L=`cat` |
|
else |
|
# read file list from argument line |
|
for arg |
|
do |
|
L="$L$NL$arg" |
|
done |
|
fi |
|
|
|
# PASS 1: PREPARATION AND SYNTACTICAL EXPANSION |
|
if [ ".$opt_v" = .yes ]; then |
|
echo "rpmtool:files: pass 1 (preparation and syntactical expansions)" 1>&2 |
|
fi |
|
T='' |
|
OIFS="$IFS"; IFS="$NL" |
|
for l in $L; do |
|
[ ".$l" = . ] && continue |
|
|
|
# replace tabs with spaces, reduce multiple spaces to single |
|
# spaces, and remove leading and trailing spaces |
|
l=`echo "$l" | sed -e "s;${TAB}; ;g" -e 's; *; ;g' -e 's;^ *;;' -e 's; *$;;'` |
|
|
|
# move tags to end of entry for easier parsing |
|
while [ ".`echo \"$l\" | grep '^%[^ ]* .*'`" != . ]; do |
|
l=`echo "$l" | sed -e 's;^\(%[^ ]*\) \(.*\);\2 \1;'` |
|
done |
|
|
|
# use `:' as a dummy path for tag-only entries (like `%defattr') |
|
# to avoid special cases in the later processing |
|
if [ ".`echo \"$l\" | grep '^%.*'`" != . ]; then |
|
l=": $l" |
|
fi |
|
|
|
# split entry into path and optional tags |
|
eval `echo ".$l" | sed -e 's;^\.\([^ ]*\)\(.*\)$;p="\1" t="\2";'` |
|
|
|
# expand `{foo,bar,quux}' constructs in path (silent |
|
# assumtion to make life easier is that the constructs |
|
# occurs only once in a path!) |
|
if [ ".`echo \".$p\" | grep '^\..*{[^}]*}.*$'`" != . ]; then |
|
|
|
# split path into prolog, the set construct, and the epilog |
|
eval `echo ".$p" | sed -e 's;^\.\(.*\){\([^}]*\)}\(.*\)$;pro="\1" set="\2" epi="\3";'` |
|
|
|
# repeat prolog and epilog for all elements in set |
|
OIFS2="$IFS"; IFS="," |
|
for x in $set; do |
|
T="$T$NL${pro}${x}${epi}${t}" |
|
done |
|
IFS="$OIFS2" |
|
else |
|
# else just take over the entry as is |
|
T="$T$NL$l" |
|
fi |
|
done |
|
L="$T" |
|
IFS="$OIFS" |
|
|
|
# PASS 2: FILESYSTEM-BASED EXPANSIONS |
|
if [ ".$opt_v" = .yes ]; then |
|
echo "rpmtool:files: pass 2 (filesystem-based expansions)" 1>&2 |
|
fi |
|
T='' |
|
OIFS="$IFS"; IFS="$NL" |
|
for l in $L; do |
|
[ ".$l" = . ] && continue |
|
|
|
# split entry into path and optional tags |
|
eval `echo ".$l" | sed -e 's;^\.\([^ ]*\)\(.*\)$;p="\1" t="\2";'` |
|
|
|
# expand... |
|
if [ -d "$br$p" -a ".`expr \".$t\" : '\..*%dir.*'`" = .0 ]; then |
|
# expand path because it is not tagged with %dir |
|
OIFS2="$IFS"; IFS="$DIFS" |
|
for x in `cd "$br$p" && find . -print | sed -e "s;^\\.;$p;"`; do |
|
T="$T$NL${x}${t}" |
|
done |
|
IFS="$OIFS2" |
|
else |
|
# expand path wildcards (`*' and `[..]') |
|
# (if not wildcards are present, this doesn't harm) |
|
OIFS2="$IFS"; IFS="$DIFS" |
|
for x in `(set +f; echo $br$p) | sed -e "s;^$br;;" -e "s; $br; ;g"`; do |
|
T="$T$NL${x}${t}" |
|
done |
|
IFS="$OIFS2" |
|
fi |
|
done |
|
IFS="$OIFS" |
|
L="$T" |
|
|
|
# PASS 3: DUPLICATION REMOVAL AND CLEANUP |
|
if [ ".$opt_v" = .yes ]; then |
|
echo "rpmtool:files: pass 3 (duplication removal and cleanup)" 1>&2 |
|
fi |
|
T='' |
|
OIFS="$IFS"; IFS="$NL" |
|
for l in $L; do |
|
[ ".$l" = . ] && continue |
|
|
|
# split entry into path and optional tags |
|
eval `echo ".$l" | sed -e 's;^\.\([^ ]*\)\(.*\)$;p="\1" t="\2";'` |
|
|
|
# add %dir tag if entry is a directory, but still not |
|
# tagged as such (else RPM would again expand it recursively) |
|
if [ -d "$br$p" ]; then |
|
if [ ".`expr \".$t\" : '\..*%dir.*'`" = .0 ]; then |
|
t="$t %dir" |
|
fi |
|
fi |
|
|
|
# remove duplicate entries in already processed part |
|
# (but make sure we keep the entries with the dummy tags) |
|
if [ ".$p" != ".:" ]; then |
|
T=`echo "$T" | grep -v "^$p " | grep -v "^$p\$"` |
|
fi |
|
|
|
# keep entry only if no %not tag is present |
|
# (else all entries are removed) |
|
if [ ".`expr \".$t\" : '\..*%not.*'`" = .0 ]; then |
|
T="$T$NL${p}${t}" |
|
fi |
|
done |
|
IFS="$OIFS" |
|
L="$T" |
|
|
|
# write out new file list |
|
if [ ".$opt_o" = . -o ".$opt_o" = ".-" ]; then |
|
outcmd="cat" |
|
else |
|
outcmd="cat > $opt_o" |
|
fi |
|
echo "$L" |\ |
|
sed -e '/^$/d' \ |
|
-e 's;^\([^ ]*\) *\(.*\)$;\2 \1;g' \ |
|
-e 's;^ *;;' \ |
|
-e 's; *$;;' \ |
|
-e 's; *:$;;' | eval $outcmd |
|
fi |
|
;; |
|
|
|
user ) |
|
# calling convention |
|
if [ ".$opt_a" = .no -a ".$opt_r" = .no ]; then |
|
echo "$msgprefix:Error: either -a or -r has to be given" 1>&2 |
|
exit 1 |
|
fi |
|
if [ ".$opt_a" = .yes -a ".$opt_r" = .yes ]; then |
|
echo "$msgprefix:Error: only -a or -r can be given" 1>&2 |
|
exit 1 |
|
fi |
|
user=$1 |
|
|
|
# default values |
|
if [ ".$opt_n" = . ]; then |
|
opt_n="$user" |
|
fi |
|
if [ ".$opt_s" = . ]; then |
|
opt_s=`which false 2>/dev/null` |
|
if [ ".$opt_s" = . ]; then |
|
opt_s="/bin/false" |
|
fi |
|
fi |
|
if [ ".$opt_d" = . ]; then |
|
opt_d="/nowhere" |
|
fi |
|
|
|
# add user |
|
if [ ".$opt_a" = .yes ]; then |
|
exists=`grep "^$user:" /etc/passwd` |
|
if [ ".$exists" != . ]; then |
|
echo "$msgprefix:Error: user $user already exists" 1>&2 |
|
exit 1 |
|
fi |
|
|
|
# seek for next free uid |
|
uid=$opt_u |
|
ok=0 |
|
while [ ".$ok" = .0 ]; do |
|
u_exists=`grep "^[^:]*:[^:]*:$uid:" /etc/passwd` |
|
g_exists=`grep "^[^:]*:[^:]*:$uid:" /etc/group` |
|
if [ ".$u_exists" = . -a ".$g_exists" = . ]; then |
|
ok=1 |
|
break |
|
fi |
|
uid=`expr $uid + 1` |
|
done |
|
|
|
# add entry to passwd database |
|
case "$platform" in |
|
*:FreeBSD:[456].*:* | *:NetBSD:1.*:* ) |
|
echo "${user}:*:${uid}:${uid}::0:0:${opt_n}:${opt_d}:${opt_s}" >>/etc/master.passwd |
|
(PATH="$PATH:/usr/sbin"; pwd_mkdb -p /etc/master.passwd) |
|
;; |
|
*:Linux:2.*:* ) |
|
echo "${user}:*:${uid}:${uid}::${opt_n}:${opt_d}:${opt_s}" >>/etc/passwd |
|
(PATH="$PATH:/usr/sbin"; pwconv) |
|
;; |
|
*:SunOS:5.*:* ) |
|
echo "${user}:*:${uid}:${uid}:${opt_n}:${opt_d}:${opt_s}" >>/etc/passwd |
|
(PATH="$PATH:/usr/sbin"; pwconv) |
|
;; |
|
*:OSF1:5.*:* ) |
|
echo "${user}:*:${uid}:${uid}:${opt_n}:${opt_d}:${opt_s}" >>/etc/passwd |
|
(PATH="$PATH:/usr/sbin"; mkpasswd /etc/passwd) |
|
;; |
|
*:HP-UX:*:* ) |
|
echo "${user}:*:${uid}:${uid}:${opt_n}:${opt_d}:${opt_s}" >>/etc/passwd |
|
;; |
|
esac |
|
|
|
# add corresponding entry to group database |
|
echo "${user}:*:${uid}:${user}" >>/etc/group |
|
|
|
# remove user |
|
elif [ ".$opt_r" = .yes ]; then |
|
exists=`grep "^$user:" /etc/passwd` |
|
if [ ".$exists" = . ]; then |
|
echo "$msgprefix:Error: user $user does not exist" 1>&2 |
|
exit 1 |
|
fi |
|
|
|
# remove entry from passwd database |
|
case "$platform" in |
|
*:FreeBSD:[456].*:* | *:NetBSD:1.*:* ) |
|
cp /etc/master.passwd /etc/master.passwd.old |
|
grep -v "^${user}:" /etc/master.passwd.old >/etc/master.passwd |
|
(PATH="$PATH:/usr/sbin"; pwd_mkdb -p /etc/master.passwd) |
|
rm -f /etc/master.passwd.old |
|
;; |
|
*:Linux:2.*:* | *:SunOS:5.*:* ) |
|
cp /etc/passwd /etc/passwd.old |
|
grep -v "^${user}:" /etc/passwd.old >/etc/passwd |
|
(PATH="$PATH:/usr/sbin"; pwconv) |
|
rm -f /etc/passwd.old |
|
;; |
|
*:OSF1:5.*:* ) |
|
cp /etc/passwd /etc/passwd.old |
|
grep -v "^${user}:" /etc/passwd.old >/etc/passwd |
|
(PATH="$PATH:/usr/sbin"; mkpasswd /etc/passwd) |
|
rm -f /etc/passwd.old |
|
;; |
|
*:HP-UX:*:* ) |
|
cp /etc/passwd /etc/passwd.old |
|
grep -v "^${user}:" /etc/passwd.old >/etc/passwd |
|
rm -f /etc/passwd.old |
|
;; |
|
esac |
|
|
|
# remove corresponding entry from group database |
|
cp /etc/group /etc/group.old |
|
grep -v "^${user}:" /etc/group.old >/etc/group |
|
rm -f /etc/group.old |
|
fi |
|
;; |
|
|
|
group ) |
|
if [ ".$opt_a" = .no -a ".$opt_r" = .no ]; then |
|
echo "$msgprefix:Error: either -a or -r has to be given" 1>&2 |
|
exit 1 |
|
fi |
|
if [ ".$opt_a" = .yes -a ".$opt_r" = .yes ]; then |
|
echo "$msgprefix:Error: only -a or -r can be given" 1>&2 |
|
exit 1 |
|
fi |
|
group=$1 |
|
|
|
# add group |
|
if [ ".$opt_a" = .yes ]; then |
|
exists=`grep "^$group:" /etc/group` |
|
if [ ".$exists" != . ]; then |
|
echo "$msgprefix:Error: group $group already exists" 1>&2 |
|
exit 1 |
|
fi |
|
|
|
# seek for next free gid |
|
gid=$opt_g |
|
ok=0 |
|
while [ ".$ok" = .0 ]; do |
|
exists=`grep "^[^:]*:[^:]*:$gid:" /etc/group` |
|
if [ ".$exists" = . ]; then |
|
ok=1 |
|
break |
|
fi |
|
gid=`expr $gid + 1` |
|
done |
|
|
|
# add entry to group database |
|
echo "${group}:*:${gid}:$*" >>/etc/group |
|
|
|
# remove group |
|
elif [ ".$opt_r" = .yes ]; then |
|
exists=`grep "^$group:" /etc/group` |
|
if [ ".$exists" = . ]; then |
|
echo "$msgprefix:Error: group $group does not exist" 1>&2 |
|
exit 1 |
|
fi |
|
|
|
# remove entry from group database |
|
cp /etc/group /etc/group.old |
|
grep -v "^${group}:" /etc/group.old >/etc/group |
|
rm -f /etc/group.old |
|
fi |
|
;; |
|
|
|
signal ) |
|
if [ ".$opt_p" = . -a ".$opt_m" = . ]; then |
|
echo "$msgprefix:Error: either option -p or -m has to be specified" 1>&2 |
|
exit 1 |
|
fi |
|
case "$platform" in |
|
*:FreeBSD:*:* | *:NetBSD:*:* ) |
|
cmd0="ps -ax -o pid" |
|
cmd1="ps -ax -o command" |
|
cmd2="ps -ax -o pid,command" |
|
cmd3="ps -ax -o pid,ppid" |
|
;; |
|
*:Linux:*:* | *:OSF1:5.*:* ) |
|
cmd0="ps axo pid" |
|
cmd1="ps axo cmd" |
|
cmd2="ps axo pid,cmd" |
|
cmd3="ps axo pid,ppid" |
|
;; |
|
*:SunOS:5.*:* ) |
|
cmd0="ps -ef -o pid" |
|
cmd1="ps -ef -o args" |
|
cmd2="ps -ef -o pid,args" |
|
cmd3="ps -ef -o pid,ppid" |
|
;; |
|
*:HP-UX:*:* ) |
|
cmd0="ps -ef" # FIXME |
|
cmd1="ps -ef" # FIXME |
|
cmd2="ps -ef" # FIXME |
|
cmd3="ps -ef" # FIXME |
|
;; |
|
esac |
|
# try all signals in order |
|
i=$# |
|
for sig in "$@"; do |
|
# check whether program is still running/active |
|
active="" |
|
if [ ".$opt_p" != . ]; then |
|
active=`$cmd0 | grep "$opt_p" | grep -v grep | grep -v rpmtool` |
|
elif [ ".$opt_m" != . ]; then |
|
active=`$cmd1 | grep "$opt_m" | grep -v grep | grep -v rpmtool` |
|
fi |
|
if [ ".$active" = . ]; then |
|
break |
|
fi |
|
|
|
# send signal to program |
|
if [ ".$opt_p" != . ]; then |
|
pids="$opt_p" |
|
elif [ ".$opt_m" != . ]; then |
|
pids=`$cmd2 | sed -e "s;^[ ${TAB}]*;;" | egrep "[0-9]* .*$opt_m" |\ |
|
grep -v grep | grep -v rpmtool |\ |
|
awk '{ printf("%s\n", $1); }'` |
|
fi |
|
for pid in $pids; do |
|
if [ ".$opt_v" = .yes ]; then |
|
echo "sending $sig signal to process $pid" |
|
fi |
|
if [ ".$opt_t" = .yes ]; then |
|
echo "kill -$sig $pid" |
|
fi |
|
if [ ".$opt_n" = .no ]; then |
|
eval "kill -$sig $pid" |
|
fi |
|
done |
|
|
|
# optionally send signal to childs of program |
|
if [ ".$opt_c" = .yes ]; then |
|
for pid in $pids; do |
|
cpids=`$cmd3 | sed -e "s;^[ ${TAB}]*;;" | egrep "[0-9]* $pid" |\ |
|
grep -v grep | grep -v rpmtool |\ |
|
awk '{ printf("%s\n", $1); }'` |
|
for cpid in $cpids; do |
|
if [ ".$opt_v" = .yes ]; then |
|
echo "sending $sig signal to child process $cpid" |
|
fi |
|
if [ ".$opt_t" = .yes ]; then |
|
echo "kill -$sig $cpid" |
|
fi |
|
if [ ".$opt_n" = .no ]; then |
|
eval "kill -$sig $cpid >/dev/null 2>&1" |
|
fi |
|
done |
|
done |
|
fi |
|
|
|
# perform optional delay |
|
i=`expr $i - 1` |
|
if [ $i -gt 0 ]; then |
|
if [ ".$opt_d" != . -a ".$opt_d" != . ]; then |
|
sleep $opt_d |
|
fi |
|
fi |
|
done |
|
;; |
|
|
|
config ) |
|
# usage consistency |
|
if [ ".$opt_a" = .no -a ".$opt_r" = .no ]; then |
|
echo "$msgprefix:Error: either option -a or -r has to be specified" 1>&2 |
|
exit 1 |
|
fi |
|
configfile="$1" |
|
|
|
# determine block markers |
|
block_start="${opt_p}<${opt_t}" |
|
if [ ".$opt_i" != . ]; then |
|
block_start="${block_start} id=\"${opt_i}\"" |
|
fi |
|
block_start="${block_start}>" |
|
block_end="${opt_p}</${opt_t}>" |
|
|
|
# slash-escaped versions of block markers (for sed(3) call) |
|
block_start_esc=`echo "$block_start" | sed -e 's;/;\\\\/;g'` |
|
block_end_esc=`echo "$block_end" | sed -e 's;/;\\\\/;g'` |
|
|
|
# determine backup extension |
|
case "X$opt_b" in |
|
X ) ext=".bak" ;; |
|
X.* ) ext="$opt_b" ;; |
|
X* ) ext=".$opt_b" ;; |
|
esac |
|
|
|
# check for block in config file |
|
if [ -f $configfile ]; then |
|
check=`grep "^${block_start}" $configfile` |
|
else |
|
touch $configfile |
|
check="" |
|
fi |
|
|
|
# add entry |
|
if [ ".$opt_a" = .yes ]; then |
|
if [ ".$check" != . ]; then |
|
if [ ".$opt_s" = .yes ]; then |
|
exit 0 |
|
else |
|
echo "$msgprefix:Error: config entry already exists" 1>&2 |
|
exit 1 |
|
fi |
|
fi |
|
cp $configfile $configfile$ext |
|
echo "${block_start}" >$tmpfile |
|
cat >>$tmpfile |
|
echo "${block_end}" >>$tmpfile |
|
cat $tmpfile >>$configfile |
|
|
|
# remove entry |
|
elif [ ".$opt_r" = .yes ]; then |
|
if [ ".$check" = . ]; then |
|
if [ ".$opt_s" = .yes ]; then |
|
exit 0 |
|
else |
|
echo "$msgprefix:Error: config entry does not exist" 1>&2 |
|
exit 1 |
|
fi |
|
fi |
|
cp $configfile $configfile$ext |
|
sed -e "/^${block_start_esc}/,/^${block_end_esc}/d" \ |
|
<$configfile$ext >$configfile |
|
fi |
|
|
|
# verbosity |
|
if [ ".$opt_v" = .yes ]; then |
|
(diff -u1 $configfile$ext $configfile >$tmpfile) 2>/dev/null |
|
if [ ".`cat $tmpfile`" = . ]; then |
|
(diff -C1 $configfile$ext $configfile >$tmpfile) 2>/dev/null |
|
if [ ".`cat $tmpfile`" = . ]; then |
|
if [ ".$opt_s" = .no ]; then |
|
echo "$msgprefix:Warning: unable to show difference for config file \`$configfile'" 1>&2 |
|
fi |
|
fi |
|
fi |
|
echo "editing $configfile:" |
|
cat $tmpfile |
|
fi |
|
|
|
# optionally remove backup file |
|
if [ ".$opt_b" = . ]; then |
|
rm -f $configfile$ext |
|
fi |
|
;; |
|
esac |
|
|
|
# cleanup |
|
if [ ".$gen_tmpfile" = .yes ]; then |
|
rm -f $tmpfile >/dev/null 2>&1 |
|
fi |
|
|
|
# die gracefully ;) |
|
exit 0 |
|
|
|
|