tools

various tools
git clone git://deadbeef.fr/tools.git
Log | Files | Refs | README | LICENSE

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:
Mfbmon/src/fbmon.cpp | 20+++++++++-----------
Mfbmon/src/service_info.cpp | 149++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mfbmon/src/service_info.hpp | 4++--
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( &regex, regex_str, REG_NEWLINE ); - if( err ) - { - char errbuf[1024]; - size_t errlen = regerror( err, &regex, 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( &regex, 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( &regex ); - - 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