2017-05-01 03:26:56 +03:00
#!/usr/bin/env python3
2017-11-18 19:32:46 +03:00
# SPDX-License-Identifier: LGPL-2.1+
#
2010-09-21 14:45:52 +04:00
# Simple udev rules syntax checker
#
# (C) 2010 Canonical Ltd.
# Author: Martin Pitt <martin.pitt@ubuntu.com>
#
2013-08-15 00:55:40 +04:00
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
2010-09-21 14:45:52 +04:00
# (at your option) any later version.
2013-08-15 00:55:40 +04:00
# systemd is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
2010-09-21 14:45:52 +04:00
#
2013-08-15 00:55:40 +04:00
# You should have received a copy of the GNU Lesser General Public License
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
2010-09-21 14:45:52 +04:00
import re
import sys
2015-01-20 22:50:35 +03:00
import os
from glob import glob
2010-09-21 14:45:52 +04:00
2015-01-20 22:50:35 +03:00
if len ( sys . argv ) > 1 :
# explicit rule file list
rules_files = sys . argv [ 1 : ]
else :
# take them from the build dir
root_dir = os . path . dirname ( os . path . dirname ( os . path . abspath ( __file__ ) ) )
rules_dir = os . path . join ( os . environ . get ( ' top_srcdir ' , root_dir ) , ' rules ' )
if not os . path . isdir ( rules_dir ) :
sys . stderr . write ( ' No rules files given, and %s does not exist, aborting ' % rules_dir )
sys . exit ( 2 )
rules_files = glob ( os . path . join ( rules_dir , ' *.rules ' ) )
2010-09-21 14:45:52 +04:00
2016-12-02 02:29:54 +03:00
no_args_tests = re . compile ( r ' (ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|RESULT|TEST) \ s*(?:=|!)= \ s* " ([^ " ]*) " $ ' )
args_tests = re . compile ( r ' (ATTRS?|ENV|TEST) { ([a-zA-Z0-9/_.* % -]+)} \ s*(?:=|!)= \ s* " ([^ " ]*) " $ ' )
no_args_assign = re . compile ( r ' (NAME|SYMLINK|OWNER|GROUP|MODE|TAG|PROGRAM|RUN|LABEL|GOTO|OPTIONS|IMPORT) \ s*(?: \ +=|:=|=) \ s* " ([^ " ]*) " $ ' )
args_assign = re . compile ( r ' (ATTR|ENV|IMPORT|RUN) { ([a-zA-Z0-9/_.* % -]+)} \ s*(=| \ +=) \ s* " ([^ " ]*) " $ ' )
2010-09-21 14:45:52 +04:00
result = 0
buffer = ' '
2015-01-20 22:50:35 +03:00
for path in rules_files :
2010-09-21 14:45:52 +04:00
lineno = 0
for line in open ( path ) :
lineno + = 1
# handle line continuation
if line . endswith ( ' \\ \n ' ) :
buffer + = line [ : - 2 ]
continue
else :
line = buffer + line
buffer = ' '
# filter out comments and empty lines
line = line . strip ( )
if not line or line . startswith ( ' # ' ) :
continue
for clause in line . split ( ' , ' ) :
clause = clause . strip ( )
if not ( no_args_tests . match ( clause ) or args_tests . match ( clause ) or
no_args_assign . match ( clause ) or args_assign . match ( clause ) ) :
2011-05-31 04:18:33 +04:00
print ( ' Invalid line %s : %i : %s ' % ( path , lineno , line ) )
2015-01-20 14:18:40 +03:00
print ( ' clause: %s ' % clause )
print ( ' ' )
2010-09-21 14:45:52 +04:00
result = 1
break
sys . exit ( result )