xref: /titanic_53/usr/src/tools/scripts/validate_paths.pl (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate#!/usr/bin/perl
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# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
25*7c478bd9Sstevel@tonic-gate# Use is subject to license terms.
26*7c478bd9Sstevel@tonic-gate#
27*7c478bd9Sstevel@tonic-gate#ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate# Given either a list of files containing paths on the command line or
30*7c478bd9Sstevel@tonic-gate# a set of paths on standard input, validate that the paths actually
31*7c478bd9Sstevel@tonic-gate# exist, and complain if they do not.  This is invoked by nightly to
32*7c478bd9Sstevel@tonic-gate# verify the contents of various control files used by the ON build
33*7c478bd9Sstevel@tonic-gate# process.
34*7c478bd9Sstevel@tonic-gate#
35*7c478bd9Sstevel@tonic-gate# Command line options:
36*7c478bd9Sstevel@tonic-gate#
37*7c478bd9Sstevel@tonic-gate#	-m	Show the matches (for debug).
38*7c478bd9Sstevel@tonic-gate#
39*7c478bd9Sstevel@tonic-gate#	-r	Allow shell globs in the paths.  Unless otherwise
40*7c478bd9Sstevel@tonic-gate#		flagged by a keyword (see -k) or exclusion (see -e),
41*7c478bd9Sstevel@tonic-gate#		it is an error if no files match the expression at
42*7c478bd9Sstevel@tonic-gate#		all.
43*7c478bd9Sstevel@tonic-gate#
44*7c478bd9Sstevel@tonic-gate#	-s/from/to/
45*7c478bd9Sstevel@tonic-gate#		Perform a substitution on all of the paths in the
46*7c478bd9Sstevel@tonic-gate#		file.  This substitution is performed after stripping
47*7c478bd9Sstevel@tonic-gate#		any in-line comments but before any exclusion matching
48*7c478bd9Sstevel@tonic-gate#		is done.  The option may include any legal Perl
49*7c478bd9Sstevel@tonic-gate#		substitution expression and may be repeated to give
50*7c478bd9Sstevel@tonic-gate#		multiple expressions.
51*7c478bd9Sstevel@tonic-gate#
52*7c478bd9Sstevel@tonic-gate#	-e <pattern>
53*7c478bd9Sstevel@tonic-gate#		Exclude paths matching the given pattern from the
54*7c478bd9Sstevel@tonic-gate#		"must exist" rule.  These paths will not be checked.
55*7c478bd9Sstevel@tonic-gate#		Option may include any legal Perl regular expression,
56*7c478bd9Sstevel@tonic-gate#		and may be repeated to give multiple patterns.
57*7c478bd9Sstevel@tonic-gate#
58*7c478bd9Sstevel@tonic-gate#	-k <keyword>
59*7c478bd9Sstevel@tonic-gate#		Exclude paths if there is either an in-line comment
60*7c478bd9Sstevel@tonic-gate#		containing the given keyword, or the preceding line
61*7c478bd9Sstevel@tonic-gate#		consists of only a comment containing that keyword.
62*7c478bd9Sstevel@tonic-gate#		Option may be repeated to provide multiple keywords.
63*7c478bd9Sstevel@tonic-gate#
64*7c478bd9Sstevel@tonic-gate#	-b <base>
65*7c478bd9Sstevel@tonic-gate#		Base directory for relative paths tested.
66*7c478bd9Sstevel@tonic-gate
67*7c478bd9Sstevel@tonic-gateuse strict;
68*7c478bd9Sstevel@tonic-gate
69*7c478bd9Sstevel@tonic-gatemy ($opt_r, $opt_m, @opt_s, @opt_e, @opt_k, $opt_b);
70*7c478bd9Sstevel@tonic-gatemy ($keywords, @exclude);
71*7c478bd9Sstevel@tonic-gate
72*7c478bd9Sstevel@tonic-gatesub usage {
73*7c478bd9Sstevel@tonic-gate    die "usage: $0 [-r] [-m]\n",
74*7c478bd9Sstevel@tonic-gate    "\t[-s/from/to/] [-e <pattern>] [-k <keyword>] [-b <base>]\n",
75*7c478bd9Sstevel@tonic-gate    "\t[files...]\n";
76*7c478bd9Sstevel@tonic-gate}
77*7c478bd9Sstevel@tonic-gate
78*7c478bd9Sstevel@tonic-gate# process the path list in a given file
79*7c478bd9Sstevel@tonic-gatesub process_paths {
80*7c478bd9Sstevel@tonic-gate    my ($FILE, $name) = @_;
81*7c478bd9Sstevel@tonic-gate    my ($ignore, $file, $line);
82*7c478bd9Sstevel@tonic-gate    $ignore = 0;
83*7c478bd9Sstevel@tonic-gate    $line = 0;
84*7c478bd9Sstevel@tonic-gate    while (<$FILE>) {
85*7c478bd9Sstevel@tonic-gate	chomp;
86*7c478bd9Sstevel@tonic-gate	$line++;
87*7c478bd9Sstevel@tonic-gate	# Ignore comment lines
88*7c478bd9Sstevel@tonic-gate	if (/^\s*#(.*)$/) {
89*7c478bd9Sstevel@tonic-gate	    $ignore = ($1 =~ /$keywords/) if defined $keywords;
90*7c478bd9Sstevel@tonic-gate	    next;
91*7c478bd9Sstevel@tonic-gate	}
92*7c478bd9Sstevel@tonic-gate	# Extract path as $1 from line
93*7c478bd9Sstevel@tonic-gate	if (/^\s*([^#]+)#(.*)$/) {
94*7c478bd9Sstevel@tonic-gate	    ($ignore = 0, next) if $ignore;
95*7c478bd9Sstevel@tonic-gate	    $ignore = ($2 =~ /$keywords/) if defined $keywords;
96*7c478bd9Sstevel@tonic-gate	    ($ignore = 0, next) if $ignore;
97*7c478bd9Sstevel@tonic-gate	} elsif (/^\s*([^#]+)$/) {
98*7c478bd9Sstevel@tonic-gate	    ($ignore = 0, next) if $ignore;
99*7c478bd9Sstevel@tonic-gate	} else {
100*7c478bd9Sstevel@tonic-gate	    # Ignore blank lines
101*7c478bd9Sstevel@tonic-gate	    $ignore = 0;
102*7c478bd9Sstevel@tonic-gate	    next;
103*7c478bd9Sstevel@tonic-gate	}
104*7c478bd9Sstevel@tonic-gate	# remove any trailing spaces from path
105*7c478bd9Sstevel@tonic-gate	($file = $1) =~ s/[	 ]*$//;
106*7c478bd9Sstevel@tonic-gate	# perform user-supplied substitutions
107*7c478bd9Sstevel@tonic-gate	foreach my $pat (@opt_s) {
108*7c478bd9Sstevel@tonic-gate	    eval '$file =~ s' . $pat;
109*7c478bd9Sstevel@tonic-gate	}
110*7c478bd9Sstevel@tonic-gate	# check if the given path is on the 'exclude' list
111*7c478bd9Sstevel@tonic-gate	$ignore = 0;
112*7c478bd9Sstevel@tonic-gate	foreach my $pat (@exclude) {
113*7c478bd9Sstevel@tonic-gate	    ($ignore = 1, last) if $file =~ /$pat/;
114*7c478bd9Sstevel@tonic-gate	}
115*7c478bd9Sstevel@tonic-gate	if ($ignore == 0) {
116*7c478bd9Sstevel@tonic-gate	    # construct the actual path to the file
117*7c478bd9Sstevel@tonic-gate	    my $path = $opt_b . $file;
118*7c478bd9Sstevel@tonic-gate	    # Expand any shell globs, if that feature is on.  Since
119*7c478bd9Sstevel@tonic-gate	    # Perl's glob() is stateful, we use an array assignment
120*7c478bd9Sstevel@tonic-gate	    # to get the first match and discard the others.
121*7c478bd9Sstevel@tonic-gate	    ($path) = glob($path) if $opt_r;
122*7c478bd9Sstevel@tonic-gate	    print "$name:$line: $file\n" unless !$opt_m && -e $path;
123*7c478bd9Sstevel@tonic-gate	    print "  $path\n" if $opt_m;
124*7c478bd9Sstevel@tonic-gate	}
125*7c478bd9Sstevel@tonic-gate	$ignore = 0;
126*7c478bd9Sstevel@tonic-gate    }
127*7c478bd9Sstevel@tonic-gate}
128*7c478bd9Sstevel@tonic-gate
129*7c478bd9Sstevel@tonic-gatesub next_arg {
130*7c478bd9Sstevel@tonic-gate    my ($arg) = @_;
131*7c478bd9Sstevel@tonic-gate    if ($arg eq "") {
132*7c478bd9Sstevel@tonic-gate	die "$0: missing argument for $_\n" if $#ARGV == -1;
133*7c478bd9Sstevel@tonic-gate	$arg = shift @ARGV;
134*7c478bd9Sstevel@tonic-gate    }
135*7c478bd9Sstevel@tonic-gate    $arg;
136*7c478bd9Sstevel@tonic-gate}
137*7c478bd9Sstevel@tonic-gate
138*7c478bd9Sstevel@tonic-gate# I'd like to use Perl's getopts here, but it doesn't handle repeated
139*7c478bd9Sstevel@tonic-gate# options, and using comma separators is just too ugly.
140*7c478bd9Sstevel@tonic-gate# This doesn't handle combined options (as in '-rm'), but I don't care.
141*7c478bd9Sstevel@tonic-gatemy $arg, $opt_r, $opt_m, @opt_s, @opt_e, @opt_k, $opt_b;
142*7c478bd9Sstevel@tonic-gatewhile ($#ARGV >= 0) {
143*7c478bd9Sstevel@tonic-gate    $_ = $ARGV[0];
144*7c478bd9Sstevel@tonic-gate    last if /^[^-]/;
145*7c478bd9Sstevel@tonic-gate    shift @ARGV;
146*7c478bd9Sstevel@tonic-gate    last if /^--$/;
147*7c478bd9Sstevel@tonic-gate    SWITCH: {
148*7c478bd9Sstevel@tonic-gate	  /^-r/ && do { $opt_r = 1; last SWITCH; };
149*7c478bd9Sstevel@tonic-gate	  /^-m/ && do { $opt_m = 1; last SWITCH; };
150*7c478bd9Sstevel@tonic-gate	  if (/^-s(.*)$/) {
151*7c478bd9Sstevel@tonic-gate	      $arg = next_arg($1);
152*7c478bd9Sstevel@tonic-gate	      push @opt_s, $arg;
153*7c478bd9Sstevel@tonic-gate	      last SWITCH;
154*7c478bd9Sstevel@tonic-gate	  }
155*7c478bd9Sstevel@tonic-gate	  if (/^-e(.*)$/) {
156*7c478bd9Sstevel@tonic-gate	      $arg = next_arg($1);
157*7c478bd9Sstevel@tonic-gate	      push @opt_e, $arg;
158*7c478bd9Sstevel@tonic-gate	      last SWITCH;
159*7c478bd9Sstevel@tonic-gate	  }
160*7c478bd9Sstevel@tonic-gate	  if (/^-k(.*)$/) {
161*7c478bd9Sstevel@tonic-gate	      $arg = next_arg($1);
162*7c478bd9Sstevel@tonic-gate	      push @opt_k, $arg;
163*7c478bd9Sstevel@tonic-gate	      last SWITCH;
164*7c478bd9Sstevel@tonic-gate	  }
165*7c478bd9Sstevel@tonic-gate	  if (/^-b(.*)$/) {
166*7c478bd9Sstevel@tonic-gate	      $opt_b = next_arg($1);
167*7c478bd9Sstevel@tonic-gate	      last SWITCH;
168*7c478bd9Sstevel@tonic-gate	  }
169*7c478bd9Sstevel@tonic-gate	  print "$0: unknown option $_\n";
170*7c478bd9Sstevel@tonic-gate	  usage();
171*7c478bd9Sstevel@tonic-gate    }
172*7c478bd9Sstevel@tonic-gate}
173*7c478bd9Sstevel@tonic-gate
174*7c478bd9Sstevel@tonic-gate# compile the 'exclude' regexps
175*7c478bd9Sstevel@tonic-gate@exclude = map qr/$_/x, @opt_e;
176*7c478bd9Sstevel@tonic-gate# if no keywords are given, then leave $keywords undefined
177*7c478bd9Sstevel@tonic-gateif (@opt_k) {
178*7c478bd9Sstevel@tonic-gate    # construct a regexp that matches the keywords specified
179*7c478bd9Sstevel@tonic-gate    my $opt_k = join("|", @opt_k);
180*7c478bd9Sstevel@tonic-gate    $keywords = qr/($opt_k)/xo;
181*7c478bd9Sstevel@tonic-gate}
182*7c478bd9Sstevel@tonic-gate$opt_b .= "/" if $opt_b =~ /[^\/]$/;
183*7c478bd9Sstevel@tonic-gate
184*7c478bd9Sstevel@tonic-gatemy $file;
185*7c478bd9Sstevel@tonic-gate
186*7c478bd9Sstevel@tonic-gateif ($#ARGV < 0) {
187*7c478bd9Sstevel@tonic-gate    process_paths(\*STDIN, "standard input");
188*7c478bd9Sstevel@tonic-gate} else {
189*7c478bd9Sstevel@tonic-gate    foreach $file (@ARGV) {
190*7c478bd9Sstevel@tonic-gate	if (! -e $file) {
191*7c478bd9Sstevel@tonic-gate	    warn "$0: $file doesn't exist\n";
192*7c478bd9Sstevel@tonic-gate	} elsif (! -f $file) {
193*7c478bd9Sstevel@tonic-gate	    warn "$0: $file isn't a regular file\n";
194*7c478bd9Sstevel@tonic-gate	} elsif (! -T $file) {
195*7c478bd9Sstevel@tonic-gate	    warn "$0: $file isn't a text file\n";
196*7c478bd9Sstevel@tonic-gate	} elsif (open FILE, "<$file") {
197*7c478bd9Sstevel@tonic-gate	    process_paths(\*FILE, $file);
198*7c478bd9Sstevel@tonic-gate	} else {
199*7c478bd9Sstevel@tonic-gate	    warn "$0: $file: $!\n";
200*7c478bd9Sstevel@tonic-gate	}
201*7c478bd9Sstevel@tonic-gate    }
202*7c478bd9Sstevel@tonic-gate}
203*7c478bd9Sstevel@tonic-gate
204*7c478bd9Sstevel@tonic-gateexit 0
205