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