chiark / gitweb /
rcopy-repeatedly debugging wip
[chiark-utils.git] / cprogs / rcopy-repeatedly.c
index 399e8aacc6e19a37a617bbae3f1d92cf5886d6ef..9c231857d5a16bc846e5500740c254f8b1cd5f5d 100644 (file)
@@ -56,7 +56,7 @@ static FILE *commsi, *commso;
 
 static double max_bandwidth_proportion_mean= 0.2;
 static double max_bandwidth_proportion_burst= 0.8;
-static int txblocksz= INT_MAX;
+static int txblocksz= INT_MAX, verbose=1;
 static int min_interval_usec= 100000; /* 100ms */
 
 static const char *rsh_program= "ssh";
@@ -145,6 +145,23 @@ static double mgettime_elapsed(struct timespec ts_base,
          (ts_ret->tv_nsec - ts_base.tv_nsec)*1e-9;
 }
 
+static void verbosespinprintf(const char *fmt, ...) {
+  static const char spinnerchars[]= "/-\\";
+  static int spinnerchar;
+
+  if (!verbose)
+    return;
+
+  va_list al;
+  va_start(al,fmt);
+  fprintf(stderr," %c ",spinnerchars[spinnerchar]);
+  spinnerchar++; spinnerchar %= sizeof(spinnerchars)-1;
+  vfprintf(stderr,fmt,al);
+  putc('\r',stderr);
+  if (ferror(stderr) || fflush(stderr))
+    diee("could not write progress to stderr");
+}
+
 static void bandlimit_sendend(uint64_t bytes, int *interval_usec_update) {
   struct timespec ts_buf;
   double elapsed= mgettime_elapsed(ts_sendstart, &ts_buf);
@@ -160,6 +177,10 @@ static void bandlimit_sendend(uint64_t bytes, int *interval_usec_update) {
 
   if (*interval_usec_update > min_update_usec)
     *interval_usec_update= min_update_usec;
+
+  verbosespinprintf("%12lluby %10fs %13gkby/s",
+                   (unsigned long long)bytes, elapsed,
+                   1e-3/secsperbyte_observed);
 }
  
 static void copyfile(FILE *sf, copyfile_die_fn *sdie, const char *sxi,
@@ -170,7 +191,7 @@ static void copyfile(FILE *sf, copyfile_die_fn *sdie, const char *sxi,
 
   ts_last= ts_sendstart;
 
-  while (l>=0) {
+  while (l>0) {
     now= l < sizeof(mainbuf) ? l : sizeof(mainbuf);
     if (now > txblocksz) now= txblocksz;
 
@@ -269,7 +290,10 @@ static void sender(const char *filename) {
   told= told_nothing;
   
   for (;;) {
-    if (interval_usec) usleep(interval_usec);
+    if (interval_usec) {
+      send_flush();
+      usleep(interval_usec);
+    }
     interval_usec= min_interval_usec;
 
     r= stat(filename, &stabtest);
@@ -277,9 +301,11 @@ static void sender(const char *filename) {
       f= 0;
     } else {
       if (told == told_file &&
-         stabtest.st_mode == stab.st_mode &&
-         stabtest.st_dev == stab.st_dev &&
-         stabtest.st_ino == stab.st_ino)
+         stabtest.st_mode  == stab.st_mode  &&
+         stabtest.st_dev   == stab.st_dev   &&
+         stabtest.st_ino   == stab.st_ino   &&
+         stabtest.st_mtime == stab.st_mtime &&
+         stabtest.st_size  == stab.st_size)
        continue;
       f= fopen(filename, "rb");
     }
@@ -287,6 +313,7 @@ static void sender(const char *filename) {
     if (!f) {
       if (errno!=ENOENT) diee("could not access source file `%s'",filename);
       if (told != told_remove) {
+       verbosespinprintf(" ENOENT                            ");
        sendbyte(REPLMSG_RM);
        told= told_remove;
       }
@@ -356,12 +383,14 @@ typedef struct {
 } FileSpecification;
 
 static FileSpecification srcspec, dstspec;
-static int upload=-1; /* -1 means not yet known; 0 means download */
+static int upcopy=-1; /* -1 means not yet known; 0 means download */
+  /* `up' means towards the client,
+   * since we regard the subprocess as `down' */
 
 static const struct cmdinfo cmdinfos[]= {
   { "help",     .call= of_help },
-  { "receiver", .iassignto=&upload, .arg=1 },
-  { "sender",   .iassignto=&upload, .arg=0 },
+  { "receiver", .iassignto=&upcopy, .arg=0 },
+  { "sender",   .iassignto=&upcopy, .arg=1 },
   { 0 }
 };
 
@@ -369,15 +398,15 @@ static void server(const char *filename) {
   int c;
   commsi= stdin;
   commso= stdout;
-  fprintf(commso, "%s0002 %c\n", banner, upload?'u':'d');
+  fprintf(commso, "%s0002 %c\n", banner, upcopy?'u':'d');
   send_flush();
   c= fgetc(commsi);  if (c==EOF) die_badrecv("initial go");
   if (c!=REPLMSG_GO) die_protocol("initial go message was %#02x instead",c);
 
-  if (upload)
-    receiver(filename);
-  else
+  if (upcopy)
     sender(filename);
+  else
+    receiver(filename);
 }
 
 static void client(void) {
@@ -393,8 +422,8 @@ static void client(void) {
   child= fork();
   if (child==-1) diee("fork failed");
   if (!child) {
-    mdup2(uppipe[0],0);
-    mdup2(downpipe[1],1);
+    mdup2(downpipe[0],0);
+    mdup2(uppipe[1],1);
     close(uppipe[0]); close(downpipe[0]);
     close(uppipe[1]); close(downpipe[1]);
     execlp(rsh_program,
@@ -403,22 +432,25 @@ static void client(void) {
     diee("failed to execute rsh program `%s'",rsh_program);
   }
 
-  commso= fdopen(uppipe[1],"wb");
-  commsi= fdopen(downpipe[0],"rb");
+  commso= fdopen(downpipe[1],"wb");
+  commsi= fdopen(uppipe[0],"rb");
   if (!commso || !commsi) diee("fdopen failed");
-  close(uppipe[0]); close(downpipe[0]);
-  close(uppipe[1]); close(downpipe[1]);
+  close(downpipe[0]);
+  close(uppipe[1]);
   
   char banbuf[sizeof(banner)-1 + 5 + 1];
   r= fread(banbuf,1,sizeof(banbuf)-1,commsi);
-  if (r!=sizeof(banbuf)-1) die_badrecv("banner");
+  if (ferror(commsi)) die_badrecv("read banner");
 
-  if (memcmp(banbuf,banner,sizeof(banner)-1) ||
+  if (r!=sizeof(banbuf)-1 ||
+      memcmp(banbuf,banner,sizeof(banner)-1) ||
       banbuf[sizeof(banner)-1 + 4] != ' ')
-    die(8,-1,"banner received was not as expected -"
+    die(8,-1,"did not receive banner as expected -"
        " shell dirty? ssh broken?\n"
-       " try running   %s %s %s --sender %s\n"
-       " and expect the first line to be   %s",
+       " try running\n"
+       "  %s %s %s --sender %s\n"
+       " and expect the first line to be\n"
+       "  %s",
        rsh_program, remotespec->userhost,
        rcopy_repeatedly_program, remotespec->path,
        banner);
@@ -434,15 +466,15 @@ static void client(void) {
   if (r!=decllen) die_badrecv("declaration");
   if (mainbuf[decllen-1] != '\n')
     die_protocol("declaration missing final newline");
-  if (mainbuf[0] != upload ? 'u' : 'd')
+  if (mainbuf[0] != upcopy ? 'u' : 'd')
     die_protocol("declaration incorrect direction indicator");
 
   sendbyte(REPLMSG_GO);
 
-  if (upload)
-    sender(srcspec.path);
-  else
+  if (upcopy)
     receiver(dstspec.path);
+  else
+    sender(srcspec.path);
 }
 
 static void parse_file_specification(FileSpecification *fs, const char *arg,
@@ -458,7 +490,7 @@ static void parse_file_specification(FileSpecification *fs, const char *arg,
       return;
     }
     if (*colon==':') {
-      char *uh= malloc(colon-arg + 1);  if (!fs->userhost) diem();
+      char *uh= malloc(colon-arg + 1);  if (!uh) diem();
       memcpy(uh,arg, colon-arg);  uh[colon-arg]= 0;
       fs->userhost= uh;
       fs->path= colon+1;
@@ -468,9 +500,11 @@ static void parse_file_specification(FileSpecification *fs, const char *arg,
 }
 
 int main(int argc, const char *const *argv) {
+  setvbuf(stderr,0,_IOLBF,BUFSIZ);
+
   myopt(&argv, cmdinfos);
 
-  if (upload>=0) {
+  if (upcopy>=0) {
     if (!argv[0] || argv[1])
       badusage("server mode must have just the filename as non-option arg");
     server(argv[0]);