1#!/bin/sh 2## 3## GNU shtool -- The GNU Portable Shell Tool 4## Copyright (c) 1994-2006 Ralf S. Engelschall <rse@engelschall.com> 5## 6## See http://www.gnu.org/software/shtool/ for more information. 7## See ftp://ftp.gnu.org/gnu/shtool/ for latest version. 8## 9## Version: 2.0.5 (07-Feb-2006) 10## Contents: 6/19 available modules 11## 12 13## 14## This program is free software; you can redistribute it and/or modify 15## it under the terms of the GNU General Public License as published by 16## the Free Software Foundation; either version 2 of the License, or 17## (at your option) any later version. 18## 19## This program is distributed in the hope that it will be useful, 20## but WITHOUT ANY WARRANTY; without even the implied warranty of 21## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22## General Public License for more details. 23## 24## You should have received a copy of the GNU General Public License 25## along with this program; if not, write to the Free Software 26## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 27## USA, or contact Ralf S. Engelschall <rse@engelschall.com>. 28## 29## NOTICE: Given that you include this file verbatim into your own 30## source tree, you are justified in saying that it remains separate 31## from your package, and that this way you are simply just using GNU 32## shtool. So, in this situation, there is no requirement that your 33## package itself is licensed under the GNU General Public License in 34## order to take advantage of GNU shtool. 35## 36 37## 38## Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]] 39## 40## Available commands: 41## echo Print string with optional construct expansion 42## move Move files with simultaneous substitution 43## install Install a program, script or datafile 44## mkdir Make one or more directories 45## mkln Make link with calculation of relative paths 46## subst Apply sed(1) substitution operations 47## 48## Not available commands (because module was not built-in): 49## mdate Pretty-print modification time of a file or dir 50## table Pretty-print a field-separated list as a table 51## prop Display progress with a running propeller 52## mkshadow Make a shadow tree through symbolic links 53## fixperm Fix file permissions inside a source tree 54## rotate Logfile rotation 55## tarball Roll distribution tarballs 56## platform Platform Identification Utility 57## arx Extended archive command 58## slo Separate linker options by library class 59## scpp Sharing C Pre-Processor 60## version Maintain a version information file 61## path Deal with program paths 62## 63 64# maximum Bourne-Shell compatibility 65if [ ".$ZSH_VERSION" != . ] && (emulate sh) >/dev/null 2>&1; then 66 # reconfigure zsh(1) 67 emulate sh 68 NULLCMD=: 69 alias -g '${1+"$@"}'='"$@"' 70elif [ ".$BASH_VERSION" != . ] && (set -o posix) >/dev/null 2>&1; then 71 # reconfigure bash(1) 72 set -o posix 73fi 74 75# maximum independence of NLS nuisances 76for var in \ 77 LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ 78 LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ 79 LC_TELEPHONE LC_TIME 80do 81 if (set +x; test -z "`(eval $var=C; export $var) 2>&1`"); then 82 eval $var=C; export $var 83 else 84 unset $var 85 fi 86done 87 88# initial command line handling 89if [ $# -eq 0 ]; then 90 echo "$0:Error: invalid command line" 1>&2 91 echo "$0:Hint: run \`$0 -h' for usage" 1>&2 92 exit 1 93fi 94if [ ".$1" = ".-h" ] || [ ".$1" = ".--help" ]; then 95 echo "This is GNU shtool, version 2.0.5 (07-Feb-2006)" 96 echo 'Copyright (c) 1994-2006 Ralf S. Engelschall <rse@engelschall.com>' 97 echo 'Report bugs to <bug-shtool@gnu.org>' 98 echo '' 99 echo 'Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]' 100 echo '' 101 echo 'Available global <options>:' 102 echo ' -v, --version display shtool version information' 103 echo ' -h, --help display shtool usage help page (this one)' 104 echo ' -d, --debug display shell trace information' 105 echo ' -r, --recreate recreate this shtool script via shtoolize' 106 echo '' 107 echo 'Available <cmd-name> [<cmd-options>] [<cmd-args>]:' 108 echo ' echo [-n|--newline] [-e|--expand] [<string> ...]' 109 echo ' move [-v|--verbose] [-t|--trace] [-e|--expand] [-p|--preserve]' 110 echo ' <src-file> <dst-file>' 111 echo ' install [-v|--verbose] [-t|--trace] [-d|--mkdir] [-c|--copy]' 112 echo ' [-C|--compare-copy] [-s|--strip] [-m|--mode <mode>]' 113 echo ' [-o|--owner <owner>] [-g|--group <group>] [-e|--exec' 114 echo ' <sed-cmd>] <file> [<file> ...] <path>' 115 echo ' mkdir [-t|--trace] [-f|--force] [-p|--parents] [-m|--mode' 116 echo ' <mode>] [-o|--owner <owner>] [-g|--group <group>] <dir>' 117 echo ' [<dir> ...]' 118 echo ' mkln [-t|--trace] [-f|--force] [-s|--symbolic] <src-path>' 119 echo ' [<src-path> ...] <dst-path>' 120 echo ' subst [-v|--verbose] [-t|--trace] [-n|--nop] [-w|--warning]' 121 echo ' [-q|--quiet] [-s|--stealth] [-i|--interactive] [-b|--backup' 122 echo ' <ext>] [-e|--exec <cmd>] [-f|--file <cmd-file>] [<file>]' 123 echo ' [...]' 124 echo '' 125 echo 'Not available <cmd-name> (because module was not built-in):' 126 echo ' mdate [-n|--newline] [-z|--zero] [-s|--shorten] [-d|--digits]' 127 echo ' [-f|--field-sep <str>] [-o|--order <spec>] <path>' 128 echo ' table [-F|--field-sep <sep>] [-w|--width <width>] [-c|--columns' 129 echo ' <cols>] [-s|--strip <strip>] <str><sep><str>...' 130 echo ' prop [-p|--prefix <str>]' 131 echo ' mkshadow [-v|--verbose] [-t|--trace] [-a|--all] <src-dir> <dst-dir>' 132 echo ' fixperm [-v|--verbose] [-t|--trace] <path> [<path> ...]' 133 echo ' rotate [-v|--verbose] [-t|--trace] [-f|--force] [-n|--num-files' 134 echo ' <count>] [-s|--size <size>] [-c|--copy] [-r|--remove]' 135 echo ' [-a|--archive-dir <dir>] [-z|--compress [<tool>:]<level>]' 136 echo ' [-b|--background] [-d|--delay] [-p|--pad <len>] [-m|--mode' 137 echo ' <mode>] [-o|--owner <owner>] [-g|--group <group>] [-M|--migrate' 138 echo ' <cmd>] [-P|--prolog <cmd>] [-E|--epilog <cmd>] <file> [...]' 139 echo ' tarball [-t|--trace] [-v|--verbose] [-o|--output <tarball>]' 140 echo ' [-c|--compress <prog>] [-d|--directory <dir>] [-u|--user' 141 echo ' <user>] [-g|--group <group>] [-e|--exclude <pattern>]' 142 echo ' <path> [<path> ...]' 143 echo ' platform [-F|--format <format>] [-S|--sep <string>] [-C|--conc' 144 echo ' <string>] [-L|--lower] [-U|--upper] [-v|--verbose]' 145 echo ' [-c|--concise] [-n|--no-newline] [-t|--type <type>]' 146 echo ' [-V|--version] [-h|--help]' 147 echo ' arx [-t|--trace] [-C|--command <cmd>] <op> <archive> [<file>' 148 echo ' ...]' 149 echo ' slo [-p|--prefix <str>] -- -L<dir> -l<lib> [-L<dir> -l<lib>' 150 echo ' ...]' 151 echo ' scpp [-v|--verbose] [-p|--preserve] [-f|--filter <filter>]' 152 echo ' [-o|--output <ofile>] [-t|--template <tfile>] [-M|--mark' 153 echo ' <mark>] [-D|--define <dname>] [-C|--class <cname>]' 154 echo ' <file> [<file> ...]' 155 echo ' version [-l|--language <lang>] [-n|--name <name>] [-p|--prefix' 156 echo ' <prefix>] [-s|--set <version>] [-e|--edit] [-i|--increase' 157 echo ' <knob>] [-d|--display <type>] <file>' 158 echo ' path [-s|--suppress] [-r|--reverse] [-d|--dirname] [-b|--basename]' 159 echo ' [-m|--magic] [-p|--path <path>] <str> [<str> ...]' 160 echo '' 161 exit 0 162fi 163if [ ".$1" = ".-v" ] || [ ".$1" = ".--version" ]; then 164 echo "GNU shtool 2.0.5 (07-Feb-2006)" 165 exit 0 166fi 167if [ ".$1" = ".-r" ] || [ ".$1" = ".--recreate" ]; then 168 shtoolize -oshtool echo move install mkdir mkln subst 169 exit 0 170fi 171if [ ".$1" = ".-d" ] || [ ".$1" = ".--debug" ]; then 172 shift 173 set -x 174fi 175name=`echo "$0" | sed -e 's;.*/\([^/]*\)$;\1;' -e 's;-sh$;;' -e 's;\.sh$;;'` 176case "$name" in 177 echo|move|install|mkdir|mkln|subst ) 178 # implicit tool command selection 179 tool="$name" 180 ;; 181 * ) 182 # explicit tool command selection 183 tool="$1" 184 shift 185 ;; 186esac 187arg_spec="" 188opt_spec="" 189gen_tmpfile=no 190 191## 192## DISPATCH INTO SCRIPT PROLOG 193## 194 195case $tool in 196 echo ) 197 str_tool="echo" 198 str_usage="[-n|--newline] [-e|--expand] [<string> ...]" 199 arg_spec="0+" 200 opt_spec="n.e." 201 opt_alias="n:newline,e:expand" 202 opt_n=no 203 opt_e=no 204 ;; 205 move ) 206 str_tool="move" 207 str_usage="[-v|--verbose] [-t|--trace] [-e|--expand] [-p|--preserve] <src-file> <dst-file>" 208 arg_spec="2=" 209 opt_spec="v.t.e.p." 210 opt_alias="v:verbose,t:trace,e:expand,p:preserve" 211 opt_v=no 212 opt_t=no 213 opt_e=no 214 opt_p=no 215 ;; 216 install ) 217 str_tool="install" 218 str_usage="[-v|--verbose] [-t|--trace] [-d|--mkdir] [-c|--copy] [-C|--compare-copy] [-s|--strip] [-m|--mode <mode>] [-o|--owner <owner>] [-g|--group <group>] [-e|--exec <sed-cmd>] <file> [<file> ...] <path>" 219 arg_spec="1+" 220 opt_spec="v.t.d.c.C.s.m:o:g:e+" 221 opt_alias="v:verbose,t:trace,d:mkdir,c:copy,C:compare-copy,s:strip,m:mode,o:owner,g:group,e:exec" 222 opt_v=no 223 opt_t=no 224 opt_d=no 225 opt_c=no 226 opt_C=no 227 opt_s=no 228 opt_m="0755" 229 opt_o="" 230 opt_g="" 231 opt_e="" 232 ;; 233 mkdir ) 234 str_tool="mkdir" 235 str_usage="[-t|--trace] [-f|--force] [-p|--parents] [-m|--mode <mode>] [-o|--owner <owner>] [-g|--group <group>] <dir> [<dir> ...]" 236 arg_spec="1+" 237 opt_spec="t.f.p.m:o:g:" 238 opt_alias="t:trace,f:force,p:parents,m:mode,o:owner,g:group" 239 opt_t=no 240 opt_f=no 241 opt_p=no 242 opt_m="" 243 opt_o="" 244 opt_g="" 245 ;; 246 mkln ) 247 str_tool="mkln" 248 str_usage="[-t|--trace] [-f|--force] [-s|--symbolic] <src-path> [<src-path> ...] <dst-path>" 249 arg_spec="2+" 250 opt_spec="t.f.s." 251 opt_alias="t:trace,f:force,s:symbolic" 252 opt_t=no 253 opt_f=no 254 opt_s=no 255 ;; 256 subst ) 257 str_tool="subst" 258 str_usage="[-v|--verbose] [-t|--trace] [-n|--nop] [-w|--warning] [-q|--quiet] [-s|--stealth] [-i|--interactive] [-b|--backup <ext>] [-e|--exec <cmd>] [-f|--file <cmd-file>] [<file>] [...]" 259 gen_tmpfile=yes 260 arg_spec="0+" 261 opt_spec="v.t.n.w.q.s.i.b:e+f:" 262 opt_alias="v:verbose,t:trace,n:nop,w:warning,q:quiet,s:stealth,i:interactive,b:backup,e:exec,f:file" 263 opt_v=no 264 opt_t=no 265 opt_n=no 266 opt_w=no 267 opt_q=no 268 opt_s=no 269 opt_i=no 270 opt_b="" 271 opt_e="" 272 opt_f="" 273 ;; 274 -* ) 275 echo "$0:Error: unknown option \`$tool'" 2>&1 276 echo "$0:Hint: run \`$0 -h' for usage" 2>&1 277 exit 1 278 ;; 279 * ) 280 echo "$0:Error: unknown command \`$tool'" 2>&1 281 echo "$0:Hint: run \`$0 -h' for usage" 2>&1 282 exit 1 283 ;; 284esac 285 286## 287## COMMON UTILITY CODE 288## 289 290# commonly used ASCII values 291ASC_TAB=" " 292ASC_NL=" 293" 294 295# determine name of tool 296if [ ".$tool" != . ]; then 297 # used inside shtool script 298 toolcmd="$0 $tool" 299 toolcmdhelp="shtool $tool" 300 msgprefix="shtool:$tool" 301else 302 # used as standalone script 303 toolcmd="$0" 304 toolcmdhelp="sh $0" 305 msgprefix="$str_tool" 306fi 307 308# parse argument specification string 309eval `echo $arg_spec |\ 310 sed -e 's/^\([0-9]*\)\([+=]\)/arg_NUMS=\1; arg_MODE=\2/'` 311 312# parse option specification string 313eval `echo h.$opt_spec |\ 314 sed -e 's/\([a-zA-Z0-9]\)\([.:+]\)/opt_MODE_\1=\2;/g'` 315 316# parse option alias string 317eval `echo h:help,$opt_alias |\ 318 sed -e 's/-/_/g' -e 's/\([a-zA-Z0-9]\):\([^,]*\),*/opt_ALIAS_\2=\1;/g'` 319 320# interate over argument line 321opt_PREV='' 322while [ $# -gt 0 ]; do 323 # special option stops processing 324 if [ ".$1" = ".--" ]; then 325 shift 326 break 327 fi 328 329 # determine option and argument 330 opt_ARG_OK=no 331 if [ ".$opt_PREV" != . ]; then 332 # merge previous seen option with argument 333 opt_OPT="$opt_PREV" 334 opt_ARG="$1" 335 opt_ARG_OK=yes 336 opt_PREV='' 337 else 338 # split argument into option and argument 339 case "$1" in 340 --[a-zA-Z0-9]*=*) 341 eval `echo "x$1" |\ 342 sed -e 's/^x--\([a-zA-Z0-9-]*\)=\(.*\)$/opt_OPT="\1";opt_ARG="\2"/'` 343 opt_STR=`echo $opt_OPT | sed -e 's/-/_/g'` 344 eval "opt_OPT=\${opt_ALIAS_${opt_STR}-${opt_OPT}}" 345 ;; 346 --[a-zA-Z0-9]*) 347 opt_OPT=`echo "x$1" | cut -c4-` 348 opt_STR=`echo $opt_OPT | sed -e 's/-/_/g'` 349 eval "opt_OPT=\${opt_ALIAS_${opt_STR}-${opt_OPT}}" 350 opt_ARG='' 351 ;; 352 -[a-zA-Z0-9]*) 353 eval `echo "x$1" |\ 354 sed -e 's/^x-\([a-zA-Z0-9]\)/opt_OPT="\1";/' \ 355 -e 's/";\(.*\)$/"; opt_ARG="\1"/'` 356 ;; 357 -[a-zA-Z0-9]) 358 opt_OPT=`echo "x$1" | cut -c3-` 359 opt_ARG='' 360 ;; 361 *) 362 break 363 ;; 364 esac 365 fi 366 367 # eat up option 368 shift 369 370 # determine whether option needs an argument 371 eval "opt_MODE=\$opt_MODE_${opt_OPT}" 372 if [ ".$opt_ARG" = . ] && [ ".$opt_ARG_OK" != .yes ]; then 373 if [ ".$opt_MODE" = ".:" ] || [ ".$opt_MODE" = ".+" ]; then 374 opt_PREV="$opt_OPT" 375 continue 376 fi 377 fi 378 379 # process option 380 case $opt_MODE in 381 '.' ) 382 # boolean option 383 eval "opt_${opt_OPT}=yes" 384 ;; 385 ':' ) 386 # option with argument (multiple occurances override) 387 eval "opt_${opt_OPT}=\"\$opt_ARG\"" 388 ;; 389 '+' ) 390 # option with argument (multiple occurances append) 391 eval "opt_${opt_OPT}=\"\$opt_${opt_OPT}\${ASC_NL}\$opt_ARG\"" 392 ;; 393 * ) 394 echo "$msgprefix:Error: unknown option: \`$opt_OPT'" 1>&2 395 echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2 396 exit 1 397 ;; 398 esac 399done 400if [ ".$opt_PREV" != . ]; then 401 echo "$msgprefix:Error: missing argument to option \`$opt_PREV'" 1>&2 402 echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2 403 exit 1 404fi 405 406# process help option 407if [ ".$opt_h" = .yes ]; then 408 echo "Usage: $toolcmdhelp $str_usage" 409 exit 0 410fi 411 412# complain about incorrect number of arguments 413case $arg_MODE in 414 '=' ) 415 if [ $# -ne $arg_NUMS ]; then 416 echo "$msgprefix:Error: invalid number of arguments (exactly $arg_NUMS expected)" 1>&2 417 echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2 418 exit 1 419 fi 420 ;; 421 '+' ) 422 if [ $# -lt $arg_NUMS ]; then 423 echo "$msgprefix:Error: invalid number of arguments (at least $arg_NUMS expected)" 1>&2 424 echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2 425 exit 1 426 fi 427 ;; 428esac 429 430# establish a temporary file on request 431if [ ".$gen_tmpfile" = .yes ]; then 432 # create (explicitly) secure temporary directory 433 if [ ".$TMPDIR" != . ]; then 434 tmpdir="$TMPDIR" 435 elif [ ".$TEMPDIR" != . ]; then 436 tmpdir="$TEMPDIR" 437 else 438 tmpdir="/tmp" 439 fi 440 tmpdir="$tmpdir/.shtool.$$" 441 ( umask 077 442 rm -rf "$tmpdir" >/dev/null 2>&1 || true 443 mkdir "$tmpdir" >/dev/null 2>&1 444 if [ $? -ne 0 ]; then 445 echo "$msgprefix:Error: failed to create temporary directory \`$tmpdir'" 1>&2 446 exit 1 447 fi 448 ) 449 450 # create (implicitly) secure temporary file 451 tmpfile="$tmpdir/shtool.tmp" 452 touch "$tmpfile" 453fi 454 455# utility function: map string to lower case 456util_lower () { 457 echo "$1" | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' 458} 459 460# utility function: map string to upper case 461util_upper () { 462 echo "$1" | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 463} 464 465# cleanup procedure 466shtool_exit () { 467 rc="$1" 468 if [ ".$gen_tmpfile" = .yes ]; then 469 rm -rf "$tmpdir" >/dev/null 2>&1 || true 470 fi 471 exit $rc 472} 473 474## 475## DISPATCH INTO SCRIPT BODY 476## 477 478case $tool in 479 480echo ) 481 ## 482 ## echo -- Print string with optional construct expansion 483 ## Copyright (c) 1998-2006 Ralf S. Engelschall <rse@engelschall.com> 484 ## 485 486 text="$*" 487 488 # check for broken escape sequence expansion 489 seo='' 490 bytes=`echo '\1' | wc -c | awk '{ printf("%s", $1); }'` 491 if [ ".$bytes" != .3 ]; then 492 bytes=`echo -E '\1' | wc -c | awk '{ printf("%s", $1); }'` 493 if [ ".$bytes" = .3 ]; then 494 seo='-E' 495 fi 496 fi 497 498 # check for existing -n option (to suppress newline) 499 minusn='' 500 bytes=`echo -n 123 2>/dev/null | wc -c | awk '{ printf("%s", $1); }'` 501 if [ ".$bytes" = .3 ]; then 502 minusn='-n' 503 fi 504 505 # determine terminal bold sequence 506 term_bold='' 507 term_norm='' 508 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[Bb]'`" != . ]; then 509 case $TERM in 510 # for the most important terminal types we directly know the sequences 511 xterm|xterm*|vt220|vt220*) 512 term_bold=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' </dev/null 2>/dev/null` 513 term_norm=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' </dev/null 2>/dev/null` 514 ;; 515 vt100|vt100*|cygwin) 516 term_bold=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' </dev/null 2>/dev/null` 517 term_norm=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' </dev/null 2>/dev/null` 518 ;; 519 # for all others, we try to use a possibly existing `tput' or `tcout' utility 520 * ) 521 paths=`echo $PATH | sed -e 's/:/ /g'` 522 for tool in tput tcout; do 523 for dir in $paths; do 524 if [ -r "$dir/$tool" ]; then 525 for seq in bold md smso; do # 'smso' is last 526 bold="`$dir/$tool $seq 2>/dev/null`" 527 if [ ".$bold" != . ]; then 528 term_bold="$bold" 529 break 530 fi 531 done 532 if [ ".$term_bold" != . ]; then 533 for seq in sgr0 me rmso init reset; do # 'reset' is last 534 norm="`$dir/$tool $seq 2>/dev/null`" 535 if [ ".$norm" != . ]; then 536 term_norm="$norm" 537 break 538 fi 539 done 540 fi 541 break 542 fi 543 done 544 if [ ".$term_bold" != . ] && [ ".$term_norm" != . ]; then 545 break; 546 fi 547 done 548 ;; 549 esac 550 if [ ".$term_bold" = . ] || [ ".$term_norm" = . ]; then 551 echo "$msgprefix:Warning: unable to determine terminal sequence for bold mode" 1>&2 552 term_bold='' 553 term_norm='' 554 fi 555 fi 556 557 # determine user name 558 username='' 559 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[uUgG]'`" != . ]; then 560 username="`(id -un) 2>/dev/null`" 561 if [ ".$username" = . ]; then 562 str="`(id) 2>/dev/null`" 563 if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then 564 username=`echo $str | sed -e 's/^uid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` 565 fi 566 if [ ".$username" = . ]; then 567 username="$LOGNAME" 568 if [ ".$username" = . ]; then 569 username="$USER" 570 if [ ".$username" = . ]; then 571 username="`(whoami) 2>/dev/null |\ 572 awk '{ printf("%s", $1); }'`" 573 if [ ".$username" = . ]; then 574 username="`(who am i) 2>/dev/null |\ 575 awk '{ printf("%s", $1); }'`" 576 if [ ".$username" = . ]; then 577 username='unknown' 578 fi 579 fi 580 fi 581 fi 582 fi 583 fi 584 fi 585 586 # determine user id 587 userid='' 588 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%U'`" != . ]; then 589 userid="`(id -u) 2>/dev/null`" 590 if [ ".$userid" = . ]; then 591 userid="`(id -u ${username}) 2>/dev/null`" 592 if [ ".$userid" = . ]; then 593 str="`(id) 2>/dev/null`" 594 if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then 595 userid=`echo $str | sed -e 's/^uid[ ]*=[ ]*//' -e 's/(.*$//'` 596 fi 597 if [ ".$userid" = . ]; then 598 userid=`(getent passwd ${username}) 2>/dev/null | \ 599 sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` 600 if [ ".$userid" = . ]; then 601 userid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ 602 sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` 603 if [ ".$userid" = . ]; then 604 userid=`(ypcat passwd) 2>/dev/null | 605 grep "^${username}:" | \ 606 sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` 607 if [ ".$userid" = . ]; then 608 userid='?' 609 fi 610 fi 611 fi 612 fi 613 fi 614 fi 615 fi 616 617 # determine (primary) group id 618 groupid='' 619 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[gG]'`" != . ]; then 620 groupid="`(id -g ${username}) 2>/dev/null`" 621 if [ ".$groupid" = . ]; then 622 str="`(id) 2>/dev/null`" 623 if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then 624 groupid=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*//' -e 's/(.*$//'` 625 fi 626 if [ ".$groupid" = . ]; then 627 groupid=`(getent passwd ${username}) 2>/dev/null | \ 628 sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 629 if [ ".$groupid" = . ]; then 630 groupid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ 631 sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 632 if [ ".$groupid" = . ]; then 633 groupid=`(ypcat passwd) 2>/dev/null | grep "^${username}:" | \ 634 sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 635 if [ ".$groupid" = . ]; then 636 groupid='?' 637 fi 638 fi 639 fi 640 fi 641 fi 642 fi 643 644 # determine (primary) group name 645 groupname='' 646 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%g'`" != . ]; then 647 groupname="`(id -gn ${username}) 2>/dev/null`" 648 if [ ".$groupname" = . ]; then 649 str="`(id) 2>/dev/null`" 650 if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then 651 groupname=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` 652 fi 653 if [ ".$groupname" = . ]; then 654 groupname=`(getent group) 2>/dev/null | \ 655 grep "^[^:]*:[^:]*:${groupid}:" | \ 656 sed -e 's/:.*$//'` 657 if [ ".$groupname" = . ]; then 658 groupname=`grep "^[^:]*:[^:]*:${groupid}:" /etc/group 2>/dev/null | \ 659 sed -e 's/:.*$//'` 660 if [ ".$groupname" = . ]; then 661 groupname=`(ypcat group) 2>/dev/null | \ 662 grep "^[^:]*:[^:]*:${groupid}:" | \ 663 sed -e 's/:.*$//'` 664 if [ ".$groupname" = . ]; then 665 groupname='?' 666 fi 667 fi 668 fi 669 fi 670 fi 671 fi 672 673 # determine host and domain name 674 hostname='' 675 domainname='' 676 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%h'`" != . ]; then 677 hostname="`(uname -n) 2>/dev/null |\ 678 awk '{ printf("%s", $1); }'`" 679 if [ ".$hostname" = . ]; then 680 hostname="`(hostname) 2>/dev/null |\ 681 awk '{ printf("%s", $1); }'`" 682 if [ ".$hostname" = . ]; then 683 hostname='unknown' 684 fi 685 fi 686 case $hostname in 687 *.* ) 688 domainname=".`echo $hostname | cut -d. -f2-`" 689 hostname="`echo $hostname | cut -d. -f1`" 690 ;; 691 esac 692 fi 693 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%d'`" != . ]; then 694 if [ ".$domainname" = . ]; then 695 if [ -f /etc/resolv.conf ]; then 696 domainname="`grep '^[ ]*domain' /etc/resolv.conf | sed -e 'q' |\ 697 sed -e 's/.*domain//' \ 698 -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ 699 -e 's/^\.//' -e 's/^/./' |\ 700 awk '{ printf("%s", $1); }'`" 701 if [ ".$domainname" = . ]; then 702 domainname="`grep '^[ ]*search' /etc/resolv.conf | sed -e 'q' |\ 703 sed -e 's/.*search//' \ 704 -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ 705 -e 's/ .*//' -e 's/ .*//' \ 706 -e 's/^\.//' -e 's/^/./' |\ 707 awk '{ printf("%s", $1); }'`" 708 fi 709 fi 710 fi 711 fi 712 713 # determine current time 714 time_day='' 715 time_month='' 716 time_year='' 717 time_monthname='' 718 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[DMYm]'`" != . ]; then 719 time_day=`date '+%d'` 720 time_month=`date '+%m'` 721 time_year=`date '+%Y' 2>/dev/null` 722 if [ ".$time_year" = . ]; then 723 time_year=`date '+%y'` 724 case $time_year in 725 [5-9][0-9]) time_year="19$time_year" ;; 726 [0-4][0-9]) time_year="20$time_year" ;; 727 esac 728 fi 729 case $time_month in 730 1|01) time_monthname='Jan' ;; 731 2|02) time_monthname='Feb' ;; 732 3|03) time_monthname='Mar' ;; 733 4|04) time_monthname='Apr' ;; 734 5|05) time_monthname='May' ;; 735 6|06) time_monthname='Jun' ;; 736 7|07) time_monthname='Jul' ;; 737 8|08) time_monthname='Aug' ;; 738 9|09) time_monthname='Sep' ;; 739 10) time_monthname='Oct' ;; 740 11) time_monthname='Nov' ;; 741 12) time_monthname='Dec' ;; 742 esac 743 fi 744 745 # expand special ``%x'' constructs 746 if [ ".$opt_e" = .yes ]; then 747 text=`echo $seo "$text" |\ 748 sed -e "s/%B/${term_bold}/g" \ 749 -e "s/%b/${term_norm}/g" \ 750 -e "s/%u/${username}/g" \ 751 -e "s/%U/${userid}/g" \ 752 -e "s/%g/${groupname}/g" \ 753 -e "s/%G/${groupid}/g" \ 754 -e "s/%h/${hostname}/g" \ 755 -e "s/%d/${domainname}/g" \ 756 -e "s/%D/${time_day}/g" \ 757 -e "s/%M/${time_month}/g" \ 758 -e "s/%Y/${time_year}/g" \ 759 -e "s/%m/${time_monthname}/g" 2>/dev/null` 760 fi 761 762 # create output 763 if [ .$opt_n = .no ]; then 764 echo $seo "$text" 765 else 766 # the harder part: echo -n is best, because 767 # awk may complain about some \xx sequences. 768 if [ ".$minusn" != . ]; then 769 echo $seo $minusn "$text" 770 else 771 echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text" 772 fi 773 fi 774 775 shtool_exit 0 776 ;; 777 778move ) 779 ## 780 ## move -- Move files with simultaneous substitution 781 ## Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com> 782 ## 783 784 src="$1" 785 dst="$2" 786 787 # consistency checks 788 if [ ".$src" = . ] || [ ".$dst" = . ]; then 789 echo "$msgprefix:Error: Invalid arguments" 1>&2 790 shtool_exit 1 791 fi 792 if [ ".$src" = ".$dst" ]; then 793 echo "$msgprefix:Error: Source and destination files are the same" 1>&2 794 shtool_exit 1 795 fi 796 expsrc="$src" 797 if [ ".$opt_e" = .yes ]; then 798 expsrc="`echo $expsrc`" 799 fi 800 if [ ".$opt_e" = .yes ]; then 801 if [ ".`echo "$src" | sed -e 's;^.*\\*.*$;;'`" = ".$src" ]; then 802 echo "$msgprefix:Error: Source doesn't contain wildcard ('*'): $dst" 1>&2 803 shtool_exit 1 804 fi 805 if [ ".`echo "$dst" | sed -e 's;^.*%[1-9].*$;;'`" = ".$dst" ]; then 806 echo "$msgprefix:Error: Destination doesn't contain substitution ('%N'): $dst" 1>&2 807 shtool_exit 1 808 fi 809 if [ ".$expsrc" = ".$src" ]; then 810 echo "$msgprefix:Error: Sources not found or no asterisk : $src" 1>&2 811 shtool_exit 1 812 fi 813 else 814 if [ ! -r "$src" ]; then 815 echo "$msgprefix:Error: Source not found: $src" 1>&2 816 shtool_exit 1 817 fi 818 fi 819 820 # determine substitution patterns 821 if [ ".$opt_e" = .yes ]; then 822 srcpat=`echo "$src" | sed -e 's/\\./\\\\./g' -e 's/;/\\;/g' -e 's;\\*;\\\\(.*\\\\);g'` 823 dstpat=`echo "$dst" | sed -e 's;%\([1-9]\);\\\\\1;g'` 824 fi 825 826 # iterate over source(s) 827 for onesrc in $expsrc; do 828 if [ .$opt_e = .yes ]; then 829 onedst=`echo $onesrc | sed -e "s;$srcpat;$dstpat;"` 830 else 831 onedst="$dst" 832 fi 833 errorstatus=0 834 if [ ".$opt_v" = .yes ]; then 835 echo "$onesrc -> $onedst" 836 fi 837 if [ ".$opt_p" = .yes ]; then 838 if [ -r $onedst ]; then 839 if cmp -s $onesrc $onedst; then 840 if [ ".$opt_t" = .yes ]; then 841 echo "rm -f $onesrc" 1>&2 842 fi 843 rm -f $onesrc || errorstatus=$? 844 else 845 if [ ".$opt_t" = .yes ]; then 846 echo "mv -f $onesrc $onedst" 1>&2 847 fi 848 mv -f $onesrc $onedst || errorstatus=$? 849 fi 850 else 851 if [ ".$opt_t" = .yes ]; then 852 echo "mv -f $onesrc $onedst" 1>&2 853 fi 854 mv -f $onesrc $onedst || errorstatus=$? 855 fi 856 else 857 if [ ".$opt_t" = .yes ]; then 858 echo "mv -f $onesrc $onedst" 1>&2 859 fi 860 mv -f $onesrc $onedst || errorstatus=$? 861 fi 862 if [ $errorstatus -ne 0 ]; then 863 break; 864 fi 865 done 866 867 shtool_exit $errorstatus 868 ;; 869 870install ) 871 ## 872 ## install -- Install a program, script or datafile 873 ## Copyright (c) 1997-2006 Ralf S. Engelschall <rse@engelschall.com> 874 ## 875 876 # special case: "shtool install -d <dir> [...]" internally 877 # maps to "shtool mkdir -f -p -m 755 <dir> [...]" 878 if [ "$opt_d" = yes ]; then 879 cmd="$0 mkdir -f -p -m 755" 880 if [ ".$opt_o" != . ]; then 881 cmd="$cmd -o '$opt_o'" 882 fi 883 if [ ".$opt_g" != . ]; then 884 cmd="$cmd -g '$opt_g'" 885 fi 886 if [ ".$opt_v" = .yes ]; then 887 cmd="$cmd -v" 888 fi 889 if [ ".$opt_t" = .yes ]; then 890 cmd="$cmd -t" 891 fi 892 for dir in "$@"; do 893 eval "$cmd $dir" || shtool_exit $? 894 done 895 shtool_exit 0 896 fi 897 898 # determine source(s) and destination 899 argc=$# 900 srcs="" 901 while [ $# -gt 1 ]; do 902 srcs="$srcs $1" 903 shift 904 done 905 dstpath="$1" 906 907 # type check for destination 908 dstisdir=0 909 if [ -d $dstpath ]; then 910 dstpath=`echo "$dstpath" | sed -e 's:/$::'` 911 dstisdir=1 912 fi 913 914 # consistency check for destination 915 if [ $argc -gt 2 ] && [ $dstisdir = 0 ]; then 916 echo "$msgprefix:Error: multiple sources require destination to be directory" 1>&2 917 shtool_exit 1 918 fi 919 920 # iterate over all source(s) 921 for src in $srcs; do 922 dst=$dstpath 923 924 # if destination is a directory, append the input filename 925 if [ $dstisdir = 1 ]; then 926 dstfile=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'` 927 dst="$dst/$dstfile" 928 fi 929 930 # check for correct arguments 931 if [ ".$src" = ".$dst" ]; then 932 echo "$msgprefix:Warning: source and destination are the same - skipped" 1>&2 933 continue 934 fi 935 if [ -d "$src" ]; then 936 echo "$msgprefix:Warning: source \`$src' is a directory - skipped" 1>&2 937 continue 938 fi 939 940 # make a temp file name in the destination directory 941 dsttmp=`echo $dst |\ 942 sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;' \ 943 -e "s;\$;/#INST@$$#;"` 944 945 # verbosity 946 if [ ".$opt_v" = .yes ]; then 947 echo "$src -> $dst" 1>&2 948 fi 949 950 # copy or move the file name to the temp name 951 # (because we might be not allowed to change the source) 952 if [ ".$opt_C" = .yes ]; then 953 opt_c=yes 954 fi 955 if [ ".$opt_c" = .yes ]; then 956 if [ ".$opt_t" = .yes ]; then 957 echo "cp $src $dsttmp" 1>&2 958 fi 959 cp $src $dsttmp || shtool_exit $? 960 else 961 if [ ".$opt_t" = .yes ]; then 962 echo "mv $src $dsttmp" 1>&2 963 fi 964 mv $src $dsttmp || shtool_exit $? 965 fi 966 967 # adjust the target file 968 if [ ".$opt_e" != . ]; then 969 sed='sed' 970 OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS" 971 for e 972 do 973 sed="$sed -e '$e'" 974 done 975 cp $dsttmp $dsttmp.old 976 chmod u+w $dsttmp 977 eval "$sed <$dsttmp.old >$dsttmp" || shtool_exit $? 978 rm -f $dsttmp.old 979 fi 980 if [ ".$opt_s" = .yes ]; then 981 if [ ".$opt_t" = .yes ]; then 982 echo "strip $dsttmp" 1>&2 983 fi 984 strip $dsttmp || shtool_exit $? 985 fi 986 if [ ".$opt_o" != . ]; then 987 if [ ".$opt_t" = .yes ]; then 988 echo "chown $opt_o $dsttmp" 1>&2 989 fi 990 chown $opt_o $dsttmp || shtool_exit $? 991 fi 992 if [ ".$opt_g" != . ]; then 993 if [ ".$opt_t" = .yes ]; then 994 echo "chgrp $opt_g $dsttmp" 1>&2 995 fi 996 chgrp $opt_g $dsttmp || shtool_exit $? 997 fi 998 if [ ".$opt_m" != ".-" ]; then 999 if [ ".$opt_t" = .yes ]; then 1000 echo "chmod $opt_m $dsttmp" 1>&2 1001 fi 1002 chmod $opt_m $dsttmp || shtool_exit $? 1003 fi 1004 1005 # determine whether to do a quick install 1006 # (has to be done _after_ the strip was already done) 1007 quick=no 1008 if [ ".$opt_C" = .yes ]; then 1009 if [ -r $dst ]; then 1010 if cmp -s $src $dst; then 1011 quick=yes 1012 fi 1013 fi 1014 fi 1015 1016 # finally, install the file to the real destination 1017 if [ $quick = yes ]; then 1018 if [ ".$opt_t" = .yes ]; then 1019 echo "rm -f $dsttmp" 1>&2 1020 fi 1021 rm -f $dsttmp 1022 else 1023 if [ ".$opt_t" = .yes ]; then 1024 echo "rm -f $dst && mv $dsttmp $dst" 1>&2 1025 fi 1026 rm -f $dst && mv $dsttmp $dst 1027 fi 1028 done 1029 1030 shtool_exit 0 1031 ;; 1032 1033mkdir ) 1034 ## 1035 ## mkdir -- Make one or more directories 1036 ## Copyright (c) 1996-2006 Ralf S. Engelschall <rse@engelschall.com> 1037 ## 1038 1039 errstatus=0 1040 for p in ${1+"$@"}; do 1041 # if the directory already exists... 1042 if [ -d "$p" ]; then 1043 if [ ".$opt_f" = .no ] && [ ".$opt_p" = .no ]; then 1044 echo "$msgprefix:Error: directory already exists: $p" 1>&2 1045 errstatus=1 1046 break 1047 else 1048 continue 1049 fi 1050 fi 1051 # if the directory has to be created... 1052 if [ ".$opt_p" = .no ]; then 1053 if [ ".$opt_t" = .yes ]; then 1054 echo "mkdir $p" 1>&2 1055 fi 1056 mkdir $p || errstatus=$? 1057 if [ ".$opt_o" != . ]; then 1058 if [ ".$opt_t" = .yes ]; then 1059 echo "chown $opt_o $p" 1>&2 1060 fi 1061 chown $opt_o $p || errstatus=$? 1062 fi 1063 if [ ".$opt_g" != . ]; then 1064 if [ ".$opt_t" = .yes ]; then 1065 echo "chgrp $opt_g $p" 1>&2 1066 fi 1067 chgrp $opt_g $p || errstatus=$? 1068 fi 1069 if [ ".$opt_m" != . ]; then 1070 if [ ".$opt_t" = .yes ]; then 1071 echo "chmod $opt_m $p" 1>&2 1072 fi 1073 chmod $opt_m $p || errstatus=$? 1074 fi 1075 else 1076 # the smart situation 1077 set fnord `echo ":$p" |\ 1078 sed -e 's/^:\//%/' \ 1079 -e 's/^://' \ 1080 -e 's/\// /g' \ 1081 -e 's/^%/\//'` 1082 shift 1083 pathcomp='' 1084 for d in ${1+"$@"}; do 1085 pathcomp="$pathcomp$d" 1086 case "$pathcomp" in 1087 -* ) pathcomp="./$pathcomp" ;; 1088 esac 1089 if [ ! -d "$pathcomp" ]; then 1090 if [ ".$opt_t" = .yes ]; then 1091 echo "mkdir $pathcomp" 1>&2 1092 fi 1093 mkdir $pathcomp || errstatus=$? 1094 if [ ".$opt_o" != . ]; then 1095 if [ ".$opt_t" = .yes ]; then 1096 echo "chown $opt_o $pathcomp" 1>&2 1097 fi 1098 chown $opt_o $pathcomp || errstatus=$? 1099 fi 1100 if [ ".$opt_g" != . ]; then 1101 if [ ".$opt_t" = .yes ]; then 1102 echo "chgrp $opt_g $pathcomp" 1>&2 1103 fi 1104 chgrp $opt_g $pathcomp || errstatus=$? 1105 fi 1106 if [ ".$opt_m" != . ]; then 1107 if [ ".$opt_t" = .yes ]; then 1108 echo "chmod $opt_m $pathcomp" 1>&2 1109 fi 1110 chmod $opt_m $pathcomp || errstatus=$? 1111 fi 1112 fi 1113 pathcomp="$pathcomp/" 1114 done 1115 fi 1116 done 1117 1118 shtool_exit $errstatus 1119 ;; 1120 1121mkln ) 1122 ## 1123 ## mkln -- Make link with calculation of relative paths 1124 ## Copyright (c) 1998-2006 Ralf S. Engelschall <rse@engelschall.com> 1125 ## 1126 1127 # determine source(s) and destination 1128 args=$? 1129 srcs="" 1130 while [ $# -gt 1 ]; do 1131 srcs="$srcs $1" 1132 shift 1133 done 1134 dst="$1" 1135 if [ ! -d $dst ]; then 1136 if [ $args -gt 2 ]; then 1137 echo "$msgprefix:Error: multiple sources not allowed when target isn't a directory" 1>&2 1138 shtool_exit 1 1139 fi 1140 fi 1141 1142 # determine link options 1143 lnopt="" 1144 if [ ".$opt_f" = .yes ]; then 1145 lnopt="$lnopt -f" 1146 fi 1147 if [ ".$opt_s" = .yes ]; then 1148 lnopt="$lnopt -s" 1149 fi 1150 1151 # iterate over sources 1152 for src in $srcs; do 1153 # determine if one of the paths is an absolute path, 1154 # because then we _have_ to use an absolute symlink 1155 oneisabs=0 1156 srcisabs=0 1157 dstisabs=0 1158 case $src in 1159 /* ) oneisabs=1; srcisabs=1 ;; 1160 esac 1161 case $dst in 1162 /* ) oneisabs=1; dstisabs=1 ;; 1163 esac 1164 1165 # split source and destination into dir and base name 1166 if [ -d $src ]; then 1167 srcdir=`echo $src | sed -e 's;/*$;;'` 1168 srcbase="" 1169 else 1170 srcdir=`echo $src | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` 1171 srcbase=`echo $src | sed -e 's;.*/\([^/]*\)$;\1;'` 1172 fi 1173 if [ -d $dst ]; then 1174 dstdir=`echo $dst | sed -e 's;/*$;;'` 1175 dstbase="" 1176 else 1177 dstdir=`echo $dst | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` 1178 dstbase=`echo $dst | sed -e 's;.*/\([^/]*\)$;\1;'` 1179 fi 1180 1181 # consistency check 1182 if [ ".$dstdir" != . ]; then 1183 if [ ! -d $dstdir ]; then 1184 echo "$msgprefix:Error: destination directory not found: $dstdir" 1>&2 1185 shtool_exit 1 1186 fi 1187 fi 1188 1189 # make sure the source is reachable from the destination 1190 if [ $dstisabs = 1 ]; then 1191 if [ $srcisabs = 0 ]; then 1192 if [ ".$srcdir" = . ]; then 1193 srcdir="`pwd | sed -e 's;/*$;;'`" 1194 srcisabs=1 1195 oneisabs=1 1196 elif [ -d $srcdir ]; then 1197 srcdir="`cd $srcdir; pwd | sed -e 's;/*$;;'`" 1198 srcisabs=1 1199 oneisabs=1 1200 fi 1201 fi 1202 fi 1203 1204 # split away a common prefix 1205 prefix="" 1206 if [ ".$srcdir" = ".$dstdir" ] && [ ".$srcdir" != . ]; then 1207 prefix="$srcdir/" 1208 srcdir="" 1209 dstdir="" 1210 else 1211 while [ ".$srcdir" != . ] && [ ".$dstdir" != . ]; do 1212 presrc=`echo $srcdir | sed -e 's;^\([^/]*\)/.*;\1;'` 1213 predst=`echo $dstdir | sed -e 's;^\([^/]*\)/.*;\1;'` 1214 if [ ".$presrc" != ".$predst" ]; then 1215 break 1216 fi 1217 prefix="$prefix$presrc/" 1218 srcdir=`echo $srcdir | sed -e 's;^[^/]*/*;;'` 1219 dstdir=`echo $dstdir | sed -e 's;^[^/]*/*;;'` 1220 done 1221 fi 1222 1223 # destination prefix is just the common prefix 1224 dstpre="$prefix" 1225 1226 # determine source prefix which is the reverse directory 1227 # step-up corresponding to the destination directory 1228 srcpre="" 1229 1230 isroot=0 1231 if [ ".$prefix" = . ] || [ ".$prefix" = ./ ]; then 1232 isroot=1 1233 fi 1234 if [ $oneisabs = 0 ] || [ $isroot = 0 ]; then 1235 pl="$dstdir/" 1236 OIFS="$IFS"; IFS='/' 1237 for pe in $pl; do 1238 [ ".$pe" = . ] && continue 1239 [ ".$pe" = .. ] && continue 1240 srcpre="../$srcpre" 1241 done 1242 IFS="$OIFS" 1243 else 1244 if [ $srcisabs = 1 ]; then 1245 srcpre="$prefix" 1246 fi 1247 fi 1248 1249 # determine destination symlink name 1250 if [ ".$dstbase" = . ]; then 1251 if [ ".$srcbase" != . ]; then 1252 dstbase="$srcbase" 1253 else 1254 dstbase=`echo "$prefix$srcdir" | sed -e 's;/*$;;' -e 's;.*/\([^/]*\)$;\1;'` 1255 fi 1256 fi 1257 1258 # now finalize source and destination directory paths 1259 srcdir=`echo $srcdir | sed -e 's;\([^/]\)$;\1/;'` 1260 dstdir=`echo $dstdir | sed -e 's;\([^/]\)$;\1/;'` 1261 1262 # run the final link command 1263 if [ ".$opt_t" = .yes ]; then 1264 echo "ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase" 1265 fi 1266 eval ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase 1267 done 1268 1269 shtool_exit 0 1270 ;; 1271 1272subst ) 1273 ## 1274 ## subst -- Apply sed(1) substitution operations 1275 ## Copyright (c) 2001-2006 Ralf S. Engelschall <rse@engelschall.com> 1276 ## 1277 1278 # remember optional list of file(s) 1279 files="$*" 1280 files_num="$#" 1281 1282 # parameter consistency check 1283 if [ $# -eq 0 ] && [ ".$opt_b" != . ]; then 1284 echo "$msgprefix:Error: option -b cannot be applied to stdin" 1>&2 1285 shtool_exit 1 1286 fi 1287 if [ $# -eq 0 ] && [ ".$opt_s" = .yes ]; then 1288 echo "$msgprefix:Error: option -s cannot be applied to stdin" 1>&2 1289 shtool_exit 1 1290 fi 1291 1292 # build underlying sed(1) command 1293 sedcmd='sed' 1294 if [ ".$opt_e" != . ]; then 1295 OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS" 1296 for e 1297 do 1298 sedcmd="$sedcmd -e '$e'" 1299 done 1300 elif [ ".$opt_f" != . ]; then 1301 if [ ! -f $opt_f ]; then 1302 echo "$msgprefix:Error: command file \`$opt_f' not found or not a regular file" 1>&2 1303 shtool_exit 1 1304 fi 1305 sedcmd="$sedcmd -f '$opt_f'" 1306 else 1307 echo "$msgprefix:Error: either -e option(s) or -f option required" 1>&2 1308 shtool_exit 1 1309 fi 1310 1311 # determine extension for original file 1312 orig=".orig" 1313 if [ ".$opt_b" != . ]; then 1314 orig="$opt_b" 1315 fi 1316 1317 # apply sed(1) operation(s) 1318 if [ ".$files" != . ]; then 1319 # apply operation(s) to files 1320 substdone=no 1321 for file in $files; do 1322 test ".$file" = . && continue 1323 if [ ! -f $file ]; then 1324 echo "$msgprefix:Warning: file \`$file' not found or not a regular file" 1>&2 1325 continue 1326 fi 1327 1328 # handle interactive mode 1329 if [ ".$opt_i" = .yes ]; then 1330 eval "$sedcmd <$file >$file.new" 1331 skip=no 1332 if cmp $file $file.new >/dev/null 2>&1; then 1333 rm -f $file.new 1334 skip=yes 1335 else 1336 (diff -U1 $file $file.new >$tmpfile) 2>/dev/null 1337 if [ ".`cat $tmpfile`" = . ]; then 1338 (diff -C1 $file $file.new >$tmpfile) 2>/dev/null 1339 if [ ".`cat $tmpfile`" = . ]; then 1340 echo "$msgprefix:Warning: unable to show difference for file \`$file'" 1>&2 1341 cp /dev/null $tmpfile 1342 fi 1343 fi 1344 rm -f $file.new 1345 cat $tmpfile 1346 echo dummy | awk '{ printf("%s", TEXT); }' TEXT=">>> Apply [Y/n]: " 1347 read input 1348 if [ ".$input" != .Y ] &&\ 1349 [ ".$input" != .y ] &&\ 1350 [ ".$input" != . ]; then 1351 skip=yes 1352 fi 1353 fi 1354 if [ ".$skip" = .yes ]; then 1355 if [ ".$opt_v" = .yes ]; then 1356 echo "file \`$file' -- skipped" 1>&2 1357 fi 1358 continue 1359 fi 1360 fi 1361 1362 # apply sed(1) operation(s) 1363 if [ ".$opt_v" = .yes ]; then 1364 echo "patching \`$file'" 1>&2 1365 fi 1366 if [ ".$opt_t" = .yes ]; then 1367 echo "\$ cp -p $file $file$orig" 1368 echo "\$ chmod u+w $file" 1369 echo "\$ $sedcmd <$file$orig >$file" 1370 fi 1371 if [ ".$opt_n" = .no ]; then 1372 cp -p $file $file$orig 1373 chmod u+w $file >/dev/null 2>&1 || true 1374 eval "$sedcmd <$file$orig >$file" 1375 fi 1376 1377 # optionally fix timestamp 1378 if [ ".$opt_s" = .yes ]; then 1379 if [ ".$opt_t" = .yes ]; then 1380 echo "\$ touch -r $file$orig $file" 1381 fi 1382 if [ ".$opt_n" = .no ]; then 1383 touch -r $file$orig $file 1384 fi 1385 fi 1386 1387 # optionally check whether any content change actually occurred 1388 if [ ".$opt_q" = .no ]; then 1389 if cmp $file$orig $file >/dev/null 2>&1; then 1390 if [ ".$opt_w" = .yes ]; then 1391 echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2 1392 fi 1393 else 1394 substdone=yes 1395 fi 1396 fi 1397 1398 # optionally remove preserved original file 1399 if [ ".$opt_b" = . ]; then 1400 if [ ".$opt_t" = .yes ]; then 1401 echo "\$ rm -f $file$orig" 1402 fi 1403 if [ ".$opt_n" = .no ]; then 1404 rm -f $file$orig 1405 fi 1406 fi 1407 done 1408 if [ ".$opt_q" = .no ] && [ ".$opt_w" = .no ]; then 1409 if [ ".$substdone" = .no ]; then 1410 if [ ".$files_num" = .1 ]; then 1411 echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2 1412 else 1413 echo "$msgprefix:Warning: substitution resulted in no content change on any file" 1>&2 1414 fi 1415 fi 1416 fi 1417 else 1418 # apply operation(s) to stdin/stdout 1419 if [ ".$opt_v" = .yes ]; then 1420 echo "patching <stdin>" 1>&2 1421 fi 1422 if [ ".$opt_t" = .yes ]; then 1423 echo "\$ $sedcmd" 1424 fi 1425 if [ ".$opt_n" = .no ]; then 1426 eval "$sedcmd" 1427 fi 1428 fi 1429 1430 shtool_exit 0 1431 ;; 1432 1433esac 1434 1435shtool_exit 0 1436 1437