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