1#!/usr/bin/ksh93 2 3# 4# CDDL HEADER START 5# 6# The contents of this file are subject to the terms of the 7# Common Development and Distribution License (the "License"). 8# You may not use this file except in compliance with the License. 9# 10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11# or http://www.opensolaris.org/os/licensing. 12# See the License for the specific language governing permissions 13# and limitations under the License. 14# 15# When distributing Covered Code, include this CDDL HEADER in each 16# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17# If applicable, add the following below this CDDL HEADER, with the 18# fields enclosed by brackets "[]" replaced with your own identifying 19# information: Portions Copyright [yyyy] [name of copyright owner] 20# 21# CDDL HEADER END 22# 23 24# 25# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 26# 27 28# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 29export PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 30 31# Make sure all math stuff runs in the "C" locale to avoid problems 32# with alternative # radix point representations (e.g. ',' instead of 33# '.' in de_DE.*-locales). This needs to be set _before_ any 34# floating-point constants are defined in this script). 35if [[ "${LC_ALL}" != "" ]] ; then 36 export \ 37 LC_MONETARY="${LC_ALL}" \ 38 LC_MESSAGES="${LC_ALL}" \ 39 LC_COLLATE="${LC_ALL}" \ 40 LC_CTYPE="${LC_ALL}" 41 unset LC_ALL 42fi 43export LC_NUMERIC=C 44 45function fatal_error 46{ 47 print -u2 "${progname}: $*" 48 exit 1 49} 50 51 52function do_directory 53{ 54 nameref tree=$1 55 typeset basedir="$2" 56 57 typeset basename 58 typeset dirname 59 typeset i 60 typeset dummy 61 62 typeset -C -A tree.files 63 typeset -C -A tree.dirs 64 65 find "${basedir}"/* -prune 2>/dev/null | while read i ; do 66 dirname="$(dirname "$i")" 67 basename="$(basename "$i")" 68 69 # define "node" 70 if [[ -d "$i" ]] ; then 71 typeset -C tree.dirs["${basename}"] 72 nameref node=tree.dirs["${basename}"] 73 typeset -C node.flags 74 node.flags.dir="true" 75 node.flags.file="false" 76 else 77 typeset -C tree.files["${basename}"] 78 nameref node=tree.files["${basename}"] 79 typeset -C node.flags 80 81 node.flags.dir="false" 82 node.flags.file="true" 83 fi 84 85 # basic attributes 86 typeset -C node.paths=( 87 dirname="${dirname}" 88 basename="${basename}" 89 path="${i}" 90 ) 91 92 nameref nflags=node.flags 93 [[ -r "$i" ]] && nflags.readable="true" || nflags.readable="false" 94 [[ -w "$i" ]] && nflags.writeable="true" || nflags.writeable="false" 95 [[ -x "$i" ]] && nflags.executable="true" || nflags.executable="false" 96 97 [[ -b "$i" ]] && nflags.blockdevice="true" || nflags.blockdevice="false" 98 [[ -c "$i" ]] && nflags.characterdevice="true" || nflags.characterdevice="false" 99 [[ -S "$i" ]] && nflags.socket="true" || nflags.socket="false" 100 101 [[ -L "$i" ]] && nflags.symlink="true" || nflags.symlink="false" 102 103 integer node.size 104 integer node.links 105 typeset -C node.owner 106 ( [[ -x /usr/bin/runat ]] && ls -@ade "$i" || ls -lade "$i" ) | 107 IFS=' ' read \ 108 node.mask \ 109 node.links \ 110 node.owner.uid \ 111 node.owner.gid \ 112 node.size \ 113 dummy 114 115 typeset -C node.extended_attributes 116 if [[ ${node.mask} == ~(Er)@ ]] ; then 117 node.extended_attributes.hasattrs="true" 118 typeset -a attrlist=( 119 $( runat "$i" "ls -1" ) 120 ) 121 else 122 node.extended_attributes.hasattrs="false" 123 fi 124 125 if ${nflags.readable} ; then 126 # note that /usr/xpg4/bin/file does not use $'\t' as seperator - we 127 # have to use ':' instead. 128 file -h "$i" | IFS=' ' read dummy node.filetype 129 fi 130 131 if ${nflags.dir} ; then 132 do_directory "${!node}" "$i" 133 fi 134 done 135 136 # remove empty lists 137 (( ${#tree.files[@]} == 0 )) && unset tree.files 138 (( ${#tree.dirs[@]} == 0 )) && unset tree.dirs 139 140 return 0 141} 142 143 144function pathtovartree 145{ 146 nameref tree=$1 147 typeset basedir="$2" 148 149 do_directory tree "${basedir}" 150 151 return 0 152} 153 154function usage 155{ 156 OPTIND=0 157 getopts -a "${progname}" "${filetree1_usage}" OPT '-?' 158 exit 2 159} 160 161# program start 162builtin basename 163builtin cat 164builtin dirname 165builtin date 166builtin uname 167 168typeset progname="${ basename "${0}" ; }" 169 170typeset -r filetree1_usage=$'+ 171[-?\n@(#)\$Id: filetree1 (Roland Mainz) 2009-05-06 \$\n] 172[-author?Roland Mainz <roland.mainz@sun.com>] 173[-author?Roland Mainz <roland.mainz@nrubsig.org>] 174[+NAME?filetree1 - file tree demo] 175[+DESCRIPTION?\bfiletree1\b is a small ksh93 compound variable demo 176 which accepts a directory name as input, and then builds tree 177 nodes for all files+directories and stores all file attributes 178 in these notes and then outputs the tree in the format 179 specified by viewmode (either "list", "namelist", "tree" or "compacttree")..] 180 181viewmode dirs 182 183[+SEE ALSO?\bksh93\b(1), \bfile\b(1)] 184' 185 186while getopts -a "${progname}" "${filetree1_usage}" OPT ; do 187# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 188 case ${OPT} in 189 *) usage ;; 190 esac 191done 192shift $((OPTIND-1)) 193 194typeset viewmode="$1" 195shift 196 197if [[ "${viewmode}" != ~(Elr)(list|namelist|tree|compacttree) ]] ; then 198 fatal_error $"Invalid view mode \"${viewmode}\"." 199fi 200 201typeset -C myfiletree 202 203while (( $# > 0 )) ; do 204 print -u2 -f "# Scanning %s ...\n" "${1}" 205 pathtovartree myfiletree "${1}" 206 shift 207done 208print -u2 $"#parsing completed." 209 210case "${viewmode}" in 211 list) 212 set | egrep "^myfiletree\[" | fgrep -v ']=$' 213 ;; 214 namelist) 215 typeset + | egrep "^myfiletree\[" 216 ;; 217 tree) 218 print -v myfiletree 219 ;; 220 compacttree) 221 print -C myfiletree 222 ;; 223 *) 224 fatal_error $"Invalid view mode \"${viewmode}\"." 225 ;; 226esac 227 228print -u2 $"#done." 229 230exit 0 231# EOF. 232