Пример #1
0
void UdevMonitor::addTagFilter(const char* tag)
	{
	/* Add a tag filter: */
	if(udev_monitor_filter_add_match_tag(monitor,tag)!=0)
		throw std::runtime_error("RawHID::UdevMonitor::addTagFilter: Internal libudev error");
	
	/* If the monitor is already listening, update its filters: */
	if(listening)
		if(udev_monitor_filter_update(monitor)!=0)
			throw std::runtime_error("RawHID::UdevMonitor::addTagFilter: Internal libudev error");
	}
Пример #2
0
void UdevMonitor::removeFilters(void)
	{
	/* Remove all filters: */
	if(udev_monitor_filter_remove(monitor)!=0)
		throw std::runtime_error("RawHID::UdevMonitor::removeFilters: Internal libudev error");
	
	/* If the monitor is already listening, update its filters: */
	if(listening)
		if(udev_monitor_filter_update(monitor)!=0)
			throw std::runtime_error("RawHID::UdevMonitor::removeFilters: Internal libudev error");
	}
Пример #3
0
void UdevMonitor::addSubsystemFilter(const char* subsystem,const char* deviceType)
	{
	/* Add a subsystem filter: */
	if(udev_monitor_filter_add_match_subsystem_devtype(monitor,subsystem,deviceType)!=0)
		throw std::runtime_error("RawHID::UdevMonitor::addSubsystemFilter: Internal libudev error");
	
	/* If the monitor is already listening, update its filters: */
	if(listening)
		if(udev_monitor_filter_update(monitor)!=0)
			throw std::runtime_error("RawHID::UdevMonitor::addSubsystemFilter: Internal libudev error");
	}
