The following commit has been merged in the master branch:
commit b75cbcef5c417b9a540ecf259f443eac9b272b58
Author: Adam D. Barratt <[EMAIL PROTECTED]>
Date:   Fri Jun 20 20:19:54 2008 +0100

    [ADB] Update bashism regexes to add new checks, improve performance and 
reduce false positives.

diff --git a/checks/scripts b/checks/scripts
index 41ff808..0fe348b 100644
--- a/checks/scripts
+++ b/checks/scripts
@@ -543,41 +543,86 @@ while (<SCRIPTS>) {
            if ($cat_string eq "" and $checkbashisms and 
!$within_another_shell) {
                my $found = 0;
                my $match = '';
+               my $LEADIN = qr'(?:(^|[`&;(|{])\s*|(if|do|while)\s+)';
+               my @bashism_single_quote_regexs = (
+                 $LEADIN . 
qr'echo\s+(?:-[^e]+\s+)?([\'])[^\']*(\\[\\abcEfnrtv0])+.*?[\']',
+                       # unsafe echo with backslashes
+               );
                my @bashism_string_regexs = (
-                 '\$\[\w+\]',                 # arith not allowed
-                 '\$\{\w+\:\d+(?::\d+)?\}',   # ${foo:3[:1]}
-                 '\$\{\w+(/.+?){1,2}\}',      # ${parm/?/pat[/str]}
-                 '[EMAIL PROTECTED]',# bash arrays, ${name[0|*|@]}
-                 '[EMAIL PROTECTED]',         # ${!prefix[*|@]}
-                 '\$\{!\w+\}',                # ${!name}
-                 '(\$\(|\`)\s*\<\s*\S+\s*(\)|\`)', # $(\< foo) should be $(cat 
foo)
-                 '\$RANDOM\b',                # $RANDOM
-                 '\$(OS|MACH)TYPE\b',         # $(OS|MACH)TYPE
-                 '\$HOST(TYPE|NAME)\b',       # $HOST(TYPE|NAME)
-                 '\$DIRSTACK\b',              # $DIRSTACK
-                 '\$EUID\b',                  # $EUID should be "id -u"
+                 qr'\$\[\w+\]',                 # arith not allowed
+                 qr'\$\{\w+\:\d+(?::\d+)?\}',   # ${foo:3[:1]}
+                 qr'\$\{\w+(/.+?){1,2}\}',      # ${parm/?/pat[/str]}
+                 qr'[EMAIL PROTECTED]',# bash arrays, ${name[0|*|@]}
+                 qr'[EMAIL PROTECTED]',                 # ${!prefix[*|@]}
+                 qr'\$\{!\w+\}',                # ${!name}
+                 qr'(\$\(|\`)\s*\<\s*\S+\s*(\)|\`)', # $(\< foo) should be 
$(cat foo)
+                 qr'\$\{?RANDOM\}?\b',          # $RANDOM
+                 qr'\$\{?(OS|MACH)TYPE\}?\b',   # $(OS|MACH)TYPE
+                 qr'\$\{?HOST(TYPE|NAME)\}?\b', # $HOST(TYPE|NAME)
+                 qr'\$\{?DIRSTACK\}?\b',        # $DIRSTACK
+                 qr'\$\{?EUID\}?\b',            # $EUID should be "id -u"
+                 qr'\$\{?UID\}?\b',             # $UID should be "id -ru"
+                 qr'\$\{?SECONDS\}?\b',         # $SECONDS
+                 qr'\$\{?BASH_[A-Z]+\}?\b',     # $BASH_SOMETHING
+                 qr'\$\{?SHELLOPTS\}?\b',       # $SHELLOPTS
+                 qr'\$\{?PIPESTATUS\}?\b',      # $PIPESTATUS
+                 qr'\$\{?SHLVL\}?\b',           # $SHLVL
+                 qr'<<<',                       # <<< here string
+                 $LEADIN . 
qr'echo\s+(?:-[^e]+\s+)?([\"])[^\"]*(\\[\\abcEfnrtv0])+.*?[\"]',
+                       # unsafe echo with backslashes
                );
                my @bashism_regexs = (
-                 'function \w+\(\s*\)',       # function is useless
-                                              # should be '.', not 'source'
-                 '(?:^|\s+)source\s+(?:\.\/|\/|\$)[^\s]+',
-                 '(\[|test|-o|-a)\s*[^\s]+\s+==\s', # should be 'b = a'
-                 '\s(\|\&)',                  # pipelining is not POSIX
-                 '[^\\\]\{([^\s]+?,)+[^\\\}\s]+\}', # brace expansion
-                 '(?:^|\s+)\w+\[\d+\]=',      # bash arrays, H[0]
-                 '(?:^|\s+)read\s*(?:;|$)',   # read without variable
-                 '(?:^|\s+)kill\s+-[^sl]\w*', # kill -[0-9] or -[A-Z]
-                 '(?:^|\s+)trap\s+["\']?.*["\']?\s+.*[1-9]', # trap with 
signal numbers
-                 '\&>',                       # cshism
-                 '(<\&|>\&)\s*((-|\d+)[^\s;|\)\`&]|[^-\d])', # should be >word 
2>&1
-                 '\[\[(?!:)',                 # alternative test command
-                 '(?:^|\s+)select\s+\w+',     # 'select' is not POSIX
-                 '(?:^|\s+)echo\s+-e',        # echo -e
-                 '(?:^|\s+)exec\s+-[acl]',    # exec -c/-l/-a name
-                 '(?:^|\s+)let\s',            # let ...
-                 '(?<![\$\(])\(\(.*\)\)',     # '((' should be '$(('
-                 '(\[|test)\s+-a',            # test with unary -a (should be 
-e)
-                 '<<<',                       # <<< here string
+                 qr'function \w+\(\s*\)',       # function is useless
+                                                # should be '.', not 'source'
+                 $LEADIN . qr'source\s+(?:\.\/|\/|\$)[^\s]+',
+                 qr'(test|-o|-a)\s*[^\s]+\s+==\s', # should be 'b = a'
+                 qr'\[\s+[^\]]+\s+==\s',        # should be 'b = a'
+                 qr'\s(\|\&)',                  # pipelining is not POSIX
+                 qr'[^\\]\{(?:[^\s\\\}]+?,)+[^\\\}\s]+\}', # brace expansion
+                 qr'(?:^|\s+)\w+\[\d+\]=',      # bash arrays, H[0]
+                 $LEADIN . qr'(read\s*(-[^r]+)*(?:;|$))',
+                       # read without variable or with option other than -r
+                 $LEADIN . qr'kill\s+-[^sl]\w*',# kill -[0-9] or -[A-Z]
+                 $LEADIN . qr'trap\s+["\']?.*["\']?\s+.*[1-9]', # trap with 
signal numbers
+                 qr'\&>',                       # cshism
+                 qr'(<\&|>\&)\s*((-|\d+)[^\s;|)`&\\\\]|[^-\d\s]+)', # should 
be >word 2>&1
+                 qr'\[\[(?!:)',                 # alternative test command
+                 $LEADIN . qr'select\s+\w+',    # 'select' is not POSIX
+                 $LEADIN . qr'echo\s+(-n\s+)?-n?en?',  # echo -e
+                 $LEADIN . qr'exec\s+-[acl]',   # exec -c/-l/-a name
+                 qr'(?:^|\s+)let\s',            # let ...
+                 qr'(?<![\$\(])\(\(.*\)\)',     # '((' should be '$(('
+                 qr'\$\[[^][]+\]',              # '$[' should be '$(('
+                 qr'(\[|test)\s+-a',            # test with unary -a (should 
be -e)
+                 qr'/dev/(tcp|udp)',            # /dev/(tcp|udp)
+                 $LEADIN . qr'\w+\+=',          # should be "VAR="${VAR}foo"
+                 $LEADIN . qr'suspend\s',
+                 $LEADIN . qr'caller\s',
+                 $LEADIN . qr'complete\s',
+                 $LEADIN . qr'compgen\s',
+                 $LEADIN . qr'declare\s',
+                 $LEADIN . qr'typeset\s',
+                 $LEADIN . qr'disown\s',
+                 $LEADIN . qr'builtin\s',
+                 $LEADIN . qr'set\s+-[BHT]+',   # set -[BHT]
+                 $LEADIN . qr'alias\s+-p',      # alias -p
+                 $LEADIN . qr'unalias\s+-a',    # unalias -a
+                 $LEADIN . qr'local\s+-[a-zA-Z]+', # local -opt
+                 $LEADIN . qr'local\s+\w+=',    # local foo=bar
+                 qr'(?:^|\s+)\s*\(?\w*[^\(\w\s]+\S*?\s*\(\)[^\"]?',
+                       # function names should only contain [a-z0-9_]
+                 $LEADIN . qr'(push|pop)d\b',   # (push|pod)d
+                 $LEADIN . qr'export\s+-[^p]',  # export only takes -p as an 
option
+                 $LEADIN . qr'ulimit\b',
+                 $LEADIN . qr'shopt\b',
+                 $LEADIN . qr'type\s',
+                 $LEADIN . qr'time\s',
+                 $LEADIN . qr'dirs\b',
+                 qr'(?:^|\s+)[<>]\(.*?\)',      # <() process substituion
+                 qr'(?:^|\s+)readonly\s+-[af]', # readonly -[af]
+                 $LEADIN . qr'(sh|\$\{?SHELL\}?) -[rD]', # sh -[rD]
+                 $LEADIN . qr'(sh|\$\{?SHELL\}?) --\w+', # sh --long-option
+                 $LEADIN . qr'(sh|\$\{?SHELL\}?) [-+]O', # sh [-+]O
                );
 
                # since this test is ugly, I have to do it by itself
