xref: /titanic_50/usr/src/cmd/fm/scripts/dictck.pl (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
17c478bd9Sstevel@tonic-gate#!/usr/bin/perl -w
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6627351e3Scy152378# Common Development and Distribution License (the "License").
7627351e3Scy152378# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
22*f6e214c7SGavin Maltby# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate#
247c478bd9Sstevel@tonic-gate#
257c478bd9Sstevel@tonic-gate# dictck -- Sanity check a .dict file and optionally the corresponding .po file
267c478bd9Sstevel@tonic-gate#
277c478bd9Sstevel@tonic-gate# example: dickck FMD.dict FMD.po
287c478bd9Sstevel@tonic-gate#
297c478bd9Sstevel@tonic-gate# usage: dickck [-vp] [ -b buildcode ] dictfile [ pofile ]
307c478bd9Sstevel@tonic-gate#
317c478bd9Sstevel@tonic-gate#	-b	specify location of "buildcode" command
327c478bd9Sstevel@tonic-gate#
337c478bd9Sstevel@tonic-gate#	-p	print a .po file template to stdout, based on dictfile given
347c478bd9Sstevel@tonic-gate#
357c478bd9Sstevel@tonic-gate#	-v	verbose, show how code is assembled
367c478bd9Sstevel@tonic-gate#
377c478bd9Sstevel@tonic-gate# Note: this program requires the "buildcode" program in your search path.
387c478bd9Sstevel@tonic-gate#
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gateuse strict;
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gateuse Getopt::Std;
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gateuse vars qw($opt_b $opt_p $opt_v);
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gatemy $Myname = $0;	# save our name for error messages
477c478bd9Sstevel@tonic-gate$Myname =~ s,.*/,,;
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate$SIG{HUP} = $SIG{INT} = $SIG{TERM} = $SIG{__DIE__} = sub {
507c478bd9Sstevel@tonic-gate	# although fatal, we prepend "WARNING:" to make sure the
517c478bd9Sstevel@tonic-gate	# commonly-used "nightly" script flags this as lint on the .dict file
527c478bd9Sstevel@tonic-gate	die "$Myname: WARNING: @_";
537c478bd9Sstevel@tonic-gate};
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate#
56*f6e214c7SGavin Maltby# Category 1 event classes
57*f6e214c7SGavin Maltby#
58*f6e214c7SGavin Maltbymy @cat1ev = qw(fault defect upset ereport list ireport);
59*f6e214c7SGavin Maltby
60*f6e214c7SGavin Maltby#
617c478bd9Sstevel@tonic-gate# usage -- print a usage message and exit
627c478bd9Sstevel@tonic-gate#
637c478bd9Sstevel@tonic-gatesub usage {
647c478bd9Sstevel@tonic-gate	my $msg = shift;
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate	warn "$Myname: $msg\n" if defined($msg);
677c478bd9Sstevel@tonic-gate	warn "usage: $Myname [-pv] [ -b buildcode ] dictfile [ pofile ]\n";
687c478bd9Sstevel@tonic-gate	exit 1;
697c478bd9Sstevel@tonic-gate}
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gatemy %keys2val;
727c478bd9Sstevel@tonic-gatemy %val2keys;
737c478bd9Sstevel@tonic-gatemy %code2val;
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gatemy $buildcode = 'buildcode';
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate#
787c478bd9Sstevel@tonic-gate# the "main" for this script...
797c478bd9Sstevel@tonic-gate#
807c478bd9Sstevel@tonic-gategetopts('b:pv') or usage;
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gatemy $dictfile = shift;
837c478bd9Sstevel@tonic-gatemy $pofile = shift;
847c478bd9Sstevel@tonic-gateusage unless defined($dictfile);
857c478bd9Sstevel@tonic-gateusage if @ARGV;
867c478bd9Sstevel@tonic-gate$buildcode = $opt_b if defined($opt_b);
877c478bd9Sstevel@tonic-gatedodict($dictfile);
887c478bd9Sstevel@tonic-gatedopo($pofile) if defined($pofile);
897c478bd9Sstevel@tonic-gateexit 0;
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate#
927c478bd9Sstevel@tonic-gate# dodict -- load up a .dict file, sanity checking it as we go
937c478bd9Sstevel@tonic-gate#
947c478bd9Sstevel@tonic-gatesub dodict {
957c478bd9Sstevel@tonic-gate	my $name = shift;
967c478bd9Sstevel@tonic-gate	my $dname;
977c478bd9Sstevel@tonic-gate	my $line = 0;
987c478bd9Sstevel@tonic-gate	my $lhs;
997c478bd9Sstevel@tonic-gate	my $rhs;
1007c478bd9Sstevel@tonic-gate	my %props;
1017c478bd9Sstevel@tonic-gate	my $maxkey = 1;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate	if ($name =~ m,([^/]+)\.dict$,) {
1047c478bd9Sstevel@tonic-gate		$dname = $1;
1057c478bd9Sstevel@tonic-gate	} else {
1067c478bd9Sstevel@tonic-gate		die "dictname \"$name\" not something.dict as expected\n";
1077c478bd9Sstevel@tonic-gate	}
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate	open(F, $name) or die "$name: $!\n";
1107c478bd9Sstevel@tonic-gate	print "parsing \"$name\"\n" if $opt_v;
1117c478bd9Sstevel@tonic-gate	while (<F>) {
1127c478bd9Sstevel@tonic-gate		$line++;
1137c478bd9Sstevel@tonic-gate		next if /^\s*#/;
1147c478bd9Sstevel@tonic-gate		chomp;
1157c478bd9Sstevel@tonic-gate		next if /^\s*$/;
1167c478bd9Sstevel@tonic-gate		die "$name:$line: first non-comment line must be FMDICT line\n"
1177c478bd9Sstevel@tonic-gate		    unless /^FMDICT:/;
1187c478bd9Sstevel@tonic-gate		print "FMDICT keyword found on line $line\n" if $opt_v;
1197c478bd9Sstevel@tonic-gate		s/FMDICT:\s*//;
1207c478bd9Sstevel@tonic-gate		my $s = $_;
1217c478bd9Sstevel@tonic-gate		while ($s =~ /^\s*([^=\s]+)(.*)$/) {
1227c478bd9Sstevel@tonic-gate			$lhs = $1;
1237c478bd9Sstevel@tonic-gate			$rhs = "";
1247c478bd9Sstevel@tonic-gate			$s = $+;
1257c478bd9Sstevel@tonic-gate			if ($s =~ /^\s*=\s*(.*)$/) {
1267c478bd9Sstevel@tonic-gate				$s = $+;
1277c478bd9Sstevel@tonic-gate				die "$name:$line: property \"$lhs\" incomplete\n"
1287c478bd9Sstevel@tonic-gate				    unless $s ne "";
1297c478bd9Sstevel@tonic-gate			}
1307c478bd9Sstevel@tonic-gate			if ($s =~ /^"((?:[^"]|\\")*)"(.*)$/) {
1317c478bd9Sstevel@tonic-gate				$s = $+;
1327c478bd9Sstevel@tonic-gate				$rhs = $1;
1337c478bd9Sstevel@tonic-gate			} else {
1347c478bd9Sstevel@tonic-gate				$s =~ /^([^\s]*)(.*)$/;
1357c478bd9Sstevel@tonic-gate				$s = $+;
1367c478bd9Sstevel@tonic-gate				$rhs = $1;
1377c478bd9Sstevel@tonic-gate			}
1387c478bd9Sstevel@tonic-gate			$rhs =~ s/\\(.)/dobs($1)/ge;
1397c478bd9Sstevel@tonic-gate			$props{$lhs} = $rhs;
1407c478bd9Sstevel@tonic-gate			print "property \"$lhs\" value \"$rhs\"\n" if $opt_v;
1417c478bd9Sstevel@tonic-gate		}
1427c478bd9Sstevel@tonic-gate		last;
1437c478bd9Sstevel@tonic-gate	}
1447c478bd9Sstevel@tonic-gate	# check for required headers
1457c478bd9Sstevel@tonic-gate	die "$name: no version property in header\n"
1467c478bd9Sstevel@tonic-gate	    unless defined($props{'version'});
1477c478bd9Sstevel@tonic-gate	die "$name: no name property in header\n"
1487c478bd9Sstevel@tonic-gate	    unless defined($props{'name'});
1497c478bd9Sstevel@tonic-gate	die "$name: no maxkey property in header\n"
1507c478bd9Sstevel@tonic-gate	    unless defined($props{'maxkey'});
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate	# check version
1537c478bd9Sstevel@tonic-gate	die "$name:$line: unexpected version: \"$props{'version'}\"\n"
1547c478bd9Sstevel@tonic-gate	    unless $props{'version'} eq "1";
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate	# check name
1577c478bd9Sstevel@tonic-gate	die "$name:$line: name \"$props{'name'}\" doesn't match \"$dname\" from filename\n"
1587c478bd9Sstevel@tonic-gate	    unless $props{'name'} eq $dname;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate	# check format of maxkey (value checked later)
1617c478bd9Sstevel@tonic-gate	die "$name:$line: maxkey property must be a number\n"
1627c478bd9Sstevel@tonic-gate	    unless $props{'maxkey'} =~ /^\d+$/;
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate	# check for old bits property
1657c478bd9Sstevel@tonic-gate	die "$name: obsolete \"bits\" property found in header\n"
1667c478bd9Sstevel@tonic-gate	    if defined($props{'bits'});
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate	# parse entries
1697c478bd9Sstevel@tonic-gate	while (<F>) {
1707c478bd9Sstevel@tonic-gate		$line++;
1717c478bd9Sstevel@tonic-gate		chomp;
1727c478bd9Sstevel@tonic-gate		s/#.*//;
1737c478bd9Sstevel@tonic-gate		next if /^\s*$/;
1747c478bd9Sstevel@tonic-gate		die "$name:$line: malformed entry\n"
1757c478bd9Sstevel@tonic-gate		    unless /^([^=]+)=(\d+)$/;
1767c478bd9Sstevel@tonic-gate		$lhs = $1;
1777c478bd9Sstevel@tonic-gate		$rhs = $2;
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate		# make sure keys are sorted
1807c478bd9Sstevel@tonic-gate		my $elhs = join(' ', sort split(/\s/, $lhs));
1817c478bd9Sstevel@tonic-gate		die "$name:$line: keys not in expected format of:\n" .
1827c478bd9Sstevel@tonic-gate		    "    \"$elhs\"\n"
1837c478bd9Sstevel@tonic-gate		    unless $elhs eq $lhs;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate		# check for duplicate or unexpected keys
1867c478bd9Sstevel@tonic-gate		my %keys;
187*f6e214c7SGavin Maltby		my $cat1pat = join('|', @cat1ev);
1887c478bd9Sstevel@tonic-gate		foreach my $e (split(/\s/, $lhs)) {
1897c478bd9Sstevel@tonic-gate			die "$name:$line: unknown event type \"$e\"\n"
1907c478bd9Sstevel@tonic-gate			    unless $e =~
191*f6e214c7SGavin Maltby			    /^($cat1pat)\..*[^.]$/;
1927c478bd9Sstevel@tonic-gate			die "$name:$line: key repeated: \"$e\"\n"
1937c478bd9Sstevel@tonic-gate			    if defined($keys{$e});
1947c478bd9Sstevel@tonic-gate			$keys{$e} = 1;
1957c478bd9Sstevel@tonic-gate		}
1967c478bd9Sstevel@tonic-gate		$maxkey = keys(%keys) if $maxkey < keys(%keys);
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate		die "$name:$line: duplicate entry for keys\n"
1997c478bd9Sstevel@tonic-gate		    if defined($keys2val{$lhs});
2007c478bd9Sstevel@tonic-gate		die "$name:$line: duplicate entry for value $rhs\n"
2017c478bd9Sstevel@tonic-gate		    if defined($val2keys{$rhs});
2027c478bd9Sstevel@tonic-gate		$keys2val{$lhs} = $rhs;
2037c478bd9Sstevel@tonic-gate		$val2keys{$rhs} = $lhs;
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate		open(B, "$buildcode $dname $rhs|") or
2067c478bd9Sstevel@tonic-gate		    die "can't run buildcode: $!\n";
2077c478bd9Sstevel@tonic-gate		my $code = <B>;
2087c478bd9Sstevel@tonic-gate		chomp $code;
2097c478bd9Sstevel@tonic-gate		close(B);
2107c478bd9Sstevel@tonic-gate		print "code: $code keys: $lhs\n" if $opt_v;
2117c478bd9Sstevel@tonic-gate		$code2val{$code} = $rhs;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate		if ($opt_p) {
2147c478bd9Sstevel@tonic-gate			print <<EOF;
2157c478bd9Sstevel@tonic-gate#
2167c478bd9Sstevel@tonic-gate# code: $code
2177c478bd9Sstevel@tonic-gate# keys: $lhs
2187c478bd9Sstevel@tonic-gate#
2197c478bd9Sstevel@tonic-gatemsgid "$code.type"
2207c478bd9Sstevel@tonic-gatemsgstr "XXX"
2217c478bd9Sstevel@tonic-gatemsgid "$code.severity"
2227c478bd9Sstevel@tonic-gatemsgstr "XXX"
2237c478bd9Sstevel@tonic-gatemsgid "$code.description"
2247c478bd9Sstevel@tonic-gatemsgstr "XXX"
2257c478bd9Sstevel@tonic-gatemsgid "$code.response"
2267c478bd9Sstevel@tonic-gatemsgstr "XXX"
2277c478bd9Sstevel@tonic-gatemsgid "$code.impact"
2287c478bd9Sstevel@tonic-gatemsgstr "XXX"
2297c478bd9Sstevel@tonic-gatemsgid "$code.action"
2307c478bd9Sstevel@tonic-gatemsgstr "XXX"
2317c478bd9Sstevel@tonic-gateEOF
2327c478bd9Sstevel@tonic-gate		}
2337c478bd9Sstevel@tonic-gate	}
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate	print "computed maxkey: $maxkey\n" if $opt_v;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate	# check maxkey
2387c478bd9Sstevel@tonic-gate	die "$name: maxkey too low, should be $maxkey\n"
2397c478bd9Sstevel@tonic-gate	    if $props{'maxkey'} < $maxkey;
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate	close(F);
2427c478bd9Sstevel@tonic-gate}
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate#
2457c478bd9Sstevel@tonic-gate# dobs -- handle backslashed sequences
2467c478bd9Sstevel@tonic-gate#
2477c478bd9Sstevel@tonic-gatesub dobs {
2487c478bd9Sstevel@tonic-gate	my $s = shift;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate	return "\n" if $s eq 'n';
2517c478bd9Sstevel@tonic-gate	return "\r" if $s eq 'r';
2527c478bd9Sstevel@tonic-gate	return "\t" if $s eq 't';
2537c478bd9Sstevel@tonic-gate	return $s;
2547c478bd9Sstevel@tonic-gate}
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate#
2577c478bd9Sstevel@tonic-gate# dopo -- sanity check a po file
2587c478bd9Sstevel@tonic-gate#
2597c478bd9Sstevel@tonic-gatesub dopo {
2607c478bd9Sstevel@tonic-gate	my $name = shift;
2617c478bd9Sstevel@tonic-gate	my $line = 0;
2627c478bd9Sstevel@tonic-gate	my $id;
2637c478bd9Sstevel@tonic-gate	my $code;
2647c478bd9Sstevel@tonic-gate	my $suffix;
2657c478bd9Sstevel@tonic-gate	my %ids;
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate	open(F, $name) or die "$name: $!\n";
2687c478bd9Sstevel@tonic-gate	print "parsing \"$name\"\n" if $opt_v;
2697c478bd9Sstevel@tonic-gate	while (<F>) {
2707c478bd9Sstevel@tonic-gate		$line++;
2717c478bd9Sstevel@tonic-gate		next if /^\s*#/;
2727c478bd9Sstevel@tonic-gate		chomp;
2737c478bd9Sstevel@tonic-gate		next if /^\s*$/;
2747c478bd9Sstevel@tonic-gate		next unless /^msgid\s*"([^"]+)"$/;
2757c478bd9Sstevel@tonic-gate		$id = $1;
2767c478bd9Sstevel@tonic-gate		next unless $id =~
2777c478bd9Sstevel@tonic-gate		   /^(.*)\.(type|severity|description|response|impact|action)$/;
2787c478bd9Sstevel@tonic-gate		$code = $1;
2797c478bd9Sstevel@tonic-gate		$suffix = $2;
2807c478bd9Sstevel@tonic-gate		die "$name:$line: no dict entry for code \"$code\"\n"
2817c478bd9Sstevel@tonic-gate		   unless defined($code2val{$code});
2827c478bd9Sstevel@tonic-gate		$ids{$id} = $line;
2837c478bd9Sstevel@tonic-gate	}
2847c478bd9Sstevel@tonic-gate	close(F);
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate	# above checks while reading in file ensured that node code was
2877c478bd9Sstevel@tonic-gate	# mentioned in .po file that didn't exist in .dict file.  now
2887c478bd9Sstevel@tonic-gate	# check the other direction: make sure the full set of entries
2897c478bd9Sstevel@tonic-gate	# exist for each code in the .dict file
2907c478bd9Sstevel@tonic-gate	foreach $code (sort keys %code2val) {
2917c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.type\"\n"
2927c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.type"});
2937c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.severity\"\n"
2947c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.severity"});
2957c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.description\"\n"
2967c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.description"});
2977c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.response\"\n"
2987c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.response"});
2997c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.impact\"\n"
3007c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.impact"});
3017c478bd9Sstevel@tonic-gate		die "$name: missing entry for \"$code.action\"\n"
3027c478bd9Sstevel@tonic-gate		    unless defined($ids{"$code.action"});
3037c478bd9Sstevel@tonic-gate	}
3047c478bd9Sstevel@tonic-gate}
305