2003-07-17 12:24:51 +04:00
/*
2010-04-12 17:58:05 +04:00
* Copyright ( C ) 2003 - 2010 Kay Sievers < kay . sievers @ vrfy . org >
2008-11-13 02:52:12 +03:00
* Copyright ( C ) 2008 Alan Jenkins < alan - jenkins @ tuffmail . co . uk >
2003-07-17 12:24:51 +04:00
*
2008-09-10 04:40:42 +04:00
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 2 of the License , or
* ( at your option ) any later version .
2006-04-28 19:52:09 +04:00
*
2008-09-10 04:40:42 +04:00
* This program 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 General Public License for more details .
2003-07-17 12:24:51 +04:00
*
2008-09-10 04:40:42 +04:00
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-07-17 12:24:51 +04:00
*/
# include <stddef.h>
2008-11-11 23:20:11 +03:00
# include <limits.h>
2003-07-17 12:24:51 +04:00
# include <stdlib.h>
2009-11-17 01:39:33 +03:00
# include <stdbool.h>
2003-07-17 12:24:51 +04:00
# include <string.h>
# include <stdio.h>
# include <fcntl.h>
# include <ctype.h>
# include <unistd.h>
# include <errno.h>
2008-03-13 18:00:25 +03:00
# include <dirent.h>
2006-08-24 11:03:15 +04:00
# include <fnmatch.h>
2009-08-31 01:58:57 +04:00
# include <time.h>
2003-07-17 12:24:51 +04:00
# include "udev.h"
2008-10-23 02:13:59 +04:00
# define PREALLOC_TOKEN 2048
# define PREALLOC_STRBUF 32 * 1024
2008-11-11 23:20:11 +03:00
# define PREALLOC_TRIE 256
2008-10-18 16:33:37 +04:00
2008-11-01 23:05:25 +03:00
struct uid_gid {
unsigned int name_off ;
union {
uid_t uid ;
gid_t gid ;
} ;
} ;
2008-11-11 23:20:11 +03:00
struct trie_node {
2008-11-13 02:52:12 +03:00
/* this node's first child */
2008-11-12 07:50:05 +03:00
unsigned int child_idx ;
2008-11-13 02:52:12 +03:00
/* the next child of our parent node's child list */
unsigned int next_child_idx ;
/* this node's last child (shortcut for append) */
2008-11-12 07:50:05 +03:00
unsigned int last_child_idx ;
2008-11-11 23:20:11 +03:00
unsigned int value_off ;
2008-11-12 07:50:05 +03:00
unsigned short value_len ;
2008-11-13 02:52:12 +03:00
unsigned char key ;
2008-11-11 23:20:11 +03:00
} ;
2008-11-01 23:05:25 +03:00
struct udev_rules {
struct udev * udev ;
int resolve_names ;
/* every key in the rules file becomes a token */
struct token * tokens ;
unsigned int token_cur ;
unsigned int token_max ;
/* all key strings are copied to a single string buffer */
char * buf ;
size_t buf_cur ;
size_t buf_max ;
unsigned int buf_count ;
2008-11-12 07:50:05 +03:00
/* during rule parsing, strings are indexed to find duplicates */
struct trie_node * trie_nodes ;
unsigned int trie_nodes_cur ;
unsigned int trie_nodes_max ;
2008-11-11 23:20:11 +03:00
2008-11-12 07:50:05 +03:00
/* during rule parsing, uid/gid lookup results are cached */
2008-11-01 23:05:25 +03:00
struct uid_gid * uids ;
unsigned int uids_cur ;
unsigned int uids_max ;
struct uid_gid * gids ;
unsigned int gids_cur ;
unsigned int gids_max ;
} ;
2008-11-11 23:20:11 +03:00
/* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */
2008-10-24 13:38:05 +04:00
enum operation_type {
OP_UNSET ,
OP_MATCH ,
OP_NOMATCH ,
OP_MATCH_MAX ,
OP_ADD ,
OP_ASSIGN ,
OP_ASSIGN_FINAL ,
2008-10-18 16:33:37 +04:00
} ;
2008-10-24 15:32:32 +04:00
enum string_glob_type {
GL_UNSET ,
2008-10-24 16:19:42 +04:00
GL_PLAIN , /* no special chars */
GL_GLOB , /* shell globs ?,*,[] */
GL_SPLIT , /* multi-value A|B */
GL_SPLIT_GLOB , /* multi-value with glob A*|B* */
GL_SOMETHING , /* commonly used "?*" */
2008-10-24 15:32:32 +04:00
} ;
2009-06-06 06:52:52 +04:00
enum string_subst_type {
SB_UNSET ,
SB_NONE ,
SB_FORMAT ,
SB_SUBSYS ,
} ;
2008-10-24 12:51:04 +04:00
/* tokens of a rule are sorted/handled in this order */
2008-10-23 02:13:59 +04:00
enum token_type {
2008-10-24 15:32:32 +04:00
TK_UNSET ,
2008-10-23 02:13:59 +04:00
TK_RULE ,
TK_M_ACTION , /* val */
TK_M_DEVPATH , /* val */
TK_M_KERNEL , /* val */
TK_M_DEVLINK , /* val */
TK_M_NAME , /* val */
TK_M_ENV , /* val, attr */
2010-04-22 20:33:24 +04:00
TK_M_TAG , /* val */
2008-10-23 02:13:59 +04:00
TK_M_SUBSYSTEM , /* val */
TK_M_DRIVER , /* val */
2008-10-23 22:37:30 +04:00
TK_M_WAITFOR , /* val */
2008-10-23 02:13:59 +04:00
TK_M_ATTR , /* val, attr */
2008-11-01 19:32:16 +03:00
TK_M_PARENTS_MIN ,
2008-10-23 02:13:59 +04:00
TK_M_KERNELS , /* val */
TK_M_SUBSYSTEMS , /* val */
TK_M_DRIVERS , /* val */
TK_M_ATTRS , /* val, attr */
2008-10-24 13:38:05 +04:00
TK_M_PARENTS_MAX ,
2008-10-23 02:13:59 +04:00
TK_M_TEST , /* val, mode_t */
TK_M_PROGRAM , /* val */
TK_M_IMPORT_FILE , /* val */
TK_M_IMPORT_PROG , /* val */
2010-04-12 17:58:05 +04:00
TK_M_IMPORT_DB , /* val */
2010-05-31 03:13:03 +04:00
TK_M_IMPORT_CMDLINE , /* val */
2008-10-23 02:13:59 +04:00
TK_M_IMPORT_PARENT , /* val */
TK_M_RESULT , /* val */
2008-10-24 15:32:32 +04:00
TK_M_MAX ,
2008-10-23 02:13:59 +04:00
TK_A_STRING_ESCAPE_NONE ,
TK_A_STRING_ESCAPE_REPLACE ,
2009-02-25 13:18:15 +03:00
TK_A_INOTIFY_WATCH , /* int */
2008-10-23 02:13:59 +04:00
TK_A_DEVLINK_PRIO , /* int */
TK_A_OWNER , /* val */
TK_A_GROUP , /* val */
TK_A_MODE , /* val */
TK_A_OWNER_ID , /* uid_t */
TK_A_GROUP_ID , /* gid_t */
TK_A_MODE_ID , /* mode_t */
2010-05-20 19:09:04 +04:00
TK_A_STATIC_NODE , /* val */
2008-10-23 02:13:59 +04:00
TK_A_ENV , /* val, attr */
2010-04-22 20:12:36 +04:00
TK_A_TAG , /* val */
2008-10-23 02:13:59 +04:00
TK_A_NAME , /* val */
TK_A_DEVLINK , /* val */
TK_A_EVENT_TIMEOUT , /* int */
TK_A_ATTR , /* val, attr */
TK_A_RUN , /* val, bool */
TK_A_GOTO , /* size_t */
TK_END ,
2008-10-18 16:33:37 +04:00
} ;
2008-11-06 00:28:52 +03:00
/* we try to pack stuff in a way that we take only 12 bytes per token */
2008-11-01 23:05:25 +03:00
struct token {
union {
2010-05-20 19:09:04 +04:00
unsigned char type ; /* same in rule and key */
2008-11-01 23:05:25 +03:00
struct {
2009-06-06 01:27:11 +04:00
enum token_type type : 8 ;
2010-05-20 19:09:04 +04:00
bool can_set_name : 1 ;
bool has_static_node : 1 ;
unsigned int unused : 6 ;
2008-11-06 00:28:52 +03:00
unsigned short token_count ;
2008-11-01 23:05:25 +03:00
unsigned int label_off ;
unsigned short filename_off ;
unsigned short filename_line ;
} rule ;
struct {
2009-06-06 01:27:11 +04:00
enum token_type type : 8 ;
enum operation_type op : 8 ;
enum string_glob_type glob : 8 ;
2009-06-06 06:52:52 +04:00
enum string_subst_type subst : 4 ;
enum string_subst_type attrsubst : 4 ;
2008-11-01 23:05:25 +03:00
unsigned int value_off ;
union {
unsigned int attr_off ;
2009-09-09 20:18:17 +04:00
int devlink_unique ;
int fail_on_error ;
2008-11-01 23:05:25 +03:00
unsigned int rule_goto ;
mode_t mode ;
uid_t uid ;
gid_t gid ;
int devlink_prio ;
int event_timeout ;
2009-02-25 13:18:15 +03:00
int watch ;
2008-11-01 23:05:25 +03:00
} ;
} key ;
} ;
} ;
# define MAX_TK 64
struct rule_tmp {
struct udev_rules * rules ;
struct token rule ;
struct token token [ MAX_TK ] ;
unsigned int token_cur ;
} ;
2009-06-14 19:53:15 +04:00
# ifdef ENABLE_DEBUG
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
static const char * operation_str ( enum operation_type type )
{
static const char * operation_strs [ ] = {
[ OP_UNSET ] = " UNSET " ,
[ OP_MATCH ] = " match " ,
[ OP_NOMATCH ] = " nomatch " ,
[ OP_MATCH_MAX ] = " MATCH_MAX " ,
[ OP_ADD ] = " add " ,
[ OP_ASSIGN ] = " assign " ,
[ OP_ASSIGN_FINAL ] = " assign-final " ,
} ;
return operation_strs [ type ] ;
}
2008-11-01 23:05:25 +03:00
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
static const char * string_glob_str ( enum string_glob_type type )
{
static const char * string_glob_strs [ ] = {
[ GL_UNSET ] = " UNSET " ,
[ GL_PLAIN ] = " plain " ,
[ GL_GLOB ] = " glob " ,
[ GL_SPLIT ] = " split " ,
[ GL_SPLIT_GLOB ] = " split-glob " ,
[ GL_SOMETHING ] = " split-glob " ,
} ;
2008-11-01 23:05:25 +03:00
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
return string_glob_strs [ type ] ;
}
static const char * token_str ( enum token_type type )
{
static const char * token_strs [ ] = {
[ TK_UNSET ] = " UNSET " ,
[ TK_RULE ] = " RULE " ,
[ TK_M_ACTION ] = " M ACTION " ,
[ TK_M_DEVPATH ] = " M DEVPATH " ,
[ TK_M_KERNEL ] = " M KERNEL " ,
[ TK_M_DEVLINK ] = " M DEVLINK " ,
[ TK_M_NAME ] = " M NAME " ,
[ TK_M_ENV ] = " M ENV " ,
2010-04-22 20:33:24 +04:00
[ TK_M_TAG ] = " M TAG " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
[ TK_M_SUBSYSTEM ] = " M SUBSYSTEM " ,
[ TK_M_DRIVER ] = " M DRIVER " ,
[ TK_M_WAITFOR ] = " M WAITFOR " ,
[ TK_M_ATTR ] = " M ATTR " ,
[ TK_M_PARENTS_MIN ] = " M PARENTS_MIN " ,
[ TK_M_KERNELS ] = " M KERNELS " ,
[ TK_M_SUBSYSTEMS ] = " M SUBSYSTEMS " ,
[ TK_M_DRIVERS ] = " M DRIVERS " ,
[ TK_M_ATTRS ] = " M ATTRS " ,
[ TK_M_PARENTS_MAX ] = " M PARENTS_MAX " ,
[ TK_M_TEST ] = " M TEST " ,
[ TK_M_PROGRAM ] = " M PROGRAM " ,
[ TK_M_IMPORT_FILE ] = " M IMPORT_FILE " ,
[ TK_M_IMPORT_PROG ] = " M IMPORT_PROG " ,
2010-04-12 17:58:05 +04:00
[ TK_M_IMPORT_DB ] = " M IMPORT_DB " ,
2010-05-31 03:13:03 +04:00
[ TK_M_IMPORT_CMDLINE ] = " M IMPORT_CMDLINE " ,
2009-08-08 17:29:38 +04:00
[ TK_M_IMPORT_PARENT ] = " M IMPORT_PARENT " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
[ TK_M_RESULT ] = " M RESULT " ,
[ TK_M_MAX ] = " M MAX " ,
[ TK_A_STRING_ESCAPE_NONE ] = " A STRING_ESCAPE_NONE " ,
[ TK_A_STRING_ESCAPE_REPLACE ] = " A STRING_ESCAPE_REPLACE " ,
2009-02-11 20:38:56 +03:00
[ TK_A_INOTIFY_WATCH ] = " A INOTIFY_WATCH " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
[ TK_A_DEVLINK_PRIO ] = " A DEVLINK_PRIO " ,
[ TK_A_OWNER ] = " A OWNER " ,
[ TK_A_GROUP ] = " A GROUP " ,
[ TK_A_MODE ] = " A MODE " ,
[ TK_A_OWNER_ID ] = " A OWNER_ID " ,
[ TK_A_GROUP_ID ] = " A GROUP_ID " ,
2010-05-20 19:09:04 +04:00
[ TK_A_STATIC_NODE ] = " A STATIC_NODE " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
[ TK_A_MODE_ID ] = " A MODE_ID " ,
[ TK_A_ENV ] = " A ENV " ,
2010-04-22 20:12:36 +04:00
[ TK_A_TAG ] = " A ENV " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
[ TK_A_NAME ] = " A NAME " ,
[ TK_A_DEVLINK ] = " A DEVLINK " ,
[ TK_A_EVENT_TIMEOUT ] = " A EVENT_TIMEOUT " ,
[ TK_A_ATTR ] = " A ATTR " ,
[ TK_A_RUN ] = " A RUN " ,
[ TK_A_GOTO ] = " A GOTO " ,
[ TK_END ] = " END " ,
} ;
return token_strs [ type ] ;
}
2008-10-18 16:33:37 +04:00
2008-11-01 23:05:25 +03:00
static void dump_token ( struct udev_rules * rules , struct token * token )
{
enum token_type type = token - > type ;
enum operation_type op = token - > key . op ;
enum string_glob_type glob = token - > key . glob ;
const char * value = & rules - > buf [ token - > key . value_off ] ;
const char * attr = & rules - > buf [ token - > key . attr_off ] ;
2008-10-24 12:51:04 +04:00
2008-11-01 23:05:25 +03:00
switch ( type ) {
case TK_RULE :
{
const char * tks_ptr = ( char * ) rules - > tokens ;
const char * tk_ptr = ( char * ) token ;
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
unsigned int idx = ( tk_ptr - tks_ptr ) / sizeof ( struct token ) ;
2008-10-24 12:51:04 +04:00
2010-05-25 17:11:02 +04:00
dbg ( rules - > udev , " * RULE %s:%u, token: %u, count: %u, label: '%s' \n " ,
2008-11-01 23:05:25 +03:00
& rules - > buf [ token - > rule . filename_off ] , token - > rule . filename_line ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
idx , token - > rule . token_count ,
2010-05-25 17:11:02 +04:00
& rules - > buf [ token - > rule . label_off ] ) ;
2008-11-01 23:05:25 +03:00
break ;
}
case TK_M_ACTION :
case TK_M_DEVPATH :
case TK_M_KERNEL :
case TK_M_SUBSYSTEM :
case TK_M_DRIVER :
case TK_M_WAITFOR :
case TK_M_DEVLINK :
case TK_M_NAME :
case TK_M_KERNELS :
case TK_M_SUBSYSTEMS :
case TK_M_DRIVERS :
case TK_M_PROGRAM :
case TK_M_IMPORT_FILE :
case TK_M_IMPORT_PROG :
2010-04-12 17:58:05 +04:00
case TK_M_IMPORT_DB :
2010-05-31 03:13:03 +04:00
case TK_M_IMPORT_CMDLINE :
2008-11-01 23:05:25 +03:00
case TK_M_IMPORT_PARENT :
case TK_M_RESULT :
case TK_A_NAME :
case TK_A_DEVLINK :
case TK_A_OWNER :
case TK_A_GROUP :
case TK_A_MODE :
case TK_A_RUN :
dbg ( rules - > udev , " %s %s '%s'(%s) \n " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
token_str ( type ) , operation_str ( op ) , value , string_glob_str ( glob ) ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_M_ATTR :
case TK_M_ATTRS :
case TK_M_ENV :
case TK_A_ATTR :
case TK_A_ENV :
dbg ( rules - > udev , " %s %s '%s' '%s'(%s) \n " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
token_str ( type ) , operation_str ( op ) , attr , value , string_glob_str ( glob ) ) ;
2008-11-01 23:05:25 +03:00
break ;
2010-04-22 20:33:24 +04:00
case TK_M_TAG :
2010-04-22 20:12:36 +04:00
case TK_A_TAG :
dbg ( rules - > udev , " %s %s '%s' \n " , token_str ( type ) , operation_str ( op ) , value ) ;
break ;
2008-11-01 23:05:25 +03:00
case TK_A_STRING_ESCAPE_NONE :
case TK_A_STRING_ESCAPE_REPLACE :
2010-04-21 17:43:05 +04:00
dbg ( rules - > udev , " %s \n " , token_str ( type ) ) ;
break ;
2008-11-01 23:05:25 +03:00
case TK_M_TEST :
dbg ( rules - > udev , " %s %s '%s'(%s) %#o \n " ,
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
token_str ( type ) , operation_str ( op ) , value , string_glob_str ( glob ) , token - > key . mode ) ;
2008-11-01 23:05:25 +03:00
break ;
2009-02-25 13:18:15 +03:00
case TK_A_INOTIFY_WATCH :
2009-03-03 18:50:58 +03:00
dbg ( rules - > udev , " %s %u \n " , token_str ( type ) , token - > key . watch ) ;
2009-02-25 13:18:15 +03:00
break ;
2008-11-01 23:05:25 +03:00
case TK_A_DEVLINK_PRIO :
2010-05-20 19:09:04 +04:00
dbg ( rules - > udev , " %s %u \n " , token_str ( type ) , token - > key . devlink_prio ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_A_OWNER_ID :
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s %s %u \n " , token_str ( type ) , operation_str ( op ) , token - > key . uid ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_A_GROUP_ID :
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s %s %u \n " , token_str ( type ) , operation_str ( op ) , token - > key . gid ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_A_MODE_ID :
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s %s %#o \n " , token_str ( type ) , operation_str ( op ) , token - > key . mode ) ;
2008-11-01 23:05:25 +03:00
break ;
2010-05-20 19:09:04 +04:00
case TK_A_STATIC_NODE :
dbg ( rules - > udev , " %s '%s' \n " , token_str ( type ) , value ) ;
break ;
2008-11-01 23:05:25 +03:00
case TK_A_EVENT_TIMEOUT :
2010-05-20 19:09:04 +04:00
dbg ( rules - > udev , " %s %u \n " , token_str ( type ) , token - > key . event_timeout ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_A_GOTO :
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s '%s' %u \n " , token_str ( type ) , value , token - > key . rule_goto ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_END :
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " * %s \n " , token_str ( type ) ) ;
2008-11-01 23:05:25 +03:00
break ;
case TK_M_PARENTS_MIN :
case TK_M_PARENTS_MAX :
case TK_M_MAX :
case TK_UNSET :
dbg ( rules - > udev , " unknown type %u \n " , type ) ;
break ;
}
}
2008-10-24 12:51:04 +04:00
2008-11-01 23:05:25 +03:00
static void dump_rules ( struct udev_rules * rules )
{
unsigned int i ;
2008-10-24 12:51:04 +04:00
2008-11-01 23:05:25 +03:00
dbg ( rules - > udev , " dumping %u (%zu bytes) tokens, %u (%zu bytes) strings \n " ,
rules - > token_cur ,
rules - > token_cur * sizeof ( struct token ) ,
rules - > buf_count ,
rules - > buf_cur ) ;
for ( i = 0 ; i < rules - > token_cur ; i + + )
dump_token ( rules , & rules - > tokens [ i ] ) ;
}
# else
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
static inline const char * operation_str ( enum operation_type type ) { return NULL ; }
static inline const char * token_str ( enum token_type type ) { return NULL ; }
2008-11-01 23:05:25 +03:00
static inline void dump_token ( struct udev_rules * rules , struct token * token ) { }
static inline void dump_rules ( struct udev_rules * rules ) { }
2009-06-14 19:53:15 +04:00
# endif /* ENABLE_DEBUG */
2008-10-18 16:33:37 +04:00
2008-11-11 23:20:11 +03:00
static int add_new_string ( struct udev_rules * rules , const char * str , size_t bytes )
2008-10-18 16:33:37 +04:00
{
2008-10-23 02:13:59 +04:00
int off ;
2008-10-18 16:33:37 +04:00
2008-10-24 10:07:37 +04:00
/* grow buffer if needed */
2008-11-11 23:20:11 +03:00
if ( rules - > buf_cur + bytes + 1 > = rules - > buf_max ) {
2008-10-23 02:13:59 +04:00
char * buf ;
unsigned int add ;
2008-10-18 16:33:37 +04:00
2008-10-23 02:13:59 +04:00
/* double the buffer size */
add = rules - > buf_max ;
2008-11-11 23:20:11 +03:00
if ( add < bytes * 8 )
add = bytes * 8 ;
2008-10-18 16:33:37 +04:00
2008-10-23 02:13:59 +04:00
buf = realloc ( rules - > buf , rules - > buf_max + add ) ;
if ( buf = = NULL )
return - 1 ;
2008-11-01 22:16:24 +03:00
dbg ( rules - > udev , " extend buffer from %zu to %zu \n " , rules - > buf_max , rules - > buf_max + add ) ;
2008-10-23 02:13:59 +04:00
rules - > buf = buf ;
rules - > buf_max + = add ;
2008-10-18 16:33:37 +04:00
}
2008-10-23 02:13:59 +04:00
off = rules - > buf_cur ;
2008-11-11 23:20:11 +03:00
memcpy ( & rules - > buf [ rules - > buf_cur ] , str , bytes ) ;
rules - > buf_cur + = bytes ;
2008-10-23 02:13:59 +04:00
rules - > buf_count + + ;
return off ;
2008-10-18 16:33:37 +04:00
}
2008-11-11 23:20:11 +03:00
static int add_string ( struct udev_rules * rules , const char * str )
2008-10-18 16:33:37 +04:00
{
2008-11-12 07:50:05 +03:00
unsigned int node_idx ;
struct trie_node * new_node ;
unsigned int new_node_idx ;
2008-11-11 23:20:11 +03:00
unsigned char key ;
2008-11-12 07:50:05 +03:00
unsigned short len ;
2008-11-12 01:47:01 +03:00
unsigned int depth ;
2008-11-11 23:20:11 +03:00
unsigned int off ;
2008-11-13 02:52:12 +03:00
struct trie_node * parent ;
2008-11-11 23:20:11 +03:00
2008-11-13 02:52:12 +03:00
/* walk trie, start from last character of str to find matching tails */
2008-11-13 20:21:28 +03:00
len = strlen ( str ) ;
2008-11-13 02:52:12 +03:00
key = str [ len - 1 ] ;
2008-11-13 20:21:28 +03:00
node_idx = 0 ;
2008-11-13 02:52:12 +03:00
for ( depth = 0 ; depth < = len ; depth + + ) {
struct trie_node * node ;
unsigned int child_idx ;
node = & rules - > trie_nodes [ node_idx ] ;
off = node - > value_off + node - > value_len - len ;
/* match against current node */
if ( depth = = len | | ( node - > value_len > = len & & memcmp ( & rules - > buf [ off ] , str , len ) = = 0 ) )
return off ;
/* lookup child node */
key = str [ len - 1 - depth ] ;
child_idx = node - > child_idx ;
while ( child_idx > 0 ) {
struct trie_node * child ;
child = & rules - > trie_nodes [ child_idx ] ;
if ( child - > key = = key )
2008-11-11 23:20:11 +03:00
break ;
2008-11-13 02:52:12 +03:00
child_idx = child - > next_child_idx ;
2008-11-11 23:20:11 +03:00
}
2008-11-13 02:52:12 +03:00
if ( child_idx = = 0 )
break ;
node_idx = child_idx ;
2008-11-11 23:20:11 +03:00
}
/* string not found, add it */
off = add_new_string ( rules , str , len + 1 ) ;
2008-11-12 07:50:05 +03:00
/* grow trie nodes if needed */
if ( rules - > trie_nodes_cur > = rules - > trie_nodes_max ) {
struct trie_node * nodes ;
unsigned int add ;
2008-11-11 23:20:11 +03:00
/* double the buffer size */
2008-11-12 07:50:05 +03:00
add = rules - > trie_nodes_max ;
2008-11-11 23:20:11 +03:00
if ( add < 8 )
add = 8 ;
2008-11-12 07:50:05 +03:00
nodes = realloc ( rules - > trie_nodes , ( rules - > trie_nodes_max + add ) * sizeof ( struct trie_node ) ) ;
if ( nodes = = NULL )
2008-11-11 23:20:11 +03:00
return - 1 ;
2008-11-12 07:50:05 +03:00
dbg ( rules - > udev , " extend trie nodes from %u to %u \n " ,
rules - > trie_nodes_max , rules - > trie_nodes_max + add ) ;
rules - > trie_nodes = nodes ;
rules - > trie_nodes_max + = add ;
2008-11-11 23:20:11 +03:00
}
2008-11-13 02:52:12 +03:00
/* get a new node */
2008-11-12 07:50:05 +03:00
new_node_idx = rules - > trie_nodes_cur ;
rules - > trie_nodes_cur + + ;
new_node = & rules - > trie_nodes [ new_node_idx ] ;
2008-11-13 02:52:12 +03:00
memset ( new_node , 0x00 , sizeof ( struct trie_node ) ) ;
2008-11-12 07:50:05 +03:00
new_node - > value_off = off ;
new_node - > value_len = len ;
2008-11-13 02:52:12 +03:00
new_node - > key = key ;
2008-11-12 07:50:05 +03:00
2008-11-13 02:52:12 +03:00
/* join the parent's child list */
parent = & rules - > trie_nodes [ node_idx ] ;
if ( parent - > child_idx = = 0 ) {
parent - > child_idx = new_node_idx ;
2008-11-12 07:50:05 +03:00
} else {
2008-11-13 02:52:12 +03:00
struct trie_node * last_child ;
2008-11-11 23:20:11 +03:00
2008-11-13 02:52:12 +03:00
last_child = & rules - > trie_nodes [ parent - > last_child_idx ] ;
last_child - > next_child_idx = new_node_idx ;
2008-11-12 07:50:05 +03:00
}
2008-11-13 02:52:12 +03:00
parent - > last_child_idx = new_node_idx ;
2008-11-11 23:20:11 +03:00
return off ;
}
static int add_token ( struct udev_rules * rules , struct token * token )
{
2008-10-24 10:07:37 +04:00
/* grow buffer if needed */
2008-10-23 02:13:59 +04:00
if ( rules - > token_cur + 1 > = rules - > token_max ) {
struct token * tokens ;
unsigned int add ;
2008-10-18 16:33:37 +04:00
2008-10-23 02:13:59 +04:00
/* double the buffer size */
add = rules - > token_max ;
2008-10-24 12:51:04 +04:00
if ( add < 8 )
add = 8 ;
2008-10-18 16:33:37 +04:00
2008-10-23 02:13:59 +04:00
tokens = realloc ( rules - > tokens , ( rules - > token_max + add ) * sizeof ( struct token ) ) ;
if ( tokens = = NULL )
return - 1 ;
2008-11-01 22:16:24 +03:00
dbg ( rules - > udev , " extend tokens from %u to %u \n " , rules - > token_max , rules - > token_max + add ) ;
2008-10-23 02:13:59 +04:00
rules - > tokens = tokens ;
rules - > token_max + = add ;
2008-10-18 16:33:37 +04:00
}
2008-10-23 02:13:59 +04:00
memcpy ( & rules - > tokens [ rules - > token_cur ] , token , sizeof ( struct token ) ) ;
rules - > token_cur + + ;
return 0 ;
2008-10-18 16:33:37 +04:00
}
[PATCH] Adding '%s' format specifier to NAME and SYMLINK
On Thu, Feb 12, 2004 at 05:34:57PM -0800, Greg KH wrote:
> On Tue, Feb 10, 2004 at 09:14:20AM +0100, Hannes Reinecke wrote:
> > Hi all,
> >
> > this patch makes the format for NAME and SYMLINK a bit more flexible:
> > I've added a new format specifier '%s{<SYSFS_var>}', which allows for
> > the value of any sysfs entry found for this device to be inserted.
> > Example (for our S/390 fcp adapter):
> >
> > BUS="ccw", SYSFS_devtype="1732/03", NAME="%k" \
> > SYMLINK="zfcp-%s{hba_id}-%s{wwpn}:%s{fcp_lun}"
> >
> > I know this could also be done with an external program, but having this
> > incorporated into udev makes life easier, especially if run from
> > initramfs. Plus it makes the rules easier to follow, as the result is
> > directly visible and need not to be looked up in some external program.
> >
> > Comments etc. welcome.
>
> Oops, sorry I missed this for the 017 release. I'll look at it tomorrow
> and get back to you. At first glance it looks like a good thing.
>
> Oh, you forgot to update the documentation, that's important to do if
> you want this change to make it in :)
I took a part of the code and made a version that uses already implemented
attribute finding logic.
The parsing of the format length '%3x' and the '%x{attribute}' is a fuction now,
maybe there are more possible users in the future.
I've also added the test to udev-test.pl.
2004-02-17 08:36:34 +03:00
2008-10-24 12:51:04 +04:00
static uid_t add_uid ( struct udev_rules * rules , const char * owner )
{
unsigned int i ;
uid_t uid ;
unsigned int off ;
/* lookup, if we know it already */
for ( i = 0 ; i < rules - > uids_cur ; i + + ) {
off = rules - > uids [ i ] . name_off ;
if ( strcmp ( & rules - > buf [ off ] , owner ) = = 0 ) {
uid = rules - > uids [ i ] . uid ;
dbg ( rules - > udev , " return existing %u for '%s' \n " , uid , owner ) ;
return uid ;
}
}
uid = util_lookup_user ( rules - > udev , owner ) ;
/* grow buffer if needed */
if ( rules - > uids_cur + 1 > = rules - > uids_max ) {
struct uid_gid * uids ;
unsigned int add ;
/* double the buffer size */
add = rules - > uids_max ;
if ( add < 1 )
add = 8 ;
uids = realloc ( rules - > uids , ( rules - > uids_max + add ) * sizeof ( struct uid_gid ) ) ;
if ( uids = = NULL )
return uid ;
2008-11-01 22:16:24 +03:00
dbg ( rules - > udev , " extend uids from %u to %u \n " , rules - > uids_max , rules - > uids_max + add ) ;
2008-10-24 12:51:04 +04:00
rules - > uids = uids ;
rules - > uids_max + = add ;
}
rules - > uids [ rules - > uids_cur ] . uid = uid ;
off = add_string ( rules , owner ) ;
if ( off < = 0 )
return uid ;
rules - > uids [ rules - > uids_cur ] . name_off = off ;
rules - > uids_cur + + ;
return uid ;
}
static gid_t add_gid ( struct udev_rules * rules , const char * group )
{
unsigned int i ;
gid_t gid ;
unsigned int off ;
/* lookup, if we know it already */
for ( i = 0 ; i < rules - > gids_cur ; i + + ) {
off = rules - > gids [ i ] . name_off ;
if ( strcmp ( & rules - > buf [ off ] , group ) = = 0 ) {
gid = rules - > gids [ i ] . gid ;
2008-10-24 15:32:32 +04:00
dbg ( rules - > udev , " return existing %u for '%s' \n " , gid , group ) ;
2008-10-24 12:51:04 +04:00
return gid ;
}
}
gid = util_lookup_group ( rules - > udev , group ) ;
/* grow buffer if needed */
if ( rules - > gids_cur + 1 > = rules - > gids_max ) {
struct uid_gid * gids ;
unsigned int add ;
/* double the buffer size */
add = rules - > gids_max ;
if ( add < 1 )
add = 8 ;
gids = realloc ( rules - > gids , ( rules - > gids_max + add ) * sizeof ( struct uid_gid ) ) ;
if ( gids = = NULL )
return gid ;
2008-11-01 22:16:24 +03:00
dbg ( rules - > udev , " extend gids from %u to %u \n " , rules - > gids_max , rules - > gids_max + add ) ;
2008-10-24 12:51:04 +04:00
rules - > gids = gids ;
rules - > gids_max + = add ;
}
rules - > gids [ rules - > gids_cur ] . gid = gid ;
off = add_string ( rules , group ) ;
if ( off < = 0 )
return gid ;
rules - > gids [ rules - > gids_cur ] . name_off = off ;
rules - > gids_cur + + ;
return gid ;
}
2008-10-17 00:41:52 +04:00
static int import_property_from_string ( struct udev_device * dev , char * line )
2005-06-25 15:10:16 +04:00
{
2008-10-17 00:41:52 +04:00
struct udev * udev = udev_device_get_udev ( dev ) ;
char * key ;
char * val ;
size_t len ;
2005-06-25 15:10:16 +04:00
2008-10-17 00:41:52 +04:00
/* find key */
key = line ;
while ( isspace ( key [ 0 ] ) )
key + + ;
2005-06-25 15:10:16 +04:00
2008-10-17 00:41:52 +04:00
/* comment or empty line */
if ( key [ 0 ] = = ' # ' | | key [ 0 ] = = ' \0 ' )
return - 1 ;
2007-09-11 19:17:29 +04:00
2008-10-17 00:41:52 +04:00
/* split key/value */
val = strchr ( key , ' = ' ) ;
if ( val = = NULL )
return - 1 ;
val [ 0 ] = ' \0 ' ;
val + + ;
2008-10-16 19:16:58 +04:00
2008-10-17 00:41:52 +04:00
/* find value */
while ( isspace ( val [ 0 ] ) )
val + + ;
/* terminate key */
len = strlen ( key ) ;
if ( len = = 0 )
return - 1 ;
while ( isspace ( key [ len - 1 ] ) )
len - - ;
key [ len ] = ' \0 ' ;
/* terminate value */
len = strlen ( val ) ;
if ( len = = 0 )
return - 1 ;
while ( isspace ( val [ len - 1 ] ) )
len - - ;
val [ len ] = ' \0 ' ;
if ( len = = 0 )
return - 1 ;
/* unquote */
if ( val [ 0 ] = = ' " ' | | val [ 0 ] = = ' \' ' ) {
if ( val [ len - 1 ] ! = val [ 0 ] ) {
info ( udev , " inconsistent quoting: '%s', skip \n " , line ) ;
return - 1 ;
2005-06-25 15:10:16 +04:00
}
2008-10-17 00:41:52 +04:00
val [ len - 1 ] = ' \0 ' ;
val + + ;
}
2008-11-01 22:16:24 +03:00
dbg ( udev , " adding '%s'='%s' \n " , key , val ) ;
2008-10-17 00:41:52 +04:00
/* handle device, renamed by external tool, returning new path */
if ( strcmp ( key , " DEVPATH " ) = = 0 ) {
char syspath [ UTIL_PATH_SIZE ] ;
info ( udev , " updating devpath from '%s' to '%s' \n " ,
udev_device_get_devpath ( dev ) , val ) ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( syspath , sizeof ( syspath ) , udev_get_sys_path ( udev ) , val , NULL ) ;
2008-10-17 00:41:52 +04:00
udev_device_set_syspath ( dev , syspath ) ;
} else {
struct udev_list_entry * entry ;
entry = udev_device_add_property ( dev , key , val ) ;
2009-06-28 04:21:58 +04:00
/* store in db, skip private keys */
if ( key [ 0 ] ! = ' . ' )
2010-03-10 16:52:42 +03:00
udev_list_entry_set_flags ( entry , 1 ) ;
2005-06-25 15:10:16 +04:00
}
2005-06-25 17:35:14 +04:00
return 0 ;
}
2008-10-23 02:13:59 +04:00
static int import_file_into_properties ( struct udev_device * dev , const char * filename )
2005-06-25 17:35:14 +04:00
{
2008-10-17 00:41:52 +04:00
FILE * f ;
char line [ UTIL_LINE_SIZE ] ;
2005-06-25 17:35:14 +04:00
2008-10-17 00:41:52 +04:00
f = fopen ( filename , " r " ) ;
if ( f = = NULL )
2005-06-25 17:35:14 +04:00
return - 1 ;
2008-10-17 02:40:03 +04:00
while ( fgets ( line , sizeof ( line ) , f ) ! = NULL )
2008-10-17 00:41:52 +04:00
import_property_from_string ( dev , line ) ;
fclose ( f ) ;
2005-06-25 17:35:14 +04:00
return 0 ;
2005-06-25 15:10:16 +04:00
}
2008-10-23 02:13:59 +04:00
static int import_program_into_properties ( struct udev_device * dev , const char * program )
2005-06-25 20:58:49 +04:00
{
2008-10-18 17:25:05 +04:00
struct udev * udev = udev_device_get_udev ( dev ) ;
char * * envp ;
2010-11-12 16:39:14 +03:00
char result [ UTIL_LINE_SIZE ] ;
2005-06-25 20:58:49 +04:00
size_t reslen ;
2008-10-17 00:41:52 +04:00
char * line ;
2005-06-25 20:58:49 +04:00
2008-10-18 17:25:05 +04:00
envp = udev_device_get_properties_envp ( dev ) ;
2010-05-12 10:46:56 +04:00
if ( util_run_program ( udev , program , envp , result , sizeof ( result ) , & reslen , NULL , false ) ! = 0 )
2005-06-25 20:58:49 +04:00
return - 1 ;
2008-10-17 00:41:52 +04:00
line = result ;
while ( line ! = NULL ) {
char * pos ;
pos = strchr ( line , ' \n ' ) ;
if ( pos ! = NULL ) {
pos [ 0 ] = ' \0 ' ;
pos = & pos [ 1 ] ;
}
import_property_from_string ( dev , line ) ;
line = pos ;
}
return 0 ;
2005-06-25 20:58:49 +04:00
}
2008-10-23 02:13:59 +04:00
static int import_parent_into_properties ( struct udev_device * dev , const char * filter )
2005-07-12 16:46:36 +04:00
{
2008-10-17 00:41:52 +04:00
struct udev * udev = udev_device_get_udev ( dev ) ;
2008-10-16 19:16:58 +04:00
struct udev_device * dev_parent ;
struct udev_list_entry * list_entry ;
2005-07-12 16:46:36 +04:00
2008-10-17 00:41:52 +04:00
dev_parent = udev_device_get_parent ( dev ) ;
2008-10-16 19:16:58 +04:00
if ( dev_parent = = NULL )
return - 1 ;
2005-07-12 16:46:36 +04:00
2008-10-17 00:41:52 +04:00
dbg ( udev , " found parent '%s', get the node name \n " , udev_device_get_syspath ( dev_parent ) ) ;
2008-10-16 19:16:58 +04:00
udev_list_entry_foreach ( list_entry , udev_device_get_properties_list_entry ( dev_parent ) ) {
const char * key = udev_list_entry_get_name ( list_entry ) ;
const char * val = udev_list_entry_get_value ( list_entry ) ;
2005-07-12 16:46:36 +04:00
2008-10-16 19:16:58 +04:00
if ( fnmatch ( filter , key , 0 ) = = 0 ) {
struct udev_list_entry * entry ;
2007-07-14 22:59:03 +04:00
2008-10-17 00:41:52 +04:00
dbg ( udev , " import key '%s=%s' \n " , key , val ) ;
entry = udev_device_add_property ( dev , key , val ) ;
2009-06-28 04:21:58 +04:00
/* store in db, skip private keys */
if ( key [ 0 ] ! = ' . ' )
2010-03-10 16:52:42 +03:00
udev_list_entry_set_flags ( entry , 1 ) ;
2008-10-16 19:16:58 +04:00
}
2007-07-14 22:59:03 +04:00
}
2008-10-16 19:16:58 +04:00
return 0 ;
2007-07-14 22:59:03 +04:00
}
2005-11-12 06:17:48 +03:00
# define WAIT_LOOP_PER_SECOND 50
2008-10-23 02:13:59 +04:00
static int wait_for_file ( struct udev_device * dev , const char * file , int timeout )
2005-07-07 22:05:51 +04:00
{
2008-10-23 02:13:59 +04:00
struct udev * udev = udev_device_get_udev ( dev ) ;
2008-09-10 23:50:21 +04:00
char filepath [ UTIL_PATH_SIZE ] ;
2008-10-26 04:31:54 +03:00
char devicepath [ UTIL_PATH_SIZE ] ;
2005-07-07 22:05:51 +04:00
struct stat stats ;
int loop = timeout * WAIT_LOOP_PER_SECOND ;
2008-05-20 17:02:17 +04:00
/* a relative path is a device attribute */
2008-10-26 04:31:54 +03:00
devicepath [ 0 ] = ' \0 ' ;
2008-05-20 17:02:17 +04:00
if ( file [ 0 ] ! = ' / ' ) {
2009-05-20 19:57:52 +04:00
util_strscpyl ( devicepath , sizeof ( devicepath ) ,
udev_get_sys_path ( udev ) , udev_device_get_devpath ( dev ) , NULL ) ;
util_strscpyl ( filepath , sizeof ( filepath ) , devicepath , " / " , file , NULL ) ;
2008-05-20 17:02:17 +04:00
file = filepath ;
}
2008-10-23 02:13:59 +04:00
dbg ( udev , " will wait %i sec for '%s' \n " , timeout , file ) ;
2005-07-07 22:05:51 +04:00
while ( - - loop ) {
2009-08-31 01:58:57 +04:00
const struct timespec duration = { 0 , 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND } ;
2006-02-15 22:43:28 +03:00
/* lookup file */
2008-05-20 17:02:17 +04:00
if ( stat ( file , & stats ) = = 0 ) {
2008-10-23 02:13:59 +04:00
info ( udev , " file '%s' appeared after %i loops \n " , file , ( timeout * WAIT_LOOP_PER_SECOND ) - loop - 1 ) ;
2005-07-07 22:05:51 +04:00
return 0 ;
}
2007-03-19 11:56:53 +03:00
/* make sure, the device did not disappear in the meantime */
2008-05-20 17:02:17 +04:00
if ( devicepath [ 0 ] ! = ' \0 ' & & stat ( devicepath , & stats ) ! = 0 ) {
2008-10-23 02:13:59 +04:00
info ( udev , " device disappeared while waiting for '%s' \n " , file ) ;
2006-02-15 22:43:28 +03:00
return - 2 ;
}
2008-10-23 02:13:59 +04:00
info ( udev , " wait for '%s' for %i mseconds \n " , file , 1000 / WAIT_LOOP_PER_SECOND ) ;
2009-08-31 01:58:57 +04:00
nanosleep ( & duration , NULL ) ;
2005-07-07 22:05:51 +04:00
}
2008-10-23 02:13:59 +04:00
info ( udev , " waiting for '%s' failed \n " , file ) ;
2005-07-07 22:05:51 +04:00
return - 1 ;
}
2008-03-15 01:40:06 +03:00
static int attr_subst_subdir ( char * attr , size_t len )
{
2010-05-20 19:09:04 +04:00
bool found = false ;
2008-03-15 01:40:06 +03:00
2009-05-20 19:57:52 +04:00
if ( strstr ( attr , " /*/ " ) ) {
char * pos ;
char dirname [ UTIL_PATH_SIZE ] ;
const char * tail ;
2008-03-15 01:40:06 +03:00
DIR * dir ;
2009-05-20 19:57:52 +04:00
util_strscpy ( dirname , sizeof ( dirname ) , attr ) ;
pos = strstr ( dirname , " /*/ " ) ;
if ( pos = = NULL )
return - 1 ;
pos [ 0 ] = ' \0 ' ;
tail = & pos [ 2 ] ;
dir = opendir ( dirname ) ;
2008-03-15 01:40:06 +03:00
if ( dir ! = NULL ) {
struct dirent * dent ;
for ( dent = readdir ( dir ) ; dent ! = NULL ; dent = readdir ( dir ) ) {
struct stat stats ;
if ( dent - > d_name [ 0 ] = = ' . ' )
continue ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( attr , len , dirname , " / " , dent - > d_name , tail , NULL ) ;
2008-03-15 01:40:06 +03:00
if ( stat ( attr , & stats ) = = 0 ) {
2010-05-20 19:09:04 +04:00
found = true ;
2008-03-15 01:40:06 +03:00
break ;
}
}
closedir ( dir ) ;
}
}
return found ;
}
2008-10-24 13:38:05 +04:00
static int get_key ( struct udev * udev , char * * line , char * * key , enum operation_type * op , char * * value )
2005-07-04 21:44:25 +04:00
{
2008-10-23 02:13:59 +04:00
char * linepos ;
char * temp ;
2005-07-04 21:44:25 +04:00
2008-10-23 02:13:59 +04:00
linepos = * line ;
2009-09-01 14:15:54 +04:00
if ( linepos = = NULL | | linepos [ 0 ] = = ' \0 ' )
2008-10-23 02:13:59 +04:00
return - 1 ;
2005-07-04 21:44:25 +04:00
2008-10-23 02:13:59 +04:00
/* skip whitespace */
while ( isspace ( linepos [ 0 ] ) | | linepos [ 0 ] = = ' , ' )
linepos + + ;
2008-10-16 19:16:58 +04:00
2008-10-23 02:13:59 +04:00
/* get the key */
if ( linepos [ 0 ] = = ' \0 ' )
return - 1 ;
* key = linepos ;
2007-03-31 04:46:32 +04:00
2010-05-27 17:11:00 +04:00
for ( ; ; ) {
2008-10-23 02:13:59 +04:00
linepos + + ;
if ( linepos [ 0 ] = = ' \0 ' )
return - 1 ;
if ( isspace ( linepos [ 0 ] ) )
2007-03-31 04:46:32 +04:00
break ;
2008-10-23 02:13:59 +04:00
if ( linepos [ 0 ] = = ' = ' )
break ;
if ( ( linepos [ 0 ] = = ' + ' ) | | ( linepos [ 0 ] = = ' ! ' ) | | ( linepos [ 0 ] = = ' : ' ) )
if ( linepos [ 1 ] = = ' = ' )
2007-07-16 15:29:28 +04:00
break ;
2007-06-03 02:01:46 +04:00
}
2008-10-23 02:13:59 +04:00
/* remember end of key */
temp = linepos ;
2005-07-07 22:05:51 +04:00
2008-10-23 02:13:59 +04:00
/* skip whitespace after key */
while ( isspace ( linepos [ 0 ] ) )
linepos + + ;
if ( linepos [ 0 ] = = ' \0 ' )
return - 1 ;
2005-07-07 22:05:51 +04:00
2008-10-23 02:13:59 +04:00
/* get operation type */
if ( linepos [ 0 ] = = ' = ' & & linepos [ 1 ] = = ' = ' ) {
2008-10-24 13:38:05 +04:00
* op = OP_MATCH ;
2008-10-23 02:13:59 +04:00
linepos + = 2 ;
} else if ( linepos [ 0 ] = = ' ! ' & & linepos [ 1 ] = = ' = ' ) {
2008-10-24 13:38:05 +04:00
* op = OP_NOMATCH ;
2008-10-23 02:13:59 +04:00
linepos + = 2 ;
} else if ( linepos [ 0 ] = = ' + ' & & linepos [ 1 ] = = ' = ' ) {
2008-10-24 13:38:05 +04:00
* op = OP_ADD ;
2008-10-23 02:13:59 +04:00
linepos + = 2 ;
} else if ( linepos [ 0 ] = = ' = ' ) {
2008-10-24 13:38:05 +04:00
* op = OP_ASSIGN ;
2008-10-23 02:13:59 +04:00
linepos + + ;
} else if ( linepos [ 0 ] = = ' : ' & & linepos [ 1 ] = = ' = ' ) {
2008-10-24 13:38:05 +04:00
* op = OP_ASSIGN_FINAL ;
2008-10-23 02:13:59 +04:00
linepos + = 2 ;
} else
return - 1 ;
2006-08-20 20:16:27 +04:00
2008-10-23 02:13:59 +04:00
/* terminate key */
temp [ 0 ] = ' \0 ' ;
2006-08-19 18:06:25 +04:00
2008-10-23 02:13:59 +04:00
/* skip whitespace after operator */
while ( isspace ( linepos [ 0 ] ) )
linepos + + ;
if ( linepos [ 0 ] = = ' \0 ' )
return - 1 ;
2008-10-16 19:16:58 +04:00
2008-10-24 15:32:32 +04:00
/* get the value */
2008-10-23 02:13:59 +04:00
if ( linepos [ 0 ] = = ' " ' )
linepos + + ;
else
return - 1 ;
* value = linepos ;
2008-10-16 19:16:58 +04:00
2008-10-24 15:32:32 +04:00
/* terminate */
2008-10-23 02:13:59 +04:00
temp = strchr ( linepos , ' " ' ) ;
if ( ! temp )
return - 1 ;
temp [ 0 ] = ' \0 ' ;
temp + + ;
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( udev , " %s '%s'-'%s' \n " , operation_str ( * op ) , * key , * value ) ;
2008-10-16 19:16:58 +04:00
2008-10-23 02:13:59 +04:00
/* move line to next key */
* line = temp ;
return 0 ;
}
2006-08-19 18:06:25 +04:00
2008-10-23 02:13:59 +04:00
/* extract possible KEY{attr} */
static char * get_key_attribute ( struct udev * udev , char * str )
{
char * pos ;
char * attr ;
2006-08-19 18:06:25 +04:00
2008-10-23 02:13:59 +04:00
attr = strchr ( str , ' { ' ) ;
if ( attr ! = NULL ) {
attr + + ;
pos = strchr ( attr , ' } ' ) ;
if ( pos = = NULL ) {
err ( udev , " missing closing brace for format \n " ) ;
return NULL ;
2006-08-19 18:06:25 +04:00
}
2008-10-23 02:13:59 +04:00
pos [ 0 ] = ' \0 ' ;
dbg ( udev , " attribute='%s' \n " , attr ) ;
return attr ;
2006-08-19 18:06:25 +04:00
}
2008-10-23 02:13:59 +04:00
return NULL ;
}
2006-08-19 18:06:25 +04:00
2008-11-01 20:34:54 +03:00
static int rule_add_key ( struct rule_tmp * rule_tmp , enum token_type type ,
enum operation_type op ,
const char * value , const void * data )
2008-10-23 02:13:59 +04:00
{
struct token * token = & rule_tmp - > token [ rule_tmp - > token_cur ] ;
2009-06-06 06:52:52 +04:00
const char * attr = NULL ;
2008-10-24 15:32:32 +04:00
memset ( token , 0x00 , sizeof ( struct token ) ) ;
2008-10-23 02:13:59 +04:00
switch ( type ) {
case TK_M_ACTION :
case TK_M_DEVPATH :
case TK_M_KERNEL :
case TK_M_SUBSYSTEM :
case TK_M_DRIVER :
2008-10-23 22:37:30 +04:00
case TK_M_WAITFOR :
2008-10-23 02:13:59 +04:00
case TK_M_DEVLINK :
case TK_M_NAME :
case TK_M_KERNELS :
case TK_M_SUBSYSTEMS :
case TK_M_DRIVERS :
case TK_M_PROGRAM :
case TK_M_IMPORT_FILE :
case TK_M_IMPORT_PROG :
2010-04-12 17:58:05 +04:00
case TK_M_IMPORT_DB :
2010-05-31 03:13:03 +04:00
case TK_M_IMPORT_CMDLINE :
2008-10-23 02:13:59 +04:00
case TK_M_IMPORT_PARENT :
case TK_M_RESULT :
case TK_A_OWNER :
case TK_A_GROUP :
case TK_A_MODE :
case TK_A_NAME :
case TK_A_GOTO :
2010-04-22 20:33:24 +04:00
case TK_M_TAG :
2010-04-22 20:12:36 +04:00
case TK_A_TAG :
2008-10-23 02:13:59 +04:00
token - > key . value_off = add_string ( rule_tmp - > rules , value ) ;
2005-02-14 03:46:05 +03:00
break ;
2008-10-23 02:13:59 +04:00
case TK_M_ENV :
case TK_M_ATTR :
case TK_M_ATTRS :
case TK_A_ATTR :
case TK_A_ENV :
2009-06-06 06:52:52 +04:00
attr = data ;
2008-10-23 02:13:59 +04:00
token - > key . value_off = add_string ( rule_tmp - > rules , value ) ;
token - > key . attr_off = add_string ( rule_tmp - > rules , attr ) ;
break ;
2009-09-09 20:18:17 +04:00
case TK_A_DEVLINK :
token - > key . value_off = add_string ( rule_tmp - > rules , value ) ;
token - > key . devlink_unique = * ( int * ) data ;
break ;
2008-10-23 02:13:59 +04:00
case TK_M_TEST :
token - > key . value_off = add_string ( rule_tmp - > rules , value ) ;
2008-10-24 15:32:32 +04:00
if ( data ! = NULL )
token - > key . mode = * ( mode_t * ) data ;
2008-10-23 02:13:59 +04:00
break ;
case TK_A_STRING_ESCAPE_NONE :
case TK_A_STRING_ESCAPE_REPLACE :
2010-04-21 17:43:05 +04:00
break ;
2008-10-23 02:13:59 +04:00
case TK_A_RUN :
token - > key . value_off = add_string ( rule_tmp - > rules , value ) ;
2009-09-09 20:18:17 +04:00
token - > key . fail_on_error = * ( int * ) data ;
2008-10-23 02:13:59 +04:00
break ;
2009-02-25 13:18:15 +03:00
case TK_A_INOTIFY_WATCH :
2008-10-23 02:13:59 +04:00
case TK_A_DEVLINK_PRIO :
token - > key . devlink_prio = * ( int * ) data ;
break ;
case TK_A_OWNER_ID :
token - > key . uid = * ( uid_t * ) data ;
break ;
case TK_A_GROUP_ID :
token - > key . gid = * ( gid_t * ) data ;
break ;
case TK_A_MODE_ID :
token - > key . mode = * ( mode_t * ) data ;
break ;
2010-05-20 19:09:04 +04:00
case TK_A_STATIC_NODE :
token - > key . value_off = add_string ( rule_tmp - > rules , value ) ;
break ;
2008-10-23 02:13:59 +04:00
case TK_A_EVENT_TIMEOUT :
token - > key . event_timeout = * ( int * ) data ;
break ;
case TK_RULE :
2008-11-01 19:32:16 +03:00
case TK_M_PARENTS_MIN :
2008-10-24 13:38:05 +04:00
case TK_M_PARENTS_MAX :
2008-10-24 15:32:32 +04:00
case TK_M_MAX :
2008-10-23 02:13:59 +04:00
case TK_END :
2008-10-24 15:32:32 +04:00
case TK_UNSET :
2008-10-23 02:13:59 +04:00
err ( rule_tmp - > rules - > udev , " wrong type %u \n " , type ) ;
return - 1 ;
2004-01-23 11:21:13 +03:00
}
2008-10-24 15:32:32 +04:00
2009-05-21 01:12:22 +04:00
if ( value ! = NULL & & type < TK_M_MAX ) {
/* check if we need to split or call fnmatch() while matching rules */
2009-06-06 06:52:52 +04:00
enum string_glob_type glob ;
2009-05-21 01:12:22 +04:00
int has_split ;
int has_glob ;
has_split = ( strchr ( value , ' | ' ) ! = NULL ) ;
2009-06-06 06:52:52 +04:00
has_glob = ( strchr ( value , ' * ' ) ! = NULL | | strchr ( value , ' ? ' ) ! = NULL | | strchr ( value , ' [ ' ) ! = NULL ) ;
2009-05-21 01:12:22 +04:00
if ( has_split & & has_glob ) {
glob = GL_SPLIT_GLOB ;
} else if ( has_split ) {
glob = GL_SPLIT ;
} else if ( has_glob ) {
if ( strcmp ( value , " ?* " ) = = 0 )
glob = GL_SOMETHING ;
else
glob = GL_GLOB ;
2009-06-06 06:52:52 +04:00
} else {
glob = GL_PLAIN ;
2008-10-24 15:32:32 +04:00
}
2009-06-06 06:52:52 +04:00
token - > key . glob = glob ;
}
if ( value ! = NULL & & type > TK_M_MAX ) {
/* check if assigned value has substitution chars */
if ( value [ 0 ] = = ' [ ' )
token - > key . subst = SB_SUBSYS ;
else if ( strchr ( value , ' % ' ) ! = NULL | | strchr ( value , ' $ ' ) ! = NULL )
token - > key . subst = SB_FORMAT ;
else
token - > key . subst = SB_NONE ;
}
if ( attr ! = NULL ) {
/* check if property/attribut name has substitution chars */
if ( attr [ 0 ] = = ' [ ' )
token - > key . attrsubst = SB_SUBSYS ;
else if ( strchr ( attr , ' % ' ) ! = NULL | | strchr ( attr , ' $ ' ) ! = NULL )
token - > key . attrsubst = SB_FORMAT ;
else
token - > key . attrsubst = SB_NONE ;
2008-10-24 15:32:32 +04:00
}
2008-11-01 20:34:54 +03:00
token - > key . type = type ;
2008-10-23 02:13:59 +04:00
token - > key . op = op ;
rule_tmp - > token_cur + + ;
if ( rule_tmp - > token_cur > = ARRAY_SIZE ( rule_tmp - > token ) ) {
err ( rule_tmp - > rules - > udev , " temporary rule array too small \n " ) ;
return - 1 ;
2005-02-14 03:46:05 +03:00
}
2008-10-23 02:13:59 +04:00
return 0 ;
}
2005-02-14 03:46:05 +03:00
2008-10-23 02:13:59 +04:00
static int sort_token ( struct udev_rules * rules , struct rule_tmp * rule_tmp )
{
unsigned int i ;
unsigned int start = 0 ;
unsigned int end = rule_tmp - > token_cur ;
for ( i = 0 ; i < rule_tmp - > token_cur ; i + + ) {
2008-10-24 15:32:32 +04:00
enum token_type next_val = TK_UNSET ;
2009-09-09 00:11:04 +04:00
unsigned int next_idx = 0 ;
2008-10-23 02:13:59 +04:00
unsigned int j ;
/* find smallest value */
for ( j = start ; j < end ; j + + ) {
2008-10-24 15:32:32 +04:00
if ( rule_tmp - > token [ j ] . type = = TK_UNSET )
2008-10-23 02:13:59 +04:00
continue ;
2008-10-24 15:32:32 +04:00
if ( next_val = = TK_UNSET | | rule_tmp - > token [ j ] . type < next_val ) {
2008-10-23 02:13:59 +04:00
next_val = rule_tmp - > token [ j ] . type ;
next_idx = j ;
2007-04-25 03:52:00 +04:00
}
2005-08-16 06:25:20 +04:00
}
2008-10-23 02:13:59 +04:00
/* add token and mark done */
if ( add_token ( rules , & rule_tmp - > token [ next_idx ] ) ! = 0 )
return - 1 ;
2008-10-24 15:32:32 +04:00
rule_tmp - > token [ next_idx ] . type = TK_UNSET ;
2007-06-11 01:53:40 +04:00
2008-10-23 02:13:59 +04:00
/* shrink range */
if ( next_idx = = start )
start + + ;
if ( next_idx + 1 = = end )
end - - ;
2006-08-20 20:16:27 +04:00
}
2005-02-14 03:46:05 +03:00
return 0 ;
2004-01-23 11:21:13 +03:00
}
2008-10-23 02:13:59 +04:00
static int add_rule ( struct udev_rules * rules , char * line ,
const char * filename , unsigned int filename_off , unsigned int lineno )
2004-01-23 11:21:13 +03:00
{
2008-10-23 02:13:59 +04:00
char * linepos ;
char * attr ;
struct rule_tmp rule_tmp ;
2009-11-17 01:39:33 +03:00
bool bus_warn = false ;
bool sysfs_warn = false ;
bool id_warn = false ;
2004-01-23 11:21:13 +03:00
2008-10-23 02:13:59 +04:00
memset ( & rule_tmp , 0x00 , sizeof ( struct rule_tmp ) ) ;
rule_tmp . rules = rules ;
rule_tmp . rule . type = TK_RULE ;
rule_tmp . rule . rule . filename_off = filename_off ;
2008-11-01 20:34:54 +03:00
rule_tmp . rule . rule . filename_line = lineno ;
2004-01-23 11:21:13 +03:00
2008-10-23 02:13:59 +04:00
linepos = line ;
2010-05-27 17:11:00 +04:00
for ( ; ; ) {
2008-10-23 02:13:59 +04:00
char * key ;
char * value ;
2008-10-24 15:32:32 +04:00
enum operation_type op ;
2008-10-23 02:13:59 +04:00
if ( get_key ( rules - > udev , & linepos , & key , & op , & value ) ! = 0 )
2005-06-24 20:05:32 +04:00
break ;
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " ACTION " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-23 02:13:59 +04:00
err ( rules - > udev , " invalid ACTION operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_ACTION , op , value , NULL ) ;
2005-06-20 02:29:38 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " DEVPATH " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-23 02:13:59 +04:00
err ( rules - > udev , " invalid DEVPATH operation \n " ) ;
goto invalid ;
2005-02-14 08:03:06 +03:00
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_DEVPATH , op , value , NULL ) ;
2008-10-23 02:13:59 +04:00
continue ;
}
2008-10-18 16:33:37 +04:00
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " KERNEL " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid KERNEL operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_KERNEL , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " SUBSYSTEM " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid SUBSYSTEM operation \n " ) ;
goto invalid ;
}
/* bus, class, subsystem events should all be the same */
if ( strcmp ( value , " subsystem " ) = = 0 | |
strcmp ( value , " bus " ) = = 0 | |
strcmp ( value , " class " ) = = 0 ) {
if ( strcmp ( value , " bus " ) = = 0 | | strcmp ( value , " class " ) = = 0 )
err ( rules - > udev , " '%s' must be specified as 'subsystem' \n "
" please fix it in %s:%u " , value , filename , lineno ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_SUBSYSTEM , op , " subsystem|class|bus " , NULL ) ;
2008-10-18 16:33:37 +04:00
} else
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_SUBSYSTEM , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " DRIVER " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid DRIVER operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_DRIVER , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strncmp ( key , " ATTR{ " , sizeof ( " ATTR{ " ) - 1 ) = = 0 ) {
2008-10-23 02:13:59 +04:00
attr = get_key_attribute ( rules - > udev , key + sizeof ( " ATTR " ) - 1 ) ;
2008-10-18 16:33:37 +04:00
if ( attr = = NULL ) {
err ( rules - > udev , " error parsing ATTR attribute \n " ) ;
goto invalid ;
}
2008-10-24 13:38:05 +04:00
if ( op < OP_MATCH_MAX ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_ATTR , op , value , attr ) ;
2008-10-23 02:13:59 +04:00
} else {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_ATTR , op , value , attr ) ;
2008-10-23 02:13:59 +04:00
}
2008-10-18 16:33:37 +04:00
continue ;
}
2009-11-17 01:39:33 +03:00
if ( strcmp ( key , " KERNELS " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid KERNELS operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_KERNELS , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-11-17 01:39:33 +03:00
if ( strcmp ( key , " ID " ) = = 0 ) {
if ( ! id_warn ) {
id_warn = true ;
err ( rules - > udev , " ID= will be removed in a future udev version, "
" please use KERNEL= to match the event device, or KERNELS= "
" to match a parent device, in %s:%u \n " , filename , lineno ) ;
}
if ( op > OP_MATCH_MAX ) {
err ( rules - > udev , " invalid KERNELS operation \n " ) ;
goto invalid ;
}
rule_add_key ( & rule_tmp , TK_M_KERNELS , op , value , NULL ) ;
continue ;
}
if ( strcmp ( key , " SUBSYSTEMS " ) = = 0 ) {
if ( op > OP_MATCH_MAX ) {
err ( rules - > udev , " invalid SUBSYSTEMS operation \n " ) ;
goto invalid ;
}
rule_add_key ( & rule_tmp , TK_M_SUBSYSTEMS , op , value , NULL ) ;
continue ;
}
if ( strcmp ( key , " BUS " ) = = 0 ) {
if ( ! bus_warn ) {
bus_warn = true ;
err ( rules - > udev , " BUS= will be removed in a future udev version, "
" please use SUBSYSTEM= to match the event device, or SUBSYSTEMS= "
" to match a parent device, in %s:%u \n " , filename , lineno ) ;
}
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid SUBSYSTEMS operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_SUBSYSTEMS , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " DRIVERS " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid DRIVERS operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_DRIVERS , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-11-17 01:39:33 +03:00
if ( strncmp ( key , " ATTRS{ " , sizeof ( " ATTRS{ " ) - 1 ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid ATTRS operation \n " ) ;
goto invalid ;
}
2008-10-23 02:13:59 +04:00
attr = get_key_attribute ( rules - > udev , key + sizeof ( " ATTRS " ) - 1 ) ;
2008-10-18 16:33:37 +04:00
if ( attr = = NULL ) {
err ( rules - > udev , " error parsing ATTRS attribute \n " ) ;
goto invalid ;
}
if ( strncmp ( attr , " device/ " , 7 ) = = 0 )
err ( rules - > udev , " the 'device' link may not be available in a future kernel, "
" please fix it in %s:%u " , filename , lineno ) ;
else if ( strstr ( attr , " ../ " ) ! = NULL )
err ( rules - > udev , " do not reference parent sysfs directories directly, "
" it may break with a future kernel, please fix it in %s:%u " , filename , lineno ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_ATTRS , op , value , attr ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-11-17 01:39:33 +03:00
if ( strncmp ( key , " SYSFS{ " , sizeof ( " SYSFS{ " ) - 1 ) = = 0 ) {
if ( ! sysfs_warn ) {
sysfs_warn = true ;
err ( rules - > udev , " SYSFS{}= will be removed in a future udev version, "
" please use ATTR{}= to match the event device, or ATTRS{}= "
" to match a parent device, in %s:%u \n " , filename , lineno ) ;
}
if ( op > OP_MATCH_MAX ) {
err ( rules - > udev , " invalid ATTRS operation \n " ) ;
goto invalid ;
}
attr = get_key_attribute ( rules - > udev , key + sizeof ( " ATTRS " ) - 1 ) ;
if ( attr = = NULL ) {
err ( rules - > udev , " error parsing ATTRS attribute \n " ) ;
goto invalid ;
}
rule_add_key ( & rule_tmp , TK_M_ATTRS , op , value , attr ) ;
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strncmp ( key , " ENV{ " , sizeof ( " ENV{ " ) - 1 ) = = 0 ) {
2008-10-23 02:13:59 +04:00
attr = get_key_attribute ( rules - > udev , key + sizeof ( " ENV " ) - 1 ) ;
2008-10-18 16:33:37 +04:00
if ( attr = = NULL ) {
err ( rules - > udev , " error parsing ENV attribute \n " ) ;
goto invalid ;
}
2008-10-24 13:38:05 +04:00
if ( op < OP_MATCH_MAX ) {
2008-11-01 20:34:54 +03:00
if ( rule_add_key ( & rule_tmp , TK_M_ENV , op , value , attr ) ! = 0 )
2008-10-23 02:13:59 +04:00
goto invalid ;
} else {
2008-11-01 20:34:54 +03:00
if ( rule_add_key ( & rule_tmp , TK_A_ENV , op , value , attr ) ! = 0 )
2008-10-23 02:13:59 +04:00
goto invalid ;
}
2008-10-18 16:33:37 +04:00
continue ;
}
2010-04-22 20:12:36 +04:00
if ( strcmp ( key , " TAG " ) = = 0 ) {
2010-04-22 20:33:24 +04:00
if ( op < OP_MATCH_MAX )
rule_add_key ( & rule_tmp , TK_M_TAG , op , value , NULL ) ;
else
rule_add_key ( & rule_tmp , TK_A_TAG , op , value , NULL ) ;
2010-04-22 20:12:36 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " PROGRAM " ) = = 0 ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_PROGRAM , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " RESULT " ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid RESULT operation \n " ) ;
goto invalid ;
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_RESULT , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strncmp ( key , " IMPORT " , sizeof ( " IMPORT " ) - 1 ) = = 0 ) {
2008-10-23 02:13:59 +04:00
attr = get_key_attribute ( rules - > udev , key + sizeof ( " IMPORT " ) - 1 ) ;
2008-10-18 16:33:37 +04:00
if ( attr ! = NULL & & strstr ( attr , " program " ) ) {
dbg ( rules - > udev , " IMPORT will be executed \n " ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_IMPORT_PROG , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
} else if ( attr ! = NULL & & strstr ( attr , " file " ) ) {
dbg ( rules - > udev , " IMPORT will be included as file \n " ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_IMPORT_FILE , op , value , NULL ) ;
2010-04-12 17:58:05 +04:00
} else if ( attr ! = NULL & & strstr ( attr , " db " ) ) {
dbg ( rules - > udev , " IMPORT will include db values \n " ) ;
rule_add_key ( & rule_tmp , TK_M_IMPORT_DB , op , value , NULL ) ;
2010-05-31 03:13:03 +04:00
} else if ( attr ! = NULL & & strstr ( attr , " cmdline " ) ) {
dbg ( rules - > udev , " IMPORT will include db values \n " ) ;
rule_add_key ( & rule_tmp , TK_M_IMPORT_CMDLINE , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
} else if ( attr ! = NULL & & strstr ( attr , " parent " ) ) {
dbg ( rules - > udev , " IMPORT will include the parent values \n " ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_IMPORT_PARENT , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
} else {
/* figure it out if it is executable */
char file [ UTIL_PATH_SIZE ] ;
char * pos ;
struct stat statbuf ;
2009-05-20 19:57:52 +04:00
/* allow programs in /lib/udev called without the path */
if ( value [ 0 ] ! = ' / ' )
2009-06-17 04:25:07 +04:00
util_strscpyl ( file , sizeof ( file ) , LIBEXECDIR " / " , value , NULL ) ;
2009-05-20 19:57:52 +04:00
else
util_strscpy ( file , sizeof ( file ) , value ) ;
2008-10-18 16:33:37 +04:00
pos = strchr ( file , ' ' ) ;
if ( pos )
pos [ 0 ] = ' \0 ' ;
dbg ( rules - > udev , " IMPORT auto mode for '%s' \n " , file ) ;
2009-05-20 19:57:52 +04:00
if ( stat ( file , & statbuf ) = = 0 & & ( statbuf . st_mode & S_IXUSR ) ) {
2008-10-23 02:13:59 +04:00
dbg ( rules - > udev , " IMPORT will be executed (autotype) \n " ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_IMPORT_PROG , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
} else {
2008-10-23 02:13:59 +04:00
dbg ( rules - > udev , " IMPORT will be included as file (autotype) \n " ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_IMPORT_FILE , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
}
}
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strncmp ( key , " TEST " , sizeof ( " TEST " ) - 1 ) = = 0 ) {
2008-10-23 02:13:59 +04:00
mode_t mode = 0 ;
2008-10-24 13:38:05 +04:00
if ( op > OP_MATCH_MAX ) {
2008-10-18 16:33:37 +04:00
err ( rules - > udev , " invalid TEST operation \n " ) ;
goto invalid ;
}
2008-10-23 02:13:59 +04:00
attr = get_key_attribute ( rules - > udev , key + sizeof ( " TEST " ) - 1 ) ;
if ( attr ! = NULL ) {
mode = strtol ( attr , NULL , 8 ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_TEST , op , value , & mode ) ;
2008-10-23 02:13:59 +04:00
} else {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_TEST , op , value , NULL ) ;
2008-10-23 02:13:59 +04:00
}
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strncmp ( key , " RUN " , sizeof ( " RUN " ) - 1 ) = = 0 ) {
2008-10-23 02:13:59 +04:00
int flag = 0 ;
attr = get_key_attribute ( rules - > udev , key + sizeof ( " RUN " ) - 1 ) ;
2009-08-06 21:23:06 +04:00
if ( attr ! = NULL & & strstr ( attr , " fail_event_on_error " ) )
2008-10-23 02:13:59 +04:00
flag = 1 ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_RUN , op , value , & flag ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " WAIT_FOR " ) = = 0 | | strcmp ( key , " WAIT_FOR_SYSFS " ) = = 0 ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_WAITFOR , 0 , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " LABEL " ) = = 0 ) {
2008-10-23 02:13:59 +04:00
rule_tmp . rule . rule . label_off = add_string ( rules , value ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " GOTO " ) = = 0 ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_GOTO , 0 , value , NULL ) ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strncmp ( key , " NAME " , sizeof ( " NAME " ) - 1 ) = = 0 ) {
2008-10-24 13:38:05 +04:00
if ( op < OP_MATCH_MAX ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_NAME , op , value , NULL ) ;
2008-10-23 02:13:59 +04:00
} else {
2010-05-05 13:14:50 +04:00
if ( strcmp ( value , " %k " ) = = 0 ) {
2010-05-08 00:57:20 +04:00
err ( rules - > udev , " NAME= \" %%k \" is ignored, because it breaks kernel supplied names, "
2010-05-05 13:14:50 +04:00
" please remove it from %s:%u \n " , filename , lineno ) ;
continue ;
}
2010-05-08 00:57:20 +04:00
if ( value [ 0 ] = = ' \0 ' ) {
info ( rules - > udev , " NAME= \" \" is ignored, because udev will not delete any device nodes, "
" please remove it from %s:%u \n " , filename , lineno ) ;
2010-05-05 13:14:50 +04:00
continue ;
2010-05-08 00:57:20 +04:00
}
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_NAME , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
}
2010-05-20 19:09:04 +04:00
rule_tmp . rule . rule . can_set_name = true ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-09-16 20:14:03 +04:00
if ( strncmp ( key , " SYMLINK " , sizeof ( " SYMLINK " ) - 1 ) = = 0 ) {
2009-09-09 20:18:17 +04:00
if ( op < OP_MATCH_MAX ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_M_DEVLINK , op , value , NULL ) ;
2009-09-09 20:18:17 +04:00
} else {
int flag = 0 ;
attr = get_key_attribute ( rules - > udev , key + sizeof ( " SYMLINK " ) - 1 ) ;
if ( attr ! = NULL & & strstr ( attr , " unique " ) ! = NULL )
flag = 1 ;
rule_add_key ( & rule_tmp , TK_A_DEVLINK , op , value , & flag ) ;
}
2010-05-20 19:09:04 +04:00
rule_tmp . rule . rule . can_set_name = true ;
2008-10-24 13:38:05 +04:00
continue ;
}
2008-10-18 16:33:37 +04:00
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " OWNER " ) = = 0 ) {
2008-10-23 02:13:59 +04:00
uid_t uid ;
char * endptr ;
uid = strtoul ( value , & endptr , 10 ) ;
if ( endptr [ 0 ] = = ' \0 ' ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_OWNER_ID , op , NULL , & uid ) ;
2009-01-21 00:33:02 +03:00
} else if ( ( rules - > resolve_names > 0 ) & & strchr ( " $% " , value [ 0 ] ) = = NULL ) {
2008-10-24 12:51:04 +04:00
uid = add_uid ( rules , value ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_OWNER_ID , op , NULL , & uid ) ;
2009-05-14 15:42:44 +04:00
} else if ( rules - > resolve_names > = 0 ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_OWNER , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
}
2010-05-20 19:09:04 +04:00
rule_tmp . rule . rule . can_set_name = true ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " GROUP " ) = = 0 ) {
2008-10-23 02:13:59 +04:00
gid_t gid ;
char * endptr ;
gid = strtoul ( value , & endptr , 10 ) ;
if ( endptr [ 0 ] = = ' \0 ' ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_GROUP_ID , op , NULL , & gid ) ;
2009-01-21 00:33:02 +03:00
} else if ( ( rules - > resolve_names > 0 ) & & strchr ( " $% " , value [ 0 ] ) = = NULL ) {
2008-10-24 12:51:04 +04:00
gid = add_gid ( rules , value ) ;
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_GROUP_ID , op , NULL , & gid ) ;
2009-05-14 15:42:44 +04:00
} else if ( rules - > resolve_names > = 0 ) {
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_GROUP , op , value , NULL ) ;
2008-10-18 16:33:37 +04:00
}
2010-05-20 19:09:04 +04:00
rule_tmp . rule . rule . can_set_name = true ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " MODE " ) = = 0 ) {
2008-10-23 02:13:59 +04:00
mode_t mode ;
char * endptr ;
mode = strtol ( value , & endptr , 8 ) ;
if ( endptr [ 0 ] = = ' \0 ' )
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_MODE_ID , op , NULL , & mode ) ;
2008-10-23 02:13:59 +04:00
else
2008-11-01 20:34:54 +03:00
rule_add_key ( & rule_tmp , TK_A_MODE , op , value , NULL ) ;
2010-05-20 19:09:04 +04:00
rule_tmp . rule . rule . can_set_name = true ;
2008-10-18 16:33:37 +04:00
continue ;
}
2009-05-21 01:45:32 +04:00
if ( strcmp ( key , " OPTIONS " ) = = 0 ) {
2008-10-18 16:33:37 +04:00
const char * pos ;
pos = strstr ( value , " link_priority= " ) ;
if ( pos ! = NULL ) {
2008-10-23 02:13:59 +04:00
int prio = atoi ( & pos [ strlen ( " link_priority= " ) ] ) ;
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_DEVLINK_PRIO , op , NULL , & prio ) ;
2008-10-23 02:13:59 +04:00
dbg ( rules - > udev , " link priority=%i \n " , prio ) ;
2008-10-18 16:33:37 +04:00
}
pos = strstr ( value , " event_timeout= " ) ;
if ( pos ! = NULL ) {
2008-10-23 02:13:59 +04:00
int tout = atoi ( & pos [ strlen ( " event_timeout= " ) ] ) ;
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_EVENT_TIMEOUT , op , NULL , & tout ) ;
2009-08-08 17:29:38 +04:00
dbg ( rules - > udev , " event timeout=%i \n " , tout ) ;
2008-10-18 16:33:37 +04:00
}
pos = strstr ( value , " string_escape= " ) ;
if ( pos ! = NULL ) {
pos = & pos [ strlen ( " string_escape= " ) ] ;
if ( strncmp ( pos , " none " , strlen ( " none " ) ) = = 0 )
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_STRING_ESCAPE_NONE , op , NULL , NULL ) ;
2008-10-18 16:33:37 +04:00
else if ( strncmp ( pos , " replace " , strlen ( " replace " ) ) = = 0 )
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_STRING_ESCAPE_REPLACE , op , NULL , NULL ) ;
2008-10-18 16:33:37 +04:00
}
2009-02-25 13:18:15 +03:00
pos = strstr ( value , " nowatch " ) ;
2009-02-11 20:38:56 +03:00
if ( pos ! = NULL ) {
2009-02-25 13:18:15 +03:00
const int off = 0 ;
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_INOTIFY_WATCH , op , NULL , & off ) ;
2009-02-25 13:18:15 +03:00
dbg ( rules - > udev , " inotify watch of device disabled \n " ) ;
} else {
pos = strstr ( value , " watch " ) ;
if ( pos ! = NULL ) {
const int on = 1 ;
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_INOTIFY_WATCH , op , NULL , & on ) ;
2009-02-25 13:18:15 +03:00
dbg ( rules - > udev , " inotify watch of device requested \n " ) ;
}
2009-02-11 20:38:56 +03:00
}
2010-05-20 19:09:04 +04:00
pos = strstr ( value , " static_node= " ) ;
if ( pos ! = NULL ) {
2010-07-07 13:35:40 +04:00
rule_add_key ( & rule_tmp , TK_A_STATIC_NODE , op , & pos [ strlen ( " static_node= " ) ] , NULL ) ;
2010-05-20 19:09:04 +04:00
rule_tmp . rule . rule . has_static_node = true ;
}
2008-10-18 16:33:37 +04:00
continue ;
}
err ( rules - > udev , " unknown key '%s' in %s:%u \n " , key , filename , lineno ) ;
}
2008-10-23 02:13:59 +04:00
/* add rule token */
2008-11-06 00:28:52 +03:00
rule_tmp . rule . rule . token_count = 1 + rule_tmp . token_cur ;
2008-10-23 02:13:59 +04:00
if ( add_token ( rules , & rule_tmp . rule ) ! = 0 )
goto invalid ;
2008-10-18 16:33:37 +04:00
2008-10-23 02:13:59 +04:00
/* add tokens to list, sorted by type */
if ( sort_token ( rules , & rule_tmp ) ! = 0 )
goto invalid ;
2008-11-06 00:28:52 +03:00
2008-10-23 02:13:59 +04:00
return 0 ;
2008-10-18 16:33:37 +04:00
invalid :
err ( rules - > udev , " invalid rule '%s:%u' \n " , filename , lineno ) ;
return - 1 ;
}
2008-11-01 20:34:54 +03:00
static int parse_file ( struct udev_rules * rules , const char * filename , unsigned short filename_off )
2008-10-18 16:33:37 +04:00
{
FILE * f ;
2009-09-06 18:53:14 +04:00
unsigned int first_token ;
2008-10-18 16:33:37 +04:00
char line [ UTIL_LINE_SIZE ] ;
2008-10-23 02:13:59 +04:00
int line_nr = 0 ;
unsigned int i ;
2008-10-18 16:33:37 +04:00
info ( rules - > udev , " reading '%s' as rules file \n " , filename ) ;
f = fopen ( filename , " r " ) ;
if ( f = = NULL )
return - 1 ;
2009-09-06 18:53:14 +04:00
first_token = rules - > token_cur ;
2009-09-07 14:15:29 +04:00
while ( fgets ( line , sizeof ( line ) , f ) ! = NULL ) {
2008-10-18 16:33:37 +04:00
char * key ;
size_t len ;
/* skip whitespace */
line_nr + + ;
key = line ;
while ( isspace ( key [ 0 ] ) )
key + + ;
/* comment */
if ( key [ 0 ] = = ' # ' )
continue ;
len = strlen ( line ) ;
if ( len < 3 )
continue ;
/* continue reading if backslash+newline is found */
while ( line [ len - 2 ] = = ' \\ ' ) {
if ( fgets ( & line [ len - 2 ] , ( sizeof ( line ) - len ) + 2 , f ) = = NULL )
break ;
2009-09-01 15:26:37 +04:00
if ( strlen ( & line [ len - 2 ] ) < 2 )
break ;
2008-10-18 16:33:37 +04:00
line_nr + + ;
len = strlen ( line ) ;
}
if ( len + 1 > = sizeof ( line ) ) {
err ( rules - > udev , " line too long '%s':%u, ignored \n " , filename , line_nr ) ;
continue ;
}
2008-10-23 02:13:59 +04:00
add_rule ( rules , key , filename , filename_off , line_nr ) ;
2008-10-18 16:33:37 +04:00
}
fclose ( f ) ;
2008-10-23 02:13:59 +04:00
/* link GOTOs to LABEL rules in this file to be able to fast-forward */
2009-09-06 18:53:14 +04:00
for ( i = first_token + 1 ; i < rules - > token_cur ; i + + ) {
2008-10-23 02:13:59 +04:00
if ( rules - > tokens [ i ] . type = = TK_A_GOTO ) {
char * label = & rules - > buf [ rules - > tokens [ i ] . key . value_off ] ;
unsigned int j ;
for ( j = i + 1 ; j < rules - > token_cur ; j + + ) {
if ( rules - > tokens [ j ] . type ! = TK_RULE )
continue ;
if ( rules - > tokens [ j ] . rule . label_off = = 0 )
continue ;
if ( strcmp ( label , & rules - > buf [ rules - > tokens [ j ] . rule . label_off ] ) ! = 0 )
continue ;
rules - > tokens [ i ] . key . rule_goto = j ;
2009-05-13 20:01:32 +04:00
break ;
2008-10-18 16:33:37 +04:00
}
2008-10-23 02:13:59 +04:00
if ( rules - > tokens [ i ] . key . rule_goto = = 0 )
err ( rules - > udev , " GOTO '%s' has no matching label in: '%s' \n " , label , filename ) ;
2008-10-18 16:33:37 +04:00
}
}
return 0 ;
}
static int add_matching_files ( struct udev * udev , struct udev_list_node * file_list , const char * dirname , const char * suffix )
{
DIR * dir ;
char filename [ UTIL_PATH_SIZE ] ;
dbg ( udev , " open directory '%s' \n " , dirname ) ;
dir = opendir ( dirname ) ;
if ( dir = = NULL ) {
2009-01-15 19:52:17 +03:00
info ( udev , " unable to open '%s': %m \n " , dirname ) ;
2008-10-18 16:33:37 +04:00
return - 1 ;
}
2010-05-27 17:11:00 +04:00
for ( ; ; ) {
2008-11-06 19:43:12 +03:00
struct dirent * dent ;
dent = readdir ( dir ) ;
if ( dent = = NULL | | dent - > d_name [ 0 ] = = ' \0 ' )
2008-10-18 16:33:37 +04:00
break ;
2008-11-06 19:43:12 +03:00
if ( dent - > d_name [ 0 ] = = ' . ' )
2008-10-18 16:33:37 +04:00
continue ;
/* look for file matching with specified suffix */
if ( suffix ! = NULL ) {
const char * ext ;
2008-11-06 19:43:12 +03:00
ext = strrchr ( dent - > d_name , ' . ' ) ;
2008-10-18 16:33:37 +04:00
if ( ext = = NULL )
continue ;
if ( strcmp ( ext , suffix ) ! = 0 )
continue ;
}
2009-05-20 20:58:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , dirname , " / " , dent - > d_name , NULL ) ;
dbg ( udev , " put file '%s' into list \n " , filename ) ;
2008-10-18 16:33:37 +04:00
udev_list_entry_add ( udev , file_list , filename , NULL , 1 , 1 ) ;
}
closedir ( dir ) ;
return 0 ;
}
2008-10-18 17:02:01 +04:00
struct udev_rules * udev_rules_new ( struct udev * udev , int resolve_names )
2008-10-18 16:33:37 +04:00
{
2008-10-18 17:02:01 +04:00
struct udev_rules * rules ;
2008-10-18 16:33:37 +04:00
struct stat statbuf ;
struct udev_list_node file_list ;
struct udev_list_entry * file_loop , * file_tmp ;
2008-10-23 02:13:59 +04:00
struct token end_token ;
2008-10-18 16:33:37 +04:00
2010-08-03 10:10:26 +04:00
rules = calloc ( 1 , sizeof ( struct udev_rules ) ) ;
2008-10-18 17:02:01 +04:00
if ( rules = = NULL )
2008-10-23 02:13:59 +04:00
return NULL ;
2008-10-18 16:33:37 +04:00
rules - > udev = udev ;
rules - > resolve_names = resolve_names ;
udev_list_init ( & file_list ) ;
2008-10-23 02:13:59 +04:00
/* init token array and string buffer */
rules - > tokens = malloc ( PREALLOC_TOKEN * sizeof ( struct token ) ) ;
2010-08-02 14:31:18 +04:00
if ( rules - > tokens = = NULL ) {
free ( rules ) ;
2008-10-24 10:07:37 +04:00
return NULL ;
2010-08-02 14:31:18 +04:00
}
2008-10-24 10:07:37 +04:00
rules - > token_max = PREALLOC_TOKEN ;
2008-11-12 07:50:05 +03:00
2008-10-23 02:13:59 +04:00
rules - > buf = malloc ( PREALLOC_STRBUF ) ;
2010-08-02 14:31:18 +04:00
if ( rules - > buf = = NULL ) {
free ( rules - > tokens ) ;
free ( rules ) ;
2008-10-24 10:07:37 +04:00
return NULL ;
2010-08-02 14:31:18 +04:00
}
2008-10-24 10:07:37 +04:00
rules - > buf_max = PREALLOC_STRBUF ;
/* offset 0 is always '\0' */
rules - > buf [ 0 ] = ' \0 ' ;
rules - > buf_cur = 1 ;
2008-11-01 22:16:24 +03:00
dbg ( udev , " prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer \n " ,
rules - > token_max * sizeof ( struct token ) , rules - > token_max , sizeof ( struct token ) , rules - > buf_max ) ;
2008-10-23 02:13:59 +04:00
2008-11-12 07:50:05 +03:00
rules - > trie_nodes = malloc ( PREALLOC_TRIE * sizeof ( struct trie_node ) ) ;
2010-08-02 14:31:18 +04:00
if ( rules - > trie_nodes = = NULL ) {
free ( rules - > buf ) ;
free ( rules - > tokens ) ;
free ( rules ) ;
2008-11-12 07:50:05 +03:00
return NULL ;
2010-08-02 14:31:18 +04:00
}
2008-11-12 07:50:05 +03:00
rules - > trie_nodes_max = PREALLOC_TRIE ;
2008-11-13 20:21:28 +03:00
/* offset 0 is the trie root, with an empty string */
2008-11-13 02:52:12 +03:00
memset ( rules - > trie_nodes , 0x00 , sizeof ( struct trie_node ) ) ;
2008-11-12 07:50:05 +03:00
rules - > trie_nodes_cur = 1 ;
2008-10-18 16:33:37 +04:00
if ( udev_get_rules_path ( udev ) ! = NULL ) {
/* custom rules location for testing */
add_matching_files ( udev , & file_list , udev_get_rules_path ( udev ) , " .rules " ) ;
} else {
2008-11-01 20:34:54 +03:00
char filename [ PATH_MAX ] ;
2008-10-18 16:33:37 +04:00
struct udev_list_node sort_list ;
struct udev_list_entry * sort_loop , * sort_tmp ;
/* read user/custom rules */
add_matching_files ( udev , & file_list , SYSCONFDIR " /udev/rules.d " , " .rules " ) ;
/* read dynamic/temporary rules */
2011-03-23 04:31:09 +03:00
util_strscpyl ( filename , sizeof ( filename ) , udev_get_run_path ( udev ) , " /rules.d " , NULL ) ;
2008-10-18 16:33:37 +04:00
udev_list_init ( & sort_list ) ;
add_matching_files ( udev , & sort_list , filename , " .rules " ) ;
/* read default rules */
2009-06-17 04:25:07 +04:00
add_matching_files ( udev , & sort_list , LIBEXECDIR " /rules.d " , " .rules " ) ;
2008-10-18 16:33:37 +04:00
/* sort all rules files by basename into list of files */
udev_list_entry_foreach_safe ( sort_loop , sort_tmp , udev_list_get_entry ( & sort_list ) ) {
const char * sort_name = udev_list_entry_get_name ( sort_loop ) ;
const char * sort_base = strrchr ( sort_name , ' / ' ) ;
if ( sort_base = = NULL )
continue ;
2008-11-04 22:19:01 +03:00
/* sort entry into existing list */
2008-10-18 16:33:37 +04:00
udev_list_entry_foreach_safe ( file_loop , file_tmp , udev_list_get_entry ( & file_list ) ) {
const char * file_name = udev_list_entry_get_name ( file_loop ) ;
const char * file_base = strrchr ( file_name , ' / ' ) ;
if ( file_base = = NULL )
continue ;
if ( strcmp ( file_base , sort_base ) = = 0 ) {
info ( udev , " rule file basename '%s' already added, ignoring '%s' \n " ,
file_name , sort_name ) ;
2008-11-04 22:19:01 +03:00
udev_list_entry_delete ( sort_loop ) ;
2008-10-18 16:33:37 +04:00
sort_loop = NULL ;
break ;
}
2008-11-04 22:19:01 +03:00
if ( strcmp ( file_base , sort_base ) > 0 ) {
/* found later file, insert before */
udev_list_entry_remove ( sort_loop ) ;
udev_list_entry_insert_before ( sort_loop , file_loop ) ;
sort_loop = NULL ;
2008-10-18 16:33:37 +04:00
break ;
2008-11-04 22:19:01 +03:00
}
2008-10-18 16:33:37 +04:00
}
2008-11-04 22:19:01 +03:00
/* current file already handled */
if ( sort_loop = = NULL )
continue ;
/* no later file, append to end of list */
udev_list_entry_remove ( sort_loop ) ;
udev_list_entry_append ( sort_loop , & file_list ) ;
2008-10-18 16:33:37 +04:00
}
}
2008-11-01 20:34:54 +03:00
/* add all filenames to the string buffer */
udev_list_entry_foreach ( file_loop , udev_list_get_entry ( & file_list ) ) {
const char * filename = udev_list_entry_get_name ( file_loop ) ;
unsigned int filename_off ;
filename_off = add_string ( rules , filename ) ;
/* the offset in the rule is limited to unsigned short */
if ( filename_off < USHRT_MAX )
2010-03-10 16:52:42 +03:00
udev_list_entry_set_flags ( file_loop , filename_off ) ;
2008-11-01 20:34:54 +03:00
}
2008-10-18 16:33:37 +04:00
/* parse list of files */
udev_list_entry_foreach_safe ( file_loop , file_tmp , udev_list_get_entry ( & file_list ) ) {
2008-11-01 20:34:54 +03:00
const char * filename = udev_list_entry_get_name ( file_loop ) ;
2010-03-10 16:52:42 +03:00
unsigned int filename_off = udev_list_entry_get_flags ( file_loop ) ;
2008-10-18 16:33:37 +04:00
2008-11-01 20:34:54 +03:00
if ( stat ( filename , & statbuf ) = = 0 & & statbuf . st_size > 0 )
parse_file ( rules , filename , filename_off ) ;
2008-10-18 16:33:37 +04:00
else
2009-08-19 09:34:07 +04:00
err ( udev , " can not read '%s' \n " , filename ) ;
2008-11-04 22:19:01 +03:00
udev_list_entry_delete ( file_loop ) ;
2008-10-18 16:33:37 +04:00
}
2008-10-23 02:13:59 +04:00
memset ( & end_token , 0x00 , sizeof ( struct token ) ) ;
end_token . type = TK_END ;
add_token ( rules , & end_token ) ;
2008-10-24 12:51:04 +04:00
/* shrink allocated token and string buffer */
2008-10-23 02:13:59 +04:00
if ( rules - > token_cur < rules - > token_max ) {
struct token * tokens ;
tokens = realloc ( rules - > tokens , rules - > token_cur * sizeof ( struct token ) ) ;
if ( tokens ! = NULL | | rules - > token_cur = = 0 ) {
rules - > tokens = tokens ;
rules - > token_max = rules - > token_cur ;
}
}
if ( rules - > buf_cur < rules - > buf_max ) {
char * buf ;
buf = realloc ( rules - > buf , rules - > buf_cur ) ;
if ( buf ! = NULL | | rules - > buf_cur = = 0 ) {
rules - > buf = buf ;
rules - > buf_max = rules - > buf_cur ;
}
}
2008-11-12 17:01:20 +03:00
info ( udev , " rules use %zu bytes tokens (%u * %zu bytes), %zu bytes buffer \n " ,
2008-10-23 02:13:59 +04:00
rules - > token_max * sizeof ( struct token ) , rules - > token_max , sizeof ( struct token ) , rules - > buf_max ) ;
2008-11-13 02:52:12 +03:00
info ( udev , " temporary index used %zu bytes (%u * %zu bytes) \n " ,
rules - > trie_nodes_cur * sizeof ( struct trie_node ) ,
rules - > trie_nodes_cur , sizeof ( struct trie_node ) ) ;
2008-11-11 23:20:11 +03:00
/* cleanup trie */
2008-11-12 07:50:05 +03:00
free ( rules - > trie_nodes ) ;
rules - > trie_nodes = NULL ;
rules - > trie_nodes_cur = 0 ;
rules - > trie_nodes_max = 0 ;
2008-10-23 02:13:59 +04:00
2008-10-24 12:51:04 +04:00
/* cleanup uid/gid cache */
free ( rules - > uids ) ;
rules - > uids = NULL ;
rules - > uids_cur = 0 ;
rules - > uids_max = 0 ;
free ( rules - > gids ) ;
rules - > gids = NULL ;
rules - > gids_cur = 0 ;
rules - > gids_max = 0 ;
2008-10-23 02:13:59 +04:00
dump_rules ( rules ) ;
2008-10-18 17:02:01 +04:00
return rules ;
2008-10-18 16:33:37 +04:00
}
2008-10-18 17:02:01 +04:00
void udev_rules_unref ( struct udev_rules * rules )
2008-10-18 16:33:37 +04:00
{
2008-10-18 17:02:01 +04:00
if ( rules = = NULL )
return ;
2008-10-23 02:13:59 +04:00
free ( rules - > tokens ) ;
free ( rules - > buf ) ;
2008-11-12 07:50:05 +03:00
free ( rules - > trie_nodes ) ;
2008-10-24 12:51:04 +04:00
free ( rules - > uids ) ;
free ( rules - > gids ) ;
2008-10-18 17:02:01 +04:00
free ( rules ) ;
2008-10-18 16:33:37 +04:00
}
2008-10-23 02:13:59 +04:00
static int match_key ( struct udev_rules * rules , struct token * token , const char * val )
{
char * key_value = & rules - > buf [ token - > key . value_off ] ;
char * pos ;
2010-05-20 19:09:04 +04:00
bool match = false ;
2008-10-23 02:13:59 +04:00
if ( val = = NULL )
val = " " ;
2008-10-24 15:32:32 +04:00
switch ( token - > key . glob ) {
case GL_PLAIN :
match = ( strcmp ( key_value , val ) = = 0 ) ;
break ;
case GL_GLOB :
match = ( fnmatch ( key_value , val , 0 ) = = 0 ) ;
break ;
case GL_SPLIT :
{
2008-10-25 05:00:03 +04:00
const char * split ;
size_t len ;
2008-10-23 02:13:59 +04:00
2008-10-25 05:00:03 +04:00
split = & rules - > buf [ token - > key . value_off ] ;
len = strlen ( val ) ;
2010-05-27 17:11:00 +04:00
for ( ; ; ) {
2008-10-25 05:00:03 +04:00
const char * next ;
next = strchr ( split , ' | ' ) ;
if ( next ! = NULL ) {
size_t matchlen = ( size_t ) ( next - split ) ;
match = ( matchlen = = len & & strncmp ( split , val , matchlen ) = = 0 ) ;
if ( match )
break ;
} else {
match = ( strcmp ( split , val ) = = 0 ) ;
2008-10-24 15:32:32 +04:00
break ;
2008-10-25 05:00:03 +04:00
}
split = & next [ 1 ] ;
2008-10-23 02:13:59 +04:00
}
2008-10-24 15:32:32 +04:00
break ;
2008-10-23 02:13:59 +04:00
}
2008-10-24 15:32:32 +04:00
case GL_SPLIT_GLOB :
{
char value [ UTIL_PATH_SIZE ] ;
2009-05-20 19:57:52 +04:00
util_strscpy ( value , sizeof ( value ) , & rules - > buf [ token - > key . value_off ] ) ;
2008-10-24 15:32:32 +04:00
key_value = value ;
while ( key_value ! = NULL ) {
pos = strchr ( key_value , ' | ' ) ;
if ( pos ! = NULL ) {
pos [ 0 ] = ' \0 ' ;
pos = & pos [ 1 ] ;
}
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " match %s '%s' <-> '%s' \n " , token_str ( token - > type ) , key_value , val ) ;
2008-10-24 15:32:32 +04:00
match = ( fnmatch ( key_value , val , 0 ) = = 0 ) ;
if ( match )
break ;
key_value = pos ;
}
break ;
}
2008-10-24 16:19:42 +04:00
case GL_SOMETHING :
match = ( val [ 0 ] ! = ' \0 ' ) ;
break ;
2008-10-24 15:32:32 +04:00
case GL_UNSET :
return - 1 ;
2008-10-23 02:13:59 +04:00
}
2008-10-24 13:38:05 +04:00
if ( match & & ( token - > key . op = = OP_MATCH ) ) {
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s is true (matching value) \n " , token_str ( token - > type ) ) ;
2008-10-23 02:13:59 +04:00
return 0 ;
}
2008-10-24 13:38:05 +04:00
if ( ! match & & ( token - > key . op = = OP_NOMATCH ) ) {
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s is true (non-matching value) \n " , token_str ( token - > type ) ) ;
2008-10-23 02:13:59 +04:00
return 0 ;
}
convert debug string arrays to functions
On Fri, Nov 7, 2008 at 13:07, Matthias Schwarzott <zzam@gentoo.org> wrote:
> I managed to let udev-131 segfault at startup.
>
> I configured it like this:
> CFLAGS="-Wall -ggdb" ./configure --prefix=/usr --sysconfdir=/etc --exec-prefix=
>
> Running it in gdb shows it segfaults at udev-rules.c:831
>
> (gdb) run
> Starting program: /tmp/udev-131/udev/udevd
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0804ea06 in get_key (udev=0x9175008, line=0xafcdc8f0, key=0xafcdc5d8,
> op=0xafcdc5d0, value=0xafcdc5d4)
> at udev-rules.c:831
> 831 dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
If compiled without optimization, the dbg() macro dereferences variables
which are not available. Convert the string array to a function, which just
returns NULL if compiled without DEBUG.
2008-11-07 17:59:58 +03:00
dbg ( rules - > udev , " %s is not true \n " , token_str ( token - > type ) ) ;
2008-10-23 02:13:59 +04:00
return - 1 ;
}
static int match_attr ( struct udev_rules * rules , struct udev_device * dev , struct udev_event * event , struct token * cur )
{
2009-06-06 06:52:52 +04:00
const char * name ;
char nbuf [ UTIL_NAME_SIZE ] ;
const char * value ;
char vbuf [ UTIL_NAME_SIZE ] ;
2008-10-23 02:13:59 +04:00
size_t len ;
2009-06-06 06:52:52 +04:00
name = & rules - > buf [ cur - > key . attr_off ] ;
switch ( cur - > key . attrsubst ) {
case SB_FORMAT :
udev_event_apply_format ( event , name , nbuf , sizeof ( nbuf ) ) ;
name = nbuf ;
/* fall through */
case SB_NONE :
value = udev_device_get_sysattr_value ( dev , name ) ;
if ( value = = NULL )
2008-10-30 00:22:12 +03:00
return - 1 ;
2009-06-06 06:52:52 +04:00
break ;
case SB_SUBSYS :
if ( util_resolve_subsys_kernel ( event - > udev , name , vbuf , sizeof ( vbuf ) , 1 ) ! = 0 )
return - 1 ;
value = vbuf ;
break ;
default :
return - 1 ;
2008-10-23 02:13:59 +04:00
}
2009-06-06 06:52:52 +04:00
/* remove trailing whitespace, if not asked to match for it */
len = strlen ( value ) ;
if ( len > 0 & & isspace ( value [ len - 1 ] ) ) {
const char * key_value ;
size_t klen ;
key_value = & rules - > buf [ cur - > key . value_off ] ;
klen = strlen ( key_value ) ;
if ( klen > 0 & & ! isspace ( key_value [ klen - 1 ] ) ) {
if ( value ! = vbuf ) {
util_strscpy ( vbuf , sizeof ( vbuf ) , value ) ;
value = vbuf ;
}
while ( len > 0 & & isspace ( vbuf [ - - len ] ) )
vbuf [ len ] = ' \0 ' ;
dbg ( rules - > udev , " removed trailing whitespace from '%s' \n " , value ) ;
}
2008-10-23 02:13:59 +04:00
}
2009-06-06 06:52:52 +04:00
2008-10-23 02:13:59 +04:00
return match_key ( rules , cur , value ) ;
}
enum escape_type {
ESCAPE_UNSET ,
ESCAPE_NONE ,
ESCAPE_REPLACE ,
} ;
int udev_rules_apply_to_event ( struct udev_rules * rules , struct udev_event * event )
{
struct token * cur ;
2008-10-24 10:07:37 +04:00
struct token * rule ;
2008-10-25 17:19:48 +04:00
enum escape_type esc = ESCAPE_UNSET ;
2010-04-12 18:52:41 +04:00
bool can_set_name ;
2008-10-23 02:13:59 +04:00
if ( rules - > tokens = = NULL )
return - 1 ;
2010-04-12 18:52:41 +04:00
can_set_name = ( ( strcmp ( udev_device_get_action ( event - > dev ) , " remove " ) ! = 0 ) & &
2008-11-01 21:12:20 +03:00
( major ( udev_device_get_devnum ( event - > dev ) ) > 0 | |
2010-12-14 13:27:02 +03:00
udev_device_get_ifindex ( event - > dev ) > 0 ) ) ;
2008-11-01 21:12:20 +03:00
2008-10-23 02:13:59 +04:00
/* loop through token list, match, run actions or forward to next rule */
cur = & rules - > tokens [ 0 ] ;
2008-10-24 10:07:37 +04:00
rule = cur ;
2010-05-20 19:09:04 +04:00
for ( ; ; ) {
2008-10-23 02:13:59 +04:00
dump_token ( rules , cur ) ;
switch ( cur - > type ) {
case TK_RULE :
/* current rule */
rule = cur ;
2008-11-01 21:12:20 +03:00
/* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */
2010-05-20 19:09:04 +04:00
if ( ! can_set_name & & rule - > rule . can_set_name )
2009-01-05 04:55:37 +03:00
goto nomatch ;
2008-10-23 02:13:59 +04:00
esc = ESCAPE_UNSET ;
break ;
case TK_M_ACTION :
if ( match_key ( rules , cur , udev_device_get_action ( event - > dev ) ) ! = 0 )
goto nomatch ;
break ;
case TK_M_DEVPATH :
if ( match_key ( rules , cur , udev_device_get_devpath ( event - > dev ) ) ! = 0 )
goto nomatch ;
break ;
case TK_M_KERNEL :
if ( match_key ( rules , cur , udev_device_get_sysname ( event - > dev ) ) ! = 0 )
goto nomatch ;
break ;
case TK_M_DEVLINK :
{
size_t devlen = strlen ( udev_get_dev_path ( event - > udev ) ) + 1 ;
struct udev_list_entry * list_entry ;
2010-05-20 19:09:04 +04:00
bool match = false ;
2008-10-23 02:13:59 +04:00
udev_list_entry_foreach ( list_entry , udev_device_get_devlinks_list_entry ( event - > dev ) ) {
const char * devlink ;
devlink = & udev_list_entry_get_name ( list_entry ) [ devlen ] ;
if ( match_key ( rules , cur , devlink ) = = 0 ) {
2010-05-20 19:09:04 +04:00
match = true ;
2008-10-23 02:13:59 +04:00
break ;
}
}
if ( ! match )
goto nomatch ;
break ;
}
case TK_M_NAME :
if ( match_key ( rules , cur , event - > name ) ! = 0 )
goto nomatch ;
break ;
case TK_M_ENV :
{
const char * key_name = & rules - > buf [ cur - > key . attr_off ] ;
const char * value ;
2009-01-06 02:26:28 +03:00
value = udev_device_get_property_value ( event - > dev , key_name ) ;
2008-10-23 02:13:59 +04:00
if ( value = = NULL ) {
dbg ( event - > udev , " ENV{%s} is not set, treat as empty \n " , key_name ) ;
value = " " ;
}
if ( match_key ( rules , cur , value ) )
goto nomatch ;
break ;
}
2010-04-22 20:33:24 +04:00
case TK_M_TAG :
{
struct udev_list_entry * list_entry ;
bool match = false ;
udev_list_entry_foreach ( list_entry , udev_device_get_tags_list_entry ( event - > dev ) ) {
if ( strcmp ( & rules - > buf [ cur - > key . value_off ] , udev_list_entry_get_name ( list_entry ) ) = = 0 ) {
match = true ;
break ;
}
}
if ( ! match & & ( cur - > key . op ! = OP_NOMATCH ) )
goto nomatch ;
break ;
}
2008-10-23 02:13:59 +04:00
case TK_M_SUBSYSTEM :
if ( match_key ( rules , cur , udev_device_get_subsystem ( event - > dev ) ) ! = 0 )
goto nomatch ;
break ;
case TK_M_DRIVER :
if ( match_key ( rules , cur , udev_device_get_driver ( event - > dev ) ) ! = 0 )
goto nomatch ;
break ;
2008-10-23 22:37:30 +04:00
case TK_M_WAITFOR :
{
char filename [ UTIL_PATH_SIZE ] ;
int found ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , filename , sizeof ( filename ) ) ;
2008-10-23 22:37:30 +04:00
found = ( wait_for_file ( event - > dev , filename , 10 ) = = 0 ) ;
2008-10-24 13:38:05 +04:00
if ( ! found & & ( cur - > key . op ! = OP_NOMATCH ) )
2008-10-23 22:37:30 +04:00
goto nomatch ;
break ;
}
2008-10-23 02:13:59 +04:00
case TK_M_ATTR :
if ( match_attr ( rules , event - > dev , event , cur ) ! = 0 )
goto nomatch ;
break ;
case TK_M_KERNELS :
case TK_M_SUBSYSTEMS :
case TK_M_DRIVERS :
case TK_M_ATTRS :
{
struct token * next ;
/* get whole sequence of parent matches */
next = cur ;
2008-11-01 19:32:16 +03:00
while ( next - > type > TK_M_PARENTS_MIN & & next - > type < TK_M_PARENTS_MAX )
2008-10-23 02:13:59 +04:00
next + + ;
/* loop over parents */
event - > dev_parent = event - > dev ;
2010-05-27 17:11:00 +04:00
for ( ; ; ) {
2008-10-23 02:13:59 +04:00
struct token * key ;
dbg ( event - > udev , " parent: '%s' \n " , udev_device_get_syspath ( event - > dev_parent ) ) ;
/* loop over sequence of parent match keys */
for ( key = cur ; key < next ; key + + ) {
dump_token ( rules , key ) ;
switch ( key - > type ) {
case TK_M_KERNELS :
if ( match_key ( rules , key , udev_device_get_sysname ( event - > dev_parent ) ) ! = 0 )
goto try_parent ;
break ;
case TK_M_SUBSYSTEMS :
if ( match_key ( rules , key , udev_device_get_subsystem ( event - > dev_parent ) ) ! = 0 )
goto try_parent ;
break ;
case TK_M_DRIVERS :
if ( match_key ( rules , key , udev_device_get_driver ( event - > dev_parent ) ) ! = 0 )
goto try_parent ;
break ;
case TK_M_ATTRS :
if ( match_attr ( rules , event - > dev_parent , event , key ) ! = 0 )
goto try_parent ;
break ;
default :
goto nomatch ;
}
dbg ( event - > udev , " parent key matched \n " ) ;
}
dbg ( event - > udev , " all parent keys matched \n " ) ;
/* all keys matched */
break ;
try_parent :
event - > dev_parent = udev_device_get_parent ( event - > dev_parent ) ;
if ( event - > dev_parent = = NULL )
goto nomatch ;
}
/* move behind our sequence of parent match keys */
cur = next ;
continue ;
}
case TK_M_TEST :
{
char filename [ UTIL_PATH_SIZE ] ;
struct stat statbuf ;
int match ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , filename , sizeof ( filename ) ) ;
if ( util_resolve_subsys_kernel ( event - > udev , filename , filename , sizeof ( filename ) , 0 ) ! = 0 ) {
2008-10-23 02:13:59 +04:00
if ( filename [ 0 ] ! = ' / ' ) {
char tmp [ UTIL_PATH_SIZE ] ;
2009-05-20 19:57:52 +04:00
util_strscpy ( tmp , sizeof ( tmp ) , filename ) ;
util_strscpyl ( filename , sizeof ( filename ) ,
udev_device_get_syspath ( event - > dev ) , " / " , tmp , NULL ) ;
2008-10-23 02:13:59 +04:00
}
2009-05-20 19:57:52 +04:00
}
2008-10-23 02:13:59 +04:00
attr_subst_subdir ( filename , sizeof ( filename ) ) ;
match = ( stat ( filename , & statbuf ) = = 0 ) ;
2008-11-01 22:16:24 +03:00
dbg ( event - > udev , " '%s' %s " , filename , match ? " exists \n " : " does not exist \n " ) ;
2008-10-23 02:13:59 +04:00
if ( match & & cur - > key . mode > 0 ) {
match = ( ( statbuf . st_mode & cur - > key . mode ) > 0 ) ;
2008-11-01 22:16:24 +03:00
dbg ( event - > udev , " '%s' has mode=%#o and %s %#o \n " , filename , statbuf . st_mode ,
match ? " matches " : " does not match " , cur - > key . mode ) ;
2008-10-23 02:13:59 +04:00
}
2008-10-24 13:38:05 +04:00
if ( match & & cur - > key . op = = OP_NOMATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
2008-10-24 13:38:05 +04:00
if ( ! match & & cur - > key . op = = OP_MATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
break ;
}
case TK_M_PROGRAM :
{
char program [ UTIL_PATH_SIZE ] ;
char * * envp ;
char result [ UTIL_PATH_SIZE ] ;
2008-10-23 04:34:22 +04:00
free ( event - > program_result ) ;
event - > program_result = NULL ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , program , sizeof ( program ) ) ;
2008-10-23 02:13:59 +04:00
envp = udev_device_get_properties_envp ( event - > dev ) ;
2008-11-05 06:05:17 +03:00
info ( event - > udev , " PROGRAM '%s' %s:%u \n " ,
program ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2010-05-12 10:46:56 +04:00
if ( util_run_program ( event - > udev , program , envp , result , sizeof ( result ) , NULL , NULL , false ) ! = 0 ) {
2008-10-24 13:38:05 +04:00
if ( cur - > key . op ! = OP_NOMATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
} else {
int count ;
util_remove_trailing_chars ( result , ' \n ' ) ;
if ( esc = = ESCAPE_UNSET | | esc = = ESCAPE_REPLACE ) {
2008-11-05 23:49:52 +03:00
count = udev_util_replace_chars ( result , UDEV_ALLOWED_CHARS_INPUT ) ;
2008-10-23 02:13:59 +04:00
if ( count > 0 )
info ( event - > udev , " %i character(s) replaced \n " , count ) ;
}
2008-10-23 04:34:22 +04:00
event - > program_result = strdup ( result ) ;
dbg ( event - > udev , " storing result '%s' \n " , event - > program_result ) ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_NOMATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
}
break ;
}
case TK_M_IMPORT_FILE :
{
char import [ UTIL_PATH_SIZE ] ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , import , sizeof ( import ) ) ;
2008-10-23 02:13:59 +04:00
if ( import_file_into_properties ( event - > dev , import ) ! = 0 )
2008-10-24 13:38:05 +04:00
if ( cur - > key . op ! = OP_NOMATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
break ;
}
case TK_M_IMPORT_PROG :
{
char import [ UTIL_PATH_SIZE ] ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , import , sizeof ( import ) ) ;
2008-11-05 06:05:17 +03:00
info ( event - > udev , " IMPORT '%s' %s:%u \n " ,
import ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
if ( import_program_into_properties ( event - > dev , import ) ! = 0 )
2008-10-24 13:38:05 +04:00
if ( cur - > key . op ! = OP_NOMATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
break ;
}
2010-04-12 17:58:05 +04:00
case TK_M_IMPORT_DB :
{
const char * key = & rules - > buf [ cur - > key . value_off ] ;
const char * value ;
value = udev_device_get_property_value ( event - > dev_db , key ) ;
if ( value ! = NULL ) {
struct udev_list_entry * entry ;
entry = udev_device_add_property ( event - > dev , key , value ) ;
udev_list_entry_set_flags ( entry , 1 ) ;
} else {
if ( cur - > key . op ! = OP_NOMATCH )
goto nomatch ;
}
break ;
}
2010-05-31 03:13:03 +04:00
case TK_M_IMPORT_CMDLINE :
{
FILE * f ;
bool imported = false ;
f = fopen ( " /proc/cmdline " , " r " ) ;
if ( f ! = NULL ) {
char cmdline [ 4096 ] ;
if ( fgets ( cmdline , sizeof ( cmdline ) , f ) ! = NULL ) {
const char * key = & rules - > buf [ cur - > key . value_off ] ;
char * pos ;
pos = strstr ( cmdline , key ) ;
if ( pos ! = NULL ) {
struct udev_list_entry * entry ;
pos + = strlen ( key ) ;
if ( pos [ 0 ] = = ' \0 ' | | isspace ( pos [ 0 ] ) ) {
/* we import simple flags as 'FLAG=1' */
entry = udev_device_add_property ( event - > dev , key , " 1 " ) ;
udev_list_entry_set_flags ( entry , 1 ) ;
imported = true ;
} else if ( pos [ 0 ] = = ' = ' ) {
2010-05-31 13:04:42 +04:00
const char * value ;
2010-05-31 03:13:03 +04:00
2010-05-31 13:04:42 +04:00
pos + + ;
value = pos ;
2010-05-31 03:13:03 +04:00
while ( pos [ 0 ] ! = ' \0 ' & & ! isspace ( pos [ 0 ] ) )
pos + + ;
pos [ 0 ] = ' \0 ' ;
entry = udev_device_add_property ( event - > dev , key , value ) ;
udev_list_entry_set_flags ( entry , 1 ) ;
imported = true ;
}
}
}
fclose ( f ) ;
}
if ( ! imported & & cur - > key . op ! = OP_NOMATCH )
goto nomatch ;
break ;
}
2008-10-23 02:13:59 +04:00
case TK_M_IMPORT_PARENT :
{
char import [ UTIL_PATH_SIZE ] ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , import , sizeof ( import ) ) ;
2008-10-23 02:13:59 +04:00
if ( import_parent_into_properties ( event - > dev , import ) ! = 0 )
2008-10-24 13:38:05 +04:00
if ( cur - > key . op ! = OP_NOMATCH )
2008-10-23 02:13:59 +04:00
goto nomatch ;
break ;
}
case TK_M_RESULT :
if ( match_key ( rules , cur , event - > program_result ) ! = 0 )
goto nomatch ;
break ;
case TK_A_STRING_ESCAPE_NONE :
esc = ESCAPE_NONE ;
break ;
case TK_A_STRING_ESCAPE_REPLACE :
esc = ESCAPE_REPLACE ;
break ;
2009-02-11 20:38:56 +03:00
case TK_A_INOTIFY_WATCH :
2010-07-07 13:35:40 +04:00
if ( event - > inotify_watch_final )
break ;
if ( cur - > key . op = = OP_ASSIGN_FINAL )
event - > inotify_watch_final = true ;
2009-02-25 13:18:15 +03:00
event - > inotify_watch = cur - > key . watch ;
2009-02-11 20:38:56 +03:00
break ;
2008-10-23 02:13:59 +04:00
case TK_A_DEVLINK_PRIO :
udev_device_set_devlink_priority ( event - > dev , cur - > key . devlink_prio ) ;
break ;
case TK_A_OWNER :
{
char owner [ UTIL_NAME_SIZE ] ;
if ( event - > owner_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > owner_final = true ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , owner , sizeof ( owner ) ) ;
2008-10-23 02:13:59 +04:00
event - > uid = util_lookup_user ( event - > udev , owner ) ;
2008-11-01 20:34:54 +03:00
info ( event - > udev , " OWNER %u %s:%u \n " ,
event - > uid ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
}
case TK_A_GROUP :
{
char group [ UTIL_NAME_SIZE ] ;
if ( event - > group_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > group_final = true ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , group , sizeof ( group ) ) ;
2008-10-23 02:13:59 +04:00
event - > gid = util_lookup_group ( event - > udev , group ) ;
2008-11-01 20:34:54 +03:00
info ( event - > udev , " GROUP %u %s:%u \n " ,
event - > gid ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
}
case TK_A_MODE :
{
char mode [ UTIL_NAME_SIZE ] ;
char * endptr ;
if ( event - > mode_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > mode_final = true ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , mode , sizeof ( mode ) ) ;
2008-10-23 02:13:59 +04:00
event - > mode = strtol ( mode , & endptr , 8 ) ;
if ( endptr [ 0 ] ! = ' \0 ' ) {
2010-05-20 19:09:04 +04:00
err ( event - > udev , " invalide mode '%s' set default mode 0600 \n " , mode ) ;
event - > mode = 0600 ;
2008-10-23 02:13:59 +04:00
}
2008-11-01 20:34:54 +03:00
info ( event - > udev , " MODE %#o %s:%u \n " ,
event - > mode ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
}
case TK_A_OWNER_ID :
if ( event - > owner_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > owner_final = true ;
2008-10-23 02:13:59 +04:00
event - > uid = cur - > key . uid ;
2008-11-01 20:34:54 +03:00
info ( event - > udev , " OWNER %u %s:%u \n " ,
event - > uid ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
case TK_A_GROUP_ID :
if ( event - > group_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > group_final = true ;
2008-10-23 02:13:59 +04:00
event - > gid = cur - > key . gid ;
2008-11-01 20:34:54 +03:00
info ( event - > udev , " GROUP %u %s:%u \n " ,
event - > gid ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
case TK_A_MODE_ID :
if ( event - > mode_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > mode_final = true ;
2008-10-23 02:13:59 +04:00
event - > mode = cur - > key . mode ;
2008-11-01 20:34:54 +03:00
info ( event - > udev , " MODE %#o %s:%u \n " ,
event - > mode ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
2010-05-20 19:09:04 +04:00
case TK_A_STATIC_NODE :
break ;
2008-10-23 02:13:59 +04:00
case TK_A_ENV :
{
const char * name = & rules - > buf [ cur - > key . attr_off ] ;
char * value = & rules - > buf [ cur - > key . value_off ] ;
if ( value [ 0 ] ! = ' \0 ' ) {
char temp_value [ UTIL_NAME_SIZE ] ;
struct udev_list_entry * entry ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , value , temp_value , sizeof ( temp_value ) ) ;
2008-10-23 02:13:59 +04:00
entry = udev_device_add_property ( event - > dev , name , temp_value ) ;
2009-06-28 04:21:58 +04:00
/* store in db, skip private keys */
if ( name [ 0 ] ! = ' . ' )
2010-03-10 16:52:42 +03:00
udev_list_entry_set_flags ( entry , 1 ) ;
2008-10-23 02:13:59 +04:00
} else {
udev_device_add_property ( event - > dev , name , NULL ) ;
}
break ;
}
2010-04-22 20:12:36 +04:00
case TK_A_TAG :
2010-04-22 21:03:11 +04:00
if ( cur - > key . op = = OP_ASSIGN | | cur - > key . op = = OP_ASSIGN_FINAL )
udev_device_cleanup_tags_list ( event - > dev ) ;
2010-04-22 20:12:36 +04:00
udev_device_add_tag ( event - > dev , & rules - > buf [ cur - > key . value_off ] ) ;
break ;
2008-10-23 02:13:59 +04:00
case TK_A_NAME :
{
const char * name = & rules - > buf [ cur - > key . value_off ] ;
2008-10-23 04:57:08 +04:00
char name_str [ UTIL_PATH_SIZE ] ;
2008-10-23 02:13:59 +04:00
int count ;
if ( event - > name_final )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > name_final = true ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , name , name_str , sizeof ( name_str ) ) ;
2008-10-23 02:13:59 +04:00
if ( esc = = ESCAPE_UNSET | | esc = = ESCAPE_REPLACE ) {
2008-11-05 23:49:52 +03:00
count = udev_util_replace_chars ( name_str , " / " ) ;
2008-10-23 02:13:59 +04:00
if ( count > 0 )
info ( event - > udev , " %i character(s) replaced \n " , count ) ;
}
2009-02-08 18:02:15 +03:00
free ( event - > name ) ;
event - > name = strdup ( name_str ) ;
info ( event - > udev , " NAME '%s' %s:%u \n " ,
event - > name ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
break ;
}
case TK_A_DEVLINK :
{
char temp [ UTIL_PATH_SIZE ] ;
char filename [ UTIL_PATH_SIZE ] ;
char * pos , * next ;
int count = 0 ;
if ( event - > devlink_final )
break ;
2008-10-23 23:42:23 +04:00
if ( major ( udev_device_get_devnum ( event - > dev ) ) = = 0 )
break ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN_FINAL )
2010-05-20 19:09:04 +04:00
event - > devlink_final = true ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN | | cur - > key . op = = OP_ASSIGN_FINAL )
2008-10-23 02:13:59 +04:00
udev_device_cleanup_devlinks_list ( event - > dev ) ;
/* allow multiple symlinks separated by spaces */
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , temp , sizeof ( temp ) ) ;
2008-10-23 02:13:59 +04:00
if ( esc = = ESCAPE_UNSET )
2008-11-05 23:49:52 +03:00
count = udev_util_replace_chars ( temp , " / " ) ;
2008-10-23 02:13:59 +04:00
else if ( esc = = ESCAPE_REPLACE )
2008-11-05 23:49:52 +03:00
count = udev_util_replace_chars ( temp , " / " ) ;
2008-10-23 02:13:59 +04:00
if ( count > 0 )
info ( event - > udev , " %i character(s) replaced \n " , count ) ;
dbg ( event - > udev , " rule applied, added symlink(s) '%s' \n " , temp ) ;
pos = temp ;
while ( isspace ( pos [ 0 ] ) )
pos + + ;
next = strchr ( pos , ' ' ) ;
2009-09-09 20:18:17 +04:00
while ( next ! = NULL ) {
2008-10-23 02:13:59 +04:00
next [ 0 ] = ' \0 ' ;
2009-09-09 20:18:17 +04:00
info ( event - > udev , " LINK '%s' %s:%u \n " , pos ,
& rules - > buf [ rule - > rule . filename_off ] , rule - > rule . filename_line ) ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , udev_get_dev_path ( event - > udev ) , " / " , pos , NULL ) ;
2009-09-09 20:18:17 +04:00
udev_device_add_devlink ( event - > dev , filename , cur - > key . devlink_unique ) ;
2008-10-23 02:13:59 +04:00
while ( isspace ( next [ 1 ] ) )
next + + ;
pos = & next [ 1 ] ;
next = strchr ( pos , ' ' ) ;
}
if ( pos [ 0 ] ! = ' \0 ' ) {
2009-09-09 20:18:17 +04:00
info ( event - > udev , " LINK '%s' %s:%u \n " , pos ,
& rules - > buf [ rule - > rule . filename_off ] , rule - > rule . filename_line ) ;
2009-05-20 19:57:52 +04:00
util_strscpyl ( filename , sizeof ( filename ) , udev_get_dev_path ( event - > udev ) , " / " , pos , NULL ) ;
2009-09-09 20:18:17 +04:00
udev_device_add_devlink ( event - > dev , filename , cur - > key . devlink_unique ) ;
2008-10-23 02:13:59 +04:00
}
}
break ;
case TK_A_EVENT_TIMEOUT :
udev_device_set_event_timeout ( event - > dev , cur - > key . event_timeout ) ;
break ;
case TK_A_ATTR :
{
const char * key_name = & rules - > buf [ cur - > key . attr_off ] ;
char attr [ UTIL_PATH_SIZE ] ;
char value [ UTIL_NAME_SIZE ] ;
FILE * f ;
2009-05-20 19:57:52 +04:00
if ( util_resolve_subsys_kernel ( event - > udev , key_name , attr , sizeof ( attr ) , 0 ) ! = 0 )
util_strscpyl ( attr , sizeof ( attr ) , udev_device_get_syspath ( event - > dev ) , " / " , key_name , NULL ) ;
2008-10-23 02:13:59 +04:00
attr_subst_subdir ( attr , sizeof ( attr ) ) ;
2009-05-20 19:57:52 +04:00
udev_event_apply_format ( event , & rules - > buf [ cur - > key . value_off ] , value , sizeof ( value ) ) ;
2008-11-01 22:16:24 +03:00
info ( event - > udev , " ATTR '%s' writing '%s' %s:%u \n " , attr , value ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
f = fopen ( attr , " w " ) ;
if ( f ! = NULL ) {
2009-01-15 22:20:16 +03:00
if ( fprintf ( f , " %s " , value ) < = 0 )
err ( event - > udev , " error writing ATTR{%s}: %m \n " , attr ) ;
2008-10-23 02:13:59 +04:00
fclose ( f ) ;
} else {
err ( event - > udev , " error opening ATTR{%s} for writing: %m \n " , attr ) ;
}
break ;
}
case TK_A_RUN :
{
struct udev_list_entry * list_entry ;
2008-10-24 13:38:05 +04:00
if ( cur - > key . op = = OP_ASSIGN | | cur - > key . op = = OP_ASSIGN_FINAL )
2008-10-23 02:13:59 +04:00
udev_list_cleanup_entries ( event - > udev , & event - > run_list ) ;
2008-11-01 20:34:54 +03:00
info ( event - > udev , " RUN '%s' %s:%u \n " ,
& rules - > buf [ cur - > key . value_off ] ,
& rules - > buf [ rule - > rule . filename_off ] ,
rule - > rule . filename_line ) ;
2008-10-23 02:13:59 +04:00
list_entry = udev_list_entry_add ( event - > udev , & event - > run_list ,
& rules - > buf [ cur - > key . value_off ] , NULL , 1 , 0 ) ;
2009-09-09 20:18:17 +04:00
if ( cur - > key . fail_on_error )
2010-03-10 16:52:42 +03:00
udev_list_entry_set_flags ( list_entry , 1 ) ;
2008-10-23 02:13:59 +04:00
break ;
}
case TK_A_GOTO :
2009-05-13 20:01:32 +04:00
if ( cur - > key . rule_goto = = 0 )
break ;
2008-10-23 02:13:59 +04:00
cur = & rules - > tokens [ cur - > key . rule_goto ] ;
continue ;
2008-10-28 11:58:18 +03:00
case TK_END :
2008-11-01 19:09:16 +03:00
return 0 ;
2008-10-23 02:13:59 +04:00
2008-11-01 19:32:16 +03:00
case TK_M_PARENTS_MIN :
2008-10-24 13:38:05 +04:00
case TK_M_PARENTS_MAX :
2008-10-24 15:32:32 +04:00
case TK_M_MAX :
case TK_UNSET :
2008-10-23 02:13:59 +04:00
err ( rules - > udev , " wrong type %u \n " , cur - > type ) ;
goto nomatch ;
}
cur + + ;
continue ;
nomatch :
/* fast-forward to next rule */
2008-11-06 00:28:52 +03:00
cur = rule + rule - > rule . token_count ;
dbg ( rules - > udev , " forward to rule: %u \n " ,
( unsigned int ) ( cur - rules - > tokens ) ) ;
2008-10-23 02:13:59 +04:00
}
}
2010-05-20 19:09:04 +04:00
void udev_rules_apply_static_dev_perms ( struct udev_rules * rules )
{
struct token * cur ;
struct token * rule ;
uid_t uid = 0 ;
gid_t gid = 0 ;
mode_t mode = 0 ;
if ( rules - > tokens = = NULL )
return ;
cur = & rules - > tokens [ 0 ] ;
rule = cur ;
for ( ; ; ) {
switch ( cur - > type ) {
case TK_RULE :
/* current rule */
rule = cur ;
/* skip rules without a static_node tag */
if ( ! rule - > rule . has_static_node )
goto next ;
uid = 0 ;
gid = 0 ;
mode = 0 ;
break ;
case TK_A_OWNER_ID :
uid = cur - > key . uid ;
break ;
case TK_A_GROUP_ID :
gid = cur - > key . gid ;
break ;
case TK_A_MODE_ID :
mode = cur - > key . mode ;
break ;
case TK_A_STATIC_NODE : {
char filename [ UTIL_PATH_SIZE ] ;
struct stat stats ;
/* we assure, that the permissions tokens are sorted before the static token */
if ( mode = = 0 & & uid = = 0 & & gid = = 0 )
goto next ;
util_strscpyl ( filename , sizeof ( filename ) , udev_get_dev_path ( rules - > udev ) , " / " ,
& rules - > buf [ cur - > key . value_off ] , NULL ) ;
if ( stat ( filename , & stats ) ! = 0 )
goto next ;
if ( ! S_ISBLK ( stats . st_mode ) & & ! S_ISCHR ( stats . st_mode ) )
goto next ;
if ( mode ! = 0 & & mode ! = ( stats . st_mode & 0777 ) ) {
chmod ( filename , mode ) ;
info ( rules - > udev , " chmod '%s' %#o \n " , filename , mode ) ;
}
if ( ( uid ! = 0 & & uid ! = stats . st_uid ) | | ( gid ! = 0 & & gid ! = stats . st_gid ) ) {
chown ( filename , uid , gid ) ;
info ( rules - > udev , " chown '%s' %u %u \n " , filename , uid , gid ) ;
}
utimensat ( AT_FDCWD , filename , NULL , 0 ) ;
break ;
}
case TK_END :
return ;
}
cur + + ;
continue ;
next :
/* fast-forward to next rule */
cur = rule + rule - > rule . token_count ;
continue ;
}
}