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";
(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);
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,
ts_last= ts_sendstart;
- while (l>=0) {
+ while (l>0) {
now= l < sizeof(mainbuf) ? l : sizeof(mainbuf);
if (now > txblocksz) now= txblocksz;
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);
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");
}
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;
}
} 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 }
};
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) {
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,
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);
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,
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;
}
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]);