xref: /freebsd/cddl/usr.sbin/dwatch/libexec/vop_readdir (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1# -*- tab-width: 4 -*- ;; Emacs
2# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
3############################################################ IDENT(1)
4#
5# $Title: dwatch(8) module for VOP_READDIR(9) [or similar] entry $
6# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
7#
8############################################################ DESCRIPTION
9#
10# Print directory paths being read by VOP_READDIR(9) [or similar]
11# NB: All paths are shown even if error prevents their reading.
12#
13############################################################ PROBE
14
15: ${PROBE:=vfs:vop:$PROFILE:entry}
16
17############################################################ ACTIONS
18
19exec 9<<EOF
20$PROBE /* probe ID $ID */
21{${TRACE:+
22	printf("<$ID>");}
23	this->vp = (struct vnode *)arg0;
24	this->ncp = this->vp != NULL ?
25		this->vp->v_cache_dst.tqh_first : 0;
26	this->mount = this->vp != NULL ?
27		this->vp->v_mount : NULL; /* ptr to vfs we are in */
28	this->fi_fs = this->mount != NULL ?
29		stringof(this->mount->mnt_stat.f_fstypename) : "";
30	this->fi_mount = this->mount != NULL ?
31		stringof(this->mount->mnt_stat.f_mntonname) : "";
32	this->d_name = args[0]->v_cache_dd != NULL ?
33		stringof(args[0]->v_cache_dd->nc_name) : "";
34
35	$( awk -v MAX_DEPTH=$MAX_DEPTH '
36		{ sub(/^\\\t/, "\t") }
37		{ buf = buf "\t" $0 "\n" }
38		END {
39			sub(/\n$/, "", buf)
40			$0 = buf
41			sub(/^[[:space:]]*/, "")
42			for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
43				gsub(/DEPTH/, DEPTH)
44				print
45				$0 = buf
46			}
47		}
48	' <<-EOFDEPTH
49	this->nameDEPTH = "";
50	EOFDEPTH
51	)
52}
53
54$PROBE /this->vp == 0 || this->fi_fs == 0 ||
55	this->fi_fs == "devfs" || this->fi_fs == ""/ /* probe ID $((
56		$ID + 1
57	)) */
58{${TRACE:+
59	printf("<$(( $ID + 1 ))>");}
60	this->ncp = 0;
61}
62
63/*********************************************************/
64
65$PROBE /this->ncp/ /* probe ID $(( $ID + 2 )) (depth 1) */
66{${TRACE:+
67	printf("<$(( $ID + 2 ))>");}
68	this->dvp = this->ncp->nc_dvp != NULL ?
69		this->ncp->nc_dvp->v_cache_dst.tqh_first : 0;
70	this->name1 = this->dvp != 0 ? (
71		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
72	) : "";
73}
74
75$PROBE /this->name1 == 0 || this->fi_fs == 0 ||
76	this->fi_fs == "devfs" || this->fi_fs == "" ||
77	this->name1 == "/" || this->name1 == ""/ /* probe ID $(( $ID + 3 )) */
78{${TRACE:+
79	printf("<$(( $ID + 3 ))>");}
80	this->dvp = 0;
81}
82
83/*********************************************************/
84
85/*
86 * BEGIN Pathname-depth iterators
87 */
88
89$( awk -v ID=$(( $ID + 4 )) -v MAX_DEPTH=$MAX_DEPTH '
90	{ buf = buf $0 "\n" }
91	END {
92		sub(/\n$/, "", buf)
93		for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
94			$0 = buf
95			gsub(/DEPTH/, DEPTH)
96			gsub(/IDNUM/, ID++)
97			print
98		}
99	}
100' <<EOFDEPTH
101$PROBE /this->dvp/ /* probe ID IDNUM (depth DEPTH) */
102{${TRACE:+
103	printf("<IDNUM>");}
104	this->dvp = this->dvp->nc_dvp != NULL ?
105		this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
106	this->nameDEPTH = this->dvp != 0 ? (
107		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
108	) : "";
109}
110
111EOFDEPTH
112)
113
114$PROBE /this->dvp/ /* probe ID $(( $ID + $MAX_DEPTH + 3 )) */
115{${TRACE:+
116	printf("<$(( $ID + $MAX_DEPTH + 3 ))>");}
117	this->dvp = this->dvp->nc_dvp != NULL ?
118		this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
119	this->name$(( $MAX_DEPTH + 1 )) = this->dvp != 0 ? (
120		this->dvp->nc_dvp != NULL ? "..." : ""
121	) : "";
122}
123
124/*
125 * END Pathname-depth iterators
126 */
127
128/*********************************************************/
129
130$PROBE /this->fi_mount != 0/ /* probe ID $(( $ID + $MAX_DEPTH + 4 )) */
131{${TRACE:+
132	printf("<$(( $ID + $MAX_DEPTH + 4 ))>");
133}
134	/*
135	 * Join full path
136	 * NB: Up-to but not including the parent directory (joined below)
137	 */
138	this->path = this->fi_mount;
139	this->path = strjoin(this->path, this->fi_mount != 0 ? (
140		this->fi_mount == "/" ? "" : "/"
141	) : "/");
142	$( awk -v MAX_DEPTH=$MAX_DEPTH '
143		{ sub(/^\\\t/, "\t") }
144		{ buf = buf "\t" $0 "\n" }
145		END {
146			sub(/\n$/, "", buf)
147			$0 = buf
148			sub(/^[[:space:]]*/, "")
149			for (N = MAX_DEPTH + 1; N > 0; N--) {
150				gsub(/N/, N)
151				print
152				$0 = buf
153			}
154		}
155	' <<-EOFDEPTH
156	this->path = strjoin(this->path,
157	\	strjoin(this->nameN, this->nameN != "" ? "/" : ""));
158	EOFDEPTH
159	)
160
161	/* Join the parent directory name */
162	this->path = strjoin(this->path, strjoin(this->name =
163		(this->d_name != 0 ? this->d_name : ""),
164		this->name != "" ? "/" : ""));
165}
166EOF
167ACTIONS=$( cat <&9 )
168ID=$(( $ID + $MAX_DEPTH + 5 ))
169
170############################################################ EVENT ACTION
171
172EVENT_TEST="this->fi_mount != 0"
173
174############################################################ EVENT DETAILS
175
176if [ ! "$CUSTOM_DETAILS" ]; then
177exec 9<<EOF
178	/*
179	 * Print full path
180	 */
181	printf("%s", this->path);
182EOF
183EVENT_DETAILS=$( cat <&9 )
184fi
185
186################################################################################
187# END
188################################################################################
189