commit 66a72927543c969d7e8fa25a1c70308d2232a562
parent 3bcdc8b606e964a795664158ef5781b5eab1c3e6
Author: Morel Bérenger <berengermorel76@gmail.com>
Date:   Mon, 15 Feb 2021 23:00:14 +0100
fbmon: uses fnmatch + fixes + (some) cleanup
* uses POSIX fnmatch for regexes
* buffer handling has been fixed and improved
* various code cleanup
Diffstat:
3 files changed, 83 insertions(+), 90 deletions(-)
diff --git a/fbmon/src/fbmon.cpp b/fbmon/src/fbmon.cpp
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <assert.h>
 #include <math.h>
+#include <limits.h>
 
 #include <iterator>
 #include <algorithm>
@@ -173,16 +174,17 @@ int main( int argc, char **argv )
 	int nbev;
 	bool stop = false;
 	assert( g_inotify_watch_fd != 0 && "TODO: 0 can't be disabled in poll" );
-	int prev_time = time( nullptr );
-	int curr_time;
-	int dist_time = 0;
+	time_t prev_time = time( nullptr );
+	time_t curr_time;
+	ssize_t dist_time = 0;
 	while( !stop )
 	{
 		if( dist_time == 0 )
 		{
 			dist_time = refresh_delay;
 		}
-		nbev = poll( pfds.data(), pfds.size(), dist_time * 1000 );
+		assert( dist_time * 1000 <= INT_MAX );
+		nbev = poll( pfds.data(), pfds.size(), static_cast<int>( dist_time * 1000 ) );
 		curr_time = time( nullptr );
 		dist_time = curr_time - prev_time;
 		prev_time = curr_time;
@@ -204,18 +206,15 @@ int main( int argc, char **argv )
 				continue;
 			}
 
-			--nbev;
 			// dynamic FDs: target files
 			if( i > INOTIF_FD )
 			{
 				if( rev & ( POLLIN | POLLPRI ) )
 				{
-					update( services[i-1], pfds[i].fd, pfds[INOTIF_FD].fd, dist_time );
-				}
-				else
-				{
-					refresh( services[i-1], dist_time );
+					update( services[i-1] );
+					pfds[i].fd = -pfds[i].fd;
 				}
+				refresh( services[i-1], dist_time );
 			}
 			else
 			{
@@ -424,7 +423,6 @@ bool linux_event_handling( size_t start, vector<service_info_t>& svcs, vector<po
 			pfd.fd = svc_it->file_fd;
 		}
 
-
 		assert( -1 != event->wd );
 		assert( svc_it->dir_wfd != svc_it->file_wfd );
 	}
diff --git a/fbmon/src/service_info.cpp b/fbmon/src/service_info.cpp
@@ -20,6 +20,8 @@
 #include <assert.h>
 #include <string.h>
 #include <errno.h>
+#include <limits.h>
+#include <fnmatch.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -282,7 +284,7 @@ size_t name_sz( service_info_t const& svc )
 }
 
 //TODO: time implementation sucks
-bool refresh( service_info_t & svc, int time )
+bool refresh( service_info_t & svc, time_t time )
 {
 	status_t s = status( svc );
 
@@ -294,6 +296,7 @@ bool refresh( service_info_t & svc, int time )
 			break;
 		case WAKING:
 			color = g_color_wake;
+			assert( time < UINT16_MAX );
 			svc.birth_time += time;
 			if( svc.birth_time < svc.live_delay )
 			{
@@ -305,103 +308,95 @@ bool refresh( service_info_t & svc, int time )
 	}
 	assert( color );
 
+	assert( name_sz( svc ) < INT_MAX );
 	fprintf( stdout, "\x1B[%d;%dH" "\x1B[30;%sm" "%.*s" "\x1B[m\n" ,
 			svc.draw_area.y, svc.draw_area.x,
 			color,
-			name_sz( svc ), name( svc ) );
+			static_cast<int>( name_sz( svc ) ), name( svc ) );
 	return false;
 }
 
