Thu, 04 Oct 2012 20:30:05 +0200
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 | } |