Run the transfer main loop for the in and out monitoring sides, using another process for "out" if monitoring both (#67).

This commit is contained in:
Andrew Wood
2026-03-20 22:12:14 +00:00
parent f647b12a2d
commit 149be3f9ab
+113 -4
View File
@@ -267,6 +267,50 @@ static int pv__store_and_forward(pvstate_t state, opts_t opts, bool can_have_eta
}
/*
* Run the main transfer loop for the given side of monitor mode, using the
* "command_fd" file descriptor as the transfer loop's output (on the "in"
* side, it's a pipe to the command) or as its input (on the "out" side,
* it's a pipe from the command). If both sides are active,
* "other_side_pid" is the PID of the other side.
*
* Returns the appropriate exit status.
*
* As side effect, "command_fd" is closed.
*/
static int pv__run_monitor(const char *program_name, pvstate_t state, pvside_t side, int command_fd, /*@unused@ */
__attribute__((unused)) pid_t other_side_pid)
{
switch (side) {
case PV_SIDE_NONE: /* fall through */
case PV_SIDE_BOTH:
return PV_ERROREXIT_MONITOR;
case PV_SIDE_IN:
/* Replace stdout with the pipe to the command. */
if (dup2(command_fd, STDOUT_FILENO) < 0) {
fprintf(stderr, "%s: %s\n", program_name, strerror(errno));
return PV_ERROREXIT_MONITOR;
}
break;
case PV_SIDE_OUT:
/* Replace stdin with the pipe from the command. */
if (dup2(command_fd, STDIN_FILENO) < 0) {
fprintf(stderr, "%s: %s\n", program_name, strerror(errno));
return PV_ERROREXIT_MONITOR;
}
break;
}
if (close(command_fd) < 0) {
fprintf(stderr, "%s: %s\n", program_name, strerror(errno));
}
/* TODO: use other_side_pid, for ratio display. */
return pv_main_loop(state);
}
/*
* Run in monitor mode: run a process and run the main transfer loop on its
* input, output, or both. Returns the appropriate exit status.
@@ -276,7 +320,7 @@ static int pv__monitor(pvstate_t state, opts_t opts)
int pipefd_in[2];
int pipefd_out[2];
int retcode;
pid_t command_pid;
pid_t command_pid, in_monitor_pid, out_monitor_pid;
/* Arguments check. */
if ((NULL == opts->argv) || (opts->argc < 1) || (NULL == opts->argv[0])) {
@@ -359,9 +403,16 @@ static int pv__monitor(pvstate_t state, opts_t opts)
}
/* Execute the command. */
(void) execvp(opts->argv[0], (char * const *) (opts->argv));
(void) execvp(opts->argv[0], (char *const *) (opts->argv)); /* flawfinder: ignore */
fprintf(stderr, "%s: %s\n", opts->program_name, strerror(errno));
exit(EXIT_FAILURE);
/*
* flawfinder recommends using a library call instead of
* executing another program with execvp(), but that isn't
* appropriate here, the whole purpose of monitor mode is to
* execute a process and monitor it.
*/
}
/* Main process, not the command process. */
@@ -373,8 +424,66 @@ static int pv__monitor(pvstate_t state, opts_t opts)
if (-1 != pipefd_out[1])
(void) close(pipefd_out[1]);
/* TODO: fork for out monitor if monitoring both. */
/* TODO: monitor the appropriate side; if both, use name1/format1 for the in side. */
/*
* If monitoring both input and output, create a process for
* monitoring the output side.
*/
in_monitor_pid = -1;
out_monitor_pid = -1;
if (PV_SIDE_BOTH == opts->side) {
in_monitor_pid = (pid_t) getpid();
out_monitor_pid = (pid_t) fork();
if (out_monitor_pid < 0) {
fprintf(stderr, "%s: %s\n", opts->program_name, strerror(errno));
if (-1 != pipefd_in[1])
(void) close(pipefd_in[1]);
if (-1 != pipefd_out[0])
(void) close(pipefd_out[0]);
(void) kill(command_pid, SIGTERM);
return PV_ERROREXIT_MONITOR;
} else if (0 == out_monitor_pid) {
/* Output side monitoring process. */
/* Close the write end of the "in" pipe. */
if (-1 != pipefd_in[1])
(void) close(pipefd_in[1]);
return pv__run_monitor(opts->program_name, state, PV_SIDE_OUT, pipefd_out[0], in_monitor_pid);
}
}
/* Monitor the remaining side. */
switch (opts->side) {
case PV_SIDE_NONE:
retcode = PV_ERROREXIT_MONITOR;
break;
case PV_SIDE_BOTH:
/* Use name1, format1 for the "in" side. */
if (NULL != opts->name1) {
pv_state_name_set(state, opts->name1);
}
if (NULL != opts->format1) {
pv_state_format_string_set(state, opts->format1);
}
/* TODO: call pv_state_set_format(). */
/*@fallthrough@ */
/* falling through as "out" is in another process (above). */
__attribute__((fallthrough));
case PV_SIDE_IN:
/* Close the read end of the "out" pipe. */
if (-1 != pipefd_out[0])
(void) close(pipefd_out[0]);
pipefd_out[0] = -1;
retcode = pv__run_monitor(opts->program_name, state, PV_SIDE_IN, pipefd_in[1], out_monitor_pid);
break;
case PV_SIDE_OUT:
/* Close the write end of the "in" pipe. */
if (-1 != pipefd_in[1])
(void) close(pipefd_in[1]);
pipefd_in[1] = -1;
retcode = pv__run_monitor(opts->program_name, state, PV_SIDE_OUT, pipefd_out[0], in_monitor_pid);
break;
}
return retcode;
}