* Minor tweaks to kaoupload.c (error handling, display).
authorUrban Wallasch <urban.wallasch@freenet.de>
Thu, 22 Apr 2021 14:36:11 +0000 (16:36 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Thu, 22 Apr 2021 15:12:49 +0000 (17:12 +0200)
Makefile
kaoupload.c

index d412d9e32a63008f7a6f774cd736c90c0c2e306f..cecc7484f6079a495b6cf1fbaee69ef3569a8e62 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 .PHONY: all clean
 
-CFLAGS += -W -Wall
+CFLAGS += -W -Wall -Wextra -std=gnu99
 CFLAGS += `pkg-config --cflags libcurl`
 LDFLAGS += `pkg-config --libs libcurl`
 
index 8a9a8d80c733dd47d663454a1c08fa9bf1607f6b..882a513b201b761875df1c1fcbfd461f55524224 100644 (file)
@@ -109,12 +109,14 @@ static uint64_t time_ms( void ) {
     return (uint64_t)tv.tv_sec * 1000 + ( tv.tv_nsec / 1000000L );
 }
 
-static void parse_cfg( const char *confpath ) {
+static int parse_cfg( const char *confpath ) {
     FILE *fp;
     char buf[256];
 
-    if ( NULL == confpath || NULL == ( fp = fopen( confpath, "r" ) ) )
-        return;
+    if ( NULL == confpath )
+        return EINVAL;
+    if ( NULL == ( fp = fopen( confpath, "r" ) ) )
+        return errno;
     while ( fgets( buf, sizeof buf - 1, fp ) ) {
         char *key, *val, *x;
         key = buf;
@@ -152,6 +154,7 @@ static void parse_cfg( const char *confpath ) {
             cfg.bwlup = str_to_bwl( val );
     }
     fclose( fp );
+    return 0;
 }
 
 static size_t write_memory_cb( void *contents, size_t size, size_t nmemb, void *userp ) {
@@ -175,7 +178,7 @@ static size_t write_memory_cb( void *contents, size_t size, size_t nmemb, void *
 #define RESP_MISMATCH   "Partfile initial sequence mismatch"
 
 static int upload_chunk( CURL *curl, struct file_info_t *fi, off_t csize ) {
-    int res = -1;
+    int n, res = -1;
     long http_code;
     ssize_t br;
     char url[2048];
@@ -198,8 +201,15 @@ static int upload_chunk( CURL *curl, struct file_info_t *fi, off_t csize ) {
     }
     if ( csize > br )
         csize = br;
-    snprintf( url, sizeof url, "%s?fname=%s&fpos=%lu&fsize=%lu", cfg.url, fi->esc_name, fi->coff, fi->size );
-
+    n = snprintf( url, sizeof url, "%s?fname=%s&fpos=%lu&fsize=%lu",
+                            cfg.url, fi->esc_name, fi->coff, fi->size );
+    if ( sizeof url <= (size_t)n ) {
+        if ( 0 > n )
+            err( "snprintf(url, ...)", errno );
+        else
+            err( "snprintf(url, ...): URL too long", 0 );
+        goto err_out;
+    }
     curl_easy_reset( curl );
     error = curl_easy_setopt( curl, CURLOPT_POST, 1L );
     error |= curl_easy_setopt( curl, CURLOPT_POSTFIELDSIZE, (long)csize );
@@ -224,9 +234,13 @@ static int upload_chunk( CURL *curl, struct file_info_t *fi, off_t csize ) {
         goto err_out;
     }
 
-    curl_easy_getinfo( curl, CURLINFO_SPEED_UPLOAD_T, &fi->speed );
-    curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &http_code );
     fi->sent += csize;
+    error = curl_easy_getinfo( curl, CURLINFO_SPEED_UPLOAD_T, &fi->speed );
+    error |= curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &http_code );
+    if ( CURLE_OK != error ) {
+        cerr( "curl_easy_getinfo", error );
+        goto err_out;
+    }
 
     // puts(reply.memory);
 
@@ -248,7 +262,7 @@ static int upload_chunk( CURL *curl, struct file_info_t *fi, off_t csize ) {
                 res = 0;
         }
         else
-            fprintf( stderr, "ERROR: unexpected response: %s", reply.memory );
+            fprintf( stderr, "\rERROR: unexpected response: %ld  %.80s\n", http_code, reply.memory );
         break;
     case 201:
         // upon receiving the first chunk, remote detected a partfile initial
@@ -258,6 +272,8 @@ static int upload_chunk( CURL *curl, struct file_info_t *fi, off_t csize ) {
             fi->remn -= csize;
             res = 0;
         }
+        else
+            fprintf( stderr, "\rERROR: unexpected response: %ld  %.80s\n", http_code, reply.memory );
         break;
     case 428:
         // remote already has data up to Skip-to-position
@@ -267,11 +283,11 @@ static int upload_chunk( CURL *curl, struct file_info_t *fi, off_t csize ) {
             res = 0;
         }
         else
-            err( "response code 428 w/o 'Skip-to-position'", 0 );
+            fprintf( stderr, "\rERROR: unexpected response: %ld  %.80s\n", http_code, reply.memory );
         break;
     default:
-        fprintf( stderr, "REMOTE ERROR: %ld  %s", http_code,
-                100 > reply.size ? reply.memory : ( 403 == http_code ? "Forbidden" : "" ) );
+        fprintf( stderr, "\rREMOTE ERROR: %ld  %.80s\n", http_code,
+                        403 == http_code ? "Forbidden" : reply.memory );
         break;
     }
 
@@ -320,13 +336,13 @@ static int upload_file( const char *fn ) {
             csize = 2 * fi.speed;
         if ( CSIZE_HARDLIMIT < csize )
             csize = CSIZE_HARDLIMIT;
-        fprintf( stderr, "\r%3.f%% (%5.1f kB/s) ", (double)fi.coff * 100 / fi.size, (double)fi.speed / 1024 );
+        fprintf( stderr, "\r%3.f%% (%5.1f KiB/s) ", (double)fi.coff * 100 / fi.size, (double)fi.speed / 1024 );
         // fprintf( stderr, "[csize: %ld] {offset: %ld} ", (long)csize, (long)fi.coff );
         fflush( stderr );
     }
 
     xfrtime = time_ms() - starttime + 1;
-    printf( "\rSent %.1f kB in %.1f seconds (%.1f kB/s).\n",
+    printf( "\rSent %.1f KiB in %.1f seconds (%.1f KiB/s).\n",
             (double)fi.sent / 1024, (double)xfrtime / 1000, (double)fi.sent / xfrtime * 1000 / 1024 );
     if ( res < 0 )
         err( "file upload incomplete", 0 );
@@ -340,56 +356,67 @@ static int upload_file( const char *fn ) {
     return res;
 }
 
-static void usage( char *pname ) {
+static void usage( char *pname, int ec ) {
     printf( "%s - upload files to Kaotan\n", basename( pname ) );
     printf( "USAGE:  %s [OPTIONS] FILE ...\n", basename( pname ) );
     printf( "OPTIONS:\n"
             "  -h         display this help text and exit\n"
-            "  -c file    specify configuration file (default: ~/%s)\n"
-            "  -l maxbps  upload speed limit in bytes per second, e.g. 100k\n"
+            "  -c file    specify configuration file; default: ~/%s\n"
+            "  -l maxbps  upload speed limit in bytes per second, e.g. 100k; default: 0 (== no limit)\n"
             "  -u user    set user name\n"
             "  -p passwd  set password\n"
-            "  -U URL     set base URL\n"
-            , CFG_BASE
+            "  -U URL     set base URL (default: %s)\n"
+            , CFG_BASE, URL_BASE
     );
-    printf( "Defaults for bandwidth limit, user, password and URL are taken "
-            "from environment and configuration file, in this order.\n" );
-    doExit( EXIT_FAILURE );
+    printf(
+        "\nDefaults for bandwidth limit ($BWLUP), user ($USER), password ($PASS) and base URL ($URL)\n"
+        "are taken from the environment and the configuration file, in this order.  Values set on\n"
+        "the command line always take precedence over default values.\n"
+    );
+    doExit( ec );
 }
 
 int main( int argc, char *argv[] ) {
     int res = 0;
     int c;
-    char confpath[256];
+    char confpath[PATH_MAX];
+
+    signal( SIGINT, sig_handler );
+    signal( SIGTERM, sig_handler );
+    signal( SIGHUP, sig_handler );
 
     cfg.user = strdup( getenv( "USER" ) ? getenv( "USER" ) : "" );
     cfg.pass = strdup( getenv( "PASS" ) ? getenv( "PASS" ) : "" );
     cfg.url = strdup( getenv( "URL" ) ? getenv( "URL" ) : URL_BASE );
     cfg.bwlup = str_to_bwl( getenv( "BWLUP" ) ? getenv( "BWLUP" ) : "0" );
     snprintf( confpath, sizeof confpath, "%s/%s", getenv( "HOME" ), CFG_BASE );
-    while ( ( c = getopt( argc, argv, "+:c:" ) ) != -1 ) {
+    while ( ( c = getopt( argc, argv, "+:c:h" ) ) != -1 ) {
         switch (c) {
         case 'c':
-            snprintf( confpath, sizeof confpath, "%s", optarg );
+            res = snprintf( confpath, sizeof confpath, "%s", optarg );
+            if ( sizeof confpath <= (size_t)res )
+                die( optarg, res < 0 ? errno : ENAMETOOLONG );
+            break;
+        case 'h':
+            usage( argv[0], EXIT_SUCCESS );
             break;
         case ':':
             fprintf( stderr, "ERROR: missing argument for option '-%c'\n", optopt );
-            usage( argv[0] );
+            usage( argv[0], EXIT_FAILURE );
             break;
         default:
             break;
         }
     }
-    parse_cfg( confpath );
+    if ( 0 != ( res = parse_cfg( confpath ) ) )
+       err( confpath, res );
 
     optind = 0;
     while ( ( c = getopt( argc, argv, "+:c:hl:p:u:U:" ) ) != -1 ) {
         switch (c) {
         case 'c':
-            // already handled above
-            break;
         case 'h':
-            usage( argv[0] );
+            // already handled above
             break;
         case 'l':
             cfg.bwlup = str_to_bwl( optarg );
@@ -408,30 +435,27 @@ int main( int argc, char *argv[] ) {
             break;
         case ':':
             fprintf( stderr, "ERROR: missing argument for option '-%c'\n", optopt );
-            usage( argv[0] );
+            usage( argv[0], EXIT_FAILURE );
             break;
         case '?':
             fprintf( stderr, "ERROR: unknown option '-%c'\n", optopt );
-            usage( argv[0] );
+            usage( argv[0], EXIT_FAILURE );
             break;
         default:
-            fprintf( stderr, "ERROR: option '-%c' not implemented, programmer PEBKAC.\n", c );
+            fprintf( stderr, "WARNING: option '-%c' not implemented, programmer PEBKAC.\n", c );
             break;
         }
     }
 
     if ( optind >= argc ) {
         err( "no file to upload", 0 );
-        usage( argv[0] );
+        usage( argv[0], EXIT_FAILURE );
     }
 
     if ( CURLE_OK != curl_global_init( CURL_GLOBAL_SSL ) )
         die( "curl_global_init", 0 );
 
-    signal( SIGINT, sig_handler );
-    signal( SIGTERM, sig_handler );
-    signal( SIGHUP, sig_handler );
-
+    res = 0;
     while ( optind < argc && !gotsig && 0 == res )
         res = upload_file( argv[optind++] );