xref: /onnv-gate/usr/src/tools/scripts/validate_paths.pl (revision 11838:32bb5d254240)
10Sstevel@tonic-gate#!/usr/bin/perl
20Sstevel@tonic-gate#
30Sstevel@tonic-gate# CDDL HEADER START
40Sstevel@tonic-gate#
50Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6*11838SLiane.Praza@Sun.COM# Common Development and Distribution License (the "License").
7*11838SLiane.Praza@Sun.COM# You may not use this file except in compliance with the License.
80Sstevel@tonic-gate#
90Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate# See the License for the specific language governing permissions
120Sstevel@tonic-gate# and limitations under the License.
130Sstevel@tonic-gate#
140Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate#
200Sstevel@tonic-gate# CDDL HEADER END
210Sstevel@tonic-gate#
220Sstevel@tonic-gate
23*11838SLiane.Praza@Sun.COM#
24*11838SLiane.Praza@Sun.COM# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
250Sstevel@tonic-gate# Use is subject to license terms.
260Sstevel@tonic-gate#
270Sstevel@tonic-gate
28*11838SLiane.Praza@Sun.COM#
290Sstevel@tonic-gate# Given either a list of files containing paths on the command line or
300Sstevel@tonic-gate# a set of paths on standard input, validate that the paths actually
310Sstevel@tonic-gate# exist, and complain if they do not.  This is invoked by nightly to
320Sstevel@tonic-gate# verify the contents of various control files used by the ON build
330Sstevel@tonic-gate# process.
340Sstevel@tonic-gate#
350Sstevel@tonic-gate# Command line options:
360Sstevel@tonic-gate#
370Sstevel@tonic-gate#	-m	Show the matches (for debug).
380Sstevel@tonic-gate#
390Sstevel@tonic-gate#	-r	Allow shell globs in the paths.  Unless otherwise
400Sstevel@tonic-gate#		flagged by a keyword (see -k) or exclusion (see -e),
410Sstevel@tonic-gate#		it is an error if no files match the expression at
420Sstevel@tonic-gate#		all.
430Sstevel@tonic-gate#
440Sstevel@tonic-gate#	-s/from/to/
450Sstevel@tonic-gate#		Perform a substitution on all of the paths in the
460Sstevel@tonic-gate#		file.  This substitution is performed after stripping
470Sstevel@tonic-gate#		any in-line comments but before any exclusion matching
480Sstevel@tonic-gate#		is done.  The option may include any legal Perl
490Sstevel@tonic-gate#		substitution expression and may be repeated to give
500Sstevel@tonic-gate#		multiple expressions.
510Sstevel@tonic-gate#
520Sstevel@tonic-gate#	-e <pattern>
530Sstevel@tonic-gate#		Exclude paths matching the given pattern from the
540Sstevel@tonic-gate#		"must exist" rule.  These paths will not be checked.
550Sstevel@tonic-gate#		Option may include any legal Perl regular expression,
560Sstevel@tonic-gate#		and may be repeated to give multiple patterns.
570Sstevel@tonic-gate#
580Sstevel@tonic-gate#	-k <keyword>
590Sstevel@tonic-gate#		Exclude paths if there is either an in-line comment
600Sstevel@tonic-gate#		containing the given keyword, or the preceding line
610Sstevel@tonic-gate#		consists of only a comment containing that keyword.
620Sstevel@tonic-gate#		Option may be repeated to provide multiple keywords.
630Sstevel@tonic-gate#
640Sstevel@tonic-gate#	-b <base>
650Sstevel@tonic-gate#		Base directory for relative paths tested.
66*11838SLiane.Praza@Sun.COM#
67*11838SLiane.Praza@Sun.COM#	-n <name>
68*11838SLiane.Praza@Sun.COM#		String to use in place of file name when using stdin
690Sstevel@tonic-gate
700Sstevel@tonic-gateuse strict;
710Sstevel@tonic-gate
72*11838SLiane.Praza@Sun.COMmy ($opt_r, $opt_m, @opt_s, @opt_e, @opt_k, $opt_b, $opt_n);
730Sstevel@tonic-gatemy ($keywords, @exclude);
740Sstevel@tonic-gate
750Sstevel@tonic-gatesub usage {
760Sstevel@tonic-gate    die "usage: $0 [-r] [-m]\n",
770Sstevel@tonic-gate    "\t[-s/from/to/] [-e <pattern>] [-k <keyword>] [-b <base>]\n",
78*11838SLiane.Praza@Sun.COM    "\t[-n <name> ] [files...]\n";
790Sstevel@tonic-gate}
800Sstevel@tonic-gate
810Sstevel@tonic-gate# process the path list in a given file
820Sstevel@tonic-gatesub process_paths {
830Sstevel@tonic-gate    my ($FILE, $name) = @_;
840Sstevel@tonic-gate    my ($ignore, $file, $line);
850Sstevel@tonic-gate    $ignore = 0;
860Sstevel@tonic-gate    $line = 0;
870Sstevel@tonic-gate    while (<$FILE>) {
880Sstevel@tonic-gate	chomp;
890Sstevel@tonic-gate	$line++;
900Sstevel@tonic-gate	# Ignore comment lines
910Sstevel@tonic-gate	if (/^\s*#(.*)$/) {
920Sstevel@tonic-gate	    $ignore = ($1 =~ /$keywords/) if defined $keywords;
930Sstevel@tonic-gate	    next;
940Sstevel@tonic-gate	}
950Sstevel@tonic-gate	# Extract path as $1 from line
960Sstevel@tonic-gate	if (/^\s*([^#]+)#(.*)$/) {
970Sstevel@tonic-gate	    ($ignore = 0, next) if $ignore;
980Sstevel@tonic-gate	    $ignore = ($2 =~ /$keywords/) if defined $keywords;
990Sstevel@tonic-gate	    ($ignore = 0, next) if $ignore;
1000Sstevel@tonic-gate	} elsif (/^\s*([^#]+)$/) {
1010Sstevel@tonic-gate	    ($ignore = 0, next) if $ignore;
1020Sstevel@tonic-gate	} else {
1030Sstevel@tonic-gate	    # Ignore blank lines
1040Sstevel@tonic-gate	    $ignore = 0;
1050Sstevel@tonic-gate	    next;
1060Sstevel@tonic-gate	}
1070Sstevel@tonic-gate	# remove any trailing spaces from path
1080Sstevel@tonic-gate	($file = $1) =~ s/[	 ]*$//;
1090Sstevel@tonic-gate	# perform user-supplied substitutions
1100Sstevel@tonic-gate	foreach my $pat (@opt_s) {
1110Sstevel@tonic-gate	    eval '$file =~ s' . $pat;
1120Sstevel@tonic-gate	}
1130Sstevel@tonic-gate	# check if the given path is on the 'exclude' list
1140Sstevel@tonic-gate	$ignore = 0;
1150Sstevel@tonic-gate	foreach my $pat (@exclude) {
1160Sstevel@tonic-gate	    ($ignore = 1, last) if $file =~ /$pat/;
1170Sstevel@tonic-gate	}
1180Sstevel@tonic-gate	if ($ignore == 0) {
1190Sstevel@tonic-gate	    # construct the actual path to the file
1200Sstevel@tonic-gate	    my $path = $opt_b . $file;
1210Sstevel@tonic-gate	    # Expand any shell globs, if that feature is on.  Since
1220Sstevel@tonic-gate	    # Perl's glob() is stateful, we use an array assignment
1230Sstevel@tonic-gate	    # to get the first match and discard the others.
1240Sstevel@tonic-gate	    ($path) = glob($path) if $opt_r;
1250Sstevel@tonic-gate	    print "$name:$line: $file\n" unless !$opt_m && -e $path;
1260Sstevel@tonic-gate	    print "  $path\n" if $opt_m;
1270Sstevel@tonic-gate	}
1280Sstevel@tonic-gate	$ignore = 0;
1290Sstevel@tonic-gate    }
1300Sstevel@tonic-gate}
1310Sstevel@tonic-gate
1320Sstevel@tonic-gatesub next_arg {
1330Sstevel@tonic-gate    my ($arg) = @_;
1340Sstevel@tonic-gate    if ($arg eq "") {
1350Sstevel@tonic-gate	die "$0: missing argument for $_\n" if $#ARGV == -1;
1360Sstevel@tonic-gate	$arg = shift @ARGV;
1370Sstevel@tonic-gate    }
1380Sstevel@tonic-gate    $arg;
1390Sstevel@tonic-gate}
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate# I'd like to use Perl's getopts here, but it doesn't handle repeated
1420Sstevel@tonic-gate# options, and using comma separators is just too ugly.
1430Sstevel@tonic-gate# This doesn't handle combined options (as in '-rm'), but I don't care.
144*11838SLiane.Praza@Sun.COMmy $arg, $opt_r, $opt_m, @opt_s, @opt_e, @opt_k, $opt_b, $opt_n;
1450Sstevel@tonic-gatewhile ($#ARGV >= 0) {
1460Sstevel@tonic-gate    $_ = $ARGV[0];
1470Sstevel@tonic-gate    last if /^[^-]/;
1480Sstevel@tonic-gate    shift @ARGV;
149*11838SLiane.Praza@Sun.COM    $opt_n = "standard input";
1500Sstevel@tonic-gate    last if /^--$/;
1510Sstevel@tonic-gate    SWITCH: {
1520Sstevel@tonic-gate	  /^-r/ && do { $opt_r = 1; last SWITCH; };
1530Sstevel@tonic-gate	  /^-m/ && do { $opt_m = 1; last SWITCH; };
1540Sstevel@tonic-gate	  if (/^-s(.*)$/) {
1550Sstevel@tonic-gate	      $arg = next_arg($1);
1560Sstevel@tonic-gate	      push @opt_s, $arg;
1570Sstevel@tonic-gate	      last SWITCH;
1580Sstevel@tonic-gate	  }
1590Sstevel@tonic-gate	  if (/^-e(.*)$/) {
1600Sstevel@tonic-gate	      $arg = next_arg($1);
1610Sstevel@tonic-gate	      push @opt_e, $arg;
1620Sstevel@tonic-gate	      last SWITCH;
1630Sstevel@tonic-gate	  }
1640Sstevel@tonic-gate	  if (/^-k(.*)$/) {
1650Sstevel@tonic-gate	      $arg = next_arg($1);
1660Sstevel@tonic-gate	      push @opt_k, $arg;
1670Sstevel@tonic-gate	      last SWITCH;
1680Sstevel@tonic-gate	  }
1690Sstevel@tonic-gate	  if (/^-b(.*)$/) {
1700Sstevel@tonic-gate	      $opt_b = next_arg($1);
1710Sstevel@tonic-gate	      last SWITCH;
1720Sstevel@tonic-gate	  }
173*11838SLiane.Praza@Sun.COM	  if (/^-n(.*)$/) {
174*11838SLiane.Praza@Sun.COM	      $opt_n = next_arg($1);
175*11838SLiane.Praza@Sun.COM	      last SWITCH;
176*11838SLiane.Praza@Sun.COM	  }
1770Sstevel@tonic-gate	  print "$0: unknown option $_\n";
1780Sstevel@tonic-gate	  usage();
1790Sstevel@tonic-gate    }
1800Sstevel@tonic-gate}
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate# compile the 'exclude' regexps
1830Sstevel@tonic-gate@exclude = map qr/$_/x, @opt_e;
1840Sstevel@tonic-gate# if no keywords are given, then leave $keywords undefined
1850Sstevel@tonic-gateif (@opt_k) {
1860Sstevel@tonic-gate    # construct a regexp that matches the keywords specified
1870Sstevel@tonic-gate    my $opt_k = join("|", @opt_k);
1880Sstevel@tonic-gate    $keywords = qr/($opt_k)/xo;
1890Sstevel@tonic-gate}
1900Sstevel@tonic-gate$opt_b .= "/" if $opt_b =~ /[^\/]$/;
1910Sstevel@tonic-gate
1920Sstevel@tonic-gatemy $file;
1930Sstevel@tonic-gate
1940Sstevel@tonic-gateif ($#ARGV < 0) {
195*11838SLiane.Praza@Sun.COM    process_paths(\*STDIN, $opt_n);
1960Sstevel@tonic-gate} else {
1970Sstevel@tonic-gate    foreach $file (@ARGV) {
1980Sstevel@tonic-gate	if (! -e $file) {
1990Sstevel@tonic-gate	    warn "$0: $file doesn't exist\n";
2000Sstevel@tonic-gate	} elsif (! -f $file) {
2010Sstevel@tonic-gate	    warn "$0: $file isn't a regular file\n";
2020Sstevel@tonic-gate	} elsif (! -T $file) {
2030Sstevel@tonic-gate	    warn "$0: $file isn't a text file\n";
2040Sstevel@tonic-gate	} elsif (open FILE, "<$file") {
2050Sstevel@tonic-gate	    process_paths(\*FILE, $file);
2060Sstevel@tonic-gate	} else {
2070Sstevel@tonic-gate	    warn "$0: $file: $!\n";
2080Sstevel@tonic-gate	}
2090Sstevel@tonic-gate    }
2100Sstevel@tonic-gate}
2110Sstevel@tonic-gate
2120Sstevel@tonic-gateexit 0
213