Пример #4
0
int main(int argc, char **argv)
{
	struct udev *udev = udev_new();
	if (udev == NULL) {
		fprintf(stderr, "Unable to initialize udev context");
		return -1;
	}

#ifdef DEBUG
	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
	if (enumerate == NULL) {
		fprintf(stderr, "Unable to enumerate devices");
		return -1;
	}

	udev_enumerate_add_match_subsystem(enumerate, "drm");
	udev_enumerate_scan_devices(enumerate);
	struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
	if (devices == NULL) {
		fprintf(stderr, "Unable to enumerate devices");
		return -1;
	}

	// List devices
	struct udev_list_entry *dev_entry;
	udev_list_entry_foreach(dev_entry, devices) {
		const char *path = udev_list_entry_get_name(dev_entry);
		struct udev_device *dev = udev_device_new_from_syspath(udev, path);
		printf("%s [devtype=%s]\n", path, udev_device_get_devtype(dev));
	}
	udev_enumerate_unref(enumerate);
#endif

	// Setup monitor
	struct udev_monitor *monitor = udev_monitor_new_from_netlink(udev, "udev");
	if (monitor == NULL) {
		fprintf(stderr, "Unable to initialize udev monitor");
		return -1;
	}

	if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "drm", "drm_minor") < 0) {
		fprintf(stderr, "Unable to setup udev monitor");
		return -1;
	}
	if (udev_monitor_filter_update(monitor) < 0) {
		fprintf(stderr, "Unable to setup udev monitor");
		return -1;
	}

	if (udev_monitor_enable_receiving(monitor) < 0) {
		fprintf(stderr, "Unable to listen in udev monitor");
		return -1;
	}

	// The same issue as in SO, receive_device does not block, use select
	// http://stackoverflow.com/questions/15687784/libudev-monitoring-returns-null-pointer-on-raspbian
	int fd = udev_monitor_get_fd(monitor);
	while(1) {
		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		int ret = select(fd+1, &fds, NULL, NULL, NULL);
		if (ret > 0 && FD_ISSET(fd, &fds)) {
			struct udev_device *dev = udev_monitor_receive_device(monitor);
			if (dev == NULL) {
				continue;
			}

			printf("%s\n", udev_device_get_syspath(dev));
			for (int i=1; i<argc; i++) {
				system(argv[i]);
			}
			udev_device_unref(dev);
		}
	}

	udev_monitor_unref(monitor);
	udev_unref(udev);
	return 0;
}
Пример #5
0
// on fork(), create a new events directory for each of this process's monitors
// and point them all to them.  This way, both the parent and child can continue 
// to receive device packets.
// NOTE: can only call async-safe methods
static void udev_monitor_atfork(void) {
   
   int errsv = errno;
   int rc = 0;
   int i = 0;
   int cnt = 0;
   pid_t pid = getpid();
   struct udev_monitor* monitor = NULL;
   int socket_fds[2];
   struct epoll_event ev;
   
   write( STDERR_FILENO, "forked! begin split\n", strlen("forked! begin split\n") );
   
   memset( &ev, 0, sizeof(struct epoll_event) );
   
   // reset each monitor's inotify fd to point to a new PID-specific directory instead
   g_monitor_table_spinlock();
   
   if( g_pid != pid ) {
   
      // child; do the fork 
      for( i = 0; i < UDEV_MAX_MONITORS; i++ ) {
         
         if( g_monitor_table[i] == NULL ) {
            continue;
         }
         
         monitor = g_monitor_table[i];
         
         if( monitor->type != UDEV_MONITOR_TYPE_UDEV ) {
            continue;
         }
         
         if( monitor->inotify_fd < 0 ) {
            continue;
         }
         
         if( monitor->epoll_fd < 0 ) {
            continue;
         }
         
         if( monitor->events_wd < 0 ) {
            continue;
         }
            
         // reset the socket buffer--the parent will be said to have 
         // received intermittent events before the child was created.
         if( monitor->sock >= 0 ) {
            
            // stop watching this socket--we'll regenerate it later
            epoll_ctl( monitor->epoll_fd, EPOLL_CTL_DEL, monitor->sock, NULL );
            close( monitor->sock );
            monitor->sock = -1;
         }
         
         if( monitor->sock_fs >= 0 ) {
            close( monitor->sock_fs );
            monitor->sock_fs = -1;
         }
         
         rc = socketpair( AF_LOCAL, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, socket_fds );
         if( rc < 0 ) {
            
            // not much we can do here, except log an error 
            write( STDERR_FILENO, "Failed to generate a socketpair\n", strlen( "Failed to generate a socketpair\n" ) );

            udev_monitor_fs_shutdown( monitor );
            g_monitor_table[i] = NULL;
            continue;
         }
         
         // child's copy of the monitor has its own socketpair 
         monitor->sock = socket_fds[0];
         monitor->sock_fs = socket_fds[1];
         
         // reinstall its filter 
         udev_monitor_filter_update( monitor );
         
         // watch the child's socket 
         ev.events = EPOLLIN;
         ev.data.fd = monitor->sock;
         rc = epoll_ctl( monitor->epoll_fd, EPOLL_CTL_ADD, monitor->sock, &ev );
         if( rc < 0 ) {
            
            // not much we can do here, except log an error 
            write( STDERR_FILENO, "Failed to add monitor socket\n", strlen("Failed to add monitor socket\n") );
          
            udev_monitor_fs_shutdown( monitor );
            g_monitor_table[i] = NULL;
            continue;
         }
         
         // reset the inotify watch
         rc = inotify_rm_watch( monitor->inotify_fd, monitor->events_wd );
         monitor->events_wd = -1;
         
         if( rc < 0 ) {
            
            rc = -errno;
            if( rc == -EINVAL ) {
               
               // monitor->events_wd was invalid 
               rc = 0;
            }
            else if( rc == -EBADF ) {
               
               // monitor->inotify_fd is invalid.
               // not much we can do here, except log an error 
               write( STDERR_FILENO, "Invalid inotify handle\n", strlen("Invalid inotify handle"));
               
               udev_monitor_fs_shutdown( monitor );
               g_monitor_table[i] = NULL;
               continue;
            }
         }
         
         if( rc == 0 ) {
            
            udev_monitor_fs_events_path( "", monitor->events_dir, i );
            
            // try to create a new directory for this monitor
            rc = mkdir( monitor->events_dir, 0700 );
   
            if( rc < 0 ) {
               // failed, we have.
               // child will not get any notifications from this monitor
               rc = -errno;
               write( STDERR_FILENO, "Failed to mkdir ", strlen("Failed to mkdir ") );
               write( STDERR_FILENO, monitor->events_dir, strlen(monitor->events_dir) );
               write( STDERR_FILENO, "\n", 1 );
      
               udev_monitor_fs_shutdown( monitor );
               g_monitor_table[i] = NULL;
               return;
            }

            // reconnect to the new directory
            monitor->events_wd = inotify_add_watch( monitor->inotify_fd, monitor->events_dir, UDEV_FS_WATCH_DIR_FLAGS );
            if( monitor->events_wd < 0 ) {
               
               // there's not much we can safely do here, besides log an error
               write( STDERR_FILENO, "Failed to watch ", strlen( "Failed to watch " ) );
               write( STDERR_FILENO, monitor->events_dir, strlen(monitor->events_dir) );
               write( STDERR_FILENO, "\n", 1 );
            }
         }
         else {
            
            // there's not much we can safely do here, besides log an error
            rc = -errno;
            write( STDERR_FILENO, "Failed to disconnect!\n", strlen("Failed to disconnect!\n") );
         }
      }
      
      g_pid = pid;
   }
      
   g_monitor_table_unlock();
   
   write( STDERR_FILENO, "end atfork()\n", strlen("end atfork()\n") );
   
   // restore...
   errno = errsv;
}