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