2001-10-19 18:36:57 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2001-10-19 18:36:57 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-10-19 18:36:57 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-10-19 18:36:57 +04:00
# include "matcher.h"
# include "parse_rx.h"
# include "ttree.h"
struct dfa_state {
int final ;
struct dfa_state * lookup [ 256 ] ;
} ;
struct state_queue {
struct dfa_state * s ;
2005-10-17 03:03:59 +04:00
dm_bitset_t bits ;
2001-10-19 18:36:57 +04:00
struct state_queue * next ;
} ;
2002-04-24 22:20:51 +04:00
struct matcher { /* Instance variables for the lexer */
2001-10-19 18:36:57 +04:00
struct dfa_state * start ;
2002-12-20 02:25:55 +03:00
unsigned num_nodes ;
int nodes_entered ;
2001-10-19 18:36:57 +04:00
struct rx_node * * nodes ;
2005-10-17 03:03:59 +04:00
struct dm_pool * scratch , * mem ;
2001-10-19 18:36:57 +04:00
} ;
# define TARGET_TRANS '\0'
static int _count_nodes ( struct rx_node * rx )
{
int r = 1 ;
2002-04-24 22:20:51 +04:00
if ( rx - > left )
2001-10-19 18:36:57 +04:00
r + = _count_nodes ( rx - > left ) ;
2002-04-24 22:20:51 +04:00
if ( rx - > right )
2001-10-19 18:36:57 +04:00
r + = _count_nodes ( rx - > right ) ;
return r ;
}
static void _fill_table ( struct matcher * m , struct rx_node * rx )
{
assert ( ( rx - > type ! = OR ) | | ( rx - > left & & rx - > right ) ) ;
2002-04-24 22:20:51 +04:00
if ( rx - > left )
2001-10-19 18:36:57 +04:00
_fill_table ( m , rx - > left ) ;
2002-04-24 22:20:51 +04:00
if ( rx - > right )
2001-10-19 18:36:57 +04:00
_fill_table ( m , rx - > right ) ;
m - > nodes [ m - > nodes_entered + + ] = rx ;
}
static void _create_bitsets ( struct matcher * m )
{
int i ;
2002-04-24 22:20:51 +04:00
for ( i = 0 ; i < m - > num_nodes ; i + + ) {
2001-10-19 18:36:57 +04:00
struct rx_node * n = m - > nodes [ i ] ;
2005-10-17 03:03:59 +04:00
n - > firstpos = dm_bitset_create ( m - > scratch , m - > num_nodes ) ;
n - > lastpos = dm_bitset_create ( m - > scratch , m - > num_nodes ) ;
n - > followpos = dm_bitset_create ( m - > scratch , m - > num_nodes ) ;
2001-10-19 18:36:57 +04:00
}
}
static void _calc_functions ( struct matcher * m )
{
int i , j , final = 1 ;
struct rx_node * rx , * c1 , * c2 ;
2002-04-24 22:20:51 +04:00
for ( i = 0 ; i < m - > num_nodes ; i + + ) {
2001-10-19 18:36:57 +04:00
rx = m - > nodes [ i ] ;
c1 = rx - > left ;
c2 = rx - > right ;
2005-10-17 03:03:59 +04:00
if ( dm_bit ( rx - > charset , TARGET_TRANS ) )
2001-10-19 18:36:57 +04:00
rx - > final = final + + ;
2002-04-24 22:20:51 +04:00
switch ( rx - > type ) {
2001-10-19 18:36:57 +04:00
case CAT :
2002-04-24 22:20:51 +04:00
if ( c1 - > nullable )
2005-10-17 03:03:59 +04:00
dm_bit_union ( rx - > firstpos ,
2001-10-19 18:36:57 +04:00
c1 - > firstpos , c2 - > firstpos ) ;
else
2005-10-17 03:03:59 +04:00
dm_bit_copy ( rx - > firstpos , c1 - > firstpos ) ;
2001-10-19 18:36:57 +04:00
2002-04-24 22:20:51 +04:00
if ( c2 - > nullable )
2005-10-17 03:03:59 +04:00
dm_bit_union ( rx - > lastpos ,
2001-10-19 18:36:57 +04:00
c1 - > lastpos , c2 - > lastpos ) ;
else
2005-10-17 03:03:59 +04:00
dm_bit_copy ( rx - > lastpos , c2 - > lastpos ) ;
2001-10-19 18:36:57 +04:00
rx - > nullable = c1 - > nullable & & c2 - > nullable ;
break ;
case PLUS :
2005-10-17 03:03:59 +04:00
dm_bit_copy ( rx - > firstpos , c1 - > firstpos ) ;
dm_bit_copy ( rx - > lastpos , c1 - > lastpos ) ;
2001-10-19 18:36:57 +04:00
rx - > nullable = c1 - > nullable ;
break ;
case OR :
2005-10-17 03:03:59 +04:00
dm_bit_union ( rx - > firstpos , c1 - > firstpos , c2 - > firstpos ) ;
dm_bit_union ( rx - > lastpos , c1 - > lastpos , c2 - > lastpos ) ;
2001-10-19 18:36:57 +04:00
rx - > nullable = c1 - > nullable | | c2 - > nullable ;
break ;
case QUEST :
case STAR :
2005-10-17 03:03:59 +04:00
dm_bit_copy ( rx - > firstpos , c1 - > firstpos ) ;
dm_bit_copy ( rx - > lastpos , c1 - > lastpos ) ;
2001-10-19 18:36:57 +04:00
rx - > nullable = 1 ;
break ;
case CHARSET :
2005-10-17 03:03:59 +04:00
dm_bit_set ( rx - > firstpos , i ) ;
dm_bit_set ( rx - > lastpos , i ) ;
2001-10-19 18:36:57 +04:00
rx - > nullable = 0 ;
break ;
default :
2002-01-28 00:30:47 +03:00
log_error ( " Internal error: Unknown calc node type " ) ;
2001-10-19 18:36:57 +04:00
}
/*
* followpos has it ' s own switch
* because PLUS and STAR do the
* same thing .
*/
2002-04-24 22:20:51 +04:00
switch ( rx - > type ) {
2001-10-19 18:36:57 +04:00
case CAT :
2002-04-24 22:20:51 +04:00
for ( j = 0 ; j < m - > num_nodes ; j + + ) {
2005-10-17 03:03:59 +04:00
if ( dm_bit ( c1 - > lastpos , j ) ) {
2001-10-19 18:36:57 +04:00
struct rx_node * n = m - > nodes [ j ] ;
2005-10-17 03:03:59 +04:00
dm_bit_union ( n - > followpos ,
2001-10-19 18:36:57 +04:00
n - > followpos , c2 - > firstpos ) ;
}
}
break ;
case PLUS :
case STAR :
2002-04-24 22:20:51 +04:00
for ( j = 0 ; j < m - > num_nodes ; j + + ) {
2005-10-17 03:03:59 +04:00
if ( dm_bit ( rx - > lastpos , j ) ) {
2001-10-19 18:36:57 +04:00
struct rx_node * n = m - > nodes [ j ] ;
2005-10-17 03:03:59 +04:00
dm_bit_union ( n - > followpos ,
2001-10-19 18:36:57 +04:00
n - > followpos , rx - > firstpos ) ;
}
}
break ;
}
}
}
2006-04-19 19:33:07 +04:00
static struct dfa_state * _create_dfa_state ( struct dm_pool * mem )
2001-10-19 18:36:57 +04:00
{
2005-10-17 03:03:59 +04:00
return dm_pool_zalloc ( mem , sizeof ( struct dfa_state ) ) ;
2001-10-19 18:36:57 +04:00
}
2005-10-17 03:03:59 +04:00
static struct state_queue * _create_state_queue ( struct dm_pool * mem ,
2001-10-19 18:36:57 +04:00
struct dfa_state * dfa ,
2005-10-17 03:03:59 +04:00
dm_bitset_t bits )
2001-10-19 18:36:57 +04:00
{
2005-10-17 03:03:59 +04:00
struct state_queue * r = dm_pool_alloc ( mem , sizeof ( * r ) ) ;
2001-10-19 18:36:57 +04:00
if ( ! r ) {
stack ;
return NULL ;
}
r - > s = dfa ;
2005-10-17 03:03:59 +04:00
r - > bits = dm_bitset_create ( mem , bits [ 0 ] ) ; /* first element is the size */
dm_bit_copy ( r - > bits , bits ) ;
2001-10-19 18:36:57 +04:00
r - > next = 0 ;
return r ;
}
static int _calc_states ( struct matcher * m , struct rx_node * rx )
{
2005-10-17 03:03:59 +04:00
unsigned iwidth = ( m - > num_nodes / DM_BITS_PER_INT ) + 1 ;
2001-10-19 18:36:57 +04:00
struct ttree * tt = ttree_create ( m - > scratch , iwidth ) ;
struct state_queue * h , * t , * tmp ;
struct dfa_state * dfa , * ldfa ;
int i , a , set_bits = 0 , count = 0 ;
2006-05-10 01:23:51 +04:00
dm_bitset_t bs , dfa_bits ;
2001-10-19 18:36:57 +04:00
2006-05-10 01:23:51 +04:00
if ( ! tt )
return_0 ;
2001-10-19 18:36:57 +04:00
2006-05-10 01:23:51 +04:00
if ( ! ( bs = dm_bitset_create ( m - > scratch , m - > num_nodes ) ) )
return_0 ;
2001-10-19 18:36:57 +04:00
/* create first state */
dfa = _create_dfa_state ( m - > mem ) ;
m - > start = dfa ;
o Filter for the dev cache that takes values from config file:
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}
Alasdair this is ready to roll into the tools now.
2001-10-19 22:20:37 +04:00
ttree_insert ( tt , rx - > firstpos + 1 , dfa ) ;
2001-10-19 18:36:57 +04:00
/* prime the queue */
h = t = _create_state_queue ( m - > scratch , dfa , rx - > firstpos ) ;
o Filter for the dev cache that takes values from config file:
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}
Alasdair this is ready to roll into the tools now.
2001-10-19 22:20:37 +04:00
while ( h ) {
2001-10-19 18:36:57 +04:00
/* pop state off front of the queue */
dfa = h - > s ;
dfa_bits = h - > bits ;
h = h - > next ;
/* iterate through all the inputs for this state */
2005-10-17 03:03:59 +04:00
dm_bit_clear_all ( bs ) ;
2002-04-24 22:20:51 +04:00
for ( a = 0 ; a < 256 ; a + + ) {
2001-10-19 18:36:57 +04:00
/* iterate through all the states in firstpos */
2005-10-17 03:03:59 +04:00
for ( i = dm_bit_get_first ( dfa_bits ) ;
i > = 0 ; i = dm_bit_get_next ( dfa_bits , i ) ) {
if ( dm_bit ( m - > nodes [ i ] - > charset , a ) ) {
2002-04-24 22:20:51 +04:00
if ( a = = TARGET_TRANS )
2001-10-19 18:36:57 +04:00
dfa - > final = m - > nodes [ i ] - > final ;
2005-10-17 03:03:59 +04:00
dm_bit_union ( bs , bs ,
2002-04-24 22:20:51 +04:00
m - > nodes [ i ] - > followpos ) ;
2001-10-19 18:36:57 +04:00
set_bits = 1 ;
}
}
2002-04-24 22:20:51 +04:00
if ( set_bits ) {
2001-10-19 18:36:57 +04:00
ldfa = ttree_lookup ( tt , bs + 1 ) ;
2002-04-24 22:20:51 +04:00
if ( ! ldfa ) {
2001-10-19 18:36:57 +04:00
/* push */
ldfa = _create_dfa_state ( m - > mem ) ;
ttree_insert ( tt , bs + 1 , ldfa ) ;
2002-04-24 22:20:51 +04:00
tmp =
_create_state_queue ( m - > scratch ,
ldfa , bs ) ;
if ( ! h )
2001-10-19 18:36:57 +04:00
h = t = tmp ;
else {
t - > next = tmp ;
t = tmp ;
}
count + + ;
}
dfa - > lookup [ a ] = ldfa ;
set_bits = 0 ;
2005-10-17 03:03:59 +04:00
dm_bit_clear_all ( bs ) ;
2001-10-19 18:36:57 +04:00
}
}
}
o Filter for the dev cache that takes values from config file:
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}
Alasdair this is ready to roll into the tools now.
2001-10-19 22:20:37 +04:00
log_debug ( " Matcher built with %d dfa states " , count ) ;
2001-10-19 18:36:57 +04:00
return 1 ;
}
2005-10-17 03:03:59 +04:00
struct matcher * matcher_create ( struct dm_pool * mem , const char * * patterns ,
2002-12-20 02:25:55 +03:00
unsigned num )
2001-10-19 18:36:57 +04:00
{
char * all , * ptr ;
2002-12-20 02:25:55 +03:00
int i ;
size_t len = 0 ;
2001-10-19 18:36:57 +04:00
struct rx_node * rx ;
2005-10-17 03:03:59 +04:00
struct dm_pool * scratch = dm_pool_create ( " regex matcher " , 10 * 1024 ) ;
2001-10-19 18:36:57 +04:00
struct matcher * m ;
if ( ! scratch ) {
stack ;
return NULL ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( m = dm_pool_alloc ( mem , sizeof ( * m ) ) ) ) {
2001-10-19 18:36:57 +04:00
stack ;
2006-05-10 01:23:51 +04:00
dm_pool_destroy ( scratch ) ;
2001-10-19 18:36:57 +04:00
return NULL ;
}
memset ( m , 0 , sizeof ( * m ) ) ;
/* join the regexps together, delimiting with zero */
2002-04-24 22:20:51 +04:00
for ( i = 0 ; i < num ; i + + )
2001-10-19 18:36:57 +04:00
len + = strlen ( patterns [ i ] ) + 8 ;
2005-10-17 03:03:59 +04:00
ptr = all = dm_pool_alloc ( scratch , len + 1 ) ;
2001-10-19 18:36:57 +04:00
if ( ! all ) {
stack ;
goto bad ;
}
2002-04-24 22:20:51 +04:00
for ( i = 0 ; i < num ; i + + ) {
ptr + = sprintf ( ptr , " (.*(%s)%c) " , patterns [ i ] , TARGET_TRANS ) ;
if ( i < ( num - 1 ) )
2001-10-19 18:36:57 +04:00
* ptr + + = ' | ' ;
}
/* parse this expression */
2002-04-24 22:20:51 +04:00
if ( ! ( rx = rx_parse_tok ( scratch , all , ptr ) ) ) {
2002-01-28 00:30:47 +03:00
log_error ( " Couldn't parse regex " ) ;
2001-10-19 18:36:57 +04:00
goto bad ;
}
m - > mem = mem ;
m - > scratch = scratch ;
m - > num_nodes = _count_nodes ( rx ) ;
2005-10-17 03:03:59 +04:00
m - > nodes = dm_pool_alloc ( scratch , sizeof ( * m - > nodes ) * m - > num_nodes ) ;
2001-10-19 18:36:57 +04:00
if ( ! m - > nodes ) {
stack ;
goto bad ;
}
_fill_table ( m , rx ) ;
_create_bitsets ( m ) ;
_calc_functions ( m ) ;
_calc_states ( m , rx ) ;
2005-10-17 03:03:59 +04:00
dm_pool_destroy ( scratch ) ;
2001-10-19 18:36:57 +04:00
m - > scratch = NULL ;
return m ;
2002-04-24 22:20:51 +04:00
bad :
2005-10-17 03:03:59 +04:00
dm_pool_destroy ( scratch ) ;
dm_pool_destroy ( mem ) ;
2001-10-19 18:36:57 +04:00
return NULL ;
}
2006-04-19 19:33:07 +04:00
static struct dfa_state * _step_matcher ( int c , struct dfa_state * cs , int * r )
2002-08-29 18:46:30 +04:00
{
2002-12-20 02:25:55 +03:00
if ( ! ( cs = cs - > lookup [ ( unsigned char ) c ] ) )
2002-08-29 18:46:30 +04:00
return NULL ;
if ( cs - > final & & ( cs - > final > * r ) )
* r = cs - > final ;
return cs ;
}
o Filter for the dev cache that takes values from config file:
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}
Alasdair this is ready to roll into the tools now.
2001-10-19 22:20:37 +04:00
int matcher_run ( struct matcher * m , const char * b )
2001-10-19 18:36:57 +04:00
{
struct dfa_state * cs = m - > start ;
o Filter for the dev cache that takes values from config file:
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}
Alasdair this is ready to roll into the tools now.
2001-10-19 22:20:37 +04:00
int r = 0 ;
2001-10-19 18:36:57 +04:00
2002-08-29 18:46:30 +04:00
if ( ! ( cs = _step_matcher ( HAT_CHAR , cs , & r ) ) )
goto out ;
2001-10-19 18:36:57 +04:00
2002-08-29 18:46:30 +04:00
for ( ; * b ; b + + )
if ( ! ( cs = _step_matcher ( * b , cs , & r ) ) )
goto out ;
2001-10-19 18:36:57 +04:00
2002-08-29 18:46:30 +04:00
_step_matcher ( DOLLAR_CHAR , cs , & r ) ;
2001-10-19 18:36:57 +04:00
2002-11-18 17:01:16 +03:00
out :
2001-10-19 18:36:57 +04:00
/* subtract 1 to get back to zero index */
o Filter for the dev cache that takes values from config file:
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}
Alasdair this is ready to roll into the tools now.
2001-10-19 22:20:37 +04:00
return r - 1 ;
2001-10-19 18:36:57 +04:00
}