-bool update( service_info_t & svc, int &pfd, int &inotify_pfd, int time )
+bool update( service_info_t & svc )
 {
-	const size_t MAX_CHARS = 4095;
-	char buf[MAX_CHARS+1];
-	assert( pfd >= 0 );
-	ssize_t len = read( svc.file_fd, buf, MAX_CHARS );
-	if( -1 == len )
-	{
-		syserr( "reading target file failed" );
-		fprintf( stderr, "%d %d\n", svc.file_fd, pfd );
-		return true;
-	}
+	char buf[4096];
+	size_t to_read = sizeof( buf ) - 1;
+	char *start = buf;
 
-	buf[len] = 0;
-	if( MAX_CHARS != len ) // done with this file, for now
-	{
-		pfd = -pfd;
-	}
-	else //disable inotify to (try to) prevent loosing data if target moved
+	status_t s = status( svc );
+	ssize_t rd;
+	while( ( rd = read( svc.file_fd, start, to_read ) ) > 0 )
 	{
-		inotify_pfd = -inotify_pfd;
-	}
+		start[rd] = '\0';
+		char * end_line = start + rd - 1;
+		while( end_line >= start && *end_line != '\n' )
+		{
+			--end_line;
+		}
+		if( end_line < start )
+		{
+			fputs( "buffer too small", stderr ); //TODO mark as DOWN?
+			return true;
+		}
+		const char * const next_start = end_line + 1;
+		char const* start_line = end_line;
+		bool found = false;
+		uint16_t pattern = 0;
 
-	status_t s = status( svc );
+		do
+		{
+			do
+			{
+				--start_line;
+			} while( *start_line != '\n' && start_line >= buf );
 
-	char const* regex_str = svc.path + 1;
-	switch( s )
-	{
-		case DOWN:
-			regex_str += svc.svstart;
-			break;
-		case WAKING:
-			svc.birth_time += time;
-			if( svc.birth_time >= svc.live_delay )
+			++start_line;
+			*end_line = '\0'; //POSIX standard only works nul-term, not sizes.
+
+			pattern = svc.svstart;
+			found = FNM_NOMATCH != fnmatch( svc.path + 1 + pattern , start_line, 0 );
+			if( !found )
 			{
-				s = UP;
+				pattern = svc.svstop;
+				found = FNM_NOMATCH != fnmatch( svc.path + 1 + pattern , start_line, 0 );
 			}
-		case UP: // fallthrough
-			regex_str += svc.svstop;
-			break;
-	}
-	assert( regex_str );
 
-	regex_t regex;
-	int err = regcomp( ®ex, regex_str, REG_NEWLINE );
-	if( err )
-	{
-		char errbuf[1024];
-		size_t errlen = regerror( err, ®ex, errbuf, sizeof( errbuf ) );
-		fprintf( stderr, "failed to compile regex: %.*s (%d)\n", static_cast<int>( errlen ), errbuf, err );
-		return true;
-	}
-	const size_t NB_MATCHES = 2;
-	regmatch_t matches[NB_MATCHES]; //1st if match, 2nd for capture, don't care for others
-	//TODO: implement capture showing
-	int ret = regexec( ®ex, buf, NB_MATCHES, matches, 0 );
-	if( REG_NOMATCH != ret )
-	{
-		if( s == DOWN )
+			*end_line = '\n'; //revert changes had to do because of POSIX shit
+			--start_line;
+		} while( !found && start_line >= buf );
+
+		if( found )
 		{
-			svc.birth_time = 0;
-			s = svc.birth_time <= svc.live_delay ? WAKING : UP;
+			assert( pattern != 0 );
+			if( pattern == svc.svstart )
+			{
+				s = WAKING;
+				svc.birth_time = 0;
+			}
+			else
+			{
+				s = DOWN;
+				svc.birth_time = UINT16_MAX;
+			}
 		}
-		else
+
+		if( static_cast<size_t>( rd ) == to_read )
 		{
-			svc.birth_time = UINT16_MAX;
-			s = DOWN;
+			assert( buf + sizeof( buf ) > next_start );
+			size_t offset = static_cast<size_t>( buf + sizeof( buf ) - next_start );
+			memmove( buf, next_start, offset );
+			start = buf + offset;
+			to_read = sizeof( buf ) - offset - 1;
 		}
 	}
-
-	char const* color = nullptr;
-	switch( s )
+	//TODO: handle errors more correctly
+	//  EINTR: signal received
+	//  EAGAIN: file is non-blocking (should not happen but...)
+	if( -1 == rd )
 	{
-		case DOWN:
-			color = g_color_down;
-			break;
-		case UP:
-			color = g_color_up;
-			break;
-		case WAKING:
-			color = g_color_wake;
-			break;
+		syserr( "reading target file failed" );
+		fprintf( stderr, "%d\n", svc.file_fd );
+		return true;
 	}
-	assert( color );
-	regfree( ®ex );
-
-	fprintf( stdout, "\x1B[%d;%dH" "\x1B[30;%sm" "%.*s" "\x1B[m\n" ,
-			svc.draw_area.y, svc.draw_area.x,
-			color,
-			name_sz( svc ), name( svc ) );
 	return false;
 }
 
diff --git a/fbmon/src/service_info.hpp b/fbmon/src/service_info.hpp
@@ -71,8 +71,8 @@ char const* name( service_info_t const& svc );
 status_t status( service_info_t const& svc );
 
 bool print_status( service_info_t const& svc );
-bool refresh( service_info_t & svc, int time );
-bool update( service_info_t & svc, int& pfd, int& inotify_pfd, int time );
+bool refresh( service_info_t & svc, time_t time );
+bool update( service_info_t & svc );
 
 // stores the "master" inotify. Inotify is used to avoid
 // active probing files and still be able to handle log