@@ -593,9 +638,20 @@ while (<SCRIPTS>) {
                    }
                }
 
+               my $line = $_;
+
+               unless ($found) {
+                   for my $re (@bashism_single_quote_regexs) {
+                       if ($line =~ m/($re)/) {
+                           $found = 1;
+                           ($match) = m/($re)/;
+                           last;
+                       }
+                   }
+               }
+               
                # Ignore anything inside single quotes; it could be an
                # argument to grep or the like.
-               my $line = $_;
 
                # $cat_line contains the version of the line we'll check
                # for heredoc delimiters later. Initially, remove any
diff --git a/debian/changelog b/debian/changelog
index 3851965..53bec99 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -20,6 +20,8 @@ lintian (1.24.2) unstable; urgency=low
     + [FL] Improve heredoc detection.  Patch by Adam D. Barratt.
     + [FL] Improve script_is_evil_and_wrong() to catch more scripts.
       Patch by Adam D. Barratt.
+    + [ADB] Update bashism regexes to add new checks, improve performance
+      and reduce false positives.
   * checks/watch-file{,.desc}:
      + [FL] Check for more Debian specific strings in version
        number.  Issue an info tag if the watch file uses
diff --git a/testset/maintainer-scripts/debian/prerm 
b/testset/maintainer-scripts/debian/prerm
index 368f9c4..7567a79 100644
--- a/testset/maintainer-scripts/debian/prerm
+++ b/testset/maintainer-scripts/debian/prerm
@@ -43,6 +43,7 @@ update-rc.d foo remove
 
 # More false positives for bashism checks.  None of these are errors.
 echo "$line" | grep -q '{fonts/map,}/{\$progname,pdftex,dvips,}//'
