xref: /titanic_44/usr/src/lib/libshell/common/scripts/filetree1.sh (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
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 -C -A tree.files
64	typeset -C -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) 2009-05-06 \$\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", "tree" or "compacttree")..]
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|compacttree) ]] ; 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		print -v myfiletree
220		;;
221	compacttree)
222		print -C myfiletree
223		;;
224	*)
225		fatal_error $"Invalid view mode \"${viewmode}\"."
226		;;
227esac
228
229print -u2 $"#done."
230
231exit 0
232# EOF.
233