diff --git a/src/include/options.h b/src/include/options.h index bf8f27e..874dd66 100644 --- a/src/include/options.h +++ b/src/include/options.h @@ -31,6 +31,7 @@ typedef enum { PV_ACTION_TRANSFER, /* transfer data */ PV_ACTION_STORE_AND_FORWARD, /* store to file, then output from it */ PV_ACTION_WATCHFD, /* watch process file descriptors */ + PV_ACTION_REMOTE_CONTROL, /* remotely control another pv */ PV_ACTION_QUERY /* watch the state of another pv */ } pvaction_t; diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 9fa2d4b..2758669 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -179,7 +179,8 @@ struct pvstate_s { double delay_start; /* delay before first display */ /*@only@*/ /*@null@*/ char *name; /* display name */ /*@only@*/ /*@null@*/ char *format_string; /* output format string */ - /*@only@*/ /*@null@*/ char *extra_format_string; /* extra format string */ + /*@only@*/ /*@null@*/ char *extra_display_spec; /* full spec for extra displays */ + /*@only@*/ /*@null@*/ char *extra_format_string; /* extra format string alone */ /*@null@*/ char *output_name; /* name of the output, for diagnostics */ /*@null@*/ char *default_bar_style; /* which bar style to use by default */ off_t error_skip_block; /* skip block size, 0 for adaptive */ @@ -193,6 +194,17 @@ struct pvstate_s { pvdisplay_width_t width; /* screen width */ unsigned int height; /* screen height */ unsigned int extra_displays; /* bitmask of extra display destinations */ + struct { /* old-style format options (used by -R) */ + size_t lastwritten; /* --last-written (amount) */ + bool progress; /* --progress */ + bool timer; /* --timer */ + bool eta; /* --eta */ + bool fineta; /* --fineta */ + bool rate; /* --rate */ + bool average_rate; /* --average-rate */ + bool bytes; /* --bytes */ + bool bufpercent; /* --buffer-percent */ + } format_option; bool force; /* display even if not on terminal */ bool cursor; /* use cursor positioning */ bool numeric; /* numeric output only */ diff --git a/src/include/pv.h b/src/include/pv.h index 89b0c96..b738bd2 100644 --- a/src/include/pv.h +++ b/src/include/pv.h @@ -297,6 +297,19 @@ extern int pv_watchfd_loop(pvstate_t); */ extern int pv_query_loop(pvstate_t, pid_t); +/* + * Set the options of another pv process. + */ +int pv_remote_set(pvstate_t, pid_t); + +/* + * Query another pv process for its elapsed transfer time, amount + * transferred, and total size, and update the local state with those + * values. Optionally also return the total size separately. Reports + * errors unless "silent" is true. + */ +int pv_remote_transferstate_fetch(pvstate_t state, pid_t query, /*@null@ */ off_t *sizeptr, bool silent); + /* * Shut down signal handlers after running the main loop. */ diff --git a/src/main/main.c b/src/main/main.c index 024a330..98a315e 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -23,9 +23,6 @@ #include #endif -int pv_remote_set(opts_t, pvstate_t); -int pv_remote_transferstate_fetch(pvstate_t, pid_t, /*@null@ */ off_t *, bool); - /* * Write a PID file, returning nonzero on error. Write it atomically, such * that the file either exists and contains the PID, or is not updated at @@ -337,23 +334,6 @@ int main(int argc, char **argv) /*@+mustfreefresh@ */ } - /* - * -R specified - send the message, then exit. - */ - if (opts->remote > 0) { - /* Initialise signal handling. */ - pv_sig_init(state); - /* Send the message. */ - retcode = pv_remote_set(opts, state); - /* Close down the signal handling. */ - pv_sig_fini(state); - /* Free resources. */ - pv_state_free(state); - opts_free(opts); - /* Early exit. */ - return retcode; - } - /* * Write a PID file if -P was specified. */ @@ -572,8 +552,12 @@ int main(int argc, char **argv) /* "Watch file descriptor(s) of another process" mode. */ retcode = pv_watchfd_loop(state); break; + case PV_ACTION_REMOTE_CONTROL: + /* Change the options of another running pv. */ + retcode = pv_remote_set(state, opts->remote); + break; case PV_ACTION_QUERY: - /* "Watch progress of another pv" mode. */ + /* Query the progress of another running pv. */ retcode = pv_query_loop(state, opts->query); break; } diff --git a/src/main/options.c b/src/main/options.c index 3b24719..f21d522 100644 --- a/src/main/options.c +++ b/src/main/options.c @@ -996,6 +996,7 @@ opts_t opts_parse(unsigned int argc, char **argv) break; case 'R': opts->remote = (pid_t) pv_getnum_count(optarg, false); + opts->action = PV_ACTION_REMOTE_CONTROL; break; case 'Q': opts->query = (pid_t) pv_getnum_count(optarg, false); diff --git a/src/main/remote.c b/src/main/remote.c index 2b53593..4386544 100644 --- a/src/main/remote.c +++ b/src/main/remote.c @@ -9,7 +9,6 @@ /* TODO: move this to srv/pv/ instead of src/main/ since it uses internal pv structures. */ #include "config.h" -#include "options.h" #include "pv.h" #include "pv-internal.h" @@ -24,8 +23,6 @@ #include #include -void pv_error(char *, ...); - #ifdef PV_REMOTE_CONTROL /* Structure for transferring settings with --remote. */ @@ -74,7 +71,7 @@ struct query_msg { * * Returns nonzero on error. */ -int pv_remote_set(opts_t opts, pvstate_t state) +int pv_remote_set(pvstate_t state, pid_t remote) { char control_filename[4096]; /* flawfinder: ignore */ FILE *control_fptr; @@ -92,59 +89,59 @@ int pv_remote_set(opts_t opts, pvstate_t state) /* * Check that the remote process exists. */ - if (kill((pid_t) (opts->remote), 0) != 0) { - pv_error("%u: %s", opts->remote, strerror(errno)); + if (kill((pid_t) (remote), 0) != 0) { + pv_error("%u: %s", remote, strerror(errno)); return PV_ERROREXIT_REMOTE_OR_PID; } - /* - * Make sure parameters are within sensible bounds. - */ - if (opts->width < 1) - opts->width = 80; - if (opts->height < 1) - opts->height = 25; - if (opts->width > 999999) - opts->width = 999999; - if (opts->height > 999999) - opts->height = 999999; - if ((opts->interval > 0) && (opts->interval < 0.1)) - opts->interval = 0.1; - if (opts->interval > 600) - opts->interval = 600; - /* * Copy parameters into message buffer. */ memset(&msgbuf, 0, sizeof(msgbuf)); - msgbuf.progress = opts->progress; - msgbuf.timer = opts->timer; - msgbuf.eta = opts->eta; - msgbuf.fineta = opts->fineta; - msgbuf.rate = opts->rate; - msgbuf.average_rate = opts->average_rate; - msgbuf.bytes = opts->bytes; - msgbuf.bufpercent = opts->bufpercent; - msgbuf.lastwritten = opts->lastwritten; - msgbuf.rate_limit = opts->rate_limit; - msgbuf.buffer_size = opts->buffer_size; - msgbuf.size = opts->size; - msgbuf.interval = opts->interval; - msgbuf.width = opts->width; - msgbuf.height = opts->height; - msgbuf.width_set_manually = opts->width_set_manually; - msgbuf.height_set_manually = opts->height_set_manually; + msgbuf.progress = state->control.format_option.progress; + msgbuf.timer = state->control.format_option.timer; + msgbuf.eta = state->control.format_option.eta; + msgbuf.fineta = state->control.format_option.fineta; + msgbuf.rate = state->control.format_option.rate; + msgbuf.average_rate = state->control.format_option.average_rate; + msgbuf.bytes = state->control.format_option.bytes; + msgbuf.bufpercent = state->control.format_option.bufpercent; + msgbuf.lastwritten = state->control.format_option.lastwritten; + msgbuf.rate_limit = state->control.rate_limit; + msgbuf.buffer_size = state->control.target_buffer_size; + msgbuf.size = state->control.size; + msgbuf.interval = state->control.interval; + msgbuf.width = (unsigned int) (state->control.width); + msgbuf.height = (unsigned int) (state->control.height); + msgbuf.width_set_manually = state->control.width_set_manually; + msgbuf.height_set_manually = state->control.height_set_manually; - if (opts->name != NULL) { - strncpy(msgbuf.name, opts->name, sizeof(msgbuf.name) - 1); /* flawfinder: ignore */ + if (state->control.name != NULL) { + strncpy(msgbuf.name, state->control.name, sizeof(msgbuf.name) - 1); /* flawfinder: ignore */ } - if (opts->format != NULL) { - strncpy(msgbuf.format, opts->format, sizeof(msgbuf.format) - 1); /* flawfinder: ignore */ + if (state->control.format_string != NULL) { + strncpy(msgbuf.format, state->control.format_string, sizeof(msgbuf.format) - 1); /* flawfinder: ignore */ } - if (opts->extra_display != NULL) { - strncpy(msgbuf.extra_display, opts->extra_display, sizeof(msgbuf.extra_display) - 1); /* flawfinder: ignore */ + if (state->control.extra_display_spec != NULL) { + strncpy(msgbuf.extra_display, state->control.extra_display_spec, sizeof(msgbuf.extra_display) - 1); /* flawfinder: ignore */ } + /* + * Make sure parameters are within sensible bounds. + */ + if (msgbuf.width < 1) + msgbuf.width = 80; + if (msgbuf.height < 1) + msgbuf.height = 25; + if (msgbuf.width > 999999) + msgbuf.width = 999999; + if (msgbuf.height > 999999) + msgbuf.height = 999999; + if ((msgbuf.interval > 0) && (msgbuf.interval < 0.1)) + msgbuf.interval = 0.1; + if (msgbuf.interval > 600) + msgbuf.interval = 600; + /* * flawfinder rationale: name, format, and extra_display are * explicitly bounded to 1 less than the size of their buffer and @@ -184,8 +181,8 @@ int pv_remote_set(opts_t opts, pvstate_t state) */ signal_sender = 0; (void) pv_sigusr2_received(state, &signal_sender); - if (kill((pid_t) (opts->remote), SIGUSR2) != 0) { - pv_error("%u: %s", opts->remote, strerror(errno)); + if (kill((pid_t) (remote), SIGUSR2) != 0) { + pv_error("%u: %s", remote, strerror(errno)); (void) remove(control_filename); return PV_ERROREXIT_REMOTE_OR_PID; } @@ -212,7 +209,7 @@ int pv_remote_set(opts_t opts, pvstate_t state) timeout -= 10000; if (pv_sigusr2_received(state, &signal_sender)) { - if (signal_sender == opts->remote) { + if (signal_sender == remote) { debug("%s", "message received"); received = true; } @@ -239,7 +236,7 @@ int pv_remote_set(opts_t opts, pvstate_t state) * warnings, but in this case it's unavoidable, and mitigated by the * fact we only translate each string once. */ - pv_error("%u: %s", opts->remote, _("message not received")); + pv_error("%u: %s", remote, _("message not received")); return PV_ERROREXIT_REMOTE_OR_PID; /*@+mustfreefresh @ */ } @@ -643,7 +640,7 @@ void pv_remote_check( /*@unused@ */ __attribute__((unused)) pvstate_t state) int pv_remote_set( /*@unused@ */ - __attribute__((unused)) opts_t opts, /*@unused@ */ __attribute__((unused)) pvstate_t state) + __attribute__((unused)) pvstate_t state, /*@unused@ */ __attribute__((unused)) pid_t remote) { /*@-mustfreefresh@ *//* splint - see above */ pv_error("%s", _("SA_SIGINFO not supported on this system")); diff --git a/src/pv/state.c b/src/pv/state.c index 800b401..a5c877d 100644 --- a/src/pv/state.c +++ b/src/pv/state.c @@ -336,6 +336,11 @@ void pv_state_free(pvstate_t state) state->control.format_string = NULL; } + if (NULL != state->control.extra_display_spec) { + free(state->control.extra_display_spec); + state->control.extra_display_spec = NULL; + } + if (NULL != state->control.extra_format_string) { free(state->control.extra_format_string); state->control.extra_format_string = NULL; @@ -384,6 +389,16 @@ void pv_state_set_format(pvstate_t state, bool progress, bool timer, bool eta, b (void) pv_strlcat(state->control.default_format, y, sizeof(state->control.default_format)); \ } + state->control.format_option.progress = progress; + state->control.format_option.timer = timer; + state->control.format_option.eta = eta; + state->control.format_option.fineta = fineta; + state->control.format_option.rate = rate; + state->control.format_option.average_rate = average_rate; + state->control.format_option.bytes = bytes; + state->control.format_option.bufpercent = bufpercent; + state->control.format_option.lastwritten = lastwritten; + state->control.default_format[0] = '\0'; if (false == state->control.numeric) { @@ -612,6 +627,11 @@ void pv_state_extra_display_set(pvstate_t state, /*@null@ */ const char *val) const char *word_start; size_t offset; + if (NULL != state->control.extra_display_spec) { + free(state->control.extra_display_spec); + state->control.extra_display_spec = NULL; + } + if (NULL != state->control.extra_format_string) { free(state->control.extra_format_string); state->control.extra_format_string = NULL; @@ -621,6 +641,9 @@ void pv_state_extra_display_set(pvstate_t state, /*@null@ */ const char *val) if (NULL == val) return; + if (NULL != val) + state->control.extra_display_spec = pv_strdup(val); + word_start = val; while (NULL != word_start && '\0' != word_start[0]) { offset = 0;