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