xref: /titanic_53/usr/src/cmd/fm/scripts/dictck.pl (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate#!/usr/bin/perl -w
2*7c478bd9Sstevel@tonic-gate#
3*7c478bd9Sstevel@tonic-gate# CDDL HEADER START
4*7c478bd9Sstevel@tonic-gate#
5*7c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6*7c478bd9Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only
7*7c478bd9Sstevel@tonic-gate# (the "License").  You may not use this file except in compliance
8*7c478bd9Sstevel@tonic-gate# with the License.
9*7c478bd9Sstevel@tonic-gate#
10*7c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*7c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
12*7c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
13*7c478bd9Sstevel@tonic-gate# and limitations under the License.
14*7c478bd9Sstevel@tonic-gate#
15*7c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
16*7c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*7c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
18*7c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
19*7c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
20*7c478bd9Sstevel@tonic-gate#
21*7c478bd9Sstevel@tonic-gate# CDDL HEADER END
22*7c478bd9Sstevel@tonic-gate#
23*7c478bd9Sstevel@tonic-gate#
24*7c478bd9Sstevel@tonic-gate# ident	"%Z%%M%	%I%	%E% SMI"
25*7c478bd9Sstevel@tonic-gate#
26*7c478bd9Sstevel@tonic-gate# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
27*7c478bd9Sstevel@tonic-gate# Use is subject to license terms.
28*7c478bd9Sstevel@tonic-gate#
29*7c478bd9Sstevel@tonic-gate#
30*7c478bd9Sstevel@tonic-gate# dictck -- Sanity check a .dict file and optionally the corresponding .po file
31*7c478bd9Sstevel@tonic-gate#
32*7c478bd9Sstevel@tonic-gate# example: dickck FMD.dict FMD.po
33*7c478bd9Sstevel@tonic-gate#
34*7c478bd9Sstevel@tonic-gate# usage: dickck [-vp] [ -b buildcode ] dictfile [ pofile ]
35*7c478bd9Sstevel@tonic-gate#
36*7c478bd9Sstevel@tonic-gate#	-b	specify location of "buildcode" command
37*7c478bd9Sstevel@tonic-gate#
38*7c478bd9Sstevel@tonic-gate#	-p	print a .po file template to stdout, based on dictfile given
39*7c478bd9Sstevel@tonic-gate#
40*7c478bd9Sstevel@tonic-gate#	-v	verbose, show how code is assembled
41*7c478bd9Sstevel@tonic-gate#
42*7c478bd9Sstevel@tonic-gate# Note: this program requires the "buildcode" program in your search path.
43*7c478bd9Sstevel@tonic-gate#
44*7c478bd9Sstevel@tonic-gate
45*7c478bd9Sstevel@tonic-gateuse strict;
46*7c478bd9Sstevel@tonic-gate
47*7c478bd9Sstevel@tonic-gateuse Getopt::Std;
48*7c478bd9Sstevel@tonic-gate
49*7c478bd9Sstevel@tonic-gateuse vars qw($opt_b $opt_p $opt_v);
50*7c478bd9Sstevel@tonic-gate
51*7c478bd9Sstevel@tonic-gatemy $Myname = $0;	# save our name for error messages
52*7c478bd9Sstevel@tonic-gate$Myname =~ s,.*/,,;
53*7c478bd9Sstevel@tonic-gate
54*7c478bd9Sstevel@tonic-gate$SIG{HUP} = $SIG{INT} = $SIG{TERM} = $SIG{__DIE__} = sub {
55*7c478bd9Sstevel@tonic-gate	# although fatal, we prepend "WARNING:" to make sure the
56*7c478bd9Sstevel@tonic-gate	# commonly-used "nightly" script flags this as lint on the .dict file
57*7c478bd9Sstevel@tonic-gate	die "$Myname: WARNING: @_";
58*7c478bd9Sstevel@tonic-gate};
59*7c478bd9Sstevel@tonic-gate
60*7c478bd9Sstevel@tonic-gate#
61*7c478bd9Sstevel@tonic-gate# usage -- print a usage message and exit
62*7c478bd9Sstevel@tonic-gate#
63*7c478bd9Sstevel@tonic-gatesub usage {
64*7c478bd9Sstevel@tonic-gate	my $msg = shift;
65*7c478bd9Sstevel@tonic-gate
66*7c478bd9Sstevel@tonic-gate	warn "$Myname: $msg\n" if defined($msg);
67*7c478bd9Sstevel@tonic-gate	warn "usage: $Myname [-pv] [ -b buildcode ] dictfile [ pofile ]\n";
68*7c478bd9Sstevel@tonic-gate	exit 1;
69*7c478bd9Sstevel@tonic-gate}
70*7c478bd9Sstevel@tonic-gate
71*7c478bd9Sstevel@tonic-gatemy %keys2val;
72*7c478bd9Sstevel@tonic-gatemy %val2keys;
73*7c478bd9Sstevel@tonic-gatemy %code2val;
74*7c478bd9Sstevel@tonic-gate
75*7c478bd9Sstevel@tonic-gatemy $buildcode = 'buildcode';
76*7c478bd9Sstevel@tonic-gate
77*7c478bd9Sstevel@tonic-gate#
78*7c478bd9Sstevel@tonic-gate# the "main" for this script...
79*7c478bd9Sstevel@tonic-gate#
80*7c478bd9Sstevel@tonic-gategetopts('b:pv') or usage;
81*7c478bd9Sstevel@tonic-gate
82*7c478bd9Sstevel@tonic-gatemy $dictfile = shift;
83*7c478bd9Sstevel@tonic-gatemy $pofile = shift;
84*7c478bd9Sstevel@tonic-gateusage unless defined($dictfile);
85*7c478bd9Sstevel@tonic-gateusage if @ARGV;
86*7c478bd9Sstevel@tonic-gate$buildcode = $opt_b if defined($opt_b);
87*7c478bd9Sstevel@tonic-gatedodict($dictfile);
88*7c478bd9Sstevel@tonic-gatedopo($pofile) if defined($pofile);
89*7c478bd9Sstevel@tonic-gateexit 0;
90*7c478bd9Sstevel@tonic-gate
91*7c478bd9Sstevel@tonic-gate#
92*7c478bd9Sstevel@tonic-gate# dodict -- load up a .dict file, sanity checking it as we go
93*7c478bd9Sstevel@tonic-gate#
94*7c478bd9Sstevel@tonic-gatesub dodict {
95*7c478bd9Sstevel@tonic-gate	my $name = shift;
96*7c478bd9Sstevel@tonic-gate	my $dname;
97*7c478bd9Sstevel@tonic-gate	my $line = 0;
98*7c478bd9Sstevel@tonic-gate	my $lhs;
99*7c478bd9Sstevel@tonic-gate	my $rhs;
100*7c478bd9Sstevel@tonic-gate	my %props;
101*7c478bd9Sstevel@tonic-gate	my $maxkey = 1;
102*7c478bd9Sstevel@tonic-gate
103*7c478bd9Sstevel@tonic-gate	if ($name =~ m,([^/]+)\.dict$,) {
104*7c478bd9Sstevel@tonic-gate		$dname = $1;
105*7c478bd9Sstevel@tonic-gate	} else {
106*7c478bd9Sstevel@tonic-gate		die "dictname \"$name\" not something.dict as expected\n";
107*7c478bd9Sstevel@tonic-gate	}
108*7c478bd9Sstevel@tonic-gate
109*7c478bd9Sstevel@tonic-gate	open(F, $name) or die "$name: $!\n";
110*7c478bd9Sstevel@tonic-gate	print "parsing \"$name\"\n" if $opt_v;
111*7c478bd9Sstevel@tonic-gate	while (<F>) {
112*7c478bd9Sstevel@tonic-gate		$line++;
113*7c478bd9Sstevel@tonic-gate		next if /^\s*#/;
114*7c478bd9Sstevel@tonic-gate		chomp;
115*7c478bd9Sstevel@tonic-gate		next if /^\s*$/;
116*7c478bd9Sstevel@tonic-gate		die "$name:$line: first non-comment line must be FMDICT line\n"
117*7c478bd9Sstevel@tonic-gate		    unless /^FMDICT:/;
118*7c478bd9Sstevel@tonic-gate		print "FMDICT keyword found on line $line\n" if $opt_v;
119*7c478bd9Sstevel@tonic-gate		s/FMDICT:\s*//;
120*7c478bd9Sstevel@tonic-gate		my $s = $_;
121*7c478bd9Sstevel@tonic-gate		while ($s =~ /^\s*([^=\s]+)(.*)$/) {
122*7c478bd9Sstevel@tonic-gate			$lhs = $1;
123*7c478bd9Sstevel@tonic-gate			$rhs = "";
124*7c478bd9Sstevel@tonic-gate			$s = $+;
125*7c478bd9Sstevel@tonic-gate			if ($s =~ /^\s*=\s*(.*)$/) {
126*7c478bd9Sstevel@tonic-gate				$s = $+;
127*7c478bd9Sstevel@tonic-gate				die "$name:$line: property \"$lhs\" incomplete\n"
128*7c478bd9Sstevel@tonic-gate				    unless $s ne "";
129*7c478bd9Sstevel@tonic-gate			}
130*7c478bd9Sstevel@tonic-gate			if ($s =~ /^"((?:[^"]|\\")*)"(.*)$/) {
131*7c478bd9Sstevel@tonic-gate				$s = $+;
132*7c478bd9Sstevel@tonic-gate				$rhs = $1;
133*7c478bd9Sstevel@tonic-gate			} else {
134*7c478bd9Sstevel@tonic-gate				$s =~ /^([^\s]*)(.*)$/;
135*7c478bd9Sstevel@tonic-gate				$s = $+;
136*7c478bd9Sstevel@tonic-gate				$rhs = $1;
137*7c478bd9Sstevel@tonic-gate			}
138*7c478bd9Sstevel@tonic-gate			$rhs =~ s/\\(.)/dobs($1)/ge;
139*7c478bd9Sstevel@tonic-gate			$props{$lhs} = $rhs;
140*7c478bd9Sstevel@tonic-gate			print "property \"$lhs\" value \"$rhs\"\n" if $opt_v;
141*7c478bd9Sstevel@tonic-gate		}
142*7c478bd9Sstevel@tonic-gate		last;
143*7c478bd9Sstevel@tonic-gate	}
144*7c478bd9Sstevel@tonic-gate	# check for required headers
145*7c478bd9Sstevel@tonic-gate	die "$name: no version property in header\n"
146*7c478bd9Sstevel@tonic-gate	    unless defined($props{'version'});
147*7c478bd9Sstevel@tonic-gate	die "$name: no name property in header\n"
148*7c478bd9Sstevel@tonic-gate	    unless defined($props{'name'});
149*7c478bd9Sstevel@tonic-gate	die "$name: no maxkey property in header\n"
150*7c478bd9Sstevel@tonic-gate	    unless defined($props{'maxkey'});
151*7c478bd9Sstevel@tonic-gate
152*7c478bd9Sstevel@tonic-gate	# check version
153*7c478bd9Sstevel@tonic-gate	die "$name:$line: unexpected version: \"$props{'version'}\"\n"
154*7c478bd9Sstevel@tonic-gate	    unless $props{'version'} eq "1";
155*7c478bd9Sstevel@tonic-gate
156*7c478bd9Sstevel@tonic-gate	# check name
157*7c478bd9Sstevel@tonic-gate	die "$name:$line: name \"$props{'name'}\" doesn't match \"$dname\" from filename\n"
158*7c478bd9Sstevel@tonic-gate	    unless $props{'name'} eq $dname;
159*7c478bd9Sstevel@tonic-gate
160*7c478bd9Sstevel@tonic-gate	# check format of maxkey (value checked later)
161*7c478bd9Sstevel@tonic-gate	die "$name:$line: maxkey property must be a number\n"
162*7c478bd9Sstevel@tonic-gate	    unless $props{'maxkey'} =~ /^\d+$/;
163*7c478bd9Sstevel@tonic-gate
164*7c478bd9Sstevel@tonic-gate	# check for old bits property
165*7c478bd9Sstevel@tonic-gate	die "$name: obsolete \"bits\" property found in header\n"
166*7c478bd9Sstevel@tonic-gate	    if defined($props{'bits'});
167*7c478bd9Sstevel@tonic-gate
168*7c478bd9Sstevel@tonic-gate	# parse entries
169*7c478bd9Sstevel@tonic-gate	while (<F>) {
170*7c478bd9Sstevel@tonic-gate		$line++;
171*7c478bd9Sstevel@tonic-gate		chomp;
172*7c478bd9Sstevel@tonic-gate		s/#.*//;
173*7c478bd9Sstevel@tonic-gate		next if /^\s*$/;
174*7c478bd9Sstevel@tonic-gate		die "$name:$line: malformed entry\n"
175*7c478bd9Sstevel@tonic-gate		    unless /^([^=]+)=(\d+)$/;
176*7c478bd9Sstevel@tonic-gate		$lhs = $1;
177*7c478bd9Sstevel@tonic-gate		$rhs = $2;
178*7c478bd9Sstevel@tonic-gate
179*7c478bd9Sstevel@tonic-gate		# make sure keys are sorted
180*7c478bd9Sstevel@tonic-gate		my $elhs = join(' ', sort split(/\s/, $lhs));
181*7c478bd9Sstevel@tonic-gate		die "$name:$line: keys not in expected format of:\n" .
182*7c478bd9Sstevel@tonic-gate		    "    \"$elhs\"\n"
183*7c478bd9Sstevel@tonic-gate		    unless $elhs eq $lhs;
184*7c478bd9Sstevel@tonic-gate
185*7c478bd9Sstevel@tonic-gate		# check for duplicate or unexpected keys
186*7c478bd9Sstevel@tonic-gate		my %keys;
187*7c478bd9Sstevel@tonic-gate		foreach my $e (split(/\s/, $lhs)) {
188*7c478bd9Sstevel@tonic-gate			die "$name:$line: unknown event type \"$e\"\n"
189*7c478bd9Sstevel@tonic-gate			    unless $e =~
190*7c478bd9Sstevel@tonic-gate			    /^(fault|defect|upset|ereport)\..*[^.]$/;
191*7c478bd9Sstevel@tonic-gate			die "$name:$line: key repeated: \"$e\"\n"
192*7c478bd9Sstevel@tonic-gate			    if defined($keys{$e});
193*7c478bd9Sstevel@tonic-gate			$keys{$e} = 1;
194*7c478bd9Sstevel@tonic-gate		}
195*7c478bd9Sstevel@tonic-gate		$maxkey = keys(%keys) if $maxkey < keys(%keys);
196*7c478bd9Sstevel@tonic-gate
197*7c478bd9Sstevel@tonic-gate		die "$name:$line: duplicate entry for keys\n"
198*7c478bd9Sstevel@tonic-gate		    if defined($keys2val{$lhs});
199*7c478bd9Sstevel@tonic-gate		die "$name:$line: duplicate entry for value $rhs\n"
200*7c478bd9Sstevel@tonic-gate		    if defined($val2keys{$rhs});
201*7c478bd9Sstevel@tonic-gate		$keys2val{$lhs} = $rhs;
202*7c478bd9Sstevel@tonic-gate		$val2keys{$rhs} = $lhs;
203*7c478bd9Sstevel@tonic-gate
204*7c478bd9Sstevel@tonic-gate		open(B, "$buildcode $dname $rhs|") or
205*7c478bd9Sstevel@tonic-gate		    die "can't run buildcode: $!\n";
206*7c478bd9Sstevel@tonic-gate		my $code = <B>;
207*7c478bd9Sstevel@tonic-gate		chomp $code;
208*7c478bd9Sstevel@tonic-gate		close(B);
209*7c478bd9Sstevel@tonic-gate		print "code: $code keys: $lhs\n" if $opt_v;
210*7c478bd9Sstevel@tonic-gate		$code2val{$code} = $rhs;
211*7c478bd9Sstevel@tonic-gate
212*7c478bd9Sstevel@tonic-gate		if ($opt_p) {
213*7c478bd9Sstevel@tonic-gate			print <<EOF;
214*7c478bd9Sstevel@tonic-gate#
215*7c478bd9Sstevel@tonic-gate# code: $code
216*7c478bd9Sstevel@tonic-gate# keys: $lhs
217*7c478bd9Sstevel@tonic-gate#
218*7c478bd9Sstevel@tonic-gatemsgid "$code.type"
219*7c478bd9Sstevel@tonic-gatemsgstr "XXX"
220*7c478bd9Sstevel@tonic-gatemsgid "$code.severity"
221*7c478bd9Sstevel@tonic-gatemsgstr "XXX"
222*7c478bd9Sstevel@tonic-gatemsgid "$code.description"
223*7c478bd9Sstevel@tonic-gatemsgstr "XXX"
224*7c478bd9Sstevel@tonic-gatemsgid "$code.response"
225*7c478bd9Sstevel@tonic-gatemsgstr "XXX"
226*7c478bd9Sstevel@tonic-gatemsgid "$code.impact"
227*7c478bd9Sstevel@tonic-gatemsgstr "XXX"
228*7c478bd9Sstevel@tonic-gatemsgid "$code.action"
229*7c478bd9Sstevel@tonic-gatemsgstr "XXX"
230*7c478bd9Sstevel@tonic-gateEOF
231*7c478bd9Sstevel@tonic-gate		}
232*7c478bd9Sstevel@tonic-gate	}
233*7c478bd9Sstevel@tonic-gate
234*7c478bd9Sstevel@tonic-gate	print "computed maxkey: $maxkey\n" if $opt_v;
235*7c478bd9Sstevel@tonic-gate
236*7c478bd9Sstevel@tonic-gate	# check maxkey
237*7c478bd9Sstevel@tonic-gate	die "$name: maxkey too low, should be $maxkey\n"
238*7c478bd9Sstevel@tonic-gate	    if $props{'maxkey'} < $maxkey;
239*7c478bd9Sstevel@tonic-gate
240*7c478bd9Sstevel@tonic-gate	close(F);
241*7c478bd9Sstevel@tonic-gate}
242*7c478bd9Sstevel@tonic-gate
243*7c478bd9Sstevel@tonic-gate#
244*7c478bd9Sstevel@tonic-gate# dobs -- handle backslashed sequences
245*7c478bd9Sstevel@tonic-gate#
246*7c478bd9Sstevel@tonic-gatesub dobs {
247*7c478bd9Sstevel@tonic-gate	my $s = shift;
248*7c478bd9Sstevel@tonic-gate
249*7c478bd9Sstevel@tonic-gate	return "\n" if $s eq 'n';
250*7c478bd9Sstevel@tonic-gate	return "\r" if $s eq 'r';
251*7c478bd9Sstevel@tonic-gate	return "\t" if $s eq 't';
252*7c478bd9Sstevel@tonic-gate	return $s;
253*7c478bd9Sstevel@tonic-gate}
254*7c478bd9Sstevel@tonic-gate
255*7c478bd9Sstevel@tonic-gate#
256*7c478bd9Sstevel@tonic-gate# dopo -- sanity check a po file
257*7c478bd9Sstevel@tonic-gate#
258*7c478bd9Sstevel@tonic-gatesub dopo {
259*7c478bd9Sstevel@tonic-gate	my $name = shift;
260*7c478bd9Sstevel@tonic-gate	my $line = 0;
261*7c478bd9Sstevel@tonic-gate	my $id;
262*7c478bd9Sstevel@tonic-gate	my $code;
263*7c478bd9Sstevel@tonic-gate	my $suffix;
264*7c478bd9Sstevel@tonic-gate	my %ids;
265*7c478bd9Sstevel@tonic-gate
266*7c478bd9Sstevel@tonic-gate	open(F, $name) or die "$name: $!\n";
267*7c478bd9Sstevel@tonic-gate	print "parsing \"$name\"\n" if $opt_v;
268*7c478bd9Sstevel@tonic-gate	while (<F>) {
269*7c478bd9Sstevel@tonic-gate		$line++;
270*7c478bd9Sstevel@tonic-gate		next if /^\s*#/;
271*7c478bd9Sstevel@tonic-gate		chomp;
272*7c478bd9Sstevel@tonic-gate		next if /^\s*$/;
273*7c478bd9Sstevel@tonic-gate		next unless /^msgid\s*"([^"]+)"$/;
274*7c478bd9Sstevel@tonic-gate		$id = $1;
275*7c478bd9Sstevel@tonic-gate		next unless $id =~
276*7c478bd9Sstevel@tonic-gate		   /^(.*)\.(type|severity|description|response|impact|action)$/;
277*7c478bd9Sstevel@tonic-gate		$code = $1;
278*7c478bd9Sstevel@tonic-gate		$suffix = $2;
279*7c478bd9Sstevel@tonic-gate		die "$name:$line: no dict entry for code \"$code\"\n"
280*7c478bd9Sstevel@tonic-gate		   unless defined($code2val{$code});
281*7c478bd9Sstevel@tonic-gate		$ids{$id} = $line;
282*7c478bd9Sstevel@tonic-gate	}
283*7c478bd9Sstevel@tonic-gate	close(F);
284*7c478bd9Sstevel@tonic-gate
285*7c478bd9Sstevel@tonic-gate	# above checks while reading in file ensured that node code was
286*7c478bd9Sstevel@tonic-gate	# mentioned in .po file that didn't exist in .dict file.  now
287*7c478bd9Sstevel@tonic-gate	# check the other direction: make sure the full set of entries
288*7c478bd9Sstevel@tonic-gate	# exist for each code in the .dict file
289*7c478bd9Sstevel@tonic-gate	foreach $code (sort keys %code2val) {
290*7c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.type\"\n"
291*7c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.type"});
292*7c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.severity\"\n"
293*7c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.severity"});
294*7c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.description\"\n"
295*7c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.description"});
296*7c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.response\"\n"
297*7c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.response"});
298*7c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.impact\"\n"
299*7c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.impact"});
300*7c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.action\"\n"
301*7c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.action"});
302*7c478bd9Sstevel@tonic-gate	}
303*7c478bd9Sstevel@tonic-gate}
304