+echo "$line" | grep -q "${fonts},${foo}"
 echo '$[1+2]'
 printf "foo |& bar"
 perl -e "print q( kill -HUP $? )"
@@ -55,3 +56,100 @@ echo "${line:3:1}"
 
 # This is the only install-sgmlcatalog call that's allowed.
 install-sgmlcatalog --quiet --remove package
+
+# More bashisms checks
+
+read -x foo
+read -x
+read -r foo
+read foo
+read
+
+echo "a\\b"
+echo 'a\nb'
+
+echo "${UID}"
+echo "$EUID"
+echo "$SHLVL"
+echo "$DIRSTACK"
+echo "$SECONDS"
+echo "$BASH"
+echo "$BASH_FOO"
+echo "$SHELLOPTS"
+echo "$PIPESTATUS"
+
+bar="$(cut '-d|' -f2 <<< "$foo")"
+
+VAR=1
+VAR+=a
+
+echos() {
+  echo -n -e "bar"
+  echo -e -n "bar"
+  echo -en "bar"
+  echo -ne "bar"
+  echo "bar"
+  echo "echo -e foo"
+}
+
+ech.os() {
+  echo foo >& 2
+  echo foo >&bar
+  echo foo >& bar
+}
+
+echoes() {
+  echo "abc\nxyz"
+  echo 'xyz\rabc'
+  echo foo\cbar
+
+  echo -e "abc\nxyz"
+  echo -net 'xyz\rabc'
+  echo -e foo\cbar
+}
+
+foobar.() {
+  suspend x
+  suspended x
+  caller x
+  complete x
+  compgen x
+  declare -a foo
+}
+
+.foobar() {
+  typeset -x bar
+  disown 1
+  builtin foo
+  set -B
+  alias -p
+  unalias -a
+}
+
+IFS="()"
+
+ulimit
+shopt
+type -v bar
+time ls
+dirs
+diff <(tac a) <(tac b)
+
+pushd
+
+local foo=bar
+local -x foo
+
+popd
+
+readonly -f
+
+echo bar > /dev/tcp
+export x
+export -x x
+export -p x
+
+sh -x
+sh -D
+sh --foo
+sh +O
diff --git a/testset/tags.maintainer-scripts b/testset/tags.maintainer-scripts
index 6c34acb..1788ad0 100644
--- a/testset/tags.maintainer-scripts
+++ b/testset/tags.maintainer-scripts
@@ -9,7 +9,7 @@ E: maintainer-scripts: init.d-script-not-included-in-package 
/etc/init.d/foo
 E: maintainer-scripts: install-sgmlcatalog-deprecated postinst:98
 E: maintainer-scripts: install-sgmlcatalog-deprecated postrm:46
 E: maintainer-scripts: interpreter-without-predep control/config 
