diff options
-rw-r--r-- | TODOS | 5 | ||||
-rw-r--r-- | src/GNUmakefile | 5 | ||||
-rw-r--r-- | src/biruda.c | 305 | ||||
-rw-r--r-- | src/cli.c | 311 | ||||
-rw-r--r-- | src/cli.h | 8 |
5 files changed, 323 insertions, 311 deletions
@@ -1,9 +1,4 @@ -- find ways to easy control subprocesses - - glibc process - - Poco - - links -http://blog.borovsak.si/2009/07/spawning-processes-using-glib.html http://www.codeguru.com/cpp/misc/misc/system/article.php/c8973/Determine-Windows-Version-and-Edition.htm - surveyor -> bus, maybe also Windows blocking problem disappears diff --git a/src/GNUmakefile b/src/GNUmakefile index 3a574e2..b6d48e3 100644 --- a/src/GNUmakefile +++ b/src/GNUmakefile @@ -13,11 +13,11 @@ LIBS += `pkg-config --libs-only-l glib-2.0` %.o : %.c $(CC) $(CFLAGS) -c -o $@ $< -biruda: biruda.o biruda_cmdline.o master.o coordinator.o worker.o system.o webserver.o 3rdParty/linenoise/linenoise.o 3rdParty/http_tiny/http_lib.o +biruda: biruda.o biruda_cmdline.o master.o coordinator.o worker.o system.o webserver.o 3rdParty/linenoise/linenoise.o 3rdParty/http_tiny/http_lib.o cli.o $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) biruda_cmdline.o: biruda_cmdline.c -biruda.o: biruda.c biruda_cmdline.h master.h coordinator.h worker.h port.h system.h webserver.h 3rdParty/linenoise/linenoise.h +biruda.o: biruda.c biruda_cmdline.h master.h coordinator.h worker.h port.h system.h webserver.h 3rdParty/linenoise/linenoise.h cli.h master.o: master.c master.h port.h coordinator.o: coordinator.c coordinator.h port.h system.h worker.o: worker.c worker.h port.h @@ -25,6 +25,7 @@ system.o: system.c system.h webserver.o: webserver.c webserver.h 3rdParty/linenoise/linenoise.o: 3rdParty/linenoise/linenoise.c 3rdParty/linenoise/linenoise.h 3rdParty/http_tiny/http_lib.o: 3rdParty/http_tiny/http_lib.c 3rdParty/http_tiny/http_lib.h +cli.o: cli.c cli.h biruda_cmdline.c: biruda.ggo gengetopt -F biruda_cmdline --unamed-opts --conf-parser --include-getopt -i $< diff --git a/src/biruda.c b/src/biruda.c index ce49544..5f73aa5 100644 --- a/src/biruda.c +++ b/src/biruda.c @@ -31,13 +31,8 @@ #include "webserver.h" #endif -// for cli/interactive biruda client #ifndef _WIN32 -#include <strings.h> -#include <ctype.h> -#include <stdarg.h> -#include "linenoise.h" -#include "http_lib.h" +#include "cli.h" #endif #include "port.h" @@ -250,304 +245,6 @@ static void terminate_foreground_func( int sig ) } #endif -#ifndef _WIN32 - -#define HISTORY_FILE ".biruda_history" - -typedef enum { - COMMAND, // command parsing - START_WORKER, // worker command expecting a worker parameter - STOP_WORKER -} command_state_t; - -static char *commands[] = { - "help", "quit", "status", "start", "stop", NULL -}; - -static bool print_colors = false; - -static bool is_interactive = false; - -static command_state_t command_state = COMMAND; - -static char *worker_names[MAX_WORKERS]; - -static int nof_worker_names = 0; - -static void cleanup_worker_names( ) -{ - for( int i = 0; i < nof_worker_names; i++ ) { - free( worker_names[i] ); - } - nof_worker_names = 0; -} - -static void print_error( const char *fmt, ... ); - -static void get_workers( ) -{ - char *url = "status"; - char *data = NULL; - int len; - http_retcode ret = http_get( url, &data, &len, NULL ); - if( ret == 200 ) { - cleanup_worker_names( ); - - char *line = strtok( data, "\n" ); - while( line != NULL ) { - char *p = strchr( line, ' ' ); - if( p == NULL ) { - line = strtok( NULL, "\n" ); - continue; - } - if( strncmp( line, "worker", p - line ) != 0 ) { - line = strtok( NULL, "\n" ); - continue; - } - char *pp = strchr( p+1, ' ' ); - if( pp == NULL ) { - line = strtok( NULL, "\n" ); - continue; - } - char s = *pp; - *pp = '\0'; - if( nof_worker_names >= MAX_WORKERS ) { - fprintf( stderr, "ERROR: Too many workers seen, ignoring rest!\n" ); - free( data ); - return; - } - worker_names[nof_worker_names++] = strdup( p + 1 ); - *pp = s; - line = strtok( NULL, "\n" ); - } - } else { - print_error( "ERROR: HTTP error %d", ret ); - } - free( data ); -} - -static void completion_func( const char *buf, linenoiseCompletions *lc ) -{ - unsigned int i; - size_t len = strlen( buf ); - - switch( command_state ) { - case COMMAND: - for (i = 0; commands[i]; ++i) { - char *cmd = commands[i]; - if( strlen( cmd ) < len ) continue; - if( strncasecmp( buf, cmd, len ) == 0 ) { - linenoiseAddCompletion( lc, cmd ); - } - } - break; - - case START_WORKER: - case STOP_WORKER: - get_workers( ); - for( int i = 0; i < nof_worker_names; i++ ) { - linenoiseAddCompletion( lc, worker_names[i] ); - } - break; - } -} - -static void print_help( ) -{ - puts( "\n" - " help - show this help page\n" - " quit - quit the client\n" - " status - status of the biruda network\n" - " start - start a worker manually\n" - " stop - stop a worker manually\n" - ); -} - -static void print_colored( const char *fmt, int color, va_list ap ) -{ - char buf[1024]; - - (void)vsnprintf( buf, sizeof( buf ), fmt, ap ); - - if( print_colors ) { - printf( "%c[9%dm%s%c[0m\n", 27, color, buf, 27 ); - } else { - puts( buf ); - } -} - -static void print_error( const char *fmt, ... ) -{ - va_list ap; - va_start( ap, fmt ); - print_colored( fmt, 1, ap ); - va_end( ap ); -} - -static void print_answer( const char *fmt, ... ) -{ - va_list ap; - va_start( ap, fmt ); - print_colored( fmt, 2, ap ); - va_end( ap ); -} - -static void print_status( ) -{ - char *url = "status"; - char *data = NULL; - int len; - http_retcode ret = http_get( url, &data, &len, NULL ); - if( ret == 200 ) { - if( strlen( data ) > 0 && data[len-1] == '\n' ) { - data[len-1] = '\0'; - len--; - } - if( strlen( data ) > 0 && data[len-1] == '\r' ) { - data[len-1] = '\0'; - } - print_answer( data ); - } else { - print_error( "ERROR: HTTP error %d", ret ); - } - free( data ); -} - -static void start_worker( const char *worker_name ) -{ - char url[128]; - snprintf( url, sizeof( url ), "worker?op=start&name=%s", worker_name ); - http_retcode ret = http_post( url, "", 0, "Content-Type: text/plain" ); - if( ret == 200 ) { - print_answer( "Request queued" ); - } else { - print_error( "ERROR: HTTP error %d", ret ); - } -} - -static void stop_worker( const char *worker_name ) -{ - char url[128]; - snprintf( url, sizeof( url ), "worker?op=stop&name=%s", worker_name ); - http_retcode ret = http_post( url, "", 0, "Content-Type: text/plain" ); - if( ret == 200 ) { - print_answer( "Request queued" ); - } else { - print_error( "ERROR: HTTP error %d", ret ); - } -} - -static int start_interactive( bool colors ) -{ - char history_filename[1024]; - - // for http_tidy, tell it where to issue requests to - http_server = "localhost"; - http_port = 8080; - - is_interactive = isatty( fileno( stdin ) ); - print_colors = is_interactive ? colors : false; - - if( is_interactive ) { - char *home = getenv( "HOME" ); - if( home != NULL ) { - snprintf( history_filename, sizeof( history_filename ), "%s/%s", home, HISTORY_FILE ); - linenoiseHistoryLoad( history_filename ); - linenoiseSetCompletionCallback( completion_func ); - } - } - - char *context = "biruda"; - for( ;; ) { - char prompt[128]; - char buf[1024]; - char *line; - - switch( command_state ) { - case COMMAND: - context = "biruda"; - break; - - case START_WORKER: - case STOP_WORKER: - context = "worker"; - break; - } - - if( is_interactive ) { - snprintf( prompt, sizeof( prompt ), "%s> ", context ); - if( ( line = linenoise( prompt ) ) == NULL ) { - switch( command_state ) { - case COMMAND: - cleanup_worker_names( ); - free( line ); - return EXIT_SUCCESS; - - case START_WORKER: - case STOP_WORKER: - command_state = COMMAND; - continue; - } - break; - } - strncpy( buf, line, sizeof( buf ) ); - free( line ); - line = buf; - } else { - if( fgets( buf, sizeof( buf ), stdin ) == NULL ) { - cleanup_worker_names( ); - return EXIT_SUCCESS; - } - line = buf; - } - - if( strlen( line ) > 1 ) { - if( line[strlen( line )-1] == '\n' ) { - line[strlen( line )-1] = '\0'; - } - } - - if( is_interactive ) { - linenoiseHistoryAdd( line ); - } - - switch( command_state ) { - case COMMAND: - if( strncasecmp( line, "quit", 4 ) == 0 ) { - if( is_interactive ) { - linenoiseHistorySave( history_filename ); - } - cleanup_worker_names( ); - return EXIT_SUCCESS; - } else if( strncasecmp( line, "help", 4 ) == 0 ) { - print_help( ); - } else if( strncasecmp( line, "status", 6 ) == 0 ) { - print_status( ); - } else if( strncasecmp( line, "start", 5 ) == 0 ) { - command_state = START_WORKER; - } else if( strncasecmp( line, "stop", 5 ) == 0 ) { - command_state = STOP_WORKER; - } else { - print_error( "Bad command '%s'.", line ); - } - break; - - case START_WORKER: - start_worker( line ); - command_state = COMMAND; - break; - - case STOP_WORKER: - stop_worker( line ); - command_state = COMMAND; - break; - } - } - - return EXIT_SUCCESS; -} -#endif - int main( int argc, char *argv[] ) { struct gengetopt_args_info args_info; diff --git a/src/cli.c b/src/cli.c new file mode 100644 index 0000000..3f2e7fd --- /dev/null +++ b/src/cli.c @@ -0,0 +1,311 @@ +#include "cli.h" + +#ifndef _WIN32 +#include <strings.h> +#include <ctype.h> +#include <stdarg.h> +#include "linenoise.h" +#include "http_lib.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#define HISTORY_FILE ".biruda_history" + +#include "coordinator.h" +#include "worker.h" + +typedef enum { + COMMAND, // command parsing + START_WORKER, // worker command expecting a worker parameter + STOP_WORKER +} command_state_t; + +static char *commands[] = { + "help", "quit", "status", "start", "stop", NULL +}; + +static bool print_colors = false; + +static bool is_interactive = false; + +static command_state_t command_state = COMMAND; + +static char *worker_names[MAX_WORKERS]; + +static int nof_worker_names = 0; + +static void cleanup_worker_names( ) +{ + for( int i = 0; i < nof_worker_names; i++ ) { + free( worker_names[i] ); + } + nof_worker_names = 0; +} + +static void print_error( const char *fmt, ... ); + +static void get_workers( ) +{ + char *url = "status"; + char *data = NULL; + int len; + http_retcode ret = http_get( url, &data, &len, NULL ); + if( ret == 200 ) { + cleanup_worker_names( ); + + char *line = strtok( data, "\n" ); + while( line != NULL ) { + char *p = strchr( line, ' ' ); + if( p == NULL ) { + line = strtok( NULL, "\n" ); + continue; + } + if( strncmp( line, "worker", p - line ) != 0 ) { + line = strtok( NULL, "\n" ); + continue; + } + char *pp = strchr( p+1, ' ' ); + if( pp == NULL ) { + line = strtok( NULL, "\n" ); + continue; + } + char s = *pp; + *pp = '\0'; + if( nof_worker_names >= MAX_WORKERS ) { + fprintf( stderr, "ERROR: Too many workers seen, ignoring rest!\n" ); + free( data ); + return; + } + worker_names[nof_worker_names++] = strdup( p + 1 ); + *pp = s; + line = strtok( NULL, "\n" ); + } + } else { + print_error( "ERROR: HTTP error %d", ret ); + } + free( data ); +} + +static void completion_func( const char *buf, linenoiseCompletions *lc ) +{ + unsigned int i; + size_t len = strlen( buf ); + + switch( command_state ) { + case COMMAND: + for (i = 0; commands[i]; ++i) { + char *cmd = commands[i]; + if( strlen( cmd ) < len ) continue; + if( strncasecmp( buf, cmd, len ) == 0 ) { + linenoiseAddCompletion( lc, cmd ); + } + } + break; + + case START_WORKER: + case STOP_WORKER: + get_workers( ); + for( int i = 0; i < nof_worker_names; i++ ) { + linenoiseAddCompletion( lc, worker_names[i] ); + } + break; + } +} + +static void print_help( ) +{ + puts( "\n" + " help - show this help page\n" + " quit - quit the client\n" + " status - status of the biruda network\n" + " start - start a worker manually\n" + " stop - stop a worker manually\n" + ); +} + +static void print_colored( const char *fmt, int color, va_list ap ) +{ + char buf[1024]; + + (void)vsnprintf( buf, sizeof( buf ), fmt, ap ); + + if( print_colors ) { + printf( "%c[9%dm%s%c[0m\n", 27, color, buf, 27 ); + } else { + puts( buf ); + } +} + +static void print_error( const char *fmt, ... ) +{ + va_list ap; + va_start( ap, fmt ); + print_colored( fmt, 1, ap ); + va_end( ap ); +} + +static void print_answer( const char *fmt, ... ) +{ + va_list ap; + va_start( ap, fmt ); + print_colored( fmt, 2, ap ); + va_end( ap ); +} + +static void print_status( ) +{ + char *url = "status"; + char *data = NULL; + int len; + http_retcode ret = http_get( url, &data, &len, NULL ); + if( ret == 200 ) { + if( strlen( data ) > 0 && data[len-1] == '\n' ) { + data[len-1] = '\0'; + len--; + } + if( strlen( data ) > 0 && data[len-1] == '\r' ) { + data[len-1] = '\0'; + } + print_answer( data ); + } else { + print_error( "ERROR: HTTP error %d", ret ); + } + free( data ); +} + +static void start_worker( const char *worker_name ) +{ + char url[128]; + snprintf( url, sizeof( url ), "worker?op=start&name=%s", worker_name ); + http_retcode ret = http_post( url, "", 0, "Content-Type: text/plain" ); + if( ret == 200 ) { + print_answer( "Request queued" ); + } else { + print_error( "ERROR: HTTP error %d", ret ); + } +} + +static void stop_worker( const char *worker_name ) +{ + char url[128]; + snprintf( url, sizeof( url ), "worker?op=stop&name=%s", worker_name ); + http_retcode ret = http_post( url, "", 0, "Content-Type: text/plain" ); + if( ret == 200 ) { + print_answer( "Request queued" ); + } else { + print_error( "ERROR: HTTP error %d", ret ); + } +} + +int start_interactive( bool colors ) +{ + char history_filename[1024]; + + // for http_tidy, tell it where to issue requests to + http_server = "localhost"; + http_port = 8080; + + is_interactive = isatty( fileno( stdin ) ); + print_colors = is_interactive ? colors : false; + + if( is_interactive ) { + char *home = getenv( "HOME" ); + if( home != NULL ) { + snprintf( history_filename, sizeof( history_filename ), "%s/%s", home, HISTORY_FILE ); + linenoiseHistoryLoad( history_filename ); + linenoiseSetCompletionCallback( completion_func ); + } + } + + char *context = "biruda"; + for( ;; ) { + char prompt[128]; + char buf[1024]; + char *line; + + switch( command_state ) { + case COMMAND: + context = "biruda"; + break; + + case START_WORKER: + case STOP_WORKER: + context = "worker"; + break; + } + + if( is_interactive ) { + snprintf( prompt, sizeof( prompt ), "%s> ", context ); + if( ( line = linenoise( prompt ) ) == NULL ) { + switch( command_state ) { + case COMMAND: + cleanup_worker_names( ); + free( line ); + return EXIT_SUCCESS; + + case START_WORKER: + case STOP_WORKER: + command_state = COMMAND; + continue; + } + break; + } + strncpy( buf, line, sizeof( buf ) ); + free( line ); + line = buf; + } else { + if( fgets( buf, sizeof( buf ), stdin ) == NULL ) { + cleanup_worker_names( ); + return EXIT_SUCCESS; + } + line = buf; + } + + if( strlen( line ) > 1 ) { + if( line[strlen( line )-1] == '\n' ) { + line[strlen( line )-1] = '\0'; + } + } + + if( is_interactive ) { + linenoiseHistoryAdd( line ); + } + + switch( command_state ) { + case COMMAND: + if( strncasecmp( line, "quit", 4 ) == 0 ) { + if( is_interactive ) { + linenoiseHistorySave( history_filename ); + } + cleanup_worker_names( ); + return EXIT_SUCCESS; + } else if( strncasecmp( line, "help", 4 ) == 0 ) { + print_help( ); + } else if( strncasecmp( line, "status", 6 ) == 0 ) { + print_status( ); + } else if( strncasecmp( line, "start", 5 ) == 0 ) { + command_state = START_WORKER; + } else if( strncasecmp( line, "stop", 5 ) == 0 ) { + command_state = STOP_WORKER; + } else { + print_error( "Bad command '%s'.", line ); + } + break; + + case START_WORKER: + start_worker( line ); + command_state = COMMAND; + break; + + case STOP_WORKER: + stop_worker( line ); + command_state = COMMAND; + break; + } + } + + return EXIT_SUCCESS; +} diff --git a/src/cli.h b/src/cli.h new file mode 100644 index 0000000..f362088 --- /dev/null +++ b/src/cli.h @@ -0,0 +1,8 @@ +#ifndef _BIRUDA_CLI_HEADER_INCLUDED +#define _BIRUDA_CLI_HEADER_INCLUDED + +#include "port.h" + +int start_interactive( bool colors ); + +#endif |