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