#!/usr/bin/python
-E: maintainer-scripts: maintainer-script-calls-init-script-directly prerm:54
+E: maintainer-scripts: maintainer-script-calls-init-script-directly prerm:55
 E: maintainer-scripts: 
maintainer-script-does-not-check-for-existence-of-wm-menu-config postinst:31
 E: maintainer-scripts: maintainer-script-modifies-inetd-conf postinst:91
 E: maintainer-scripts: maintainer-script-modifies-inetd-conf postinst:92
@@ -64,6 +64,40 @@ W: maintainer-scripts: possible-bashism-in-maintainer-script 
postinst:18 'read'
 W: maintainer-scripts: possible-bashism-in-maintainer-script postinst:20 
'H[0]='
 W: maintainer-scripts: possible-bashism-in-maintainer-script postinst:21 
'${H[0]}'
 W: maintainer-scripts: possible-bashism-in-maintainer-script postinst:23 
'[EMAIL PROTECTED]'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:102 '  echo 
"abc\nxyz"'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:103 '  echo 
'xyz\rabc''
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:106 '  echo 
-e'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:107 '  echo 
-ne'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:108 '  echo 
-e'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:111 
'foobar.() '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:112 '  
suspend '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:114 '  
caller '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:115 '  
complete '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:116 '  
compgen '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:117 '  
declare '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:120 
'.foobar() '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:121 '  
typeset '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:122 '  
disown '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:123 '  
builtin '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:124 '  set 
-B'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:125 '  
alias -p'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:126 '  
unalias -a'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:131 'ulimit'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:132 'shopt'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:133 'type '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:134 'time '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:135 'dirs'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:136 ' <(tac 
a)'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:138 'pushd'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:140 'local 
foo='
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:141 'local 
-x'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:143 'popd'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:145 
'readonly -f'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:147 
'/dev/tcp'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:149 'export 
-x'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:153 'sh -D'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:154 'sh 
--foo'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:155 'sh +O'
 W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:19 '[ "$2" 
== '
 W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:23 
'function foo( )'
 W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:26 '&>'
@@ -71,7 +105,29 @@ W: maintainer-scripts: 
possible-bashism-in-maintainer-script prerm:29 'source $F
 W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:31 'trap 
"echo hi" EXIT HUP 3'
 W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:33 '[['
 W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:34 '    
kill -HUP'
-W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:51 
'${line:3:1}'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:52 
'${line:3:1}'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:62 'read -x 
foo'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:63 'read -x'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:66 'read'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:68 'echo 
"a\\b"'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:69 'echo 
'a\nb''
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:71 '${UID'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:72 '$EUID'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:73 '$SHLVL'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:74 
'$DIRSTACK'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:75 
'$SECONDS'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:77 
'$BASH_FOO'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:78 
'$SHELLOPTS'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:79 
'$PIPESTATUS'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:81 '<<<'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:84 'VAR+='
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:87 '  echo 
-n -e'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:88 '  echo 
-e'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:89 '  echo 
-en'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:90 '  echo 
-ne'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:95 
'ech.os() '
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:97 '>&bar'
+W: maintainer-scripts: possible-bashism-in-maintainer-script prerm:98 '>& bar'
 W: maintainer-scripts: 
possibly-insecure-handling-of-tmp-files-in-maintainer-script postinst:50
 W: maintainer-scripts: 
possibly-insecure-handling-of-tmp-files-in-maintainer-script postrm:39
 W: maintainer-scripts: postinst-does-not-load-confmodule
@@ -79,5 +135,10 @@ W: maintainer-scripts: postinst-should-not-set-usr-doc-link
 W: maintainer-scripts: postrm-does-not-purge-debconf
 W: maintainer-scripts: postrm-has-useless-call-to-ldconfig
 W: maintainer-scripts: read-in-maintainer-script postinst:18
+W: maintainer-scripts: read-in-maintainer-script prerm:62
+W: maintainer-scripts: read-in-maintainer-script prerm:63
+W: maintainer-scripts: read-in-maintainer-script prerm:64
+W: maintainer-scripts: read-in-maintainer-script prerm:65
+W: maintainer-scripts: read-in-maintainer-script prerm:66
 W: maintainer-scripts: start-stop-daemon-in-maintainer-script postinst:159
 W: maintainer-scripts: update-alternatives-remove-called-in-postrm

-- 
Debian package checker


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to