1#!/bin/sh 2## 3## GNU shtool -- The GNU Portable Shell Tool 4## Copyright (c) 1994-2008 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.8 (18-Jul-2008) 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.8 (18-Jul-2008)" 96 echo 'Copyright (c) 1994-2008 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.8 (18-Jul-2008)" 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# iterate 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 occurrences override) 387 eval "opt_${opt_OPT}=\"\$opt_ARG\"" 388 ;; 389 '+' ) 390 # option with argument (multiple occurrences 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-2008 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=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \ 605 sed -e 'q' | sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` 606 if [ ".$userid" = . ]; then 607 userid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \ 608 sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` 609 if [ ".$userid" = . ]; then 610 userid='?' 611 fi 612 fi 613 fi 614 fi 615 fi 616 fi 617 fi 618 fi 619 620 # determine (primary) group id 621 groupid='' 622 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[gG]'`" != . ]; then 623 groupid="`(id -g ${username}) 2>/dev/null`" 624 if [ ".$groupid" = . ]; then 625 str="`(id) 2>/dev/null`" 626 if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then 627 groupid=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*//' -e 's/(.*$//'` 628 fi 629 if [ ".$groupid" = . ]; then 630 groupid=`(getent passwd ${username}) 2>/dev/null | \ 631 sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 632 if [ ".$groupid" = . ]; then 633 groupid=`grep "^${username}:" /etc/passwd 2>/dev/null | \ 634 sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 635 if [ ".$groupid" = . ]; then 636 groupid=`(ypmatch "${username}" passwd; nismatch "${username}" passwd) 2>/dev/null | \ 637 sed -e 'q' | sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 638 if [ ".$groupid" = . ]; then 639 groupid=`(nidump passwd . | grep "^${username}:") 2>/dev/null | \ 640 sed -e 's/[^:]*:[^:]*:[^:]*://' -e 's/:.*$//'` 641 if [ ".$groupid" = . ]; then 642 groupid='?' 643 fi 644 fi 645 fi 646 fi 647 fi 648 fi 649 fi 650 651 # determine (primary) group name 652 groupname='' 653 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%g'`" != . ]; then 654 groupname="`(id -gn ${username}) 2>/dev/null`" 655 if [ ".$groupname" = . ]; then 656 str="`(id) 2>/dev/null`" 657 if [ ".`echo $str | grep 'gid[ ]*=[ ]*[0-9]*('`" != . ]; then 658 groupname=`echo $str | sed -e 's/^.*gid[ ]*=[ ]*[0-9]*(//' -e 's/).*$//'` 659 fi 660 if [ ".$groupname" = . ]; then 661 groupname=`(getent group) 2>/dev/null | \ 662 grep "^[^:]*:[^:]*:${groupid}:" | \ 663 sed -e 's/:.*$//'` 664 if [ ".$groupname" = . ]; then 665 groupname=`grep "^[^:]*:[^:]*:${groupid}:" /etc/group 2>/dev/null | \ 666 sed -e 's/:.*$//'` 667 if [ ".$groupname" = . ]; then 668 groupname=`(ypcat group; niscat group) 2>/dev/null | \ 669 sed -e 'q' | grep "^[^:]*:[^:]*:${groupid}:" | \ 670 sed -e 's/:.*$//'` 671 if [ ".$groupname" = . ]; then 672 groupname=`(nidump group .) 2>/dev/null | \ 673 grep "^[^:]*:[^:]*:${groupid}:" | \ 674 sed -e 's/:.*$//'` 675 if [ ".$groupname" = . ]; then 676 groupname='?' 677 fi 678 fi 679 fi 680 fi 681 fi 682 fi 683 fi 684 685 # determine host and domain name 686 hostname='' 687 domainname='' 688 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%h'`" != . ]; then 689 hostname="`(uname -n) 2>/dev/null |\ 690 awk '{ printf("%s", $1); }'`" 691 if [ ".$hostname" = . ]; then 692 hostname="`(hostname) 2>/dev/null |\ 693 awk '{ printf("%s", $1); }'`" 694 if [ ".$hostname" = . ]; then 695 hostname='unknown' 696 fi 697 fi 698 case $hostname in 699 *.* ) 700 domainname=".`echo $hostname | cut -d. -f2-`" 701 hostname="`echo $hostname | cut -d. -f1`" 702 ;; 703 esac 704 fi 705 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%d'`" != . ]; then 706 if [ ".$domainname" = . ]; then 707 if [ -f /etc/resolv.conf ]; then 708 domainname="`grep '^[ ]*domain' /etc/resolv.conf | sed -e 'q' |\ 709 sed -e 's/.*domain//' \ 710 -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ 711 -e 's/^\.//' -e 's/^/./' |\ 712 awk '{ printf("%s", $1); }'`" 713 if [ ".$domainname" = . ]; then 714 domainname="`grep '^[ ]*search' /etc/resolv.conf | sed -e 'q' |\ 715 sed -e 's/.*search//' \ 716 -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ 717 -e 's/ .*//' -e 's/ .*//' \ 718 -e 's/^\.//' -e 's/^/./' |\ 719 awk '{ printf("%s", $1); }'`" 720 fi 721 fi 722 fi 723 fi 724 725 # determine current time 726 time_day='' 727 time_month='' 728 time_year='' 729 time_monthname='' 730 if [ ".$opt_e" = .yes ] && [ ".`echo $text | grep '%[DMYm]'`" != . ]; then 731 time_day=`date '+%d'` 732 time_month=`date '+%m'` 733 time_year=`date '+%Y' 2>/dev/null` 734 if [ ".$time_year" = . ]; then 735 time_year=`date '+%y'` 736 case $time_year in 737 [5-9][0-9]) time_year="19$time_year" ;; 738 [0-4][0-9]) time_year="20$time_year" ;; 739 esac 740 fi 741 case $time_month in 742 1|01) time_monthname='Jan' ;; 743 2|02) time_monthname='Feb' ;; 744 3|03) time_monthname='Mar' ;; 745 4|04) time_monthname='Apr' ;; 746 5|05) time_monthname='May' ;; 747 6|06) time_monthname='Jun' ;; 748 7|07) time_monthname='Jul' ;; 749 8|08) time_monthname='Aug' ;; 750 9|09) time_monthname='Sep' ;; 751 10) time_monthname='Oct' ;; 752 11) time_monthname='Nov' ;; 753 12) time_monthname='Dec' ;; 754 esac 755 fi 756 757 # expand special ``%x'' constructs 758 if [ ".$opt_e" = .yes ]; then 759 text=`echo $seo "$text" |\ 760 sed -e "s/%B/${term_bold}/g" \ 761 -e "s/%b/${term_norm}/g" \ 762 -e "s/%u/${username}/g" \ 763 -e "s/%U/${userid}/g" \ 764 -e "s/%g/${groupname}/g" \ 765 -e "s/%G/${groupid}/g" \ 766 -e "s/%h/${hostname}/g" \ 767 -e "s/%d/${domainname}/g" \ 768 -e "s/%D/${time_day}/g" \ 769 -e "s/%M/${time_month}/g" \ 770 -e "s/%Y/${time_year}/g" \ 771 -e "s/%m/${time_monthname}/g" 2>/dev/null` 772 fi 773 774 # create output 775 if [ .$opt_n = .no ]; then 776 echo $seo "$text" 777 else 778 # the harder part: echo -n is best, because 779 # awk may complain about some \xx sequences. 780 if [ ".$minusn" != . ]; then 781 echo $seo $minusn "$text" 782 else 783 echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text" 784 fi 785 fi 786 787 shtool_exit 0 788 ;; 789 790move ) 791 ## 792 ## move -- Move files with simultaneous substitution 793 ## Copyright (c) 1999-2008 Ralf S. Engelschall <rse@engelschall.com> 794 ## 795 796 src="$1" 797 dst="$2" 798 799 # consistency checks 800 if [ ".$src" = . ] || [ ".$dst" = . ]; then 801 echo "$msgprefix:Error: Invalid arguments" 1>&2 802 shtool_exit 1 803 fi 804 if [ ".$src" = ".$dst" ]; then 805 echo "$msgprefix:Error: Source and destination files are the same" 1>&2 806 shtool_exit 1 807 fi 808 expsrc="$src" 809 if [ ".$opt_e" = .yes ]; then 810 expsrc="`echo $expsrc`" 811 fi 812 if [ ".$opt_e" = .yes ]; then 813 if [ ".`echo "$src" | sed -e 's;^.*\\*.*$;;'`" = ".$src" ]; then 814 echo "$msgprefix:Error: Source doesn't contain wildcard ('*'): $dst" 1>&2 815 shtool_exit 1 816 fi 817 if [ ".`echo "$dst" | sed -e 's;^.*%[1-9].*$;;'`" = ".$dst" ]; then 818 echo "$msgprefix:Error: Destination doesn't contain substitution ('%N'): $dst" 1>&2 819 shtool_exit 1 820 fi 821 if [ ".$expsrc" = ".$src" ]; then 822 echo "$msgprefix:Error: Sources not found or no asterisk : $src" 1>&2 823 shtool_exit 1 824 fi 825 else 826 if [ ! -r "$src" ]; then 827 echo "$msgprefix:Error: Source not found: $src" 1>&2 828 shtool_exit 1 829 fi 830 fi 831 832 # determine substitution patterns 833 if [ ".$opt_e" = .yes ]; then 834 srcpat=`echo "$src" | sed -e 's/\\./\\\\./g' -e 's/;/\\;/g' -e 's;\\*;\\\\(.*\\\\);g'` 835 dstpat=`echo "$dst" | sed -e 's;%\([1-9]\);\\\\\1;g'` 836 fi 837 838 # iterate over source(s) 839 for onesrc in $expsrc; do 840 if [ .$opt_e = .yes ]; then 841 onedst=`echo $onesrc | sed -e "s;$srcpat;$dstpat;"` 842 else 843 onedst="$dst" 844 fi 845 errorstatus=0 846 if [ ".$opt_v" = .yes ]; then 847 echo "$onesrc -> $onedst" 848 fi 849 if [ ".$opt_p" = .yes ]; then 850 if [ -r $onedst ]; then 851 if cmp -s $onesrc $onedst; then 852 if [ ".$opt_t" = .yes ]; then 853 echo "rm -f $onesrc" 1>&2 854 fi 855 rm -f $onesrc || errorstatus=$? 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 else 863 if [ ".$opt_t" = .yes ]; then 864 echo "mv -f $onesrc $onedst" 1>&2 865 fi 866 mv -f $onesrc $onedst || errorstatus=$? 867 fi 868 else 869 if [ ".$opt_t" = .yes ]; then 870 echo "mv -f $onesrc $onedst" 1>&2 871 fi 872 mv -f $onesrc $onedst || errorstatus=$? 873 fi 874 if [ $errorstatus -ne 0 ]; then 875 break; 876 fi 877 done 878 879 shtool_exit $errorstatus 880 ;; 881 882install ) 883 ## 884 ## install -- Install a program, script or datafile 885 ## Copyright (c) 1997-2008 Ralf S. Engelschall <rse@engelschall.com> 886 ## 887 888 # special case: "shtool install -d <dir> [...]" internally 889 # maps to "shtool mkdir -f -p -m 755 <dir> [...]" 890 if [ "$opt_d" = yes ]; then 891 cmd="$0 mkdir -f -p -m 755" 892 if [ ".$opt_o" != . ]; then 893 cmd="$cmd -o '$opt_o'" 894 fi 895 if [ ".$opt_g" != . ]; then 896 cmd="$cmd -g '$opt_g'" 897 fi 898 if [ ".$opt_v" = .yes ]; then 899 cmd="$cmd -v" 900 fi 901 if [ ".$opt_t" = .yes ]; then 902 cmd="$cmd -t" 903 fi 904 for dir in "$@"; do 905 eval "$cmd $dir" || shtool_exit $? 906 done 907 shtool_exit 0 908 fi 909 910 # determine source(s) and destination 911 argc=$# 912 srcs="" 913 while [ $# -gt 1 ]; do 914 srcs="$srcs $1" 915 shift 916 done 917 dstpath="$1" 918 919 # type check for destination 920 dstisdir=0 921 if [ -d $dstpath ]; then 922 dstpath=`echo "$dstpath" | sed -e 's:/$::'` 923 dstisdir=1 924 fi 925 926 # consistency check for destination 927 if [ $argc -gt 2 ] && [ $dstisdir = 0 ]; then 928 echo "$msgprefix:Error: multiple sources require destination to be directory" 1>&2 929 shtool_exit 1 930 fi 931 932 # iterate over all source(s) 933 for src in $srcs; do 934 dst=$dstpath 935 936 # if destination is a directory, append the input filename 937 if [ $dstisdir = 1 ]; then 938 dstfile=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'` 939 dst="$dst/$dstfile" 940 fi 941 942 # check for correct arguments 943 if [ ".$src" = ".$dst" ]; then 944 echo "$msgprefix:Warning: source and destination are the same - skipped" 1>&2 945 continue 946 fi 947 if [ -d "$src" ]; then 948 echo "$msgprefix:Warning: source \`$src' is a directory - skipped" 1>&2 949 continue 950 fi 951 952 # make a temp file name in the destination directory 953 dsttmp=`echo $dst |\ 954 sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;' \ 955 -e "s;\$;/#INST@$$#;"` 956 957 # verbosity 958 if [ ".$opt_v" = .yes ]; then 959 echo "$src -> $dst" 1>&2 960 fi 961 962 # copy or move the file name to the temp name 963 # (because we might be not allowed to change the source) 964 if [ ".$opt_C" = .yes ]; then 965 opt_c=yes 966 fi 967 if [ ".$opt_c" = .yes ]; then 968 if [ ".$opt_t" = .yes ]; then 969 echo "cp $src $dsttmp" 1>&2 970 fi 971 cp "$src" "$dsttmp" || shtool_exit $? 972 else 973 if [ ".$opt_t" = .yes ]; then 974 echo "mv $src $dsttmp" 1>&2 975 fi 976 mv "$src" "$dsttmp" || shtool_exit $? 977 fi 978 979 # adjust the target file 980 if [ ".$opt_e" != . ]; then 981 sed='sed' 982 OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS" 983 for e 984 do 985 sed="$sed -e '$e'" 986 done 987 cp "$dsttmp" "$dsttmp.old" 988 chmod u+w $dsttmp 989 eval "$sed <$dsttmp.old >$dsttmp" || shtool_exit $? 990 rm -f $dsttmp.old 991 fi 992 if [ ".$opt_s" = .yes ]; then 993 if [ ".$opt_t" = .yes ]; then 994 echo "strip $dsttmp" 1>&2 995 fi 996 ${STRIP:-strip} $dsttmp || shtool_exit $? 997 fi 998 if [ ".$opt_o" != . ]; then 999 if [ ".$opt_t" = .yes ]; then 1000 echo "chown $opt_o $dsttmp" 1>&2 1001 fi 1002 chown $opt_o $dsttmp || shtool_exit $? 1003 fi 1004 if [ ".$opt_g" != . ]; then 1005 if [ ".$opt_t" = .yes ]; then 1006 echo "chgrp $opt_g $dsttmp" 1>&2 1007 fi 1008 chgrp $opt_g $dsttmp || shtool_exit $? 1009 fi 1010 if [ ".$opt_m" != ".-" ]; then 1011 if [ ".$opt_t" = .yes ]; then 1012 echo "chmod $opt_m $dsttmp" 1>&2 1013 fi 1014 chmod $opt_m $dsttmp || shtool_exit $? 1015 fi 1016 1017 # determine whether to do a quick install 1018 # (has to be done _after_ the strip was already done) 1019 quick=no 1020 if [ ".$opt_C" = .yes ]; then 1021 if [ -r $dst ]; then 1022 if cmp -s "$src" "$dst"; then 1023 quick=yes 1024 fi 1025 fi 1026 fi 1027 1028 # finally, install the file to the real destination 1029 if [ $quick = yes ]; then 1030 if [ ".$opt_t" = .yes ]; then 1031 echo "rm -f $dsttmp" 1>&2 1032 fi 1033 rm -f $dsttmp 1034 else 1035 if [ ".$opt_t" = .yes ]; then 1036 echo "rm -f $dst && mv $dsttmp $dst" 1>&2 1037 fi 1038 rm -f $dst && mv $dsttmp $dst 1039 fi 1040 done 1041 1042 shtool_exit 0 1043 ;; 1044 1045mkdir ) 1046 ## 1047 ## mkdir -- Make one or more directories 1048 ## Copyright (c) 1996-2008 Ralf S. Engelschall <rse@engelschall.com> 1049 ## 1050 1051 errstatus=0 1052 for p in ${1+"$@"}; do 1053 # if the directory already exists... 1054 if [ -d "$p" ]; then 1055 if [ ".$opt_f" = .no ] && [ ".$opt_p" = .no ]; then 1056 echo "$msgprefix:Error: directory already exists: $p" 1>&2 1057 errstatus=1 1058 break 1059 else 1060 continue 1061 fi 1062 fi 1063 # if the directory has to be created... 1064 if [ ".$opt_p" = .no ]; then 1065 if [ ".$opt_t" = .yes ]; then 1066 echo "mkdir $p" 1>&2 1067 fi 1068 mkdir $p || errstatus=$? 1069 if [ ".$opt_o" != . ]; then 1070 if [ ".$opt_t" = .yes ]; then 1071 echo "chown $opt_o $p" 1>&2 1072 fi 1073 chown $opt_o $p || errstatus=$? 1074 fi 1075 if [ ".$opt_g" != . ]; then 1076 if [ ".$opt_t" = .yes ]; then 1077 echo "chgrp $opt_g $p" 1>&2 1078 fi 1079 chgrp $opt_g $p || errstatus=$? 1080 fi 1081 if [ ".$opt_m" != . ]; then 1082 if [ ".$opt_t" = .yes ]; then 1083 echo "chmod $opt_m $p" 1>&2 1084 fi 1085 chmod $opt_m $p || errstatus=$? 1086 fi 1087 else 1088 # the smart situation 1089 set fnord `echo ":$p" |\ 1090 sed -e 's/^:\//%/' \ 1091 -e 's/^://' \ 1092 -e 's/\// /g' \ 1093 -e 's/^%/\//'` 1094 shift 1095 pathcomp='' 1096 for d in ${1+"$@"}; do 1097 pathcomp="$pathcomp$d" 1098 case "$pathcomp" in 1099 -* ) pathcomp="./$pathcomp" ;; 1100 esac 1101 if [ ! -d "$pathcomp" ]; then 1102 if [ ".$opt_t" = .yes ]; then 1103 echo "mkdir $pathcomp" 1>&2 1104 fi 1105 mkdir $pathcomp || errstatus=$? 1106 if [ ".$opt_o" != . ]; then 1107 if [ ".$opt_t" = .yes ]; then 1108 echo "chown $opt_o $pathcomp" 1>&2 1109 fi 1110 chown $opt_o $pathcomp || errstatus=$? 1111 fi 1112 if [ ".$opt_g" != . ]; then 1113 if [ ".$opt_t" = .yes ]; then 1114 echo "chgrp $opt_g $pathcomp" 1>&2 1115 fi 1116 chgrp $opt_g $pathcomp || errstatus=$? 1117 fi 1118 if [ ".$opt_m" != . ]; then 1119 if [ ".$opt_t" = .yes ]; then 1120 echo "chmod $opt_m $pathcomp" 1>&2 1121 fi 1122 chmod $opt_m $pathcomp || errstatus=$? 1123 fi 1124 fi 1125 pathcomp="$pathcomp/" 1126 done 1127 fi 1128 done 1129 1130 shtool_exit $errstatus 1131 ;; 1132 1133mkln ) 1134 ## 1135 ## mkln -- Make link with calculation of relative paths 1136 ## Copyright (c) 1998-2008 Ralf S. Engelschall <rse@engelschall.com> 1137 ## 1138 1139 # determine source(s) and destination 1140 args=$# 1141 srcs="" 1142 while [ $# -gt 1 ]; do 1143 srcs="$srcs $1" 1144 shift 1145 done 1146 dst="$1" 1147 if [ ! -d $dst ]; then 1148 if [ $args -gt 2 ]; then 1149 echo "$msgprefix:Error: multiple sources not allowed when target isn't a directory" 1>&2 1150 shtool_exit 1 1151 fi 1152 fi 1153 1154 # determine link options 1155 lnopt="" 1156 if [ ".$opt_f" = .yes ]; then 1157 lnopt="$lnopt -f" 1158 fi 1159 if [ ".$opt_s" = .yes ]; then 1160 lnopt="$lnopt -s" 1161 fi 1162 1163 # iterate over sources 1164 for src in $srcs; do 1165 # determine if one of the paths is an absolute path, 1166 # because then we _have_ to use an absolute symlink 1167 oneisabs=0 1168 srcisabs=0 1169 dstisabs=0 1170 case $src in 1171 /* ) oneisabs=1; srcisabs=1 ;; 1172 esac 1173 case $dst in 1174 /* ) oneisabs=1; dstisabs=1 ;; 1175 esac 1176 1177 # split source and destination into dir and base name 1178 if [ -d $src ]; then 1179 srcdir=`echo $src | sed -e 's;/*$;;'` 1180 srcbase="" 1181 else 1182 srcdir=`echo $src | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` 1183 srcbase=`echo $src | sed -e 's;.*/\([^/]*\)$;\1;'` 1184 fi 1185 if [ -d $dst ]; then 1186 dstdir=`echo $dst | sed -e 's;/*$;;'` 1187 dstbase="" 1188 else 1189 dstdir=`echo $dst | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` 1190 dstbase=`echo $dst | sed -e 's;.*/\([^/]*\)$;\1;'` 1191 fi 1192 1193 # consistency check 1194 if [ ".$dstdir" != . ]; then 1195 if [ ! -d $dstdir ]; then 1196 echo "$msgprefix:Error: destination directory not found: $dstdir" 1>&2 1197 shtool_exit 1 1198 fi 1199 fi 1200 1201 # make sure the source is reachable from the destination 1202 if [ $dstisabs = 1 ]; then 1203 if [ $srcisabs = 0 ]; then 1204 if [ ".$srcdir" = . ]; then 1205 srcdir="`pwd | sed -e 's;/*$;;'`" 1206 srcisabs=1 1207 oneisabs=1 1208 elif [ -d $srcdir ]; then 1209 srcdir="`cd $srcdir; pwd | sed -e 's;/*$;;'`" 1210 srcisabs=1 1211 oneisabs=1 1212 fi 1213 fi 1214 fi 1215 1216 # split away a common prefix 1217 prefix="" 1218 if [ ".$srcdir" = ".$dstdir" ] && [ ".$srcdir" != . ]; then 1219 prefix="$srcdir/" 1220 srcdir="" 1221 dstdir="" 1222 else 1223 while [ ".$srcdir" != . ] && [ ".$dstdir" != . ]; do 1224 presrc=`echo $srcdir | sed -e 's;^\([^/]*\)/.*;\1;'` 1225 predst=`echo $dstdir | sed -e 's;^\([^/]*\)/.*;\1;'` 1226 if [ ".$presrc" != ".$predst" ]; then 1227 break 1228 fi 1229 prefix="$prefix$presrc/" 1230 srcdir=`echo $srcdir | sed -e 's;^[^/]*/*;;'` 1231 dstdir=`echo $dstdir | sed -e 's;^[^/]*/*;;'` 1232 done 1233 fi 1234 1235 # destination prefix is just the common prefix 1236 dstpre="$prefix" 1237 1238 # determine source prefix which is the reverse directory 1239 # step-up corresponding to the destination directory 1240 srcpre="" 1241 allow_relative_srcpre=no 1242 if [ ".$prefix" != . ] && [ ".$prefix" != ./ ]; then 1243 allow_relative_srcpre=yes 1244 fi 1245 if [ $oneisabs = 0 ]; then 1246 allow_relative_srcpre=yes 1247 fi 1248 if [ ".$opt_s" != .yes ]; then 1249 allow_relative_srcpre=no 1250 fi 1251 if [ ".$allow_relative_srcpre" = .yes ]; then 1252 pl="$dstdir/" 1253 OIFS="$IFS"; IFS='/' 1254 for pe in $pl; do 1255 [ ".$pe" = . ] && continue 1256 [ ".$pe" = .. ] && continue 1257 srcpre="../$srcpre" 1258 done 1259 IFS="$OIFS" 1260 else 1261 if [ $srcisabs = 1 ]; then 1262 srcpre="$prefix" 1263 fi 1264 fi 1265 1266 # determine destination symlink name 1267 if [ ".$dstbase" = . ]; then 1268 if [ ".$srcbase" != . ]; then 1269 dstbase="$srcbase" 1270 else 1271 dstbase=`echo "$prefix$srcdir" | sed -e 's;/*$;;' -e 's;.*/\([^/]*\)$;\1;'` 1272 fi 1273 fi 1274 1275 # now finalize source and destination directory paths 1276 srcdir=`echo $srcdir | sed -e 's;\([^/]\)$;\1/;'` 1277 dstdir=`echo $dstdir | sed -e 's;\([^/]\)$;\1/;'` 1278 1279 # run the final link command 1280 if [ ".$opt_t" = .yes ]; then 1281 echo "ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase" 1282 fi 1283 eval ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase 1284 done 1285 1286 shtool_exit 0 1287 ;; 1288 1289subst ) 1290 ## 1291 ## subst -- Apply sed(1) substitution operations 1292 ## Copyright (c) 2001-2008 Ralf S. Engelschall <rse@engelschall.com> 1293 ## 1294 1295 # remember optional list of file(s) 1296 files="$*" 1297 files_num="$#" 1298 1299 # parameter consistency check 1300 if [ $# -eq 0 ] && [ ".$opt_b" != . ]; then 1301 echo "$msgprefix:Error: option -b cannot be applied to stdin" 1>&2 1302 shtool_exit 1 1303 fi 1304 if [ $# -eq 0 ] && [ ".$opt_s" = .yes ]; then 1305 echo "$msgprefix:Error: option -s cannot be applied to stdin" 1>&2 1306 shtool_exit 1 1307 fi 1308 1309 # build underlying sed(1) command 1310 sedcmd='sed' 1311 if [ ".$opt_e" != . ]; then 1312 OIFS="$IFS"; IFS="$ASC_NL"; set -- $opt_e; IFS="$OIFS" 1313 for e 1314 do 1315 sedcmd="$sedcmd -e '$e'" 1316 done 1317 elif [ ".$opt_f" != . ]; then 1318 if [ ! -f $opt_f ]; then 1319 echo "$msgprefix:Error: command file \`$opt_f' not found or not a regular file" 1>&2 1320 shtool_exit 1 1321 fi 1322 sedcmd="$sedcmd -f '$opt_f'" 1323 else 1324 echo "$msgprefix:Error: either -e option(s) or -f option required" 1>&2 1325 shtool_exit 1 1326 fi 1327 1328 # determine extension for original file 1329 orig=".orig" 1330 if [ ".$opt_b" != . ]; then 1331 orig="$opt_b" 1332 fi 1333 1334 # apply sed(1) operation(s) 1335 if [ ".$files" != . ]; then 1336 # apply operation(s) to files 1337 substdone=no 1338 for file in $files; do 1339 test ".$file" = . && continue 1340 if [ ! -f $file ]; then 1341 echo "$msgprefix:Warning: file \`$file' not found or not a regular file" 1>&2 1342 continue 1343 fi 1344 1345 # handle interactive mode 1346 if [ ".$opt_i" = .yes ]; then 1347 eval "$sedcmd <$file >$file.new" 1348 skip=no 1349 if cmp $file $file.new >/dev/null 2>&1; then 1350 rm -f $file.new 1351 skip=yes 1352 else 1353 (diff -U1 $file $file.new >$tmpfile) 2>/dev/null 1354 if [ ".`cat $tmpfile`" = . ]; then 1355 (diff -C1 $file $file.new >$tmpfile) 2>/dev/null 1356 if [ ".`cat $tmpfile`" = . ]; then 1357 echo "$msgprefix:Warning: unable to show difference for file \`$file'" 1>&2 1358 cp /dev/null $tmpfile 1359 fi 1360 fi 1361 rm -f $file.new 1362 cat $tmpfile 1363 echo dummy | awk '{ printf("%s", TEXT); }' TEXT=">>> Apply [Y/n]: " 1364 read input 1365 if [ ".$input" != .Y ] &&\ 1366 [ ".$input" != .y ] &&\ 1367 [ ".$input" != . ]; then 1368 skip=yes 1369 fi 1370 fi 1371 if [ ".$skip" = .yes ]; then 1372 if [ ".$opt_v" = .yes ]; then 1373 echo "file \`$file' -- skipped" 1>&2 1374 fi 1375 continue 1376 fi 1377 fi 1378 1379 # apply sed(1) operation(s) 1380 if [ ".$opt_v" = .yes ]; then 1381 echo "patching \`$file'" 1>&2 1382 fi 1383 if [ ".$opt_t" = .yes ]; then 1384 echo "\$ cp -p $file $file$orig" 1385 echo "\$ chmod u+w $file" 1386 echo "\$ $sedcmd <$file$orig >$file" 1387 fi 1388 if [ ".$opt_n" = .no ]; then 1389 cp -p $file $file$orig 1390 chmod u+w $file >/dev/null 2>&1 || true 1391 eval "$sedcmd <$file$orig >$file" 1392 fi 1393 1394 # optionally fix timestamp 1395 if [ ".$opt_s" = .yes ]; then 1396 if [ ".$opt_t" = .yes ]; then 1397 echo "\$ touch -r $file$orig $file" 1398 fi 1399 if [ ".$opt_n" = .no ]; then 1400 touch -r $file$orig $file 1401 fi 1402 fi 1403 1404 # optionally check whether any content change actually occurred 1405 if [ ".$opt_q" = .no ]; then 1406 if cmp $file$orig $file >/dev/null 2>&1; then 1407 if [ ".$opt_w" = .yes ]; then 1408 echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2 1409 fi 1410 else 1411 substdone=yes 1412 fi 1413 fi 1414 1415 # optionally remove preserved original file 1416 if [ ".$opt_b" = . ]; then 1417 if [ ".$opt_t" = .yes ]; then 1418 echo "\$ rm -f $file$orig" 1419 fi 1420 if [ ".$opt_n" = .no ]; then 1421 rm -f $file$orig 1422 fi 1423 fi 1424 done 1425 if [ ".$opt_q" = .no ] && [ ".$opt_w" = .no ]; then 1426 if [ ".$substdone" = .no ]; then 1427 if [ ".$files_num" = .1 ]; then 1428 echo "$msgprefix:Warning: substitution resulted in no content change on file \"$file\"" 1>&2 1429 else 1430 echo "$msgprefix:Warning: substitution resulted in no content change on any file" 1>&2 1431 fi 1432 fi 1433 fi 1434 else 1435 # apply operation(s) to stdin/stdout 1436 if [ ".$opt_v" = .yes ]; then 1437 echo "patching <stdin>" 1>&2 1438 fi 1439 if [ ".$opt_t" = .yes ]; then 1440 echo "\$ $sedcmd" 1441 fi 1442 if [ ".$opt_n" = .no ]; then 1443 eval "$sedcmd" 1444 fi 1445 fi 1446 1447 shtool_exit 0 1448 ;; 1449 1450esac 1451 1452shtool_exit 0 1453 1454