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.
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@471 | 152 | # extend runtime 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@471 | 163 | # (rc.openpkg is special: has to be first and requires preinclusion 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@471 | 190 | # (rc.openpkg is special: has to be first and requires preinclusion 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@471 | 274 | # apply random runtime delay |
michael@428 | 275 | # (hint: $RANDOM is a random value 0..32767) |
michael@428 | 276 | sleep $(( ($RANDOM * $delay) / 32767 )) |
michael@428 | 277 | |
michael@471 | 278 | # wrap ourself for mutual exclusion runtime |
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@471 | 308 | # determine current runtime 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@469 | 319 | # Avoid handing control to OpenPKG binary logic until |
michael@469 | 320 | # the binary is is ready for prime time on all platforms. |
michael@471 | 321 | ## just call OpenPKG RPM to let it once perform the runtime integrity checks |
michael@469 | 322 | #$prefix/bin/openpkg rpm -q openpkg >/dev/null || exit $? |
michael@428 | 323 | |
michael@13 | 324 | # iterate over the specified commands |
michael@13 | 325 | rv=0 |
michael@13 | 326 | cmds="$*" |
michael@13 | 327 | for cmd in $cmds; do |
michael@13 | 328 | # create "all outputs" file for execution operation (i.e. not --print and --eval) |
michael@13 | 329 | if [ ".$print" = .0 -a ".$eval" = .0 ]; then |
michael@13 | 330 | rm -f $allfile |
michael@13 | 331 | touch $allfile |
michael@13 | 332 | fi |
michael@13 | 333 | |
michael@13 | 334 | # find scripts which contain the command and determine |
michael@13 | 335 | # their individual user/priority settings |
michael@13 | 336 | list='' |
michael@13 | 337 | for s_name in $scripts; do |
michael@13 | 338 | enable=yes |
michael@13 | 339 | |
michael@13 | 340 | # check for upgraded package with unresolved configuration file conflicts |
michael@13 | 341 | if [ -d "$prefix/etc/$s_name" -a ".$eval" != .1 ]; then |
michael@13 | 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 |
michael@13 | 343 | case "$cmd" in |
michael@13 | 344 | start|restart ) type="ERROR" ;; |
michael@13 | 345 | * ) type="WARNING" ;; |
michael@13 | 346 | esac |
michael@13 | 347 | echo "openpkg:rc:${type}: package \"$s_name\" has unresolved configuration file conflicts" 1>&2 |
michael@13 | 348 | echo "openpkg:rc:${type}: indicated by \"*.rpm(new|orig|save)\" files in or below the" 1>&2 |
michael@13 | 349 | echo "openpkg:rc:${type}: directory \"$prefix/etc/$s_name\". Please resolve first!" 1>&2 |
michael@13 | 350 | if [ ".$type" = .ERROR ]; then |
michael@13 | 351 | continue |
michael@13 | 352 | fi |
michael@13 | 353 | fi |
michael@13 | 354 | fi |
michael@13 | 355 | |
michael@13 | 356 | # check whether command exists in script at all |
michael@13 | 357 | cmdline=`grep "^%$cmd" $rcdir/rc.$s_name | sed -e "s;^%$cmd[^ ].*;;"` |
michael@13 | 358 | if [ ".$cmdline" != . ]; then |
michael@13 | 359 | # parse local command options |
michael@13 | 360 | cmdopts=`echo "$cmdline" | sed -e "s;^%$cmd *;;"` |
michael@13 | 361 | s_user=$user |
michael@13 | 362 | s_prio=500 |
michael@13 | 363 | s_output=no |
michael@13 | 364 | set -- $cmdopts |
michael@13 | 365 | prev='' |
michael@13 | 366 | for opt |
michael@13 | 367 | do |
michael@13 | 368 | if [ ".$prev" != . ]; then |
michael@13 | 369 | opt="$prev$opt" |
michael@13 | 370 | prev='' |
michael@13 | 371 | fi |
michael@13 | 372 | case $opt in |
michael@13 | 373 | -*=* ) arg=${opt/-*=/} ;; |
michael@13 | 374 | -[a-zA-Z]* ) arg=${opt/-[a-zA-Z0-9]/} ;; |
michael@13 | 375 | *) arg='' ;; |
michael@13 | 376 | esac |
michael@13 | 377 | case $opt in |
michael@13 | 378 | -u|-p ) prev=$opt ;; |
michael@13 | 379 | -e|--enable ) enable=yes ;; |
michael@13 | 380 | -d|--disable ) enable=no ;; |
michael@13 | 381 | -o|--output ) s_output=yes ;; |
michael@13 | 382 | -u*|--user=* ) s_user=$arg ;; |
michael@13 | 383 | -p*|--prio=* ) s_prio=$arg ;; |
michael@13 | 384 | * ) echo "openpkg:rc:WARNING: invalid local option \"$opt\" in \"$rcdir/rc.$s_name:%$cmd\""; break ;; |
michael@13 | 385 | esac |
michael@13 | 386 | shift |
michael@13 | 387 | done |
michael@13 | 388 | |
michael@13 | 389 | # sanity check: is operation supported by current environment? |
michael@13 | 390 | if [ ".$s_user" != ".$user" -a ".$user" != ".root" -a ".$print" = .0 ]; then |
michael@13 | 391 | echo "openpkg:rc:ERROR: $s_name:%$cmd: require root privileges to run as user \"$s_user\"" 1>&2 |
michael@13 | 392 | exit 1 |
michael@13 | 393 | fi |
michael@13 | 394 | |
michael@13 | 395 | # skip this script if script is disabled |
michael@13 | 396 | if [ ".$enable" != .yes ]; then |
michael@13 | 397 | continue |
michael@13 | 398 | fi |
michael@13 | 399 | |
michael@13 | 400 | # accumulate the determined information |
michael@13 | 401 | list="$list,$s_prio:$s_name:$s_user:$s_output" |
michael@13 | 402 | else |
michael@13 | 403 | # command not found in script |
michael@13 | 404 | if [ ".$isall" = .0 ]; then |
michael@13 | 405 | echo "openpkg:rc:ERROR: $s_name: command \"$cmd\" not found" 1>&2 |
michael@13 | 406 | exit 1 |
michael@13 | 407 | fi |
michael@13 | 408 | fi |
michael@13 | 409 | done |
michael@13 | 410 | |
michael@471 | 411 | # if operating on all scripts, complain if a nonstandard command |
michael@13 | 412 | # was used and it was not found in any(!) script at all. The |
michael@13 | 413 | # standard commands are accepted to perform no operation if no |
michael@13 | 414 | # packages are currently installed which provide such commands. |
michael@13 | 415 | if [ ".$list" = . -a ".$isall" = .1 ]; then |
michael@13 | 416 | case "$cmd" in |
michael@13 | 417 | start|stop|monthly|weekly|daily|hourly|quarterly ) |
michael@13 | 418 | ;; |
michael@13 | 419 | * ) |
michael@13 | 420 | echo "openpkg:rc:ERROR: command \"$cmd\" not found in any script" 1>&2 |
michael@13 | 421 | rv=1 |
michael@13 | 422 | break |
michael@13 | 423 | ;; |
michael@13 | 424 | esac |
michael@13 | 425 | fi |
michael@13 | 426 | |
michael@13 | 427 | # generate global (loop invariant) header for script in case of |
michael@13 | 428 | # --print and --eval (for the execution approach we cannot do |
michael@13 | 429 | # this, because there a new script is generated from scratch for |
michael@13 | 430 | # each package. |
michael@13 | 431 | if [ ".$print" = .1 -o ".$eval" = .1 ]; then |
michael@13 | 432 | rm -f $tmpfile |
michael@13 | 433 | touch $tmpfile |
michael@13 | 434 | |
michael@13 | 435 | # generate: optionally enable shell debugging |
michael@13 | 436 | if [ ".$debug" = .1 ]; then |
michael@13 | 437 | echo "set -x" >>$tmpfile |
michael@13 | 438 | fi |
michael@13 | 439 | |
michael@471 | 440 | # generate: inclusion of the runcommand helper functions |
michael@13 | 441 | echo ". $rcfunc" >>$tmpfile |
michael@13 | 442 | |
michael@13 | 443 | # generate: all %config sections of all(!) scripts. We cannot |
michael@13 | 444 | # just include those which have the current command in it |
michael@13 | 445 | # because by design all command scripts see the %config |
michael@13 | 446 | # section of all(!) scripts. Because of $openpkg_rc_def the |
michael@13 | 447 | # variable, we place the %config section of "openpkg" to the front. |
michael@471 | 448 | # And we have to extra preinclude the rc.conf to allow |
michael@13 | 449 | # rc.conf to override the default of $openpkg_rc_def, too. |
michael@13 | 450 | sed <$rcdir/rc.openpkg >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d' |
michael@13 | 451 | echo ". $rcconf" >>$tmpfile |
michael@428 | 452 | echo ". $deffile" >>$tmpfile |
michael@13 | 453 | l_scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;" | egrep -v '^openpkg$'` |
michael@13 | 454 | for l_name in $l_scripts; do |
michael@13 | 455 | sed <$rcdir/rc.$l_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d' |
michael@13 | 456 | done |
michael@13 | 457 | |
michael@13 | 458 | # generate: inclusion of the application of override variables |
michael@13 | 459 | echo ". $rcconf" >>$tmpfile |
michael@428 | 460 | echo ". $deffile" >>$tmpfile |
michael@13 | 461 | |
michael@13 | 462 | # for --eval redirect stderr and stdout (but remember stdout) |
michael@13 | 463 | # (let stderr pass unfiltered in case of debug mode) |
michael@13 | 464 | if [ ".$eval" = .1 ]; then |
michael@13 | 465 | if [ ".$debug" = .1 ]; then |
michael@13 | 466 | echo "exec 3<&1- 1>/dev/null" >>$tmpfile |
michael@13 | 467 | else |
michael@13 | 468 | echo "exec 3<&1- 1>/dev/null 2>/dev/null" >>$tmpfile |
michael@13 | 469 | fi |
michael@13 | 470 | fi |
michael@13 | 471 | fi |
michael@13 | 472 | |
michael@13 | 473 | # iterate over all packages (in priority order!) where the command |
michael@13 | 474 | # was found in order to execute, print, or evaluate their scripts |
michael@13 | 475 | verbose_pos=0 |
michael@13 | 476 | for entry in `echo $list | tr ',' '\012' | sort -n`; do |
michael@13 | 477 | [ ".$entry" = . ] && continue |
michael@13 | 478 | |
michael@471 | 479 | # redetermine the script name, script and whether to print output |
michael@13 | 480 | eval `echo $entry | sed -e 's%^[0-9]*:\(.*\):\(.*\):\(.*\)$%s_name="\1"; s_user="\2"; s_output="\3";%'` |
michael@13 | 481 | |
michael@13 | 482 | # display verbose progress message parts |
michael@13 | 483 | if [ ".$print" = .0 -a ".$eval" = .0 -a ".$silent" = .0 ]; then |
michael@13 | 484 | # line break if we already have output more than 70 |
michael@13 | 485 | # characters (notice that usually already more characters |
michael@13 | 486 | # where printed, because of the name of the last script) |
michael@13 | 487 | if [ $verbose_pos -gt 70 ]; then |
michael@13 | 488 | verbose_pos=0 |
michael@13 | 489 | echo "" 1>&2 |
michael@13 | 490 | fi |
michael@13 | 491 | |
michael@13 | 492 | # display verbose message parts: prefix (on first), separator and package |
michael@13 | 493 | if [ $verbose_pos -eq 0 ]; then |
michael@13 | 494 | output=$(printf "OpenPKG: %s: " "$cmd") |
michael@13 | 495 | echo -n "$output" 1>&2 |
michael@13 | 496 | verbose_pos=$(($verbose_pos + ${#output})) |
michael@13 | 497 | output_prefix="" |
michael@13 | 498 | else |
michael@13 | 499 | output_prefix=", " |
michael@13 | 500 | fi |
michael@13 | 501 | output=$(printf "%s%s" "$output_prefix" "$s_name") |
michael@13 | 502 | echo -n "$output" 1>&2 |
michael@13 | 503 | verbose_pos=$(($verbose_pos + ${#output})) |
michael@13 | 504 | fi |
michael@13 | 505 | |
michael@13 | 506 | # now operate on the particular script |
michael@13 | 507 | if [ ".$print" = .1 ]; then |
michael@13 | 508 | # special case: under --print we just add the %common and |
michael@13 | 509 | # command scripts to the generated output script and do |
michael@13 | 510 | # not execute anything at this point. |
michael@13 | 511 | sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d' |
michael@13 | 512 | sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d' |
michael@13 | 513 | elif [ ".$eval" = .1 ]; then |
michael@13 | 514 | # special case: under --eval we just add the %common and |
michael@13 | 515 | # command scripts to the generated output script and do |
michael@13 | 516 | # not execute anything at this point. Additionally, we |
michael@471 | 517 | # emulate a real subshell environment. |
michael@13 | 518 | sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d' |
michael@13 | 519 | echo "while [ 1 ]; do" >>$tmpfile |
michael@13 | 520 | sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d' \ |
michael@13 | 521 | -e 's/^exit[^;]*/break 99/' -e 's/\([^a-zA-Z0-9_]\)exit[^;]*/\1break 99/g' \ |
michael@13 | 522 | -e 's/^return[^;]*/break 99/' -e 's/\([^a-zA-Z0-9_]\)return[^;]*/\1break 99/g' |
michael@13 | 523 | echo "break" >>$tmpfile |
michael@13 | 524 | echo "done" >>$tmpfile |
michael@13 | 525 | else |
michael@13 | 526 | # the regular case of executing the command script directly |
michael@13 | 527 | |
michael@13 | 528 | # prepare temporary files |
michael@13 | 529 | rm -f $tmpfile $outfile $errfile |
michael@13 | 530 | (umask 077; touch $tmpfile $outfile $errfile) |
michael@13 | 531 | |
michael@13 | 532 | # generate: optionally enable shell debugging |
michael@13 | 533 | if [ ".$debug" = .1 ]; then |
michael@13 | 534 | echo "set -x" >>$tmpfile |
michael@13 | 535 | fi |
michael@13 | 536 | |
michael@471 | 537 | # generate: inclusion of the runcommand helper functions |
michael@13 | 538 | echo ". $rcfunc" >>$tmpfile |
michael@13 | 539 | |
michael@13 | 540 | # generate: all %config sections of all(!) scripts. We cannot |
michael@13 | 541 | # just include those which have the current command in it |
michael@13 | 542 | # because by design all command scripts see the %config |
michael@13 | 543 | # section of all(!) scripts. Because of $openpkg_rc_def the |
michael@13 | 544 | # variable, we place the %config section of "openpkg" to the front. |
michael@471 | 545 | # And we have to extra preinclude the rc.conf to allow |
michael@13 | 546 | # rc.conf to override the default of $openpkg_rc_def, too. |
michael@13 | 547 | sed <$rcdir/rc.openpkg >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d' |
michael@13 | 548 | echo ". $rcconf" >>$tmpfile |
michael@428 | 549 | echo ". $deffile" >>$tmpfile |
michael@13 | 550 | l_scripts=`/bin/ls $rcdir/rc.* | sed -e "s;^$rcdir/rc\.;;" | egrep -v '^openpkg$'` |
michael@13 | 551 | for l_name in $l_scripts; do |
michael@13 | 552 | sed <$rcdir/rc.$l_name >>$tmpfile -e "1,/^%config/d" -e '/^%.*/,$d' |
michael@13 | 553 | done |
michael@13 | 554 | |
michael@13 | 555 | # generate: inclusion of the application of override variables |
michael@13 | 556 | echo ". $rcconf" >>$tmpfile |
michael@428 | 557 | echo ". $deffile" >>$tmpfile |
michael@13 | 558 | |
michael@13 | 559 | # generate: %common section and particular command section |
michael@13 | 560 | sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%common/d" -e '/^%.*/,$d' |
michael@13 | 561 | sed <$rcdir/rc.$s_name >>$tmpfile -e "1,/^%$cmd/d" -e '/^%.*/,$d' |
michael@13 | 562 | |
michael@13 | 563 | # execute the generated script with GNU Bash |
michael@13 | 564 | if [ ".$user" != ".$s_user" ]; then |
michael@13 | 565 | # execute as different user |
michael@13 | 566 | if [ ".$verbose" = .1 ]; then |
michael@13 | 567 | echo "openpkg:rc:NOTICE: $prefix:$s_name:%$cmd: executing as user $s_user" |
michael@13 | 568 | fi |
michael@13 | 569 | if [ ".$user" = ".@l_susr@" -a ".@l_susr@" = ".root" ]; then |
michael@13 | 570 | chown $s_user $tmpfile |
michael@13 | 571 | if [ ".$debug" = .1 ]; then |
michael@13 | 572 | su - $s_user -c "PATH=\"$PATH\"; $bash $tmpfile" >$outfile |
michael@13 | 573 | rc=$? |
michael@13 | 574 | else |
michael@13 | 575 | su - $s_user -c "PATH=\"$PATH\"; $bash $tmpfile" >$outfile 2>$errfile |
michael@13 | 576 | rc=$? |
michael@13 | 577 | fi |
michael@13 | 578 | elif [ ".@l_susr@" != ".root" ]; then |
michael@13 | 579 | # do not complain if we would not have any chance |
michael@13 | 580 | # at all to switch the user because we are running |
michael@471 | 581 | # in a unprivileged instance. Else we would just |
michael@13 | 582 | # trash the mailbox of the user receiving the |
michael@471 | 583 | # output of periodic runcommands. |
michael@13 | 584 | rc=0 |
michael@13 | 585 | else |
michael@13 | 586 | echo "openpkg:rc:WARNING: $prefix:$s_name:%$cmd: require root privileges to run as user \"$s_user\"" 1>&2 |
michael@13 | 587 | rc=1 |
michael@13 | 588 | fi |
michael@13 | 589 | else |
michael@13 | 590 | # execute as current user |
michael@13 | 591 | if [ ".$verbose" = .1 ]; then |
michael@13 | 592 | echo "openpkg:rc:NOTICE: $prefix:$s_name:%$cmd: executing as user $user" |
michael@13 | 593 | fi |
michael@13 | 594 | if [ ".$debug" = .1 ]; then |
michael@13 | 595 | $bash $tmpfile >$outfile |
michael@13 | 596 | rc=$? |
michael@13 | 597 | else |
michael@13 | 598 | $bash $tmpfile >$outfile 2>$errfile |
michael@13 | 599 | rc=$? |
michael@13 | 600 | fi |
michael@13 | 601 | fi |
michael@13 | 602 | if [ $rc -ne 0 ]; then |
michael@13 | 603 | if [ ".$silent" = .0 ]; then |
michael@13 | 604 | # indicate failure of execution on verbose message line |
michael@13 | 605 | echo ":FAILED" 1>&2 |
michael@13 | 606 | verbose_pos=0 |
michael@13 | 607 | fi |
michael@13 | 608 | # give details of execution failure |
michael@13 | 609 | ( echo "openpkg:rc:WARNING: $prefix:$s_name:%$cmd: failed with return code $rc" |
michael@13 | 610 | if [ ".`cat $outfile $errfile`" != . ]; then |
michael@13 | 611 | echo "openpkg:rc:NOTICE: output from stdout/stderr is following:" |
michael@13 | 612 | echo "+----------------------------------------------------------------------" |
michael@13 | 613 | cat $outfile $errfile | sed -e 's;^;| ;' |
michael@13 | 614 | echo "+----------------------------------------------------------------------" |
michael@13 | 615 | else |
michael@13 | 616 | echo "openpkg:rc:NOTICE: no output occurred on stdout/stderr" |
michael@13 | 617 | fi |
michael@13 | 618 | ) 1>&2 |
michael@13 | 619 | |
michael@13 | 620 | # enforce global return value |
michael@13 | 621 | rv=1 |
michael@13 | 622 | else |
michael@13 | 623 | # give details of execution success in case verbose operation is requested |
michael@13 | 624 | if [ ".$verbose" = .1 ]; then |
michael@13 | 625 | ( echo "openpkg:rc:NOTICE: $prefix:$s_name:%$cmd: succeeded with return code $rc" |
michael@13 | 626 | if [ ".`cat $outfile $errfile`" != . ]; then |
michael@13 | 627 | echo "openpkg:rc:NOTICE: output from stdout/stderr is following:" |
michael@13 | 628 | echo "+----------------------------------------------------------------------" |
michael@13 | 629 | cat $outfile $errfile | sed -e 's;^;| ;' |
michael@13 | 630 | echo "+----------------------------------------------------------------------" |
michael@13 | 631 | else |
michael@13 | 632 | echo "openpkg:rc:NOTICE: no output occurred on stdout/stderr" |
michael@13 | 633 | fi |
michael@13 | 634 | ) 1>&2 |
michael@13 | 635 | fi |
michael@13 | 636 | if [ ".$s_output" = .yes ]; then |
michael@13 | 637 | # accumulate script output for later display |
michael@13 | 638 | cat $outfile >>$allfile |
michael@13 | 639 | fi |
michael@13 | 640 | fi |
michael@13 | 641 | fi |
michael@13 | 642 | done |
michael@13 | 643 | |
michael@471 | 644 | # postprocessing for each command |
michael@13 | 645 | if [ ".$print" = .1 ]; then |
michael@13 | 646 | # for --print just print the resulting script to stdout |
michael@13 | 647 | cat $tmpfile |
michael@13 | 648 | elif [ ".$eval" = .1 ]; then |
michael@13 | 649 | # finish generation of temporary script by restoring stdout |
michael@13 | 650 | # and printing the exported environment variables into a format |
michael@13 | 651 | # suitable for evaluation by the callers shell. |
michael@13 | 652 | echo "exec 1<&3-" >>$tmpfile |
michael@13 | 653 | echo "unset PWD SHLVL" >>$tmpfile |
michael@13 | 654 | echo "env |\\" >>$tmpfile |
michael@13 | 655 | echo "egrep '^[A-Z_][A-Z0-9_]*=.' |\\" >>$tmpfile |
michael@13 | 656 | echo "sed -e '/^_=/d' -e 's/\\\\/\\\\\\\\/g' -e 's/\"/\\\\\"/g' \\" >>$tmpfile |
michael@13 | 657 | case $SHELL in |
michael@13 | 658 | csh|*/csh|tcsh|*/tcsh ) |
michael@13 | 659 | echo "-e 's/^\\([^=]*\\)=\\(.*\\)\$/setenv \\1 \"\\2\"/'" >>$tmpfile |
michael@13 | 660 | ;; |
michael@13 | 661 | * ) |
michael@13 | 662 | echo "-e 's/^\\([^=]*\\)=\\(.*\\)\$/\\1=\"\\2\"; export \\1/'" >>$tmpfile |
michael@13 | 663 | ;; |
michael@13 | 664 | esac |
michael@13 | 665 | |
michael@13 | 666 | # prepare temporary files |
michael@13 | 667 | rm -f $outfile $errfile |
michael@13 | 668 | touch $outfile $errfile |
michael@13 | 669 | |
michael@13 | 670 | # now replace temporary script with its output |
michael@13 | 671 | # by executing it and capturing its output |
michael@13 | 672 | # (let stderr pass unfiltered in case of debug mode) |
michael@13 | 673 | if [ ".$debug" = .1 ]; then |
michael@13 | 674 | env -i \ |
michael@13 | 675 | HOME="$HOME" \ |
michael@13 | 676 | USER="$USER" \ |
michael@13 | 677 | LOGNAME="$LOGNAME" \ |
michael@13 | 678 | TERM="$TERM" \ |
michael@13 | 679 | PATH="$PATH_ORIG" \ |
michael@13 | 680 | MANPATH="$MANPATH" \ |
michael@13 | 681 | INFOPATH="$INFOPATH" \ |
michael@13 | 682 | LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ |
michael@13 | 683 | $bash --norc --noprofile --posix \ |
michael@13 | 684 | $tmpfile >$outfile |
michael@13 | 685 | else |
michael@13 | 686 | env -i \ |
michael@13 | 687 | HOME="$HOME" \ |
michael@13 | 688 | USER="$USER" \ |
michael@13 | 689 | LOGNAME="$LOGNAME" \ |
michael@13 | 690 | TERM="$TERM" \ |
michael@13 | 691 | PATH="$PATH_ORIG" \ |
michael@13 | 692 | MANPATH="$MANPATH" \ |
michael@13 | 693 | INFOPATH="$INFOPATH" \ |
michael@13 | 694 | LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \ |
michael@13 | 695 | $bash --norc --noprofile --posix \ |
michael@13 | 696 | $tmpfile >$outfile 2>/dev/null |
michael@13 | 697 | fi |
michael@13 | 698 | cp $outfile $tmpfile |
michael@13 | 699 | |
michael@13 | 700 | # for --eval we cannot just print the resulting script because |
michael@471 | 701 | # not all Bourne Shell implementations like to "eval" large |
michael@471 | 702 | # multiline outputs. Hence we output a little one liner which |
michael@13 | 703 | # "sources" the script instead and cleans up. |
michael@13 | 704 | case $SHELL in |
michael@13 | 705 | csh|*/csh|tcsh|*/tcsh ) |
michael@13 | 706 | echo "source $tmpfile; rm -rf $tmpdir 2>/dev/null || true" |
michael@13 | 707 | ;; |
michael@13 | 708 | * ) |
michael@13 | 709 | echo ". $tmpfile; rm -rf $tmpdir 2>/dev/null || true" |
michael@13 | 710 | ;; |
michael@13 | 711 | esac |
michael@13 | 712 | else |
michael@13 | 713 | # for the execution situation just make sure we |
michael@13 | 714 | # terminate the verbose message output. |
michael@13 | 715 | if [ ".$silent" = .0 -a $verbose_pos -gt 0 ]; then |
michael@13 | 716 | echo "." 1>&2 |
michael@13 | 717 | fi |
michael@13 | 718 | |
michael@13 | 719 | # additionally, if a script wants its output to be displayed, |
michael@13 | 720 | # now do it. In case there was no such request, do not bother |
michael@13 | 721 | # -- we then just output an empty file and so can avoid an |
michael@13 | 722 | # extra test surrounding the next command. |
michael@13 | 723 | cat $allfile |
michael@13 | 724 | fi |
michael@13 | 725 | done |
michael@13 | 726 | |
michael@13 | 727 | # cleanup temporary files except the result script in |
michael@13 | 728 | # case of --eval (which is then removed by the caller). |
michael@13 | 729 | # keep those files for debugging purposes if requested. |
michael@13 | 730 | if [ ".$keep" = .0 ]; then |
michael@13 | 731 | rm -f $outfile $errfile $allfile >/dev/null 2>&1 || true |
michael@13 | 732 | if [ ".$eval" = .0 ]; then |
michael@13 | 733 | rm -f $tmpfile >/dev/null 2>&1 || true |
michael@13 | 734 | rm -rf $tmpdir >/dev/null 2>&1 || true |
michael@13 | 735 | fi |
michael@13 | 736 | fi |
michael@13 | 737 | |
michael@13 | 738 | # now clean the exit trap and exit with the global return value |
michael@13 | 739 | # indicating to the caller whether all scripts were executed |
michael@13 | 740 | # successfully or at least one failed. |
michael@13 | 741 | trap - EXIT |
michael@13 | 742 | exit $rv |
michael@13 | 743 |