openpkg/rc

Wed, 01 Aug 2012 23:24:50 +0200

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 01 Aug 2012 23:24:50 +0200
changeset 431
127559aa0c5e
parent 427
71503088f51b
child 469
65414bdd541c
permissions
-rw-r--r--

Renumber patch hunks to avoid almost all patch(1) warnings.

michael@13 1 #!@l_prefix@/lib/openpkg/bash --noprofile
michael@13 2 ##
michael@428 3 ## rc -- OpenPKG Run-Command Processor
michael@428 4 ## Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>
michael@13 5 ##
michael@428 6 ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
michael@428 7 ## All rights reserved. Licenses which grant limited permission to use,
michael@428 8 ## copy, modify and distribute this software are available from the
michael@428 9 ## OpenPKG GmbH.
michael@13 10 ##
michael@428 11 ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
michael@13 12 ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
michael@13 13 ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@13 14 ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
michael@13 15 ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@13 16 ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@13 17 ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
michael@13 18 ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@13 19 ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@13 20 ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@13 21 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@13 22 ## SUCH DAMAGE.
michael@13 23 ##
michael@13 24
michael@13 25 ##
michael@13 26 ## configuration
michael@13 27 ##
michael@13 28
michael@13 29 # program name, version and date
michael@13 30 progname="rc"
michael@428 31 progvers="1.2.1"
michael@428 32 progdate="2007-12-27"
michael@13 33
michael@13 34 # path to OpenPKG instance
michael@13 35 prefix="@l_prefix@"
michael@13 36
michael@13 37 # path to GNU bash and GNU shtool
michael@13 38 bash="$prefix/lib/openpkg/bash"
michael@13 39 shtool="$prefix/lib/openpkg/shtool"
michael@13 40
michael@13 41 # path to rc.d, rc.conf and rc.func
michael@13 42 rcdir="$prefix/etc/rc.d"
michael@13 43 rcconf="$prefix/etc/rc.conf"
michael@13 44 rcfunc="$prefix/etc/rc.func"
michael@13 45
michael@13 46 # helper variables
michael@13 47 NL="
michael@13 48 "
michael@13 49
michael@13 50 ##
michael@428 51 ## temporary file handling
michael@428 52 ##
michael@428 53
michael@428 54 # establish secure temporary directory
michael@428 55 i=0
michael@428 56 while [ $i -lt 10 ]; do
michael@428 57 tmpdir="/tmp/rc-`date '+%Y%m%d%H%M%S'`-$$"
michael@428 58 (umask 022; mkdir $tmpdir >/dev/null 2>&1) && break
michael@428 59 i=$(($i + 1))
michael@428 60 sleep 1
michael@428 61 done
michael@428 62 if [ $i -eq 10 ]; then
michael@428 63 echo "openpkg:rc:ERROR: unable to establish secure temporary directory" 1>&2
michael@428 64 exit 1
michael@428 65 fi
michael@428 66 declare -r tmpdir
michael@428 67 cleanup () {
michael@428 68 if [ ".$tmpdir" != . ]; then
michael@428 69 if [ -d $tmpdir ]; then
michael@428 70 rm -rf $tmpdir >/dev/null 2>&1 || true
michael@428 71 fi
michael@428 72 fi
michael@428 73 }
michael@428 74 trap "cleanup; trap - EXIT INT ABRT QUIT TERM" EXIT INT ABRT QUIT TERM
michael@428 75
michael@428 76 # determine reasonable temporary files
michael@428 77 tmpfile="$tmpdir/rc.tmp"
michael@428 78 outfile="$tmpdir/rc.out"
michael@428 79 errfile="$tmpdir/rc.err"
michael@428 80 allfile="$tmpdir/rc.all"
michael@428 81 deffile="$tmpdir/rc.def"
michael@428 82
michael@428 83 # initialize files
michael@428 84 cp /dev/null $deffile
michael@428 85
michael@428 86 ##
michael@13 87 ## command line option parsing
michael@13 88 ##
michael@13 89
michael@13 90 # default parameters
michael@13 91 silent=0
michael@13 92 verbose=0
michael@13 93 debug=0
michael@13 94 help=0
michael@13 95 keep=0
michael@13 96 print=0
michael@13 97 eval=0
michael@13 98 config=0
michael@13 99 query=0
michael@13 100
michael@13 101 # iterate over argument line
michael@13 102 while [ $# -gt 0 ]; do
michael@428 103 case "$1" in
michael@13 104 -s|--silent ) silent=1 ;;
michael@13 105 -v|--verbose ) verbose=1 ;;
michael@13 106 -d|--debug ) debug=1 ;;
michael@13 107 -h|--help ) help="Usage" ;;
michael@13 108 -k|--keep ) keep=1 ;;
michael@13 109 -p|--print ) print=1 ;;
michael@13 110 -e|--eval ) eval=1 ;;
michael@13 111 -c|--config ) config=1 ;;
michael@13 112 -q|--query ) query=1 ;;
michael@428 113 -D|--define ) echo "@$2" | \
michael@428 114 sed -e "s;';\\\\';g" | \
michael@428 115 sed -e "s;^@\\([a-z][a-zA-Z0-9_]*\\)=\\(.*\\)\$;\1='\2';" \
michael@428 116 -e "s;^@.*;;" >>$deffile; shift ;;
michael@428 117 -* ) help="Invalid option \`$1'"; break ;;
michael@428 118 * ) break ;;
michael@13 119 esac
michael@13 120 shift
michael@13 121 done
michael@13 122
michael@13 123 # display error or usage message
michael@13 124 if [ ".$help" != .0 ]; then
michael@13 125 if [ ".$help" != ".Usage" ]; then
michael@13 126 echo "$progname:ERROR: $help" 1>&2
michael@13 127 fi
michael@13 128 echo "Usage: $progname [-s|--silent] [-v|--verbose] [-d|--debug] [-k|--keep] [-h|--help]" 1>&2
michael@428 129 echo " [-p|--print] [-e|--eval] [-c|--config] [-q|--query] [-D|--define <name>=<value>]" 1>&2
michael@13 130 echo " <package> <command> [<command> ...]" 1>&2
michael@13 131 if [ ".$help" != ".Usage" ]; then
michael@13 132 exit 1
michael@13 133 else
michael@13 134 exit 0
michael@13 135 fi
michael@13 136 fi
michael@13 137
michael@13 138 # determine a reasonable default silent/verbose situation in case
michael@13 139 # nothing was explicitly specified or a conflicting situation was
michael@13 140 # specified. Else is silent either disabled by default or was
michael@13 141 # explicitly enabled.
michael@13 142 if [ $silent -eq $verbose ]; then
michael@13 143 if [ -t 2 ]; then
michael@13 144 # stdout connected to a terminal device, so no need to be silent
michael@13 145 silent=0
michael@13 146 else
michael@13 147 # stdout NOT connected to a terminal device, so be silent
michael@13 148 silent=1
michael@13 149 fi
michael@13 150 fi
michael@13 151
michael@13 152 # extend run-time environment with local OpenPKG tools (shtool, rpmtool, etc)
michael@13 153 PATH_ORIG="$PATH"
michael@428 154 PATH="$prefix/lib/openpkg/fallback:$PATH"
michael@13 155 PATH="$prefix/bin:$PATH"
michael@13 156 PATH="$prefix/sbin:$PATH"
michael@13 157 PATH="$prefix/lib/openpkg:$PATH"
michael@428 158 PATH="$prefix/lib/openpkg/override:$PATH"
michael@13 159
michael@13 160 # handle --query option
michael@13 161 if [ ".$query" = .1 ]; then
michael@13 162 # suck in all %config sections of all scripts
michael@13 163 # (rc.openpkg is special: has to be first and requires pre-inclusion of rc.conf)
michael@13 164 touch $tmpfile
michael@13 165 sed <$rcdir/rc.openpkg >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 166 echo ". $rcconf" >>$tmpfile
michael@428 167 echo ". $deffile" >>$tmpfile
michael@13 168 scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;" | egrep -v '^openpkg$'`
michael@13 169 for s_name in $scripts; do
michael@13 170 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 171 done
michael@13 172 . $tmpfile
michael@13 173
michael@13 174 # apply override values to get effective values
michael@13 175 . $rcconf
michael@428 176 . $deffile
michael@13 177
michael@13 178 # display variable value
michael@13 179 for var in $*; do
michael@13 180 eval "echo \${$var}"
michael@13 181 done
michael@13 182
michael@13 183 # stop processing immediately
michael@13 184 exit 0
michael@13 185 fi
michael@13 186
michael@13 187 # handle --config option
michael@13 188 if [ ".$config" = .1 ]; then
michael@13 189 # suck in all %config sections of all scripts
michael@13 190 # (rc.openpkg is special: has to be first and requires pre-inclusion of rc.conf)
michael@13 191 touch $tmpfile
michael@13 192 sed <$rcdir/rc.openpkg >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 193 echo ". $rcconf" >>$tmpfile
michael@428 194 echo ". $deffile" >>$tmpfile
michael@13 195 scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;" | egrep -v '^openpkg$'`
michael@13 196 for s_name in $scripts; do
michael@13 197 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 198 done
michael@13 199 . $tmpfile
michael@13 200
michael@13 201 # remember default values
michael@13 202 vars=""
michael@13 203 OIFS="$IFS"; IFS="$NL"
michael@13 204 for assign in `egrep '[ ]*[a-zA-Z_][a-zA-Z_0-9]*=' $tmpfile | sort`; do
michael@13 205 var=`echo "$assign" | sed -e 's;^[ ]*\([a-zA-Z_][a-zA-Z_0-9]*\)=.*;\1;'`
michael@13 206 vars="$vars $var"
michael@13 207 eval "${var}_def=\"\$$var\""
michael@13 208 done
michael@13 209 IFS="$OIFS"
michael@13 210
michael@13 211 # apply override values to get effective values
michael@13 212 . $rcconf
michael@428 213 . $deffile
michael@13 214
michael@13 215 # determine how to print in bold mode in case output
michael@13 216 # is connected to a terminal device
michael@13 217 if [ -t 1 ]; then
michael@13 218 begin_bold=`$shtool echo -e '%B'`
michael@13 219 end_bold=`$shtool echo -e '%b'`
michael@13 220 else
michael@13 221 begin_bold=""
michael@13 222 end_bold=""
michael@13 223 fi
michael@13 224
michael@13 225 # iterate over all variables and display name, default and effective value
michael@13 226 echo "${begin_bold}Configuration Variable Effective Value Default Value${end_bold}"
michael@13 227 echo "------------------------ ------------------------- -- -------------------------"
michael@13 228 for var in . $vars; do
michael@13 229 test ".$var" = .. && continue
michael@13 230 eval "val=\"\$$var\""
michael@13 231 eval "def=\"\$${var}_def\""
michael@13 232 tag="!="
michael@13 233 begin="$begin_bold"
michael@13 234 end="$end_bold"
michael@13 235 if [ ".$val" = ".$def" ]; then
michael@13 236 tag="=="
michael@13 237 begin=""
michael@13 238 end=""
michael@13 239 fi
michael@13 240 printf "%s%-24s %-25s %s %-25s%s\n" "$begin" "$var" "\"$val\"" "$tag" "\"$def\"" "$end"
michael@13 241 done
michael@13 242
michael@13 243 # stop processing immediately
michael@13 244 exit 0
michael@13 245 fi
michael@13 246
michael@13 247 # determine script(s) to use and make sure they exist
michael@13 248 if [ $# -lt 1 ]; then
michael@13 249 echo "openpkg:rc:ERROR: no package and command(s) specified" 1>&2
michael@13 250 exit 1
michael@13 251 fi
michael@13 252 if [ $# -lt 2 ]; then
michael@13 253 echo "openpkg:rc:ERROR: no command(s) specified for package" 1>&2
michael@13 254 exit 1
michael@13 255 fi
michael@13 256 scripts="${1/*rc./}"
michael@13 257 shift
michael@13 258 isall=0
michael@428 259 if [ ".$scripts" = ".cron" ]; then
michael@428 260 # "cron" is an "all" with a random delay (to ensure that multiple
michael@428 261 # OpenPKG instances do not all startup at exactly the same time)
michael@428 262 # plus a mutex lock to ensure that multiple OpenPKG cron tasks of
michael@428 263 # the same OpenPKG instance do not stumble over each other).
michael@428 264
michael@428 265 # determine delay range and timeout
michael@428 266 case "${1-quarterly}" in
michael@428 267 monthly ) delay=1800; timeout=28800 ;; # 30m / 8h
michael@428 268 weekly ) delay=1800; timeout=14400 ;; # 30m / 4h
michael@428 269 daily ) delay=900; timeout=7200 ;; # 15m / 2h
michael@428 270 hourly ) delay=600; timeout=3600 ;; # 5m / 1h
michael@428 271 quarterly|* ) delay=30; timeout=900 ;; # 30s / 15m
michael@428 272 esac
michael@428 273
michael@428 274 # apply random run-time delay
michael@428 275 # (hint: $RANDOM is a random value 0..32767)
michael@428 276 sleep $(( ($RANDOM * $delay) / 32767 ))
michael@428 277
michael@428 278 # wrap ourself for mutual exclusion run-time
michael@428 279 # and then perform the "all" command
michael@428 280 cleanup
michael@428 281 exec $prefix/lib/openpkg/mutex \
michael@428 282 -t $timeout $prefix/RPM/TMP/openpkg-rc-cron.mutex \
michael@428 283 sh -c "exec $0 all $*" || exit $?
michael@428 284 fi
michael@13 285 if [ ".$scripts" = ".all" ]; then
michael@13 286 isall=1
michael@13 287 . $rcconf
michael@428 288 . $deffile
michael@13 289 case "$openpkg_rc_all" in
michael@13 290 [Nn][Oo] | [Ff][Aa][Ll][Ss][Ee] | [Oo][Ff][Ff] | 0 ) exit 0 ;;
michael@13 291 esac
michael@13 292 scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;"`
michael@428 293
michael@428 294 # the "all" target is usually called from system startup scripts,
michael@428 295 # and we really want to ensure that no potentially corrupt
michael@428 296 # (because of an unclean shutdown of the system) RPM DB journal
michael@428 297 # files are staying around and preventing the startup of the
michael@428 298 # OpenPKG instance. When called manually it also doesn't hurt to
michael@428 299 # cleanup.
michael@428 300 rm -f $prefix/RPM/DB/__db.* >/dev/null 2>&1 || true
michael@13 301 else
michael@13 302 if [ ! -f "$rcdir/rc.$scripts" ]; then
michael@13 303 echo "openpkg:rc:ERROR: package \"$scripts\" not found" 1>&2
michael@13 304 exit 1
michael@13 305 fi
michael@13 306 fi
michael@13 307
michael@13 308 # determine current run-time user
michael@13 309 user=`(id -un) 2>/dev/null ||\
michael@13 310 (id | sed -e 's;^[^(]*(\([^)]*\)).*;\1;') 2>/dev/null ||\
michael@13 311 (whoami) 2>/dev/null ||\
michael@13 312 (who am i | cut "-d " -f1) 2>/dev/null ||\
michael@13 313 echo ${LOGNAME:-${USER}}`
michael@13 314 if [ ".$user" = . ]; then
michael@13 315 echo "openpkg:rc:ERROR: unable to determine current username" 1>&2
michael@13 316 exit 1
michael@13 317 fi
michael@13 318
michael@428 319 # just call OpenPKG RPM to let it once perform the run-time integrity checks
michael@428 320 $prefix/bin/openpkg rpm -q openpkg >/dev/null || exit $?
michael@428 321
michael@13 322 # iterate over the specified commands
michael@13 323 rv=0
michael@13 324 cmds="$*"
michael@13 325 for cmd in $cmds; do
michael@13 326 # create "all outputs" file for execution operation (i.e. not --print and --eval)
michael@13 327 if [ ".$print" = .0 -a ".$eval" = .0 ]; then
michael@13 328 rm -f $allfile
michael@13 329 touch $allfile
michael@13 330 fi
michael@13 331
michael@13 332 # find scripts which contain the command and determine
michael@13 333 # their individual user/priority settings
michael@13 334 list=''
michael@13 335 for s_name in $scripts; do
michael@13 336 enable=yes
michael@13 337
michael@13 338 # check for upgraded package with unresolved configuration file conflicts
michael@13 339 if [ -d "$prefix/etc/$s_name" -a ".$eval" != .1 ]; then
michael@13 340 if [ ".`(find $prefix/etc/$s_name -type f -print; find $prefix/etc/$s_name -type l -print) 2>/dev/null | egrep -v '.*/\.(snap|snapshot)/.*' | egrep '.*\.rpm(new|orig|save)$'`" != . ]; then
michael@13 341 case "$cmd" in
michael@13 342 start|restart ) type="ERROR" ;;
michael@13 343 * ) type="WARNING" ;;
michael@13 344 esac
michael@13 345 echo "openpkg:rc:${type}: package \"$s_name\" has unresolved configuration file conflicts" 1>&2
michael@13 346 echo "openpkg:rc:${type}: indicated by \"*.rpm(new|orig|save)\" files in or below the" 1>&2
michael@13 347 echo "openpkg:rc:${type}: directory \"$prefix/etc/$s_name\". Please resolve first!" 1>&2
michael@13 348 if [ ".$type" = .ERROR ]; then
michael@13 349 continue
michael@13 350 fi
michael@13 351 fi
michael@13 352 fi
michael@13 353
michael@13 354 # check whether command exists in script at all
michael@13 355 cmdline=`grep "^%$cmd" $rcdir/rc.$s_name | sed -e "s;^%$cmd[^ ].*;;"`
michael@13 356 if [ ".$cmdline" != . ]; then
michael@13 357 # parse local command options
michael@13 358 cmdopts=`echo "$cmdline" | sed -e "s;^%$cmd *;;"`
michael@13 359 s_user=$user
michael@13 360 s_prio=500
michael@13 361 s_output=no
michael@13 362 set -- $cmdopts
michael@13 363 prev=''
michael@13 364 for opt
michael@13 365 do
michael@13 366 if [ ".$prev" != . ]; then
michael@13 367 opt="$prev$opt"
michael@13 368 prev=''
michael@13 369 fi
michael@13 370 case $opt in
michael@13 371 -*=* ) arg=${opt/-*=/} ;;
michael@13 372 -[a-zA-Z]* ) arg=${opt/-[a-zA-Z0-9]/} ;;
michael@13 373 *) arg='' ;;
michael@13 374 esac
michael@13 375 case $opt in
michael@13 376 -u|-p ) prev=$opt ;;
michael@13 377 -e|--enable ) enable=yes ;;
michael@13 378 -d|--disable ) enable=no ;;
michael@13 379 -o|--output ) s_output=yes ;;
michael@13 380 -u*|--user=* ) s_user=$arg ;;
michael@13 381 -p*|--prio=* ) s_prio=$arg ;;
michael@13 382 * ) echo "openpkg:rc:WARNING: invalid local option \"$opt\" in \"$rcdir/rc.$s_name:%$cmd\""; break ;;
michael@13 383 esac
michael@13 384 shift
michael@13 385 done
michael@13 386
michael@13 387 # sanity check: is operation supported by current environment?
michael@13 388 if [ ".$s_user" != ".$user" -a ".$user" != ".root" -a ".$print" = .0 ]; then
michael@13 389 echo "openpkg:rc:ERROR: $s_name:%$cmd: require root privileges to run as user \"$s_user\"" 1>&2
michael@13 390 exit 1
michael@13 391 fi
michael@13 392
michael@13 393 # skip this script if script is disabled
michael@13 394 if [ ".$enable" != .yes ]; then
michael@13 395 continue
michael@13 396 fi
michael@13 397
michael@13 398 # accumulate the determined information
michael@13 399 list="$list,$s_prio:$s_name:$s_user:$s_output"
michael@13 400 else
michael@13 401 # command not found in script
michael@13 402 if [ ".$isall" = .0 ]; then
michael@13 403 echo "openpkg:rc:ERROR: $s_name: command \"$cmd\" not found" 1>&2
michael@13 404 exit 1
michael@13 405 fi
michael@13 406 fi
michael@13 407 done
michael@13 408
michael@13 409 # if operating on all scripts, complain if a non-standard command
michael@13 410 # was used and it was not found in any(!) script at all. The
michael@13 411 # standard commands are accepted to perform no operation if no
michael@13 412 # packages are currently installed which provide such commands.
michael@13 413 if [ ".$list" = . -a ".$isall" = .1 ]; then
michael@13 414 case "$cmd" in
michael@13 415 start|stop|monthly|weekly|daily|hourly|quarterly )
michael@13 416 ;;
michael@13 417 * )
michael@13 418 echo "openpkg:rc:ERROR: command \"$cmd\" not found in any script" 1>&2
michael@13 419 rv=1
michael@13 420 break
michael@13 421 ;;
michael@13 422 esac
michael@13 423 fi
michael@13 424
michael@13 425 # generate global (loop invariant) header for script in case of
michael@13 426 # --print and --eval (for the execution approach we cannot do
michael@13 427 # this, because there a new script is generated from scratch for
michael@13 428 # each package.
michael@13 429 if [ ".$print" = .1 -o ".$eval" = .1 ]; then
michael@13 430 rm -f $tmpfile
michael@13 431 touch $tmpfile
michael@13 432
michael@13 433 # generate: optionally enable shell debugging
michael@13 434 if [ ".$debug" = .1 ]; then
michael@13 435 echo "set -x" >>$tmpfile
michael@13 436 fi
michael@13 437
michael@13 438 # generate: inclusion of the run-command helper functions
michael@13 439 echo ". $rcfunc" >>$tmpfile
michael@13 440
michael@13 441 # generate: all %config sections of all(!) scripts. We cannot
michael@13 442 # just include those which have the current command in it
michael@13 443 # because by design all command scripts see the %config
michael@13 444 # section of all(!) scripts. Because of $openpkg_rc_def the
michael@13 445 # variable, we place the %config section of "openpkg" to the front.
michael@13 446 # And we have to extra pre-include the rc.conf to allow
michael@13 447 # rc.conf to override the default of $openpkg_rc_def, too.
michael@13 448 sed <$rcdir/rc.openpkg >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 449 echo ". $rcconf" >>$tmpfile
michael@428 450 echo ". $deffile" >>$tmpfile
michael@13 451 l_scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;" | egrep -v '^openpkg$'`
michael@13 452 for l_name in $l_scripts; do
michael@13 453 sed <$rcdir/rc.$l_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 454 done
michael@13 455
michael@13 456 # generate: inclusion of the application of override variables
michael@13 457 echo ". $rcconf" >>$tmpfile
michael@428 458 echo ". $deffile" >>$tmpfile
michael@13 459
michael@13 460 # for --eval redirect stderr and stdout (but remember stdout)
michael@13 461 # (let stderr pass unfiltered in case of debug mode)
michael@13 462 if [ ".$eval" = .1 ]; then
michael@13 463 if [ ".$debug" = .1 ]; then
michael@13 464 echo "exec 3<&1- 1>/dev/null" >>$tmpfile
michael@13 465 else
michael@13 466 echo "exec 3<&1- 1>/dev/null 2>/dev/null" >>$tmpfile
michael@13 467 fi
michael@13 468 fi
michael@13 469 fi
michael@13 470
michael@13 471 # iterate over all packages (in priority order!) where the command
michael@13 472 # was found in order to execute, print, or evaluate their scripts
michael@13 473 verbose_pos=0
michael@13 474 for entry in `echo $list | tr ',' '\012' | sort -n`; do
michael@13 475 [ ".$entry" = . ] && continue
michael@13 476
michael@13 477 # re-determine the script name, script and whether to print output
michael@13 478 eval `echo $entry | sed -e 's%^[0-9]*:\(.*\):\(.*\):\(.*\)$%s_name="\1"; s_user="\2"; s_output="\3";%'`
michael@13 479
michael@13 480 # display verbose progress message parts
michael@13 481 if [ ".$print" = .0 -a ".$eval" = .0 -a ".$silent" = .0 ]; then
michael@13 482 # line break if we already have output more than 70
michael@13 483 # characters (notice that usually already more characters
michael@13 484 # where printed, because of the name of the last script)
michael@13 485 if [ $verbose_pos -gt 70 ]; then
michael@13 486 verbose_pos=0
michael@13 487 echo "" 1>&2
michael@13 488 fi
michael@13 489
michael@13 490 # display verbose message parts: prefix (on first), separator and package
michael@13 491 if [ $verbose_pos -eq 0 ]; then
michael@13 492 output=$(printf "OpenPKG: %s: " "$cmd")
michael@13 493 echo -n "$output" 1>&2
michael@13 494 verbose_pos=$(($verbose_pos + ${#output}))
michael@13 495 output_prefix=""
michael@13 496 else
michael@13 497 output_prefix=", "
michael@13 498 fi
michael@13 499 output=$(printf "%s%s" "$output_prefix" "$s_name")
michael@13 500 echo -n "$output" 1>&2
michael@13 501 verbose_pos=$(($verbose_pos + ${#output}))
michael@13 502 fi
michael@13 503
michael@13 504 # now operate on the particular script
michael@13 505 if [ ".$print" = .1 ]; then
michael@13 506 # special case: under --print we just add the %common and
michael@13 507 # command scripts to the generated output script and do
michael@13 508 # not execute anything at this point.
michael@13 509 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d'
michael@13 510 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d'
michael@13 511 elif [ ".$eval" = .1 ]; then
michael@13 512 # special case: under --eval we just add the %common and
michael@13 513 # command scripts to the generated output script and do
michael@13 514 # not execute anything at this point. Additionally, we
michael@13 515 # emulate a real sub-shell environment.
michael@13 516 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d'
michael@13 517 echo "while [ 1 ]; do" >>$tmpfile
michael@13 518 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d' \
michael@13 519 -e 's/^exit[^;]*/break 99/' -e 's/\([^a-zA-Z0-9_]\)exit[^;]*/\1break 99/g' \
michael@13 520 -e 's/^return[^;]*/break 99/' -e 's/\([^a-zA-Z0-9_]\)return[^;]*/\1break 99/g'
michael@13 521 echo "break" >>$tmpfile
michael@13 522 echo "done" >>$tmpfile
michael@13 523 else
michael@13 524 # the regular case of executing the command script directly
michael@13 525
michael@13 526 # prepare temporary files
michael@13 527 rm -f $tmpfile $outfile $errfile
michael@13 528 (umask 077; touch $tmpfile $outfile $errfile)
michael@13 529
michael@13 530 # generate: optionally enable shell debugging
michael@13 531 if [ ".$debug" = .1 ]; then
michael@13 532 echo "set -x" >>$tmpfile
michael@13 533 fi
michael@13 534
michael@13 535 # generate: inclusion of the run-command helper functions
michael@13 536 echo ". $rcfunc" >>$tmpfile
michael@13 537
michael@13 538 # generate: all %config sections of all(!) scripts. We cannot
michael@13 539 # just include those which have the current command in it
michael@13 540 # because by design all command scripts see the %config
michael@13 541 # section of all(!) scripts. Because of $openpkg_rc_def the
michael@13 542 # variable, we place the %config section of "openpkg" to the front.
michael@13 543 # And we have to extra pre-include the rc.conf to allow
michael@13 544 # rc.conf to override the default of $openpkg_rc_def, too.
michael@13 545 sed <$rcdir/rc.openpkg >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 546 echo ". $rcconf" >>$tmpfile
michael@428 547 echo ". $deffile" >>$tmpfile
michael@13 548 l_scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;" | egrep -v '^openpkg$'`
michael@13 549 for l_name in $l_scripts; do
michael@13 550 sed <$rcdir/rc.$l_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d'
michael@13 551 done
michael@13 552
michael@13 553 # generate: inclusion of the application of override variables
michael@13 554 echo ". $rcconf" >>$tmpfile
michael@428 555 echo ". $deffile" >>$tmpfile
michael@13 556
michael@13 557 # generate: %common section and particular command section
michael@13 558 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d'
michael@13 559 sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d'
michael@13 560
michael@13 561 # execute the generated script with GNU Bash
michael@13 562 if [ ".$user" != ".$s_user" ]; then
michael@13 563 # execute as different user
michael@13 564 if [ ".$verbose" = .1 ]; then
michael@13 565 echo "openpkg:rc:NOTICE: $prefix:$s_name:%$cmd: executing as user $s_user"
michael@13 566 fi
michael@13 567 if [ ".$user" = ".@l_susr@" -a ".@l_susr@" = ".root" ]; then
michael@13 568 chown $s_user $tmpfile
michael@13 569 if [ ".$debug" = .1 ]; then
michael@13 570 su - $s_user -c "PATH=\"$PATH\"; $bash $tmpfile" >$outfile
michael@13 571 rc=$?
michael@13 572 else
michael@13 573 su - $s_user -c "PATH=\"$PATH\"; $bash $tmpfile" >$outfile 2>$errfile
michael@13 574 rc=$?
michael@13 575 fi
michael@13 576 elif [ ".@l_susr@" != ".root" ]; then
michael@13 577 # do not complain if we would not have any chance
michael@13 578 # at all to switch the user because we are running
michael@13 579 # in a non-privileged instance. Else we would just
michael@13 580 # trash the mailbox of the user receiving the
michael@13 581 # output of periodic run-commands.
michael@13 582 rc=0
michael@13 583 else
michael@13 584 echo "openpkg:rc:WARNING: $prefix:$s_name:%$cmd: require root privileges to run as user \"$s_user\"" 1>&2
michael@13 585 rc=1
michael@13 586 fi
michael@13 587 else
michael@13 588 # execute as current user
michael@13 589 if [ ".$verbose" = .1 ]; then
michael@13 590 echo "openpkg:rc:NOTICE: $prefix:$s_name:%$cmd: executing as user $user"
michael@13 591 fi
michael@13 592 if [ ".$debug" = .1 ]; then
michael@13 593 $bash $tmpfile >$outfile
michael@13 594 rc=$?
michael@13 595 else
michael@13 596 $bash $tmpfile >$outfile 2>$errfile
michael@13 597 rc=$?
michael@13 598 fi
michael@13 599 fi
michael@13 600 if [ $rc -ne 0 ]; then
michael@13 601 if [ ".$silent" = .0 ]; then
michael@13 602 # indicate failure of execution on verbose message line
michael@13 603 echo ":FAILED" 1>&2
michael@13 604 verbose_pos=0
michael@13 605 fi
michael@13 606 # give details of execution failure
michael@13 607 ( echo "openpkg:rc:WARNING: $prefix:$s_name:%$cmd: failed with return code $rc"
michael@13 608 if [ ".`cat $outfile $errfile`" != . ]; then
michael@13 609 echo "openpkg:rc:NOTICE: output from stdout/stderr is following:"
michael@13 610 echo "+----------------------------------------------------------------------"
michael@13 611 cat $outfile $errfile | sed -e 's;^;| ;'
michael@13 612 echo "+----------------------------------------------------------------------"
michael@13 613 else
michael@13 614 echo "openpkg:rc:NOTICE: no output occurred on stdout/stderr"
michael@13 615 fi
michael@13 616 ) 1>&2
michael@13 617
michael@13 618 # enforce global return value
michael@13 619 rv=1
michael@13 620 else
michael@13 621 # give details of execution success in case verbose operation is requested
michael@13 622 if [ ".$verbose" = .1 ]; then
michael@13 623 ( echo "openpkg:rc:NOTICE: $prefix:$s_name:%$cmd: succeeded with return code $rc"
michael@13 624 if [ ".`cat $outfile $errfile`" != . ]; then
michael@13 625 echo "openpkg:rc:NOTICE: output from stdout/stderr is following:"
michael@13 626 echo "+----------------------------------------------------------------------"
michael@13 627 cat $outfile $errfile | sed -e 's;^;| ;'
michael@13 628 echo "+----------------------------------------------------------------------"
michael@13 629 else
michael@13 630 echo "openpkg:rc:NOTICE: no output occurred on stdout/stderr"
michael@13 631 fi
michael@13 632 ) 1>&2
michael@13 633 fi
michael@13 634 if [ ".$s_output" = .yes ]; then
michael@13 635 # accumulate script output for later display
michael@13 636 cat $outfile >>$allfile
michael@13 637 fi
michael@13 638 fi
michael@13 639 fi
michael@13 640 done
michael@13 641
michael@13 642 # post-processing for each command
michael@13 643 if [ ".$print" = .1 ]; then
michael@13 644 # for --print just print the resulting script to stdout
michael@13 645 cat $tmpfile
michael@13 646 elif [ ".$eval" = .1 ]; then
michael@13 647 # finish generation of temporary script by restoring stdout
michael@13 648 # and printing the exported environment variables into a format
michael@13 649 # suitable for evaluation by the callers shell.
michael@13 650 echo "exec 1<&3-" >>$tmpfile
michael@13 651 echo "unset PWD SHLVL" >>$tmpfile
michael@13 652 echo "env |\\" >>$tmpfile
michael@13 653 echo "egrep '^[A-Z_][A-Z0-9_]*=.' |\\" >>$tmpfile
michael@13 654 echo "sed -e '/^_=/d' -e 's/\\\\/\\\\\\\\/g' -e 's/\"/\\\\\"/g' \\" >>$tmpfile
michael@13 655 case $SHELL in
michael@13 656 csh|*/csh|tcsh|*/tcsh )
michael@13 657 echo "-e 's/^\\([^=]*\\)=\\(.*\\)\$/setenv \\1 \"\\2\"/'" >>$tmpfile
michael@13 658 ;;
michael@13 659 * )
michael@13 660 echo "-e 's/^\\([^=]*\\)=\\(.*\\)\$/\\1=\"\\2\"; export \\1/'" >>$tmpfile
michael@13 661 ;;
michael@13 662 esac
michael@13 663
michael@13 664 # prepare temporary files
michael@13 665 rm -f $outfile $errfile
michael@13 666 touch $outfile $errfile
michael@13 667
michael@13 668 # now replace temporary script with its output
michael@13 669 # by executing it and capturing its output
michael@13 670 # (let stderr pass unfiltered in case of debug mode)
michael@13 671 if [ ".$debug" = .1 ]; then
michael@13 672 env -i \
michael@13 673 HOME="$HOME" \
michael@13 674 USER="$USER" \
michael@13 675 LOGNAME="$LOGNAME" \
michael@13 676 TERM="$TERM" \
michael@13 677 PATH="$PATH_ORIG" \
michael@13 678 MANPATH="$MANPATH" \
michael@13 679 INFOPATH="$INFOPATH" \
michael@13 680 LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
michael@13 681 $bash --norc --noprofile --posix \
michael@13 682 $tmpfile >$outfile
michael@13 683 else
michael@13 684 env -i \
michael@13 685 HOME="$HOME" \
michael@13 686 USER="$USER" \
michael@13 687 LOGNAME="$LOGNAME" \
michael@13 688 TERM="$TERM" \
michael@13 689 PATH="$PATH_ORIG" \
michael@13 690 MANPATH="$MANPATH" \
michael@13 691 INFOPATH="$INFOPATH" \
michael@13 692 LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
michael@13 693 $bash --norc --noprofile --posix \
michael@13 694 $tmpfile >$outfile 2>/dev/null
michael@13 695 fi
michael@13 696 cp $outfile $tmpfile
michael@13 697
michael@13 698 # for --eval we cannot just print the resulting script because
michael@13 699 # not all Bourne-Shell implementations like to "eval" large
michael@13 700 # multi-line outputs. Hence we output a little one-liner which
michael@13 701 # "sources" the script instead and cleans up.
michael@13 702 case $SHELL in
michael@13 703 csh|*/csh|tcsh|*/tcsh )
michael@13 704 echo "source $tmpfile; rm -rf $tmpdir 2>/dev/null || true"
michael@13 705 ;;
michael@13 706 * )
michael@13 707 echo ". $tmpfile; rm -rf $tmpdir 2>/dev/null || true"
michael@13 708 ;;
michael@13 709 esac
michael@13 710 else
michael@13 711 # for the execution situation just make sure we
michael@13 712 # terminate the verbose message output.
michael@13 713 if [ ".$silent" = .0 -a $verbose_pos -gt 0 ]; then
michael@13 714 echo "." 1>&2
michael@13 715 fi
michael@13 716
michael@13 717 # additionally, if a script wants its output to be displayed,
michael@13 718 # now do it. In case there was no such request, do not bother
michael@13 719 # -- we then just output an empty file and so can avoid an
michael@13 720 # extra test surrounding the next command.
michael@13 721 cat $allfile
michael@13 722 fi
michael@13 723 done
michael@13 724
michael@13 725 # cleanup temporary files except the result script in
michael@13 726 # case of --eval (which is then removed by the caller).
michael@13 727 # keep those files for debugging purposes if requested.
michael@13 728 if [ ".$keep" = .0 ]; then
michael@13 729 rm -f $outfile $errfile $allfile >/dev/null 2>&1 || true
michael@13 730 if [ ".$eval" = .0 ]; then
michael@13 731 rm -f $tmpfile >/dev/null 2>&1 || true
michael@13 732 rm -rf $tmpdir >/dev/null 2>&1 || true
michael@13 733 fi
michael@13 734 fi
michael@13 735
michael@13 736 # now clean the exit trap and exit with the global return value
michael@13 737 # indicating to the caller whether all scripts were executed
michael@13 738 # successfully or at least one failed.
michael@13 739 trap - EXIT
michael@13 740 exit $rv
michael@13 741

mercurial