xref: /freebsd/sys/tools/vnode_if.awk (revision 4a0f765fbf09711e612e86fce8bb09ec43f482d9)
1#!/bin/sh -
2#
3# Copyright (c) 1992, 1993
4#	The Regents of the University of California.  All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14# 3. All advertising materials mentioning features or use of this software
15#    must display the following acknowledgement:
16#	This product includes software developed by the University of
17#	California, Berkeley and its contributors.
18# 4. Neither the name of the University nor the names of its contributors
19#    may be used to endorse or promote products derived from this software
20#    without specific prior written permission.
21#
22# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32# SUCH DAMAGE.
33#
34#	@(#)vnode_if.sh	8.1 (Berkeley) 6/10/93
35# $Id$
36#
37
38# Script to produce VFS front-end sugar.
39#
40# usage: vnode_if.sh srcfile
41#	(where srcfile is currently /sys/kern/vnode_if.src)
42#
43# These awk scripts are not particularly well written, specifically they
44# don't use arrays well and figure out the same information repeatedly.
45# Please rewrite them if you actually understand how to use awk.  Note,
46# they use nawk extensions and gawk's toupper.
47
48if [ $# -ne 1 ] ; then
49	echo 'usage: vnode_if.sh srcfile'
50	exit 1
51fi
52
53# Name of the source file.
54SRC=$1
55
56# Names of the created files.
57CFILE=vnode_if.c
58HEADER=vnode_if.h
59
60# Awk program (must support nawk extensions and gawk's "toupper")
61# Use "awk" at Berkeley, "gawk" elsewhere.
62AWK=awk
63
64# Print out header information for vnode_if.h.
65cat << END_OF_LEADING_COMMENT > $HEADER
66/*
67 * This file is produced automatically.
68 * Do not modify anything in here by hand.
69 *
70 * Created from @(#)vnode_if.sh	8.1 (Berkeley) 6/10/93
71 */
72
73extern struct vnodeop_desc vop_default_desc;
74END_OF_LEADING_COMMENT
75
76# Awk script to take vnode_if.src and turn it into vnode_if.h.
77$AWK '
78	NF == 0 || $0 ~ "^#" {
79		next;
80	}
81	{
82		# Get the function name.
83		name = $1;
84		uname = toupper(name);
85
86		# Get the function arguments.
87		for (c1 = 0;; ++c1) {
88			if (getline <= 0)
89				exit
90			if ($0 ~ "^};")
91				break;
92			a[c1] = $0;
93		}
94
95		# Print out the vop_F_args structure.
96		printf("struct %s_args {\n\tstruct vnodeop_desc *a_desc;\n",
97		    name);
98		for (c2 = 0; c2 < c1; ++c2) {
99			c3 = split(a[c2], t);
100			printf("\t");
101			if (t[2] ~ "WILLRELE")
102				c4 = 3;
103			else
104				c4 = 2;
105			for (; c4 < c3; ++c4)
106				printf("%s ", t[c4]);
107			beg = match(t[c3], "[^*]");
108			printf("%sa_%s\n",
109			    substr(t[c4], 0, beg - 1), substr(t[c4], beg));
110		}
111		printf("};\n");
112
113		# Print out extern declaration.
114		printf("extern struct vnodeop_desc %s_desc;\n", name);
115
116		# Print out prototype.
117		printf("static int %s __P((\n", uname);
118		sep = ",\n";
119		for (c2 = 0; c2 < c1; ++c2) {
120			if (c2 == c1 - 1)
121				sep = "));\n";
122			c3 = split(a[c2], t);
123			printf("\t");
124			if (t[2] ~ "WILLRELE")
125				c4 = 3;
126			else
127				c4 = 2;
128			for (; c4 < c3; ++c4)
129				printf("%s ", t[c4]);
130			beg = match(t[c3], "[^*]");
131			end = match(t[c3], ";");
132			printf("%s%s%s",
133			    substr(t[c4], 0, beg - 1),
134			    substr(t[c4], beg, end - beg), sep);
135		}
136
137		# Print out inline struct.
138		printf("static inline int %s(", uname);
139		sep = ", ";
140		for (c2 = 0; c2 < c1; ++c2) {
141			if (c2 == c1 - 1)
142				sep = ")\n";
143			c3 = split(a[c2], t);
144			beg = match(t[c3], "[^*]");
145			end = match(t[c3], ";");
146			printf("%s%s", substr(t[c3], beg, end - beg), sep);
147		}
148		for (c2 = 0; c2 < c1; ++c2) {
149			c3 = split(a[c2], t);
150			printf("\t");
151			if (t[2] ~ "WILLRELE")
152				c4 = 3;
153			else
154				c4 = 2;
155			for (; c4 < c3; ++c4)
156				printf("%s ", t[c4]);
157			beg = match(t[c3], "[^*]");
158			printf("%s%s\n",
159			    substr(t[c4], 0, beg - 1), substr(t[c4], beg));
160		}
161		printf("{\n\tstruct %s_args a;\n\n", name);
162		printf("\ta.a_desc = VDESC(%s);\n", name);
163		for (c2 = 0; c2 < c1; ++c2) {
164			c3 = split(a[c2], t);
165			printf("\t");
166			beg = match(t[c3], "[^*]");
167			end = match(t[c3], ";");
168			printf("a.a_%s = %s\n",
169			    substr(t[c3], beg, end - beg), substr(t[c3], beg));
170		}
171		c1 = split(a[0], t);
172		beg = match(t[c1], "[^*]");
173		end = match(t[c1], ";");
174		printf("\treturn (VCALL(%s, VOFFSET(%s), &a));\n}\n",
175		    substr(t[c1], beg, end - beg), name);
176	}' < $SRC >> $HEADER
177
178# Print out header information for vnode_if.c.
179cat << END_OF_LEADING_COMMENT > $CFILE
180/*
181 * This file is produced automatically.
182 * Do not modify anything in here by hand.
183 *
184 * Created from @(#)vnode_if.sh	8.1 (Berkeley) 6/10/93
185 */
186
187#include <sys/param.h>
188#include <sys/mount.h>
189#include <sys/vnode.h>
190
191struct vnodeop_desc vop_default_desc = {
192	0,
193	"default",
194	0,
195	NULL,
196	VDESC_NO_OFFSET,
197	VDESC_NO_OFFSET,
198	VDESC_NO_OFFSET,
199	VDESC_NO_OFFSET,
200	NULL,
201};
202
203END_OF_LEADING_COMMENT
204
205# Awk script to take vnode_if.src and turn it into vnode_if.c.
206$AWK 'function kill_surrounding_ws (s) {
207		sub (/^[ \t]*/, "", s);
208		sub (/[ \t]*$/, "", s);
209		return s;
210	}
211
212	function read_args() {
213		numargs = 0;
214		while (getline ln) {
215			if (ln ~ /}/) {
216				break;
217			};
218
219			# Delete comments, if any.
220			gsub (/\/\*.*\*\//, "", ln);
221
222			# Delete leading/trailing space.
223			ln = kill_surrounding_ws(ln);
224
225			# Pick off direction.
226			if (1 == sub(/^INOUT[ \t]+/, "", ln))
227				dir = "INOUT";
228			else if (1 == sub(/^IN[ \t]+/, "", ln))
229				dir = "IN";
230			else if (1 == sub(/^OUT[ \t]+/, "", ln))
231				dir = "OUT";
232			else
233				bail("No IN/OUT direction for \"" ln "\".");
234
235			# check for "WILLRELE"
236			if (1 == sub(/^WILLRELE[ \t]+/, "", ln)) {
237				rele = "WILLRELE";
238			} else {
239				rele = "WONTRELE";
240			};
241
242			# kill trailing ;
243			if (1 != sub (/;$/, "", ln)) {
244				bail("Missing end-of-line ; in \"" ln "\".");
245			};
246
247			# pick off variable name
248			if (!(i = match(ln, /[A-Za-z0-9_]+$/))) {
249				bail("Missing var name \"a_foo\" in \"" ln "\".");
250			};
251			arg = substr (ln, i);
252			# Want to <<substr(ln, i) = "";>>, but nawk cannot.
253			# Hack around this.
254			ln = substr(ln, 1, i-1);
255
256			# what is left must be type
257			# (put clean it up some)
258			type = ln;
259			gsub (/[ \t]+/, " ", type);   # condense whitespace
260			type = kill_surrounding_ws(type);
261
262			# (boy this was easier in Perl)
263
264			numargs++;
265			dirs[numargs] = dir;
266			reles[numargs] = rele;
267			types[numargs] = type;
268			args[numargs] = arg;
269		};
270	}
271
272	function generate_operation_vp_offsets() {
273		printf ("static int %s_vp_offsets[] = {\n", name);
274		# as a side effect, figure out the releflags
275		releflags = "";
276		vpnum = 0;
277		for (i=1; i<=numargs; i++) {
278			if (types[i] == "struct vnode *") {
279				printf ("\tVOPARG_OFFSETOF(struct %s_args,a_%s),\n",
280					name, args[i]);
281				if (reles[i] == "WILLRELE") {
282					releflags = releflags "|VDESC_VP" vpnum "_WILLRELE";
283				};
284				vpnum++;
285			};
286		};
287		sub (/^\|/, "", releflags);
288		print "\tVDESC_NO_OFFSET";
289		print "};";
290	}
291
292	function find_arg_with_type (type) {
293		for (i=1; i<=numargs; i++) {
294			if (types[i] == type) {
295				return "VOPARG_OFFSETOF(struct " name "_args,a_" args[i] ")";
296			};
297		};
298		return "VDESC_NO_OFFSET";
299	}
300
301	function generate_operation_desc() {
302		printf ("struct vnodeop_desc %s_desc = {\n", name);
303		# offset
304		printf ("\t0,\n");
305		# printable name
306		printf ("\t\"%s\",\n", name);
307		# flags
308		vppwillrele = "";
309		for (i=1; i<=numargs; i++) {
310			if (types[i] == "struct vnode **" &&
311				(reles[i] == "WILLRELE")) {
312				vppwillrele = "|VDESC_VPP_WILLRELE";
313			};
314		};
315		if (releflags == "") {
316			printf ("\t0%s,\n", vppwillrele);
317		} else {
318			printf ("\t%s%s,\n", releflags, vppwillrele);
319		};
320		# vp offsets
321		printf ("\t%s_vp_offsets,\n", name);
322		# vpp (if any)
323		printf ("\t%s,\n", find_arg_with_type("struct vnode **"));
324		# cred (if any)
325		printf ("\t%s,\n", find_arg_with_type("struct ucred *"));
326		# proc (if any)
327		printf ("\t%s,\n", find_arg_with_type("struct proc *"));
328		# componentname
329		printf ("\t%s,\n", find_arg_with_type("struct componentname *"));
330		# transport layer information
331		printf ("\tNULL,\n};\n");
332	}
333
334	NF == 0 || $0 ~ "^#" {
335		next;
336	}
337	{
338		# get the function name
339		name = $1;
340
341		# get the function arguments
342		read_args();
343
344		# Print out the vop_F_vp_offsets structure.  This all depends
345		# on naming conventions and nothing else.
346		generate_operation_vp_offsets();
347
348		# Print out the vnodeop_desc structure.
349		generate_operation_desc();
350
351		printf "\n";
352
353	}' < $SRC >> $CFILE
354# THINGS THAT DON'T WORK RIGHT YET.
355#
356# Two existing BSD vnodeops (bwrite and strategy) don't take any vnodes as
357# arguments.  This means that these operations can't function successfully
358# through a bypass routine.
359#
360# Bwrite and strategy will be replaced when the VM page/buffer cache
361# integration happens.
362#
363# To get around this problem for now we handle these ops as special cases.
364
365cat << END_OF_SPECIAL_CASES >> $HEADER
366#include <sys/buf.h>
367struct vop_strategy_args {
368	struct vnodeop_desc *a_desc;
369	struct buf *a_bp;
370};
371extern struct vnodeop_desc vop_strategy_desc;
372static int VOP_STRATEGY __P((
373	struct buf *bp));
374static inline int VOP_STRATEGY(bp)
375	struct buf *bp;
376{
377	struct vop_strategy_args a;
378
379	a.a_desc = VDESC(vop_strategy);
380	a.a_bp = bp;
381	return (VCALL((bp)->b_vp, VOFFSET(vop_strategy), &a));
382}
383
384struct vop_bwrite_args {
385	struct vnodeop_desc *a_desc;
386	struct buf *a_bp;
387};
388extern struct vnodeop_desc vop_bwrite_desc;
389static int VOP_BWRITE __P((
390	struct buf *bp));
391static inline int VOP_BWRITE(bp)
392	struct buf *bp;
393{
394	struct vop_bwrite_args a;
395
396	a.a_desc = VDESC(vop_bwrite);
397	a.a_bp = bp;
398	return (VCALL((bp)->b_vp, VOFFSET(vop_bwrite), &a));
399}
400END_OF_SPECIAL_CASES
401
402cat << END_OF_SPECIAL_CASES >> $CFILE
403static int vop_strategy_vp_offsets[] = {
404	VDESC_NO_OFFSET
405};
406struct vnodeop_desc vop_strategy_desc = {
407	0,
408	"vop_strategy",
409	0,
410	vop_strategy_vp_offsets,
411	VDESC_NO_OFFSET,
412	VDESC_NO_OFFSET,
413	VDESC_NO_OFFSET,
414	VDESC_NO_OFFSET,
415	NULL,
416};
417static int vop_bwrite_vp_offsets[] = {
418	VDESC_NO_OFFSET
419};
420struct vnodeop_desc vop_bwrite_desc = {
421	0,
422	"vop_bwrite",
423	0,
424	vop_bwrite_vp_offsets,
425	VDESC_NO_OFFSET,
426	VDESC_NO_OFFSET,
427	VDESC_NO_OFFSET,
428	VDESC_NO_OFFSET,
429	NULL,
430};
431END_OF_SPECIAL_CASES
432
433# Add the vfs_op_descs array to the C file.
434$AWK '
435	BEGIN {
436		printf("\nstruct vnodeop_desc *vfs_op_descs[] = {\n");
437		printf("\t&vop_default_desc,	/* MUST BE FIRST */\n");
438		printf("\t&vop_strategy_desc,	/* XXX: SPECIAL CASE */\n");
439		printf("\t&vop_bwrite_desc,	/* XXX: SPECIAL CASE */\n");
440	}
441	END {
442		printf("\tNULL\n};\n");
443	}
444	NF == 0 || $0 ~ "^#" {
445		next;
446	}
447	{
448		# Get the function name.
449		printf("\t&%s_desc,\n", $1);
450
451		# Skip the function arguments.
452		for (;;) {
453			if (getline <= 0)
454				exit
455			if ($0 ~ "^};")
456				break;
457		}
458	}' < $SRC >> $CFILE
459
460