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