home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / setperm < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  6.9 KB  |  255 lines

  1. #!/bin/ksh
  2. # setperm: set mode, ownership and group of a file.
  3. # @(#) setperm.ksh 1.1 95/09/14
  4. # 90/05/28 john h. dubois iii (john@armory.com)
  5. # 91/01/12 Set executability if mode included 's'
  6. # 91/02/25 cleaned up
  7. # 92/10/14 deal with t and T in mode
  8. # 92/12/05 made h option real, print warning if no files of correct type
  9. # 93/03/19 Added n to l options to avoid problems with truncated group names
  10. # 93/04/07 Do an extra chmod for +s
  11. # 93/05/20 Replaced various commands with shell builtins, improved efficiency
  12. # 94/03/27 Added c option
  13. # 95/09/14 Use ls -lL instead of l, since symlinks don't have their own perms
  14. #          and chmod follows symlinks.
  15.  
  16. # todo: this program will fail miserably (possibly setting modes on the wrong
  17. #       files) if any filenames contain whitespace.  Needs to be cleaned up.
  18.  
  19. set -o noglob
  20.  
  21. alias istrue="test 0 -ne"
  22. alias isfalse="test 0 -eq"
  23. name=${0##*/}
  24.  
  25. # Usage: getperm cfile
  26. # gets permissions and type of file cfile into global variables
  27. # type, mode, user, and group.
  28. getperm() {
  29.     typeset file=$1 perm nperm comp ptype
  30.     if [[ ! -a "$file" ]]; then
  31.     echo "Could not access dup file $file."
  32.     exit 1
  33.     fi
  34.     set -- `ls -lLnd "$file"`
  35.  
  36.     typeset perm=$1
  37.  
  38.     nperm=${perm#?}
  39.     # get type of file if all & type are not set
  40.     # (all is set if files of any type are to be acted on;
  41.     # type is set if type of file to act on is given explicitly)
  42.     if [[ -z "$all" && -z "$type" ]]; then
  43.     type=${perm%$nperm}
  44.     if [ $type = - ]; then
  45.         type=f
  46.     fi
  47.     fi
  48.     perm=$nperm
  49.  
  50.     if [ -z "$mode" ]; then        # if mode not already given...
  51.     for ptype in u g o; do        # get perms for user, group and other
  52.         mode=$mode$ptype=        # add perm type to mode string
  53.         for wperm in r w xsStT; do    # strip off each mode letter
  54.         nperm=${perm#?}
  55.         # get next component of perms
  56.         comp=${perm%$nperm}
  57.         # Make sure each mode bit has one of the expected values for it
  58.         [[ "$comp" != [-$wperm] ]] && print -u2 \
  59.     "Warning: unrecognized permission '$comp'; should be one of: -$wperm"
  60.         case $comp in
  61.         -) ;;
  62.         # add executability if perm was s or t
  63.         s) mode=${mode}x$comp;;
  64.         S) mode=${mode}s;;
  65.         t) mode=${mode}x,u+t;;
  66.         T) mode=$mode,u+t;;
  67.         *) mode=$mode$comp;;
  68.         esac
  69.         perm=$nperm
  70.         done
  71.         if [ $ptype != o ]; then # add a comma after u=* & g=*
  72.         mode=$mode,
  73.         fi
  74.     done
  75.     fi
  76.     # get owner and group if not given explicitly
  77.     [ -z "$owner" ] && owner=$3
  78.     [ -z "$group" ] && group=$4
  79. }
  80.  
  81. usage="$name: set file mode, ownership and group.
  82. syntax: $name [-GOMrLlahq] [-f dupfile] [-g group] [-o owner]
  83.                 [ -m mode] [-t type] [dupfile] file ..."
  84.  
  85. while getopts :cGOMrLlahf:g:o:m:t: opt; do
  86.     case $opt in
  87.     h) echo "$usage"
  88.        echo \
  89. "If a dupfile is given, the owner, group, and mode are copied from it, 
  90. and only files of its type are acted on.  This is modified by the flags 
  91. as described.  If no dupfile is given, all files are acted on (unless -t 
  92. is given), and only values given (owner, group, mode) are set.
  93. Options:
  94. -G, -O, -M: don't set {group, owner, mode}
  95. -r: do recursively for each file argument
  96. -L: list files that will be affected.
  97. -l: list files that would be affected, but don't change anything.
  98. -q: list files and action that would be taken, then ask before proceding.
  99. -a: do for all types of files, regardless of dupfile type.
  100. -h: print this help.
  101. -c: create target files that don't exist.
  102. -f dupfile: read type, mode, owner and group from file dupfile.
  103. -g group: set group to group.
  104. -o owner: set owner to to owner.
  105. -m mode: set mode to mode (as in chmod).
  106. -t type: only act on files of type type (one of [bcdpf] as in find).  
  107.          Only one type can be specified.
  108. dupfile: if none of -g, -o, -m and -f are given, the first file
  109.          argument given is used as the dupfile (as in -f).
  110. file ...: files to act on."
  111.         exit;;
  112.     G) nosetgroup=true;;
  113.     O) nosetowner=true;;
  114.     M) nosetmode=true;;
  115.     c) create=true;;
  116.     l) listfiles=quit;;
  117.     L) listfiles=continue;;
  118.     q) listfiles=query;;
  119.     f) getperm "$OPTARG";;
  120.     g) group="$OPTARG";;
  121.     o) owner="$OPTARG";;
  122.     m) mode="$OPTARG";;
  123.     r) recursive=true;;
  124.     t) type="$OPTARG"; 
  125.        if [[ "$type" != [bcdpf] ]]; then
  126.        echo "$name: Invalid file type '$type'.  Exiting."
  127.        exit 1
  128.        fi;;
  129.     a) all=true;;
  130.     +?) echo "$name: options should not be preceded by a '+'."; exit 1;;
  131.     :) 
  132.     print -r -u2 -- \
  133.     "$name: Option '$OPTARG' requires a value.  Use -h for help."
  134.     exit 1
  135.     ;;
  136.     ?) echo "$name: bad option '$OPTARG'.  Use -h for help."; exit 1;;
  137.     esac
  138. done
  139.  
  140. # remove args that were options
  141. let OPTIND=OPTIND-1
  142. shift $OPTIND
  143.  
  144. if [ $# -lt 1 ]; then
  145.     echo "$usage"
  146.     exit
  147. fi
  148.  
  149. # if nothing set explicitly or via -f, first non-option arg is the name
  150. # of a file to duplicate perms from.
  151. if [[ (-z "$group" && -z "$owner") && -z "$mode" ]]; then
  152.     if [ $# -lt 2 ]; then
  153.     echo "Not enough arguments."
  154.     exit
  155.     fi
  156.     getperm "$1"
  157.     shift
  158. fi
  159.  
  160. [ -n "$nosetowner" ] && owner=
  161. [ -n "$nosetgroup" ] && group=
  162. [ -n "$nosetmode" ] && mode=
  163.  
  164. # generate files list
  165. if [[ -n "$recursive" ]]; then
  166.     if [[ -n "$type" ]]; then
  167.     files=$(find "$@" -type $type -print)
  168.     else
  169.     files=$(find "$@" -print)
  170.     fi
  171. else
  172.     if [[ -n "$type" ]]; then
  173.     if [ "$type" = f ]; then  # l gives '-' for an ordinary file
  174.         type=-
  175.     fi
  176.     ls -lLd "$@" 2>&1 | while read line; do
  177.         set -- $line
  178.         if [ $# -eq 3 ]; then
  179.         if [ -n "$create" ]; then
  180.             case $type in
  181.             d) mkdir "$1" && files="$files $1"
  182.             ;;
  183.             p) mknod "$1" p && files="$files $1"
  184.             ;;
  185.             -) > "$1" && files="$files $1"
  186.             ;;
  187.             default)
  188.             print -u2 "Can't create file of type '$type'".
  189.             ;;
  190.             esac
  191.         else
  192.             print -- "$line"
  193.         fi
  194.         elif [[ "$1" = "$type"* ]]; then
  195.         shift $(($# - 1))
  196.         files="$files $1"
  197.         fi
  198.     done
  199.     else
  200.     files=$*
  201.     fi
  202. fi
  203.  
  204. set -- $files
  205. numfiles=$#
  206.  
  207. [ -n "$owner" ] && action=" owner=$owner"
  208. [ -n "$group" ] && action="$action group=$group"
  209. [ -n "$mode" ] && action="$action mode=$mode"
  210.  
  211. if [[ -n "$listfiles" ]]; then
  212.     for file in $files; do
  213.     echo $file
  214.     done
  215.     case $listfiles in
  216.     quit)    exit 0;;
  217.     query)    echo -n "Would set$action on $numfiles files.  Continue? ";
  218.         read answer
  219.         if [[ "$answer" != [yY]* ]]; then
  220.             exit 0;
  221.         fi;;
  222.     continue)    ;;
  223.     esac
  224. fi
  225.  
  226. if [ $numfiles -eq 0 ]; then
  227.     print -u2 "No target files of correct type ($type)."
  228.     exit 1
  229. fi
  230.  
  231. echo "Setting$action on $numfiles files."
  232.  
  233. # Set mode & group first; if owner is changed it will be too late
  234. # for non-superuser
  235. [ "${#files}" -le 400 ]
  236. doxargs=$?
  237.  
  238. if [[ -n "$mode" ]]; then
  239.      istrue doxargs && echo "$files" | xargs chmod $mode || chmod $mode $files
  240. fi
  241.  
  242. if [[ -n "$group" ]]; then
  243.     istrue doxargs && echo "$files" | xargs chgrp $group || chgrp $group $files
  244. fi
  245.  
  246. if [[ -n "$owner" ]]; then
  247.     istrue doxargs && echo "$files" | xargs chown $owner || chown $owner $files
  248. fi
  249.  
  250. # If set[ug]id was included it was lost with chgrp/chown, so do it now,
  251. # if still possible
  252. if [[ "$mode" = *s* ]]; then
  253.     istrue doxargs && echo "$files" | xargs chmod $mode || chmod $mode $files
  254. fi
  255.