openpkg/lint-rc.pl

Mon, 28 Jan 2013 17:37:18 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Mon, 28 Jan 2013 17:37:18 +0100
changeset 758
a2c6460cfb16
permissions
-rw-r--r--

Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.

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