2005-08-01 22:22:46 +04:00
/*
2006-08-05 15:24:05 +04:00
* Copyright ( C ) 2004 - 2006 Kay Sievers < kay . sievers @ vrfy . org >
2005-08-01 22:22:46 +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 version 2 of the License .
*
* 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 .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
2006-08-28 02:29:11 +04:00
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2005-08-01 22:22:46 +04:00
*
*/
# include <unistd.h>
# include <stdio.h>
# include <stdlib.h>
2006-05-01 22:36:21 +04:00
# include <stddef.h>
2005-08-01 22:22:46 +04:00
# include <string.h>
# include <fcntl.h>
# include <errno.h>
2005-08-25 02:38:25 +04:00
# include <signal.h>
2007-03-10 17:12:42 +03:00
# include <getopt.h>
2005-11-07 04:23:06 +03:00
# include <sys/time.h>
2005-08-01 22:22:46 +04:00
# include <sys/socket.h>
# include <sys/un.h>
# include <sys/select.h>
2005-11-12 07:09:34 +03:00
# include <linux/types.h>
2005-08-01 22:22:46 +04:00
# include <linux/netlink.h>
# include "udev.h"
2008-09-09 16:07:08 +04:00
static int udev_exit ;
2005-08-01 22:22:46 +04:00
2005-08-25 02:38:25 +04:00
static void asmlinkage sig_handler ( int signum )
{
if ( signum = = SIGINT | | signum = = SIGTERM )
udev_exit = 1 ;
}
2008-09-09 19:41:17 +04:00
static int print_properties_cb ( struct udev_device * udev_device , const char * key , const char * value , void * data )
2007-02-16 15:57:08 +03:00
{
2008-09-09 19:41:17 +04:00
printf ( " %s=%s \n " , key , value ) ;
return 0 ;
}
2007-02-16 15:57:08 +03:00
2008-09-09 19:41:17 +04:00
static void print_properties ( struct udev_device * device )
{
udev_device_get_properties ( device , print_properties_cb , NULL ) ;
printf ( " \n " ) ;
2007-02-16 15:57:08 +03:00
}
2008-09-06 17:45:31 +04:00
int udevadm_monitor ( struct udev * udev , int argc , char * argv [ ] )
2005-08-01 22:22:46 +04:00
{
2005-08-25 02:38:25 +04:00
struct sigaction act ;
2007-03-10 17:12:42 +03:00
int option ;
2005-08-01 22:22:46 +04:00
int env = 0 ;
2008-09-06 17:45:31 +04:00
int print_kernel = 0 ;
int print_udev = 0 ;
2008-09-09 16:07:08 +04:00
struct udev_monitor * udev_monitor = NULL ;
2008-09-09 19:41:17 +04:00
struct udev_monitor * kernel_monitor = NULL ;
2005-08-01 22:22:46 +04:00
fd_set readfds ;
2008-09-09 16:07:08 +04:00
int rc = 0 ;
2005-08-01 22:22:46 +04:00
2007-03-10 17:12:42 +03:00
static const struct option options [ ] = {
{ " environment " , 0 , NULL , ' e ' } ,
{ " kernel " , 0 , NULL , ' k ' } ,
{ " udev " , 0 , NULL , ' u ' } ,
{ " help " , 0 , NULL , ' h ' } ,
{ }
} ;
while ( 1 ) {
option = getopt_long ( argc , argv , " ekuh " , options , NULL ) ;
if ( option = = - 1 )
break ;
switch ( option ) {
case ' e ' :
2005-08-11 22:34:24 +04:00
env = 1 ;
2007-03-10 17:12:42 +03:00
break ;
case ' k ' :
2008-09-06 17:45:31 +04:00
print_kernel = 1 ;
2007-03-10 17:12:42 +03:00
break ;
case ' u ' :
2008-09-06 17:45:31 +04:00
print_udev = 1 ;
2007-03-10 17:12:42 +03:00
break ;
case ' h ' :
2007-11-08 19:51:59 +03:00
printf ( " Usage: udevadm monitor [--environment] [--kernel] [--udev] [--help] \n "
2007-03-10 17:12:42 +03:00
" --env print the whole event environment \n "
" --kernel print kernel uevents \n "
" --udev print udev events \n "
" --help print this help text \n \n " ) ;
default :
goto out ;
2005-08-11 22:34:24 +04:00
}
}
2008-09-06 17:45:31 +04:00
if ( ! print_kernel & & ! print_udev ) {
print_kernel = 1 ;
print_udev = 1 ;
2007-03-10 17:12:42 +03:00
}
2008-09-06 17:45:31 +04:00
if ( getuid ( ) ! = 0 & & print_kernel ) {
2007-03-10 17:12:42 +03:00
fprintf ( stderr , " root privileges needed to subscribe to kernel events \n " ) ;
goto out ;
2005-08-01 22:22:46 +04:00
}
2005-08-25 02:38:25 +04:00
/* set signal handlers */
memset ( & act , 0x00 , sizeof ( struct sigaction ) ) ;
act . sa_handler = ( void ( * ) ( int ) ) sig_handler ;
sigemptyset ( & act . sa_mask ) ;
act . sa_flags = SA_RESTART ;
sigaction ( SIGINT , & act , NULL ) ;
sigaction ( SIGTERM , & act , NULL ) ;
2008-09-06 17:45:31 +04:00
printf ( " monitor will print the received events for: \n " ) ;
if ( print_udev ) {
2008-09-09 16:07:08 +04:00
udev_monitor = udev_monitor_new_from_socket ( udev , " @/org/kernel/udev/monitor " ) ;
if ( udev_monitor = = NULL ) {
rc = 1 ;
goto out ;
}
if ( udev_monitor_enable_receiving ( udev_monitor ) < 0 ) {
rc = 2 ;
2007-03-10 17:12:42 +03:00
goto out ;
2008-09-09 16:07:08 +04:00
}
2007-03-15 18:30:08 +03:00
printf ( " UDEV the event which udev sends out after rule processing \n " ) ;
2007-03-10 17:12:42 +03:00
}
2008-09-06 17:45:31 +04:00
if ( print_kernel ) {
2008-09-09 19:41:17 +04:00
kernel_monitor = udev_monitor_new_from_netlink ( udev ) ;
if ( kernel_monitor = = NULL ) {
2008-09-09 16:07:08 +04:00
rc = 3 ;
2007-03-10 17:12:42 +03:00
goto out ;
2008-09-09 16:07:08 +04:00
}
2008-09-09 19:41:17 +04:00
if ( udev_monitor_enable_receiving ( kernel_monitor ) < 0 ) {
rc = 4 ;
goto out ;
}
2007-03-15 18:30:08 +03:00
printf ( " UEVENT the kernel uevent \n " ) ;
2007-03-10 17:12:42 +03:00
}
printf ( " \n " ) ;
2005-08-11 22:34:24 +04:00
2005-08-25 02:38:25 +04:00
while ( ! udev_exit ) {
2005-08-15 13:57:04 +04:00
int fdcount ;
2005-11-07 04:23:06 +03:00
struct timeval tv ;
struct timezone tz ;
char timestr [ 64 ] ;
2005-08-01 22:22:46 +04:00
2005-08-15 13:57:04 +04:00
FD_ZERO ( & readfds ) ;
2008-09-09 19:41:17 +04:00
if ( kernel_monitor ! = NULL )
FD_SET ( udev_monitor_get_fd ( kernel_monitor ) , & readfds ) ;
2008-09-09 16:07:08 +04:00
if ( udev_monitor ! = NULL )
FD_SET ( udev_monitor_get_fd ( udev_monitor ) , & readfds ) ;
2005-08-15 13:57:04 +04:00
2008-09-09 19:41:17 +04:00
fdcount = select ( UDEV_MAX ( udev_monitor_get_fd ( kernel_monitor ) , udev_monitor_get_fd ( udev_monitor ) ) + 1 ,
2008-09-09 16:07:08 +04:00
& readfds , NULL , NULL , NULL ) ;
2005-08-15 13:57:04 +04:00
if ( fdcount < 0 ) {
2005-08-01 22:22:46 +04:00
if ( errno ! = EINTR )
2005-11-07 20:44:18 +03:00
fprintf ( stderr , " error receiving uevent message: %s \n " , strerror ( errno ) ) ;
2005-08-01 22:22:46 +04:00
continue ;
}
2005-11-07 04:23:06 +03:00
if ( gettimeofday ( & tv , & tz ) = = 0 ) {
snprintf ( timestr , sizeof ( timestr ) , " %llu.%06u " ,
( unsigned long long ) tv . tv_sec , ( unsigned int ) tv . tv_usec ) ;
} else
timestr [ 0 ] = ' \0 ' ;
2008-09-09 19:41:17 +04:00
if ( ( kernel_monitor ! = NULL ) & & FD_ISSET ( udev_monitor_get_fd ( kernel_monitor ) , & readfds ) ) {
struct udev_device * device = udev_monitor_receive_device ( kernel_monitor ) ;
if ( device = = NULL )
2005-08-01 22:22:46 +04:00
continue ;
2008-09-09 19:41:17 +04:00
printf ( " UEVENT[%s] %-8s %s (%s) \n " , timestr ,
udev_device_get_action ( device ) ,
udev_device_get_devpath ( device ) ,
udev_device_get_subsystem ( device ) ) ;
if ( env )
print_properties ( device ) ;
udev_device_unref ( device ) ;
2005-08-01 22:22:46 +04:00
}
2008-09-09 16:07:08 +04:00
if ( ( udev_monitor ! = NULL ) & & FD_ISSET ( udev_monitor_get_fd ( udev_monitor ) , & readfds ) ) {
2008-09-09 19:41:17 +04:00
struct udev_device * device = udev_monitor_receive_device ( udev_monitor ) ;
if ( device = = NULL )
2005-08-01 22:22:46 +04:00
continue ;
2008-09-09 19:41:17 +04:00
printf ( " UDEV [%s] %-8s %s (%s) \n " , timestr ,
udev_device_get_action ( device ) ,
udev_device_get_devpath ( device ) ,
udev_device_get_subsystem ( device ) ) ;
if ( env )
print_properties ( device ) ;
udev_device_unref ( device ) ;
2005-08-01 22:22:46 +04:00
}
}
2005-08-15 13:57:04 +04:00
out :
2008-09-09 16:07:08 +04:00
udev_monitor_unref ( udev_monitor ) ;
2008-09-09 19:41:17 +04:00
udev_monitor_unref ( kernel_monitor ) ;
2008-09-09 16:07:08 +04:00
return rc ;
2005-08-01 22:22:46 +04:00
}