openpkg/lint-rc.pl

Thu, 04 Oct 2012 20:30:05 +0200

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 04 Oct 2012 20:30:05 +0200
changeset 715
c10fb90893b9
permissions
-rw-r--r--

Correct out of date build configuration, porting to Solaris 11 network
link infrastructure and new libpcap logic. This additionally allows for
device drivers in subdirectories of /dev. Correct packaged nmap
personalities and signatures to work out of the box. Finally, hack
arpd logic to properly close sockets and quit on TERM by repeating
signaling in the run command script. Sadly, all this fails to correct
the run time behaviour of honeyd which fails to bind to the IP layer.

michael@428 1 ##
michael@428 2 ## lint-rc.pl -- OpenPKG rc.* File Checker
michael@428 3 ## Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/>
michael@428 4 ##
michael@428 5 ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
michael@428 6 ## All rights reserved. Licenses which grant limited permission to use,
michael@428 7 ## copy, modify and distribute this software are available from the
michael@428 8 ## OpenPKG GmbH.
michael@428 9 ##
michael@428 10 ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
michael@428 11 ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
michael@428 12 ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
michael@428 13 ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
michael@428 14 ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@428 15 ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@428 16 ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
michael@428 17 ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@428 18 ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@428 19 ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@428 20 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@428 21 ## SUCH DAMAGE.
michael@428 22 ##
michael@428 23
michael@428 24 # Perl run-time requirement
michael@428 25 require 5;
michael@428 26 BEGIN {
michael@428 27 eval "use Getopt::Long; use IO;";
michael@428 28 if ($@) {
michael@428 29 print STDERR
michael@428 30 "lint-rc: ERROR: This command requires a full-size Perl installation!\n" .
michael@428 31 "lint-rc: HINT: Install OpenPKG \"perl\" package to use this command.\n";
michael@428 32 exit(1);
michael@428 33 }
michael@428 34 }
michael@428 35
michael@428 36 # OpenPKG instance prefix
michael@428 37 my $my_prefix = $ENV{'OPENPKG_PREFIX'};
michael@428 38 delete $ENV{'OPENPKG_PREFIX'};
michael@428 39
michael@428 40 # program information
michael@428 41 my $progname = "lint-rc";
michael@428 42 my $progvers = "1.0.0";
michael@428 43
michael@428 44 # parameters (defaults)
michael@428 45 my $version = 0;
michael@428 46 my $verbose = 0;
michael@428 47 my $help = 0;
michael@428 48 my $check = 'all';
michael@428 49 my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname";
michael@428 50 my $rpm = "$my_prefix/bin/openpkg rpm";
michael@428 51
michael@428 52 # exception handling support
michael@428 53 $SIG{__DIE__} = sub {
michael@428 54 my ($err) = @_;
michael@428 55 $err =~ s|\s+at\s+.*||s if (not $verbose);
michael@428 56 print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n";
michael@428 57 exit(1);
michael@428 58 };
michael@428 59
michael@428 60 # command line parsing
michael@428 61 Getopt::Long::Configure("bundling");
michael@428 62 my $result = GetOptions(
michael@428 63 'V|version' => \$version,
michael@428 64 'v|verbose' => \$verbose,
michael@428 65 'h|help' => \$help,
michael@428 66 'c|check=s' => \$check,
michael@428 67 't|tmpdir=s' => \$tmpdir,
michael@428 68 'r|rpm=s' => \$rpm,
michael@428 69 ) || die "option parsing failed";
michael@428 70 if ($help) {
michael@428 71 print "Usage: $progname [options] [RPMFILE ...]\n" .
michael@428 72 "Available options:\n" .
michael@428 73 " -v,--verbose enable verbose run-time mode\n" .
michael@428 74 " -h,--help print out this usage page\n" .
michael@428 75 " -c,--check=CHECKS select checks to perform (default='all')\n" .
michael@428 76 " -r,--rpm=FILE filesystem path to RPM program\n" .
michael@428 77 " -t,--tmpdir=PATH filesystem path to temporary directory\n" .
michael@428 78 " -V,--version print program version\n";
michael@428 79 exit(0);
michael@428 80 }
michael@428 81 if ($version) {
michael@428 82 print "OpenPKG $progname $progvers\n";
michael@428 83 exit(0);
michael@428 84 }
michael@428 85
michael@428 86 # verbose message printing
michael@428 87 sub msg_verbose {
michael@428 88 my ($msg) = @_;
michael@428 89 print STDERR "$msg\n" if ($verbose);
michael@428 90 }
michael@428 91
michael@428 92 # warning message printing
michael@428 93 sub msg_warning {
michael@428 94 my ($msg) = @_;
michael@428 95 print STDERR "$progname:WARNING: $msg\n";
michael@428 96 }
michael@428 97
michael@428 98 # error message printing
michael@428 99 sub msg_error {
michael@428 100 my ($msg) = @_;
michael@428 101 print STDERR "$progname:ERROR: $msg\n";
michael@428 102 }
michael@428 103
michael@428 104 # determine check list
michael@428 105 my @check_list = (qw(
michael@428 106 blank
michael@428 107 comment
michael@428 108 section
michael@428 109 script
michael@428 110 global
michael@428 111 ));
michael@428 112 my @checks = ();
michael@428 113 if ($check eq 'all') {
michael@428 114 @checks = @check_list;
michael@428 115 }
michael@428 116 else {
michael@428 117 foreach my $c (split(/,/, $check)) {
michael@428 118 if (not grep(/^$c$/, @check_list)) {
michael@428 119 die "invalid check \"$c\"";
michael@428 120 }
michael@428 121 push(@checks, $c);
michael@428 122 }
michael@428 123 }
michael@428 124
michael@428 125 # global return code
michael@428 126 $main::GRC = 0;
michael@428 127
michael@428 128 # environment preparation
michael@428 129 system("rm -rf $tmpdir");
michael@428 130 system("mkdir -p $tmpdir");
michael@428 131
michael@428 132 # iterate over all rc. files
michael@428 133 foreach my $filename (@ARGV) {
michael@428 134 my $io = new IO::File "<$filename"
michael@428 135 or die "unable to open file \"$filename\" for reading";
michael@428 136 my $spec; { local $/ = undef; $spec = <$io>; }
michael@428 137 $io->close;
michael@428 138 foreach my $check (@checks) {
michael@428 139 &msg_verbose("$check in $filename");
michael@428 140 eval "\&check_$check(\$filename, \$spec);";
michael@428 141 }
michael@428 142 }
michael@428 143
michael@428 144 # environment cleanup
michael@428 145 system("rm -rf $tmpdir");
michael@428 146
michael@428 147 # die gracefully
michael@428 148 exit($main::GRC);
michael@428 149
michael@428 150 ## _________________________________________________________________
michael@428 151 ##
michael@428 152 ## COMMON SUBROUTINES
michael@428 153 ## _________________________________________________________________
michael@428 154 ##
michael@428 155
michael@428 156 sub lines {
michael@428 157 my ($txt) = @_;
michael@428 158 my $l = 0;
michael@428 159 $txt =~ s|\n|$l++, ''|sge;
michael@428 160 return $l;
michael@428 161 }
michael@428 162
michael@428 163 sub lint_message {
michael@428 164 my ($type, $file, $done, $this, $msg) = @_;
michael@428 165 if (defined($done) and defined($this)) {
michael@428 166 my $start = &lines($done) + 1;
michael@428 167 my $end = $start + &lines($this);
michael@428 168 my $pos = $start;
michael@428 169 $pos .= "-". $end if ($end > $start);
michael@428 170 printf("%s:%s: %s:%s: %s\n", $progname, $type, $file, $pos, $msg);
michael@428 171 }
michael@428 172 else {
michael@428 173 printf("%s:%s: %s: %s\n", $progname, $type, $file, $msg);
michael@428 174 }
michael@428 175 }
michael@428 176
michael@428 177 sub lint_warning {
michael@428 178 my ($file, $done, $this, $msg) = @_;
michael@428 179 &lint_message("WARNING", $file, $done, $this, $msg);
michael@428 180 $main::GRC = 1 if ($main::GRC < 1);
michael@428 181 }
michael@428 182
michael@428 183 sub lint_error {
michael@428 184 my ($file, $done, $this, $msg) = @_;
michael@428 185 &lint_message("ERROR", $file, $done, $this, $msg);
michael@428 186 $main::GRC = 2 if ($main::GRC < 2);
michael@428 187 }
michael@428 188
michael@428 189 ## _________________________________________________________________
michael@428 190 ##
michael@428 191 ## CHECK "blank": whitespace and blank lines
michael@428 192 ## _________________________________________________________________
michael@428 193 ##
michael@428 194
michael@428 195 sub check_blank {
michael@428 196 my ($file, $spec) = @_;
michael@428 197
michael@428 198 # check for CR-LF combination
michael@428 199 my $done = ''; my $this = ''; my $todo = $spec;
michael@428 200 while ($todo =~ m/\r\n/s) {
michael@428 201 $done .= $`; $this = $&; $todo = $';
michael@428 202 &lint_warning($file, $done, $this, "carriage-return (CR, 0x0d) line-feed (NL, 0x0a) combination (expected just line-feed)");
michael@428 203 $done .= $this;
michael@428 204 }
michael@428 205
michael@428 206 # check for multiple blank lines
michael@428 207 $done = ''; $this = ''; $todo = $spec;
michael@428 208 while ($todo =~ m/(\r?\n[ \t]*){3,}/s) {
michael@428 209 $done .= $`; $this = $&; $todo = $';
michael@428 210 &lint_warning($file, $done, $this, "multiple subsequent blank lines (expected single blank line)");
michael@428 211 $done .= $this;
michael@428 212 }
michael@428 213
michael@428 214 # check for trailing whitespaces
michael@428 215 $done = ''; $this = ''; $todo = $spec;
michael@428 216 while ($todo =~ m/[ \t]+\r?\n/s) {
michael@428 217 $done .= $`; $this = $&; $todo = $';
michael@428 218 if ($done eq '' or $done =~ m|\n$|s) {
michael@428 219 &lint_warning($file, $done, $this, "whitespace on empty line (expected none)");
michael@428 220 }
michael@428 221 else {
michael@428 222 &lint_warning($file, $done, $this, "trailing whitespace (expected none)");
michael@428 223 }
michael@428 224 $done .= $this;
michael@428 225 }
michael@428 226
michael@428 227 # check for bogus line continuations
michael@428 228 $done = ''; $this = ''; $todo = $spec;
michael@428 229 while ($todo =~ m/\\[ \t]*\r?\n(?=[ \t]*\r?\n)/s) {
michael@428 230 $done .= $`; $this = $&; $todo = $';
michael@428 231 &lint_warning($file, $done, $this, "bogus line continuation for following empty line (expect no line continuation)");
michael@428 232 $done .= $this;
michael@428 233 }
michael@428 234
michael@428 235 # check for leading whitespaces before line continuations
michael@428 236 $done = ''; $this = ''; $todo = $spec;
michael@428 237 while ($todo =~ m/[ \t]{2,}\\[ \t]*\r?\n/s) {
michael@428 238 $done .= $`; $this = $&; $todo = $';
michael@428 239 &lint_warning($file, $done, $this, "multiple leading whitespace before line continuation (expected just a single space)");
michael@428 240 $done .= $this;
michael@428 241 }
michael@428 242
michael@428 243 # check for leading tabs
michael@428 244 $done = ''; $this = ''; $todo = $spec;
michael@428 245 while ($todo =~ m/^ *\t+ *[^ \t]/m) {
michael@428 246 $done .= $`; $this = $&; $todo = $';
michael@428 247 &lint_warning($file, $done, $this, "leading tabs (expected spaces)");
michael@428 248 $done .= $this;
michael@428 249 }
michael@428 250
michael@428 251 # check for mandatory/wished trailing blank line
michael@428 252 if ($spec !~ m|\n\n$|s) {
michael@428 253 &lint_warning($file, $done, "", "mandatory/wished trailing blank line at end of file missing (expected one)");
michael@428 254 }
michael@428 255 }
michael@428 256
michael@428 257 ## _________________________________________________________________
michael@428 258 ##
michael@428 259 ## CHECK "comment": sharp-comments
michael@428 260 ## _________________________________________________________________
michael@428 261 ##
michael@428 262
michael@428 263 sub check_comment {
michael@428 264 my ($file, $spec) = @_;
michael@428 265 my ($pkg);
michael@428 266
michael@428 267 # determine package name
michael@428 268 $pkg = $file;
michael@428 269 $pkg =~ s|^.+/||;
michael@428 270 $pkg =~ s|^rc\.||;
michael@428 271
michael@428 272 # check "shebang" header
michael@428 273 my $re = "";
michael@428 274 $re .= "#!\@l_prefix\@/bin/openpkg rc\\n";
michael@428 275 if ($spec !~ m|^$re|s) {
michael@428 276 &lint_warning($file, "", "", "invalid shebang header (expected $re)");
michael@428 277 }
michael@428 278
michael@428 279 # check comment header
michael@428 280 my $re = "";
michael@428 281 $re .= ".*?\\n##\\n## rc.$pkg -- Run-Commands\\n##\\n\\n";
michael@428 282 if ($pkg ne "openpkg" and $spec !~ m|^$re|s) {
michael@428 283 &lint_warning($file, "", "", "invalid comment header (expected $re)");
michael@428 284 }
michael@428 285
michael@428 286 # check for comment indentation
michael@428 287 my $done .= $`; my $this = $&; my $todo = $';
michael@428 288 while ($todo =~ m/^([ \t]*)(#+)([ \t]*)(.*?)$/m) {
michael@428 289 $done .= $`; $this = $&; $todo = $';
michael@428 290 my ($lead, $sharp, $pad, $text) = ($1, $2, $3, $4);
michael@428 291 if (length($lead) % 2 != 0) {
michael@428 292 &lint_warning($file, $done, $this, "incorrect comment indentation (expected a multiple of 2 spaces)");
michael@428 293 }
michael@428 294 if (length($lead) > 1 && length($sharp) > 1) {
michael@428 295 &lint_warning($file, $done, $this, "indented comment has introduced with multiple sharps (expected single sharp character)");
michael@428 296 }
michael@428 297 if (length($pad.$text) > 0 && length($sharp.$pad) % 4 != 0) {
michael@428 298 &lint_warning($file, $done, $this, "incorrect comment text padding (expected a multiple of 4 sharps or spaces)");
michael@428 299 }
michael@428 300 if (length($pad) == 0 && length($text) > 0) {
michael@428 301 &lint_warning($file, $done, $this, "missing leading space before comment text (expected padding spaces)");
michael@428 302 }
michael@428 303 if (length($pad) > 0 && length($text) == 0) {
michael@428 304 &lint_warning($file, $done, $this, "empty comment text (expected a reasonable text)");
michael@428 305 }
michael@428 306 $done .= $this;
michael@428 307 }
michael@428 308 }
michael@428 309
michael@428 310 ## _________________________________________________________________
michael@428 311 ##
michael@428 312 ## CHECK "section": run command sections
michael@428 313 ## _________________________________________________________________
michael@428 314 ##
michael@428 315
michael@428 316 sub check_section {
michael@428 317 my ($file, $spec) = @_;
michael@428 318
michael@428 319 my $require = qq{
michael@428 320 (%config,)?
michael@428 321 (%common,)?
michael@428 322 (%status,)?
michael@428 323 (%info,)?
michael@428 324 (%start,)?
michael@428 325 (%stop,)?
michael@428 326 (%restart,)?
michael@428 327 (%reload,)?
michael@428 328 (%quarterly,)?
michael@428 329 (%hourly,)?
michael@428 330 (%daily,)?
michael@428 331 (%weekly,)?
michael@428 332 (%monthly,)?
michael@428 333 (%env,)?
michael@428 334 };
michael@428 335
michael@428 336 # check for order of headers
michael@428 337 my $sections = "";
michael@428 338 my $done = ''; my $this = ''; my $todo = $spec;
michael@428 339 while ($todo =~ m/^(\S+:|%\S+).*$/m) {
michael@428 340 $done .= $`; $this = $&; $todo = $';
michael@428 341 my $section = $1;
michael@428 342 $sections .= "$section,";
michael@428 343 $done .= $this;
michael@428 344 }
michael@428 345 my $regex = $require;
michael@428 346 $regex =~ s|\s+||sg;
michael@428 347 if ($sections !~ m/^$regex$/s) {
michael@428 348 $regex =~ s|,| |sg;
michael@428 349 &lint_error($file, undef, undef, "invalid run command section order (expected \"$regex\")");
michael@428 350 }
michael@428 351 }
michael@428 352
michael@428 353 ## _________________________________________________________________
michael@428 354 ##
michael@428 355 ## CHECK "script": shell scripts
michael@428 356 ## _________________________________________________________________
michael@428 357 ##
michael@428 358
michael@428 359 sub check_script {
michael@428 360 my ($file, $spec) = @_;
michael@428 361
michael@428 362 my $done = ''; my $this = ''; my $todo = $spec;
michael@428 363 while ($todo =~ m/(\%(?:config|info|common|status|start|stop|restart|reload|quarterly|hourly|daily|weekly|env))([^\n]*)\n(.*?\n)(?=\%(?:config|info|common|status|start|stop|restart|reload|quarterly|hourly|daily|weekly|env)|$)/s) {
michael@428 364 $done .= $`; $this = $&; $todo = $';
michael@428 365 my ($section, $args, $script) = ($1, $2, $3);
michael@428 366
michael@428 367 # perform checks for a single script section
michael@428 368 &check_script_section($file, $done, $this, $section, $args, $script);
michael@428 369
michael@428 370 $done .= $this;
michael@428 371 }
michael@428 372 }
michael@428 373
michael@428 374 sub check_script_section {
michael@428 375 my ($file, $outer_done, $outer_this, $section, $args, $script) = @_;
michael@428 376 my ($done, $this, $todo);
michael@428 377 my ($pkg, $pkgu);
michael@428 378
michael@428 379 # determine package name
michael@428 380 $pkg = $file;
michael@428 381 $pkg =~ s|^.+/||;
michael@428 382 $pkg =~ s|^rc\.||;
michael@428 383
michael@428 384 # determine package name, dash becomes underscore
michael@428 385 $pkgu = $pkg;
michael@428 386 $pkgu =~ s|-|_|;
michael@428 387
michael@428 388 # remove comment contents
michael@428 389 $outer_this =~ s|^[ \t]*#[^\n]*\n||mg;
michael@428 390
michael@428 391 # check config
michael@428 392 if ($section =~ m/^%(config)$/) {
michael@428 393
michael@428 394 # check for badly prefixed variables
michael@428 395 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 396 while ($todo =~ m/ [^=]+=[^\n]+/s) {
michael@428 397 $done .= $`; $this = $&; $todo = $';
michael@428 398 if ($this !~ m/ ([A-Z]+|$pkgu)_[a-z_][a-z0-9_]*=/) {
michael@428 399 &lint_warning($file, $done, $this, "section $section: badly prefixed variable");
michael@428 400 }
michael@428 401 $done .= $this;
michael@428 402 }
michael@428 403
michael@428 404 # enforce _enable to default to openpkg_rc_def
michael@428 405 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 406 if ( $todo =~ m/ [^=]+_enable=[^\n]+/s and $todo !~ m/ [^=]+_enable="\$openpkg_rc_def"\n+/s) {
michael@428 407 &lint_warning($file, $done, $this, "section $section: wrong default for ${pkgu}_enable");
michael@428 408 }
michael@428 409
michael@428 410 if ($pkg eq "openpkg") {
michael@428 411 # openpkg_rc before _enable, if used, must be the first variable
michael@428 412 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 413 if ( $todo !~ m/%config\n( [A-Z]+_[a-z_]+=[^\n]*\n)* openpkg_rc_def=[^\n]+?\n openpkg_rc_all=[^\n]+?\n [^=]+_enable=[^\n]+/s) {
michael@428 414 &lint_warning($file, $done, $this, "section $section: openpkg_rc_def, openpkg_rc_all and ${pkgu}_enable must be the first lowercase variable");
michael@428 415 }
michael@428 416 }
michael@428 417 else {
michael@428 418 # _enable, if used, must be the first variable
michael@428 419 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 420 if ( $todo =~ m/ [^=]+_enable=[^\n]+/s and $todo !~ m/%config\n( [A-Z]+_[a-z_]+=[^\n]*\n)* [^=]+_enable=[^\n]+/s) {
michael@428 421 &lint_warning($file, $done, $this, "section $section: ${pkgu}_enable must be the first lowercase variable");
michael@428 422 }
michael@428 423 }
michael@428 424 }
michael@428 425
michael@428 426 if ($section =~ m/^%(config|info|status)$/) {
michael@428 427 # check illegal use of return/exit
michael@428 428 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 429 if ( $todo =~ m/[^a-zA-Z0-9_](return|exit)\s/s ) {
michael@428 430 &lint_warning($file, $done, $this, "section $section: return or exit not allowed here");
michael@428 431 }
michael@428 432 return;
michael@428 433 }
michael@428 434
michael@428 435 # check rcService only used for enable|usable|active PR#232
michael@428 436 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 437 while ( $todo =~ m/rcService\s+\w+\s+(\w+)/s ) {
michael@428 438 $done .= $`; $this = $&; $todo = $';
michael@428 439 if ( $1 !~ m/^(enable|usable|active)$/ ) {
michael@428 440 &lint_warning($file, $done, $this, "section $section: rcService must check for (enable|usable|active) only, found check for \"$1\"");
michael@428 441 }
michael@428 442 $done .= $this;
michael@428 443 }
michael@428 444
michael@428 445 # check rcService short circuit
michael@428 446 if ($section !~ m/^%(config|common|info)$/) {
michael@428 447 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 448 if ( $todo !~ m/^[^\n]+\n rcService $pkg enable yes \|\| exit 0\n/s ) {
michael@428 449 &lint_warning($file, $done, $this, "section $section: \"rcService ... enable yes\" short circuit missing");
michael@428 450 }
michael@428 451 else {
michael@428 452 # check rcService package reference
michael@428 453 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 454 if ( $todo !~ m/\brcService\s+$pkg\s+/s ) {
michael@428 455 &lint_warning($file, $done, $this, "section $section: rcService referencing wrong package");
michael@428 456 }
michael@428 457 }
michael@428 458 }
michael@428 459
michael@428 460 # check shell redirections
michael@428 461 $done = $outer_done; $this = ''; $todo = $outer_this;
michael@428 462 while ( $todo =~ m/[ \t]+(\d+)?[><][ \t]+\S+/s
michael@428 463 or $todo =~ m/[ \t]+[><](\&\d+)?[ \t]+\S+/s) {
michael@428 464 $done .= $`; $this = $&; $todo = $';
michael@428 465 &lint_warning($file, $done, $this, "section $section: whitespace after shell redirection (expected none)");
michael@428 466 $done .= $this;
michael@428 467 }
michael@428 468 }
michael@428 469
michael@428 470 ## _________________________________________________________________
michael@428 471 ##
michael@428 472 ## CHECK "global": globals
michael@428 473 ## _________________________________________________________________
michael@428 474 ##
michael@428 475
michael@428 476 sub check_global {
michael@428 477 my ($file, $spec) = @_;
michael@428 478
michael@428 479 # utility function: extract a single shell command
michael@428 480 sub command_extract {
michael@428 481 my ($script) = @_;
michael@428 482 my $cmd = '';
michael@428 483 while ($script ne '') {
michael@428 484 $script =~ s/^([ \t]*'[^']*')/ $cmd .= $1, ''/se && next;
michael@428 485 $script =~ s/^([ \t]*"[^"]*")/ $cmd .= $1, ''/se && next;
michael@428 486 $script =~ s/^([ \t]*[^ \t;\)\\\r\n]+)/$cmd .= $1, ''/se && next;
michael@428 487 $script =~ s/^([ \t]*\\[ \t]*\r?\n)/ $cmd .= $1, ''/se && next;
michael@428 488 last;
michael@428 489 }
michael@428 490 return ($cmd, $script);
michael@428 491 }
michael@428 492
michael@428 493 # check for deprecated use of opServiceEnabled function
michael@428 494 my $done = ''; my $this = ''; my $todo = $spec;
michael@428 495 while ($todo =~ m/\bopServiceEnabled\b/s) {
michael@428 496 $done .= $`; $this = $&; $todo = $';
michael@428 497 &lint_warning($file, $done, $this, "deprecated usage of opServiceEnabled macro (expected rcService ... enable yes)");
michael@428 498 $done .= $this;
michael@428 499 }
michael@428 500
michael@428 501 my $done = ''; my $this = ''; my $todo = $spec;
michael@428 502 while ($todo =~ m/shtool\s+/s) {
michael@428 503 $done .= $`; $this = $&; $todo = $';
michael@428 504 ($this, $todo) = &command_extract($this . $todo);
michael@428 505
michael@428 506 # check for shtool options with no space before argument
michael@428 507 my $subthis = $this;
michael@428 508 $subthis =~ s/%{[^}]*?}//sg;
michael@428 509 $subthis =~ s/'[^']*'//sg;
michael@428 510 $subthis =~ s/"[^"]*"//sg;
michael@428 511 $subthis =~ s/[;|&].*$//s; # catch command termination by semicolon, pipe, or, and;
michael@428 512 if ($subthis =~ m/\s-[a-zA-Z]\S/) {
michael@428 513 &lint_warning($file, $done, $this, "found use of shtool option with space omitted before argument");
michael@428 514 }
michael@428 515 $done .= $this;
michael@428 516 }
michael@428 517 }

mercurial