Group state structure into sub-structures to allow future changes to watchpid code that will do a better job of duplicating the relevant parts of the internal state for each fd.

This commit is contained in:
Andrew Wood
2023-10-14 01:23:54 +01:00
parent 376aa5a8fa
commit 94ffdaf60d
13 changed files with 1028 additions and 987 deletions
+19 -19
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
"POT-Creation-Date: 2023-10-14 00:07+0100\n"
"POT-Creation-Date: 2023-10-14 01:21+0100\n"
"Language: de\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Date: 1999-06-01 15:18:29+0100\n"
@@ -364,31 +364,31 @@ msgstr ""
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:701 src/pv/transfer.c:903
#: src/pv/display.c:704 src/pv/transfer.c:911
msgid "buffer allocation failed"
msgstr "Puffer konnte nicht allokiert werden"
#: src/pv/display.c:763
#: src/pv/display.c:767
msgid "b"
msgstr ""
#: src/pv/display.c:768 src/pv/transfer.c:591
#: src/pv/display.c:772 src/pv/transfer.c:595
msgid "B"
msgstr "B"
#: src/pv/display.c:820 src/pv/display.c:833
#: src/pv/display.c:825 src/pv/display.c:838
msgid "b/s"
msgstr ""
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "/s"
msgstr ""
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "B/s"
msgstr ""
#: src/pv/display.c:875 src/pv/display.c:879 src/pv/display.c:938
#: src/pv/display.c:880 src/pv/display.c:884 src/pv/display.c:943
msgid "ETA"
msgstr "ETA"
@@ -420,7 +420,7 @@ msgstr ""
msgid "(stdin)"
msgstr ""
#: src/pv/loop.c:545 src/pv/loop.c:599 src/pv/loop.c:641 src/pv/watchpid.c:73
#: src/pv/loop.c:546 src/pv/loop.c:601 src/pv/loop.c:643 src/pv/watchpid.c:73
#: src/pv/watchpid.c:83 src/pv/watchpid.c:94 src/pv/watchpid.c:102
#: src/pv/watchpid.c:139 src/pv/watchpid.c:150 src/pv/watchpid.c:158
#: src/pv/watchpid.c:169 src/pv/watchpid.c:256 src/pv/watchpid.c:264
@@ -432,43 +432,43 @@ msgstr ""
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:385 src/pv/state.c:395
#: src/pv/state.c:385 src/pv/state.c:396
msgid "file list allocation failed"
msgstr ""
#: src/pv/transfer.c:453
#: src/pv/transfer.c:457
msgid "read failed"
msgstr "read-Aufruf fehlgeschlagen"
#: src/pv/transfer.c:476
#: src/pv/transfer.c:480
msgid "warning: read errors detected"
msgstr "warnung: lesefehler erkannt"
#: src/pv/transfer.c:492
#: src/pv/transfer.c:496
msgid "file is not seekable"
msgstr "datei ist nicht durchsuchbar"
#: src/pv/transfer.c:570
#: src/pv/transfer.c:574
msgid "failed to seek past error"
msgstr "konnte den Fehler nicht überwinden"
#: src/pv/transfer.c:590
#: src/pv/transfer.c:594
msgid "skipped past read error"
msgstr "über den Lesefehler hinaus verschoben"
#: src/pv/transfer.c:630
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:643
#: src/pv/transfer.c:647
msgid "failed to set alarm signal handler"
msgstr ""
#: src/pv/transfer.c:768
#: src/pv/transfer.c:775
msgid "write failed"
msgstr "write-Aufruf fehlgeschlagen"
#: src/pv/transfer.c:1000
#: src/pv/transfer.c:1008
msgid "select call failed"
msgstr "select-Aufruf fehlgeschlagen"
+19 -19
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
"POT-Creation-Date: 2023-10-14 00:07+0100\n"
"POT-Creation-Date: 2023-10-14 01:21+0100\n"
"Language: fr\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Date: 1999-06-01 15:18:29+0100\n"
@@ -365,31 +365,31 @@ msgstr ""
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:701 src/pv/transfer.c:903
#: src/pv/display.c:704 src/pv/transfer.c:911
msgid "buffer allocation failed"
msgstr "l'allocation de mémoire tampon a échoué"
#: src/pv/display.c:763
#: src/pv/display.c:767
msgid "b"
msgstr ""
#: src/pv/display.c:768 src/pv/transfer.c:591
#: src/pv/display.c:772 src/pv/transfer.c:595
msgid "B"
msgstr "O"
#: src/pv/display.c:820 src/pv/display.c:833
#: src/pv/display.c:825 src/pv/display.c:838
msgid "b/s"
msgstr ""
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "/s"
msgstr "/s"
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "B/s"
msgstr "O/s"
#: src/pv/display.c:875 src/pv/display.c:879 src/pv/display.c:938
#: src/pv/display.c:880 src/pv/display.c:884 src/pv/display.c:943
msgid "ETA"
msgstr "ETA"
@@ -421,7 +421,7 @@ msgstr ""
msgid "(stdin)"
msgstr ""
#: src/pv/loop.c:545 src/pv/loop.c:599 src/pv/loop.c:641 src/pv/watchpid.c:73
#: src/pv/loop.c:546 src/pv/loop.c:601 src/pv/loop.c:643 src/pv/watchpid.c:73
#: src/pv/watchpid.c:83 src/pv/watchpid.c:94 src/pv/watchpid.c:102
#: src/pv/watchpid.c:139 src/pv/watchpid.c:150 src/pv/watchpid.c:158
#: src/pv/watchpid.c:169 src/pv/watchpid.c:256 src/pv/watchpid.c:264
@@ -433,43 +433,43 @@ msgstr ""
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:385 src/pv/state.c:395
#: src/pv/state.c:385 src/pv/state.c:396
msgid "file list allocation failed"
msgstr ""
#: src/pv/transfer.c:453
#: src/pv/transfer.c:457
msgid "read failed"
msgstr "la lecture a échoué"
#: src/pv/transfer.c:476
#: src/pv/transfer.c:480
msgid "warning: read errors detected"
msgstr "avertissement: erreurs de lecture détectées"
#: src/pv/transfer.c:492
#: src/pv/transfer.c:496
msgid "file is not seekable"
msgstr "ne peut pas se déplacer dans le fichier"
#: src/pv/transfer.c:570
#: src/pv/transfer.c:574
msgid "failed to seek past error"
msgstr "n'a pas réussi à dépasser l'erreur"
#: src/pv/transfer.c:590
#: src/pv/transfer.c:594
msgid "skipped past read error"
msgstr "erreur de lecture dépassée"
#: src/pv/transfer.c:630
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:643
#: src/pv/transfer.c:647
msgid "failed to set alarm signal handler"
msgstr ""
#: src/pv/transfer.c:768
#: src/pv/transfer.c:775
msgid "write failed"
msgstr "l'écriture a échoué"
#: src/pv/transfer.c:1000
#: src/pv/transfer.c:1008
msgid "select call failed"
msgstr "appel de sélection a échoué"
+19 -19
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
"POT-Creation-Date: 2023-10-14 00:07+0100\n"
"POT-Creation-Date: 2023-10-14 01:21+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -353,31 +353,31 @@ msgstr ""
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:701 src/pv/transfer.c:903
#: src/pv/display.c:704 src/pv/transfer.c:911
msgid "buffer allocation failed"
msgstr "nie udało się zaalokować bufora"
#: src/pv/display.c:763
#: src/pv/display.c:767
msgid "b"
msgstr ""
#: src/pv/display.c:768 src/pv/transfer.c:591
#: src/pv/display.c:772 src/pv/transfer.c:595
msgid "B"
msgstr "B"
#: src/pv/display.c:820 src/pv/display.c:833
#: src/pv/display.c:825 src/pv/display.c:838
msgid "b/s"
msgstr ""
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "/s"
msgstr "/s"
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "B/s"
msgstr "B/s"
#: src/pv/display.c:875 src/pv/display.c:879 src/pv/display.c:938
#: src/pv/display.c:880 src/pv/display.c:884 src/pv/display.c:943
msgid "ETA"
msgstr "ETA"
@@ -410,7 +410,7 @@ msgstr ""
msgid "(stdin)"
msgstr ""
#: src/pv/loop.c:545 src/pv/loop.c:599 src/pv/loop.c:641 src/pv/watchpid.c:73
#: src/pv/loop.c:546 src/pv/loop.c:601 src/pv/loop.c:643 src/pv/watchpid.c:73
#: src/pv/watchpid.c:83 src/pv/watchpid.c:94 src/pv/watchpid.c:102
#: src/pv/watchpid.c:139 src/pv/watchpid.c:150 src/pv/watchpid.c:158
#: src/pv/watchpid.c:169 src/pv/watchpid.c:256 src/pv/watchpid.c:264
@@ -422,43 +422,43 @@ msgstr ""
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:385 src/pv/state.c:395
#: src/pv/state.c:385 src/pv/state.c:396
msgid "file list allocation failed"
msgstr ""
#: src/pv/transfer.c:453
#: src/pv/transfer.c:457
msgid "read failed"
msgstr "błąd odczytu"
#: src/pv/transfer.c:476
#: src/pv/transfer.c:480
msgid "warning: read errors detected"
msgstr ""
#: src/pv/transfer.c:492
#: src/pv/transfer.c:496
msgid "file is not seekable"
msgstr ""
#: src/pv/transfer.c:570
#: src/pv/transfer.c:574
msgid "failed to seek past error"
msgstr ""
#: src/pv/transfer.c:590
#: src/pv/transfer.c:594
msgid "skipped past read error"
msgstr ""
#: src/pv/transfer.c:630
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:643
#: src/pv/transfer.c:647
msgid "failed to set alarm signal handler"
msgstr ""
#: src/pv/transfer.c:768
#: src/pv/transfer.c:775
msgid "write failed"
msgstr "błąd zapisu"
#: src/pv/transfer.c:1000
#: src/pv/transfer.c:1008
msgid "select call failed"
msgstr "nie udało się wywołać funkcji select"
+19 -19
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
"POT-Creation-Date: 2023-10-14 00:07+0100\n"
"POT-Creation-Date: 2023-10-14 01:21+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -356,31 +356,31 @@ msgstr ""
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:701 src/pv/transfer.c:903
#: src/pv/display.c:704 src/pv/transfer.c:911
msgid "buffer allocation failed"
msgstr "erro alocando o buffer"
#: src/pv/display.c:763
#: src/pv/display.c:767
msgid "b"
msgstr ""
#: src/pv/display.c:768 src/pv/transfer.c:591
#: src/pv/display.c:772 src/pv/transfer.c:595
msgid "B"
msgstr ""
#: src/pv/display.c:820 src/pv/display.c:833
#: src/pv/display.c:825 src/pv/display.c:838
msgid "b/s"
msgstr ""
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "/s"
msgstr ""
#: src/pv/display.c:824 src/pv/display.c:838
#: src/pv/display.c:829 src/pv/display.c:843
msgid "B/s"
msgstr "B/s"
#: src/pv/display.c:875 src/pv/display.c:879 src/pv/display.c:938
#: src/pv/display.c:880 src/pv/display.c:884 src/pv/display.c:943
msgid "ETA"
msgstr "ETA"
@@ -412,7 +412,7 @@ msgstr ""
msgid "(stdin)"
msgstr ""
#: src/pv/loop.c:545 src/pv/loop.c:599 src/pv/loop.c:641 src/pv/watchpid.c:73
#: src/pv/loop.c:546 src/pv/loop.c:601 src/pv/loop.c:643 src/pv/watchpid.c:73
#: src/pv/watchpid.c:83 src/pv/watchpid.c:94 src/pv/watchpid.c:102
#: src/pv/watchpid.c:139 src/pv/watchpid.c:150 src/pv/watchpid.c:158
#: src/pv/watchpid.c:169 src/pv/watchpid.c:256 src/pv/watchpid.c:264
@@ -424,43 +424,43 @@ msgstr ""
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:385 src/pv/state.c:395
#: src/pv/state.c:385 src/pv/state.c:396
msgid "file list allocation failed"
msgstr ""
#: src/pv/transfer.c:453
#: src/pv/transfer.c:457
msgid "read failed"
msgstr "erro de leitura"
#: src/pv/transfer.c:476
#: src/pv/transfer.c:480
msgid "warning: read errors detected"
msgstr "aviso: erros de leitura detectados"
#: src/pv/transfer.c:492
#: src/pv/transfer.c:496
msgid "file is not seekable"
msgstr "não pode mover dentro do arquivo"
#: src/pv/transfer.c:570
#: src/pv/transfer.c:574
msgid "failed to seek past error"
msgstr "não pode ir além do erro"
#: src/pv/transfer.c:590
#: src/pv/transfer.c:594
msgid "skipped past read error"
msgstr "ignorado erro de leitura"
#: src/pv/transfer.c:630
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:643
#: src/pv/transfer.c:647
msgid "failed to set alarm signal handler"
msgstr ""
#: src/pv/transfer.c:768
#: src/pv/transfer.c:775
msgid "write failed"
msgstr "erro de gravação"
#: src/pv/transfer.c:1000
#: src/pv/transfer.c:1008
msgid "select call failed"
msgstr "erro na chamada da função select"
+158 -135
View File
@@ -84,136 +84,154 @@ struct pvcursorstate_s {
* Structure for holding PV internal state. Opaque outside the PV library.
*/
struct pvstate_s {
/******************
* Program status *
******************/
struct {
/*@only@*/ char *program_name; /* program name for error reporting */
char cwd[PV_SIZEOF_CWD]; /* current working directory for relative path */
int current_input_file; /* index of current file being read */
int exit_status; /* exit status to give (0=OK) */
} status;
/***************
* Input files *
***************/
unsigned int input_file_count; /* number of input files */
/*@only@*/ /*@null@*/ char **input_files; /* input files */
struct {
unsigned int file_count; /* number of input files */
/*@only@*/ /*@null@*/ char **filename; /* input filenames */
} files;
/*******************
* Program control *
*******************/
bool force; /* display even if not on terminal */
bool cursor; /* use cursor positioning */
bool numeric; /* numeric output only */
bool wait; /* wait for data before display */
bool linemode; /* count lines instead of bytes */
bool bits; /* report bits instead of bytes */
bool null_terminated_lines; /* lines are null-terminated */
bool no_display; /* do nothing other than pipe data */
unsigned int skip_errors; /* skip read errors counter */
off_t error_skip_block; /* skip block size, 0 for adaptive */
bool stop_at_size; /* set if we stop at "size" bytes */
bool sync_after_write; /* set if we sync after every write */
bool direct_io; /* set if O_DIRECT is to be used */
bool direct_io_changed; /* set when direct_io is changed */
bool no_splice; /* never use splice() */
bool discard_input; /* write nothing to stdout */
off_t rate_limit; /* rate limit, in bytes per second */
size_t target_buffer_size; /* buffer size (0=default) */
off_t size; /* total size of data */
double interval; /* interval between updates */
double delay_start; /* delay before first display */
pid_t watch_pid; /* process to watch fds of */
int watch_fd; /* fd to watch */
unsigned int width; /* screen width */
unsigned int height; /* screen height */
bool width_set_manually; /* width was set manually, not detected */
bool height_set_manually; /* height was set manually, not detected */
/*@only@*/ /*@null@*/ char *name; /* display name */
char default_format[PV_SIZEOF_DEFAULT_FORMAT]; /* default format string */
/*@only@*/ /*@null@*/ char *format_string; /* output format string */
/******************
* Program status *
******************/
/*@only@*/ char *program_name; /* program name for error reporting */
char cwd[PV_SIZEOF_CWD]; /* current working directory for relative path */
int current_input_file; /* index of current file being read */
int exit_status; /* exit status to give (0=OK) */
struct {
bool force; /* display even if not on terminal */
bool cursor; /* use cursor positioning */
bool numeric; /* numeric output only */
bool wait; /* wait for data before display */
bool linemode; /* count lines instead of bytes */
bool bits; /* report bits instead of bytes */
bool null_terminated_lines; /* lines are null-terminated */
bool no_display; /* do nothing other than pipe data */
unsigned int skip_errors; /* skip read errors counter */
off_t error_skip_block; /* skip block size, 0 for adaptive */
bool stop_at_size; /* set if we stop at "size" bytes */
bool sync_after_write; /* set if we sync after every write */
bool direct_io; /* set if O_DIRECT is to be used */
bool direct_io_changed; /* set when direct_io is changed */
bool no_splice; /* never use splice() */
bool discard_input; /* write nothing to stdout */
off_t rate_limit; /* rate limit, in bytes per second */
size_t target_buffer_size; /* buffer size (0=default) */
off_t size; /* total size of data */
double interval; /* interval between updates */
double delay_start; /* delay before first display */
pid_t watch_pid; /* process to watch fds of */
int watch_fd; /* fd to watch */
unsigned int width; /* screen width */
unsigned int height; /* screen height */
bool width_set_manually; /* width was set manually, not detected */
bool height_set_manually; /* height was set manually, not detected */
/*@only@*/ /*@null@*/ char *name; /* display name */
char default_format[PV_SIZEOF_DEFAULT_FORMAT]; /* default format string */
/*@only@*/ /*@null@*/ char *format_string; /* output format string */
} control;
/*******************
* Signal handling *
*******************/
int pv_sig_old_stderr; /* see pv_sig_ttou() */
bool pv_tty_tostop_added; /* whether we had to set TOSTOP on the terminal */
struct timespec pv_sig_tstp_time; /* see pv_sig_tstp() / __cont() */
struct timespec pv_sig_toffset; /* total time spent stopped */
volatile sig_atomic_t pv_sig_newsize; /* whether we need to get term size again */
volatile sig_atomic_t pv_sig_abort; /* whether we need to abort right now */
volatile sig_atomic_t reparse_display; /* whether to re-check format string */
struct {
int old_stderr; /* see pv_sig_ttou() */
bool pv_tty_tostop_added; /* whether we had to set TOSTOP on the terminal */
struct timespec tstp_time; /* see pv_sig_tstp() / __cont() */
struct timespec toffset; /* total time spent stopped */
#ifdef SA_SIGINFO
volatile sig_atomic_t pv_sig_rxusr2; /* whether SIGUSR2 was received */
volatile pid_t pv_sig_sender; /* PID of sending process for SIGUSR2 */
volatile sig_atomic_t rxusr2; /* whether SIGUSR2 was received */
volatile pid_t sender; /* PID of sending process for SIGUSR2 */
#endif
struct sigaction pv_sig_old_sigpipe;
struct sigaction pv_sig_old_sigttou;
struct sigaction pv_sig_old_sigtstp;
struct sigaction pv_sig_old_sigcont;
struct sigaction pv_sig_old_sigwinch;
struct sigaction pv_sig_old_sigint;
struct sigaction pv_sig_old_sighup;
struct sigaction pv_sig_old_sigterm;
struct sigaction old_sigpipe;
struct sigaction old_sigttou;
struct sigaction old_sigtstp;
struct sigaction old_sigcont;
struct sigaction old_sigwinch;
struct sigaction old_sigint;
struct sigaction old_sighup;
struct sigaction old_sigterm;
#ifdef SA_SIGINFO
struct sigaction pv_sig_old_sigusr2;
struct sigaction old_sigusr2;
#endif
} signal;
/*******************
* Transient flags *
*******************/
struct {
volatile sig_atomic_t reparse_display; /* whether to re-check format string */
volatile sig_atomic_t terminal_resized; /* whether we need to get term size again */
volatile sig_atomic_t trigger_exit; /* whether we need to abort right now */
} flag;
/*****************
* Display state *
*****************/
long percentage;
long double prev_elapsed_sec;
long double prev_rate;
long double prev_trans;
/* Keep track of progress over last intervals to compute current average rate. */
/*@null@*/ pvhistory_t *history; /* state at previous intervals (circular buffer) */
unsigned int history_len; /* total size */
int history_interval; /* seconds between each history entry */
int history_first;
int history_last;
long double current_avg_rate; /* current average rate over last history intervals */
off_t initial_offset;
/*@only@*/ char *display_buffer;
long display_buffer_size;
size_t lastoutput_length; /* number of last-output bytes to show */
char lastoutput_buffer[PV_SIZEOF_LASTOUTPUT_BUFFER];
int prev_width; /* screen width last time we were called */
int prev_length; /* length of last string we output */
char str_name[PV_SIZEOF_STR_NAME];
char str_transferred[PV_SIZEOF_STR_TRANSFERRED];
char str_bufpercent[PV_SIZEOF_STR_BUFPERCENT];
char str_timer[PV_SIZEOF_STR_TIMER];
char str_rate[PV_SIZEOF_STR_RATE];
char str_average_rate[PV_SIZEOF_STR_AVERAGE_RATE];
char str_progress[PV_SIZEOF_STR_PROGRESS];
char str_lastoutput[PV_SIZEOF_STR_LASTOUTPUT];
char str_eta[PV_SIZEOF_STR_ETA];
char str_fineta[PV_SIZEOF_STR_FINETA];
unsigned long components_used; /* bitmask of components used */
struct {
const char *string;
int length;
} format[PV_FORMAT_ARRAY_MAX];
bool display_visible; /* set once anything written to terminal */
long percentage;
long double prev_elapsed_sec;
long double prev_rate;
long double prev_trans;
/* Keep track of progress over last intervals to compute current average rate. */
/*@null@*/ pvhistory_t *history; /* state at previous intervals (circular buffer) */
unsigned int history_len; /* total size */
int history_interval; /* seconds between each history entry */
int history_first;
int history_last;
long double current_avg_rate; /* current average rate over last history intervals */
off_t initial_offset;
/*@only@*/ char *display_buffer;
long display_buffer_size;
size_t lastoutput_length; /* number of last-output bytes to show */
char lastoutput_buffer[PV_SIZEOF_LASTOUTPUT_BUFFER];
int prev_width; /* screen width last time we were called */
int prev_length; /* length of last string we output */
char str_name[PV_SIZEOF_STR_NAME];
char str_transferred[PV_SIZEOF_STR_TRANSFERRED];
char str_bufpercent[PV_SIZEOF_STR_BUFPERCENT];
char str_timer[PV_SIZEOF_STR_TIMER];
char str_rate[PV_SIZEOF_STR_RATE];
char str_average_rate[PV_SIZEOF_STR_AVERAGE_RATE];
char str_progress[PV_SIZEOF_STR_PROGRESS];
char str_lastoutput[PV_SIZEOF_STR_LASTOUTPUT];
char str_eta[PV_SIZEOF_STR_ETA];
char str_fineta[PV_SIZEOF_STR_FINETA];
unsigned long components_used; /* bitmask of components used */
struct {
const char *string;
int length;
} format[PV_FORMAT_ARRAY_MAX];
bool display_visible; /* set once anything written to terminal */
} display;
/********************
* Cursor/IPC state *
********************/
struct {
#ifdef HAVE_IPC
int crs_shmid; /* ID of our shared memory segment */
int crs_pvcount; /* number of `pv' processes in total */
int crs_pvmax; /* highest number of `pv's seen */
/*@keep@*/ /*@null@*/ struct pvcursorstate_s *crs_shared; /* data shared between instances */
int crs_y_lastread; /* last value of _y_top seen */
int crs_y_offset; /* our Y offset from this top position */
int crs_needreinit; /* counter if we need to reinit cursor pos */
bool crs_noipc; /* set if we can't use IPC */
int shmid; /* ID of our shared memory segment */
int pvcount; /* number of `pv' processes in total */
int pvmax; /* highest number of `pv's seen */
/*@keep@*/ /*@null@*/ struct pvcursorstate_s *shared; /* data shared between instances */
int y_lastread; /* last value of _y_top seen */
int y_offset; /* our Y offset from this top position */
int needreinit; /* counter if we need to reinit cursor pos */
bool noipc; /* set if we can't use IPC */
#endif /* HAVE_IPC */
int crs_lock_fd; /* fd of lockfile, -1 if none open */
char crs_lock_file[PV_SIZEOF_CRS_LOCK_FILE];
int crs_y_start; /* our initial Y coordinate */
int lock_fd; /* fd of lockfile, -1 if none open */
char lock_file[PV_SIZEOF_CRS_LOCK_FILE];
int y_start; /* our initial Y coordinate */
} cursor;
/*******************
* Transfer state *
@@ -233,40 +251,45 @@ struct pvstate_s {
* is the offset in the buffer that we've written data up to. It
* will always be less than or equal to read_position.
*/
/*@only@*/ /*@null@*/ char *transfer_buffer; /* data transfer buffer */
size_t buffer_size; /* size of buffer */
size_t read_position; /* amount of data in buffer */
size_t write_position; /* buffered data written */
struct {
/*@only@*/ /*@null@*/ char *transfer_buffer; /* data transfer buffer */
size_t buffer_size; /* size of buffer */
size_t read_position; /* amount of data in buffer */
size_t write_position; /* buffered data written */
/*
* While reading from a file descriptor we keep track of how many
* times in a row we've seen errors (read_errors_in_a_row), and
* whether or not we have put a warning on stderr about read errors
* on this fd (read_error_warning_shown).
*
* Whenever the active file descriptor changes from
* last_read_skip_fd, we reset read_errors_in_a_row to 0 and
* read_error_warning_shown to false for the new file descriptor and
* set last_read_skip_fd to the new fd number.
*
* This way, we're treating each input file separately.
*/
int last_read_skip_fd;
off_t read_errors_in_a_row;
bool read_error_warning_shown;
/*
* While reading from a file descriptor we keep track of how
* many times in a row we've seen errors
* (read_errors_in_a_row), and whether or not we have put a
* warning on stderr about read errors on this fd
* (read_error_warning_shown).
*
* Whenever the active file descriptor changes from
* last_read_skip_fd, we reset read_errors_in_a_row to 0 and
* read_error_warning_shown to false for the new file
* descriptor and set last_read_skip_fd to the new fd
* number.
*
* This way, we're treating each input file separately.
*/
int last_read_skip_fd;
off_t read_errors_in_a_row;
bool read_error_warning_shown;
#ifdef HAVE_SPLICE
/*
* These variables are used to keep track of whether splice() was
* used; splice_failed_fd is the file descriptor that splice() last
* failed on, so that we don't keep trying to use it on an fd that
* doesn't support it, and splice_used is set to true if splice()
* was used this time within pv_transfer().
*/
int splice_failed_fd;
bool splice_used;
/*
* These variables are used to keep track of whether
* splice() was used; splice_failed_fd is the file
* descriptor that splice() last failed on, so that we don't
* keep trying to use it on an fd that doesn't support it,
* and splice_used is set to true if splice() was used this
* time within pv_transfer().
*/
int splice_failed_fd;
bool splice_used;
#endif
ssize_t to_write; /* max to write this time around */
ssize_t written; /* bytes sent to stdout this time */
ssize_t to_write; /* max to write this time around */
ssize_t written; /* bytes sent to stdout this time */
} transfer;
};
+99 -99
View File
@@ -79,18 +79,18 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
char *tmpdir;
int openflags;
state->crs_lock_fd = -1;
state->cursor.lock_fd = -1;
ttydev = ttyname(fd);
if (!ttydev) {
if (!state->force) {
if (!state->control.force) {
pv_error(state, "%s: %s", _("failed to get terminal name"), strerror(errno));
}
/*
* If we don't know our terminal name, we can neither do IPC
* nor make a lock file, so turn off cursor positioning.
*/
state->cursor = 0;
state->control.cursor = 0;
debug("%s", "ttyname failed - cursor positioning disabled");
return;
}
@@ -104,8 +104,8 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
*/
tmpdir = "/tmp";
memset(state->crs_lock_file, 0, PV_SIZEOF_CRS_LOCK_FILE);
(void) pv_snprintf(state->crs_lock_file,
memset(state->cursor.lock_file, 0, PV_SIZEOF_CRS_LOCK_FILE);
(void) pv_snprintf(state->cursor.lock_file,
PV_SIZEOF_CRS_LOCK_FILE, "%s/pv-%s-%i.lock", tmpdir, basename(ttydev), (int) geteuid());
/*
@@ -117,7 +117,7 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
openflags = O_RDWR | O_CREAT;
#endif
state->crs_lock_fd = open(state->crs_lock_file, openflags, 0600); /* flawfinder: ignore */
state->cursor.lock_fd = open(state->cursor.lock_file, openflags, 0600); /* flawfinder: ignore */
/*
* flawfinder rationale: we aren't truncating the lock file, we
@@ -126,9 +126,9 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
* open() is as safe as we can make it.
*/
if (state->crs_lock_fd < 0) {
pv_error(state, "%s: %s: %s", state->crs_lock_file, _("failed to open lock file"), strerror(errno));
state->cursor = 0;
if (state->cursor.lock_fd < 0) {
pv_error(state, "%s: %s: %s", state->cursor.lock_file, _("failed to open lock file"), strerror(errno));
state->control.cursor = 0;
return;
}
}
@@ -144,8 +144,8 @@ static void pv_crs_lock(pvstate_t state, int fd)
int lock_fd;
lock_fd = fd;
if (state->crs_lock_fd >= 0)
lock_fd = state->crs_lock_fd;
if (state->cursor.lock_fd >= 0)
lock_fd = state->cursor.lock_fd;
memset(&lock, 0, sizeof(lock));
lock.l_type = (short) F_WRLCK;
@@ -154,10 +154,10 @@ static void pv_crs_lock(pvstate_t state, int fd)
lock.l_len = 1;
while (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
if (errno != EINTR) {
if (state->crs_lock_fd == -2) {
if (state->cursor.lock_fd == -2) {
pv_crs_open_lockfile(state, fd);
if (state->crs_lock_fd >= 0) {
lock_fd = state->crs_lock_fd;
if (state->cursor.lock_fd >= 0) {
lock_fd = state->cursor.lock_fd;
}
} else {
pv_error(state, "%s: %s", _("lock attempt failed"), strerror(errno));
@@ -166,8 +166,8 @@ static void pv_crs_lock(pvstate_t state, int fd)
}
}
if (state->crs_lock_fd >= 0) {
debug("%s: %s", state->crs_lock_file, "terminal lockfile acquired");
if (state->cursor.lock_fd >= 0) {
debug("%s: %s", state->cursor.lock_file, "terminal lockfile acquired");
} else {
debug("%s", "terminal lock acquired");
}
@@ -184,8 +184,8 @@ static void pv_crs_unlock(pvstate_t state, int fd)
int lock_fd;
lock_fd = fd;
if (state->crs_lock_fd >= 0)
lock_fd = state->crs_lock_fd;
if (state->cursor.lock_fd >= 0)
lock_fd = state->cursor.lock_fd;
memset(&lock, 0, sizeof(lock));
lock.l_type = (short) F_UNLCK;
@@ -194,8 +194,8 @@ static void pv_crs_unlock(pvstate_t state, int fd)
lock.l_len = 1;
(void) fcntl(lock_fd, F_SETLK, &lock);
if (state->crs_lock_fd >= 0) {
debug("%s: %s", state->crs_lock_file, "terminal lockfile released");
if (state->cursor.lock_fd >= 0) {
debug("%s: %s", state->cursor.lock_file, "terminal lockfile released");
} else {
debug("%s", "terminal lock released");
}
@@ -216,13 +216,13 @@ static void pv_crs_ipccount(pvstate_t state)
memset(&buf, 0, sizeof(buf));
buf.shm_nattch = 0;
(void) shmctl(state->crs_shmid, IPC_STAT, &buf);
state->crs_pvcount = (int) (buf.shm_nattch);
(void) shmctl(state->cursor.shmid, IPC_STAT, &buf);
state->cursor.pvcount = (int) (buf.shm_nattch);
if (state->crs_pvcount > state->crs_pvmax)
state->crs_pvmax = state->crs_pvcount;
if (state->cursor.pvcount > state->cursor.pvmax)
state->cursor.pvmax = state->cursor.pvcount;
debug("%s: %d", "pvcount", state->crs_pvcount);
debug("%s: %d", "pvcount", state->cursor.pvcount);
}
#endif /* HAVE_IPC */
@@ -334,13 +334,13 @@ static int pv_crs_ipcinit(pvstate_t state, char *ttyfile, int terminalfd)
}
pv_crs_lock(state, terminalfd);
if (!state->cursor) {
if (!state->control.cursor) {
debug("%s", "early return - cursor has been disabled");
return 1;
}
state->crs_shmid = shmget(key, sizeof(struct pvcursorstate_s), 0600 | IPC_CREAT);
if (state->crs_shmid < 0) {
state->cursor.shmid = shmget(key, sizeof(struct pvcursorstate_s), 0600 | IPC_CREAT);
if (state->cursor.shmid < 0) {
debug("%s: %s", "shmget failed", strerror(errno));
pv_crs_unlock(state, terminalfd);
return 1;
@@ -348,7 +348,7 @@ static int pv_crs_ipcinit(pvstate_t state, char *ttyfile, int terminalfd)
/*@-nullpass@ */
/* splint doesn't know shmaddr can be NULL */
state->crs_shared = shmat(state->crs_shmid, NULL, 0);
state->cursor.shared = shmat(state->cursor.shmid, NULL, 0);
/*@+nullpass@ */
pv_crs_ipccount(state);
@@ -359,26 +359,26 @@ static int pv_crs_ipcinit(pvstate_t state, char *ttyfile, int terminalfd)
* current Y cursor co-ordinate and with an initial false value for
* the TOSTOP-added flag.
*/
if (state->crs_pvcount < 2) {
state->crs_y_start = pv_crs_get_ypos(terminalfd);
state->crs_shared->y_topmost = state->crs_y_start;
state->crs_shared->tty_tostop_added = false;
state->crs_y_lastread = state->crs_y_start;
if (state->cursor.pvcount < 2) {
state->cursor.y_start = pv_crs_get_ypos(terminalfd);
state->cursor.shared->y_topmost = state->cursor.y_start;
state->cursor.shared->tty_tostop_added = false;
state->cursor.y_lastread = state->cursor.y_start;
debug("%s", "we are the first to attach");
}
state->crs_y_offset = state->crs_pvcount - 1;
if (state->crs_y_offset < 0)
state->crs_y_offset = 0;
state->cursor.y_offset = state->cursor.pvcount - 1;
if (state->cursor.y_offset < 0)
state->cursor.y_offset = 0;
/*
* If anyone else had attached to the shared memory segment, we need
* to read the top Y co-ordinate from it.
*/
if (state->crs_pvcount > 1) {
state->crs_y_start = state->crs_shared->y_topmost;
state->crs_y_lastread = state->crs_y_start;
debug("%s: %d", "not the first to attach - got top y", state->crs_y_start);
if (state->cursor.pvcount > 1) {
state->cursor.y_start = state->cursor.shared->y_topmost;
state->cursor.y_lastread = state->cursor.y_start;
debug("%s: %d", "not the first to attach - got top y", state->cursor.y_start);
}
pv_crs_unlock(state, terminalfd);
@@ -396,10 +396,10 @@ void pv_crs_init(pvstate_t state)
char *ttyfile;
int terminalfd;
state->crs_lock_fd = -2;
state->crs_lock_file[0] = '\0';
state->cursor.lock_fd = -2;
state->cursor.lock_file[0] = '\0';
if (!state->cursor)
if (!state->control.cursor)
return;
debug("%s", "init");
@@ -407,7 +407,7 @@ void pv_crs_init(pvstate_t state)
ttyfile = ttyname(STDERR_FILENO);
if (NULL == ttyfile) {
debug("%s: %s", "disabling cursor positioning because ttyname failed", strerror(errno));
state->cursor = false;
state->control.cursor = false;
return;
}
@@ -422,22 +422,22 @@ void pv_crs_init(pvstate_t state)
if (terminalfd < 0) {
pv_error(state, "%s: %s: %s", _("failed to open terminal"), ttyfile, strerror(errno));
state->cursor = false;
state->control.cursor = false;
return;
}
#ifdef HAVE_IPC
if (pv_crs_ipcinit(state, ttyfile, terminalfd) != 0) {
debug("%s", "ipcinit failed, setting noipc flag");
state->crs_noipc = true;
state->cursor.noipc = true;
}
/*
* If we have already set the terminal TOSTOP attribute, set the
* flag in shared memory to let the other instances know.
*/
if ((!state->crs_noipc) && state->pv_tty_tostop_added && (NULL != state->crs_shared)) {
if ((!state->cursor.noipc) && state->signal.pv_tty_tostop_added && (NULL != state->cursor.shared)) {
debug("%s", "propagating local pv_tty_tostop_added true value to shared flag");
state->crs_shared->tty_tostop_added = true;
state->cursor.shared->tty_tostop_added = true;
}
/*
@@ -445,7 +445,7 @@ void pv_crs_init(pvstate_t state)
* co-ordinate. If we are using IPC, then the pv_crs_ipcinit()
* function takes care of this in a more multi-process-friendly way.
*/
if (state->crs_noipc) {
if (state->cursor.noipc) {
#else /* ! HAVE_IPC */
if (1) {
#endif /* HAVE_IPC */
@@ -453,18 +453,18 @@ void pv_crs_init(pvstate_t state)
* Get current cursor position + 1.
*/
pv_crs_lock(state, terminalfd);
state->crs_y_start = pv_crs_get_ypos(terminalfd);
state->cursor.y_start = pv_crs_get_ypos(terminalfd);
/*
* Move down a line while the terminal is locked, so that
* other processes in the pipeline will get a different
* initial ypos.
*/
if (state->crs_y_start > 0)
if (state->cursor.y_start > 0)
pv_write_retry(STDERR_FILENO, "\n", 1);
pv_crs_unlock(state, terminalfd);
if (state->crs_y_start < 1)
state->cursor = 0;
if (state->cursor.y_start < 1)
state->control.cursor = 0;
}
(void) close(terminalfd);
@@ -477,9 +477,9 @@ void pv_crs_init(pvstate_t state)
*/
void pv_crs_needreinit(pvstate_t state)
{
state->crs_needreinit += 2;
if (state->crs_needreinit > 3)
state->crs_needreinit = 3;
state->cursor.needreinit += 2;
if (state->cursor.needreinit > 3)
state->cursor.needreinit = 3;
}
#endif
@@ -495,23 +495,23 @@ static void pv_crs_reinit(pvstate_t state)
pv_crs_lock(state, STDERR_FILENO);
state->crs_needreinit--;
if (state->crs_y_offset < 1)
state->crs_needreinit = 0;
state->cursor.needreinit--;
if (state->cursor.y_offset < 1)
state->cursor.needreinit = 0;
if (state->crs_needreinit > 0) {
if (state->cursor.needreinit > 0) {
pv_crs_unlock(state, STDERR_FILENO);
return;
}
debug("%s", "reinit full");
state->crs_y_start = pv_crs_get_ypos(STDERR_FILENO);
state->cursor.y_start = pv_crs_get_ypos(STDERR_FILENO);
if ((state->crs_y_offset < 1) && (NULL != state->crs_shared)) {
state->crs_shared->y_topmost = state->crs_y_start;
if ((state->cursor.y_offset < 1) && (NULL != state->cursor.shared)) {
state->cursor.shared->y_topmost = state->cursor.y_start;
}
state->crs_y_lastread = state->crs_y_start;
state->cursor.y_lastread = state->cursor.y_start;
pv_crs_unlock(state, STDERR_FILENO);
}
@@ -539,24 +539,24 @@ void pv_crs_update(pvstate_t state, const char *output_line)
/* flawfinder - output_line is explictly expected to be \0-terminated. */
#ifdef HAVE_IPC
if (!state->crs_noipc) {
if (state->crs_needreinit > 0)
if (!state->cursor.noipc) {
if (state->cursor.needreinit > 0)
pv_crs_reinit(state);
pv_crs_ipccount(state);
if (NULL != state->crs_shared) {
if (state->crs_y_lastread != state->crs_shared->y_topmost) {
state->crs_y_start = state->crs_shared->y_topmost;
state->crs_y_lastread = state->crs_y_start;
if (NULL != state->cursor.shared) {
if (state->cursor.y_lastread != state->cursor.shared->y_topmost) {
state->cursor.y_start = state->cursor.shared->y_topmost;
state->cursor.y_lastread = state->cursor.y_start;
}
}
if (state->crs_needreinit > 0)
if (state->cursor.needreinit > 0)
return;
}
#endif /* HAVE_IPC */
y = state->crs_y_start;
y = state->cursor.y_start;
#ifdef HAVE_IPC
/*
@@ -565,27 +565,27 @@ void pv_crs_update(pvstate_t state, const char *output_line)
* scroll the screen (only if we're the first `pv'), and then move
* our initial Y co-ordinate up.
*/
if (((state->crs_y_start + state->crs_pvmax) > (int) (state->height))
&& (!state->crs_noipc)
if (((state->cursor.y_start + state->cursor.pvmax) > (int) (state->control.height))
&& (!state->cursor.noipc)
) {
int offs;
offs = ((state->crs_y_start + state->crs_pvmax) - state->height);
offs = ((state->cursor.y_start + state->cursor.pvmax) - state->control.height);
state->crs_y_start -= offs;
if (state->crs_y_start < 1)
state->crs_y_start = 1;
state->cursor.y_start -= offs;
if (state->cursor.y_start < 1)
state->cursor.y_start = 1;
debug("%s: %d", "scroll offset", offs);
/*
* Scroll the screen if we're the first `pv'.
*/
if (0 == state->crs_y_offset) {
if (0 == state->cursor.y_offset) {
pv_crs_lock(state, STDERR_FILENO);
memset(cup_cmd, 0, sizeof(cup_cmd));
(void) pv_snprintf(cup_cmd, sizeof(cup_cmd), "\033[%u;1H", state->height);
(void) pv_snprintf(cup_cmd, sizeof(cup_cmd), "\033[%u;1H", state->control.height);
cup_cmd_length = strlen(cup_cmd); /* flawfinder: ignore */
pv_write_retry(STDERR_FILENO, cup_cmd, cup_cmd_length);
for (; offs > 0; offs--) {
@@ -598,8 +598,8 @@ void pv_crs_update(pvstate_t state, const char *output_line)
}
}
if (!state->crs_noipc)
y = state->crs_y_start + state->crs_y_offset;
if (!state->cursor.noipc)
y = state->cursor.y_start + state->cursor.y_offset;
#endif /* HAVE_IPC */
/*
@@ -641,15 +641,15 @@ void pv_crs_fini(pvstate_t state)
debug("%s", "fini");
y = (unsigned int) (state->crs_y_start);
y = (unsigned int) (state->cursor.y_start);
#ifdef HAVE_IPC
if ((state->crs_pvmax > 0) && (!state->crs_noipc))
y += state->crs_pvmax - 1;
if ((state->cursor.pvmax > 0) && (!state->cursor.noipc))
y += state->cursor.pvmax - 1;
#endif /* HAVE_IPC */
if (y > state->height)
y = state->height;
if (y > state->control.height)
y = state->control.height;
/*
* Absolute bounds check.
@@ -671,40 +671,40 @@ void pv_crs_fini(pvstate_t state)
* attribute, set our local flag so pv_sig_fini() will know about
* it.
*/
if ((!state->crs_noipc) && (NULL != state->crs_shared) && state->crs_shared->tty_tostop_added) {
if (!state->pv_tty_tostop_added) {
if ((!state->cursor.noipc) && (NULL != state->cursor.shared) && state->cursor.shared->tty_tostop_added) {
if (!state->signal.pv_tty_tostop_added) {
debug("%s", "propagating shared tty_tostop_added true value to local flag");
state->pv_tty_tostop_added = true;
state->signal.pv_tty_tostop_added = true;
}
}
pv_crs_ipccount(state);
if (NULL != state->crs_shared) {
(void) shmdt(state->crs_shared);
if (NULL != state->cursor.shared) {
(void) shmdt(state->cursor.shared);
}
state->crs_shared = NULL;
state->cursor.shared = NULL;
/*
* If we are the last instance detaching from the shared memory,
* delete it so it's not left lying around.
*/
if (state->crs_pvcount < 2) {
if (state->cursor.pvcount < 2) {
struct shmid_ds shm_buf;
memset(&shm_buf, 0, sizeof(shm_buf));
(void) shmctl(state->crs_shmid, IPC_RMID, &shm_buf);
(void) shmctl(state->cursor.shmid, IPC_RMID, &shm_buf);
}
#endif /* HAVE_IPC */
pv_crs_unlock(state, STDERR_FILENO);
if (state->crs_lock_fd >= 0) {
(void) close(state->crs_lock_fd);
if (state->cursor.lock_fd >= 0) {
(void) close(state->cursor.lock_fd);
/*
* We can get away with removing this on exit because all
* the other PVs will be finishing at the same sort of time.
*/
(void) remove(state->crs_lock_file);
(void) remove(state->cursor.lock_file);
}
}
+225 -220
View File
@@ -42,9 +42,9 @@
void pv_error(pvstate_t state, char *format, ...)
{
va_list ap;
if (state->display_visible)
if (state->display.display_visible)
fprintf(stderr, "\n");
fprintf(stderr, "%s: ", state->program_name);
fprintf(stderr, "%s: ", state->status.program_name);
va_start(ap, format);
(void) vfprintf(stderr, format, ap);
va_end(ap);
@@ -374,22 +374,22 @@ static void pv__format_init(pvstate_t state)
if (NULL == state)
return;
state->str_name[0] = '\0';
state->str_transferred[0] = '\0';
state->str_timer[0] = '\0';
state->str_rate[0] = '\0';
state->str_average_rate[0] = '\0';
state->str_progress[0] = '\0';
state->str_eta[0] = '\0';
memset(state->format, 0, PV_FORMAT_ARRAY_MAX * sizeof(state->format[0]));
state->display.str_name[0] = '\0';
state->display.str_transferred[0] = '\0';
state->display.str_timer[0] = '\0';
state->display.str_rate[0] = '\0';
state->display.str_average_rate[0] = '\0';
state->display.str_progress[0] = '\0';
state->display.str_eta[0] = '\0';
memset(state->display.format, 0, PV_FORMAT_ARRAY_MAX * sizeof(state->display.format[0]));
if (state->name) {
(void) pv_snprintf(state->str_name, PV_SIZEOF_STR_NAME, "%9.500s:", state->name);
if (state->control.name) {
(void) pv_snprintf(state->display.str_name, PV_SIZEOF_STR_NAME, "%9.500s:", state->control.name);
}
formatstr = state->format_string ? state->format_string : state->default_format;
formatstr = state->control.format_string ? state->control.format_string : state->control.default_format;
state->components_used = 0;
state->display.components_used = 0;
/*
* Split the format string into segments. Each segment consists
@@ -403,7 +403,7 @@ static void pv__format_init(pvstate_t state)
* sized component which will be recalculated by pv__format()
* after the length of all fixed-size segments is known, and so
* the string is a pointer to another state->str_* buffer
* (currently it will only ever be state->str_progress).
* (currently it will only ever be state->display.str_progress).
*
* A length above zero indicates that the segment is a constant
* string of the given length (not necessarily null terminated).
@@ -443,74 +443,74 @@ static void pv__format_init(pvstate_t state)
switch (formatstr[strpos]) {
case 'p':
state->format[segment].string = state->str_progress;
state->format[segment].length = -1;
state->components_used |= PV_DISPLAY_PROGRESS;
state->display.format[segment].string = state->display.str_progress;
state->display.format[segment].length = -1;
state->display.components_used |= PV_DISPLAY_PROGRESS;
break;
case 't':
state->format[segment].string = state->str_timer;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_TIMER;
state->display.format[segment].string = state->display.str_timer;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_TIMER;
break;
case 'e':
state->format[segment].string = state->str_eta;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_ETA;
state->display.format[segment].string = state->display.str_eta;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_ETA;
break;
case 'I':
state->format[segment].string = state->str_fineta;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_FINETA;
state->display.format[segment].string = state->display.str_fineta;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_FINETA;
break;
case 'A':
state->format[segment].string = state->str_lastoutput;
state->format[segment].length = 0;
state->display.format[segment].string = state->display.str_lastoutput;
state->display.format[segment].length = 0;
if (number_prefix > PV_SIZEOF_LASTOUTPUT_BUFFER)
number_prefix = PV_SIZEOF_LASTOUTPUT_BUFFER;
if (number_prefix < 1)
number_prefix = 1;
state->lastoutput_length = number_prefix;
state->components_used |= PV_DISPLAY_OUTPUTBUF;
state->display.lastoutput_length = number_prefix;
state->display.components_used |= PV_DISPLAY_OUTPUTBUF;
break;
case 'r':
state->format[segment].string = state->str_rate;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_RATE;
state->display.format[segment].string = state->display.str_rate;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_RATE;
break;
case 'a':
state->format[segment].string = state->str_average_rate;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_AVERAGERATE;
state->display.format[segment].string = state->display.str_average_rate;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_AVERAGERATE;
break;
case 'b':
state->format[segment].string = state->str_transferred;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_BYTES;
state->display.format[segment].string = state->display.str_transferred;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_BYTES;
break;
case 'T':
state->format[segment].string = state->str_bufpercent;
state->format[segment].length = 0;
state->components_used |= PV_DISPLAY_BUFPERCENT;
state->display.format[segment].string = state->display.str_bufpercent;
state->display.format[segment].length = 0;
state->display.components_used |= PV_DISPLAY_BUFPERCENT;
break;
case 'N':
state->format[segment].string = state->str_name;
state->format[segment].length = (int) strlen(state->str_name);
state->components_used |= PV_DISPLAY_NAME;
state->display.format[segment].string = state->display.str_name;
state->display.format[segment].length = (int) strlen(state->display.str_name);
state->display.components_used |= PV_DISPLAY_NAME;
break;
case '%':
/* %% => % */
state->format[segment].string = &(formatstr[strpos]);
state->format[segment].length = 1;
state->display.format[segment].string = &(formatstr[strpos]);
state->display.format[segment].length = 1;
break;
case 0:
/* % at end => just % */
state->format[segment].string = &(formatstr[--strpos]);
state->format[segment].length = 1;
state->display.format[segment].string = &(formatstr[--strpos]);
state->display.format[segment].length = 1;
break;
default:
/* %z (unknown) => %z */
state->format[segment].string = &(formatstr[--strpos]);
state->format[segment].length = 2;
state->display.format[segment].string = &(formatstr[--strpos]);
state->display.format[segment].length = 2;
strpos++;
break;
}
@@ -522,14 +522,14 @@ static void pv__format_init(pvstate_t state)
} else {
foundlength = searchptr - &(formatstr[strpos]);
}
state->format[segment].string = &(formatstr[strpos]);
state->format[segment].length = foundlength;
state->display.format[segment].string = &(formatstr[strpos]);
state->display.format[segment].length = foundlength;
strpos += foundlength - 1;
}
}
state->format[segment].string = 0;
state->format[segment].length = 0;
state->display.format[segment].string = 0;
state->display.format[segment].length = 0;
}
/*
@@ -544,21 +544,21 @@ static long bound_long(long x, long min, long max)
/* Update history and current average rate */
static void update_history_avg_rate(pvstate_t state, long long total_bytes, long double elapsed_sec, long double rate)
{
int first = state->history_first;
int last = state->history_last;
int first = state->display.history_first;
int last = state->display.history_last;
long double last_elapsed;
if (NULL == state->history)
if (NULL == state->display.history)
return;
last_elapsed = state->history[last].elapsed_sec;
last_elapsed = state->display.history[last].elapsed_sec;
/*
* Do nothing if this is not the first call but not enough time has
* elapsed since the previous call yet.
*/
if ((last_elapsed > 0.0)
&& (elapsed_sec < (last_elapsed + state->history_interval)))
&& (elapsed_sec < (last_elapsed + state->display.history_interval)))
return;
/*
@@ -566,21 +566,23 @@ static void update_history_avg_rate(pvstate_t state, long long total_bytes, long
* buffer.
*/
if (last_elapsed > 0.0) {
int len = state->history_len;
state->history_last = last = (last + 1) % len;
int len = state->display.history_len;
state->display.history_last = last = (last + 1) % len;
if (last == first)
state->history_first = first = (first + 1) % len;
state->display.history_first = first = (first + 1) % len;
}
state->history[last].elapsed_sec = elapsed_sec;
state->history[last].total_bytes = total_bytes;
state->display.history[last].elapsed_sec = elapsed_sec;
state->display.history[last].total_bytes = total_bytes;
if (first == last) {
state->current_avg_rate = rate;
state->display.current_avg_rate = rate;
} else {
long long bytes = (state->history[last].total_bytes - state->history[first].total_bytes);
long double sec = (state->history[last].elapsed_sec - state->history[first].elapsed_sec);
state->current_avg_rate = (long double) bytes / sec;
long long bytes =
(state->display.history[last].total_bytes - state->display.history[first].total_bytes);
long double sec =
(state->display.history[last].elapsed_sec - state->display.history[first].elapsed_sec);
state->display.current_avg_rate = (long double) bytes / sec;
}
}
@@ -617,9 +619,9 @@ static const char *pv__format(pvstate_t state,
/* Negative total transfer - free memory and exit */
if (total_bytes < 0) {
if (state->display_buffer)
free(state->display_buffer);
state->display_buffer = NULL;
if (state->display.display_buffer)
free(state->display.display_buffer);
state->display.display_buffer = NULL;
return NULL;
}
@@ -629,20 +631,20 @@ static const char *pv__format(pvstate_t state,
* adding to that until a reasonable amount of time has passed to
* avoid rate spikes or division by zero.
*/
time_since_last = elapsed_sec - state->prev_elapsed_sec;
time_since_last = elapsed_sec - state->display.prev_elapsed_sec;
if (time_since_last <= 0.01) {
rate = state->prev_rate;
state->prev_trans += bytes_since_last;
rate = state->display.prev_rate;
state->display.prev_trans += bytes_since_last;
} else {
rate = ((long double) bytes_since_last + state->prev_trans) / time_since_last;
state->prev_elapsed_sec = elapsed_sec;
state->prev_trans = 0;
rate = ((long double) bytes_since_last + state->display.prev_trans) / time_since_last;
state->display.prev_elapsed_sec = elapsed_sec;
state->display.prev_trans = 0;
}
state->prev_rate = rate;
state->display.prev_rate = rate;
/* Update history and current average rate for ETA. */
update_history_avg_rate(state, total_bytes, elapsed_sec, rate);
average_rate = state->current_avg_rate;
average_rate = state->display.current_avg_rate;
/*
* If this is the final update at the end of the transfer, we
@@ -654,11 +656,12 @@ static const char *pv__format(pvstate_t state,
if (elapsed_sec < 0.000001)
elapsed_sec = 0.000001;
average_rate =
(((long double) total_bytes) - ((long double) state->initial_offset)) / (long double) elapsed_sec;
(((long double) total_bytes) -
((long double) state->display.initial_offset)) / (long double) elapsed_sec;
rate = average_rate;
}
if (state->size <= 0) {
if (state->control.size <= 0) {
/*
* If we don't know the total size of the incoming data,
* then for a percentage, we gradually increase the
@@ -668,41 +671,41 @@ static const char *pv__format(pvstate_t state,
* 0%-100%, 100%-0%, 0%-100%, and so on.
*/
if (rate > 0)
state->percentage += 2;
if (state->percentage > 199)
state->percentage = 0;
} else if (state->numeric || ((state->components_used & PV_DISPLAY_PROGRESS) != 0)) {
state->display.percentage += 2;
if (state->display.percentage > 199)
state->display.percentage = 0;
} else if (state->control.numeric || ((state->display.components_used & PV_DISPLAY_PROGRESS) != 0)) {
/*
* If we do know the total size, and we're going to show
* the percentage (numeric mode or a progress bar),
* calculate the percentage completion.
*/
state->percentage = pv__calc_percentage(total_bytes, state->size);
state->display.percentage = pv__calc_percentage(total_bytes, state->control.size);
}
/*
* Reallocate output buffer if width changes.
*/
if (state->display_buffer != NULL && state->display_buffer_size < (state->width * 2)) {
free(state->display_buffer);
state->display_buffer = NULL;
state->display_buffer_size = 0;
if (state->display.display_buffer != NULL && state->display.display_buffer_size < (state->control.width * 2)) {
free(state->display.display_buffer);
state->display.display_buffer = NULL;
state->display.display_buffer_size = 0;
}
/*
* Allocate output buffer if there isn't one.
*/
if (NULL == state->display_buffer) {
state->display_buffer_size = (2 * state->width) + 80;
if (state->name)
state->display_buffer_size += strlen(state->name);
state->display_buffer = malloc(state->display_buffer_size + 16);
if (NULL == state->display_buffer) {
if (NULL == state->display.display_buffer) {
state->display.display_buffer_size = (2 * state->control.width) + 80;
if (state->control.name)
state->display.display_buffer_size += strlen(state->control.name);
state->display.display_buffer = malloc(state->display.display_buffer_size + 16);
if (NULL == state->display.display_buffer) {
pv_error(state, "%s: %s", _("buffer allocation failed"), strerror(errno));
state->exit_status |= 64;
state->status.exit_status |= 64;
return NULL;
}
state->display_buffer[0] = '\0';
state->display.display_buffer[0] = '\0';
}
/*
@@ -713,30 +716,31 @@ static const char *pv__format(pvstate_t state,
* With --bytes we output the bytes transferred so far instead
* of the percentage. (Or lines, if --lines was given with --bytes).
*/
if (state->numeric) {
if (state->control.numeric) {
char numericprefix[128];
numericprefix[0] = '\0';
if ((state->components_used & PV_DISPLAY_TIMER) != 0)
if ((state->display.components_used & PV_DISPLAY_TIMER) != 0)
(void) pv_snprintf(numericprefix, sizeof(numericprefix), "%.4Lf ", elapsed_sec);
if ((state->components_used & PV_DISPLAY_BYTES) != 0) {
if (state->bits) {
(void) pv_snprintf(state->display_buffer,
state->display_buffer_size,
if ((state->display.components_used & PV_DISPLAY_BYTES) != 0) {
if (state->control.bits) {
(void) pv_snprintf(state->display.display_buffer,
state->display.display_buffer_size,
"%.99s%lld\n", numericprefix, 8 * total_bytes);
} else {
(void) pv_snprintf(state->display_buffer,
state->display_buffer_size,
(void) pv_snprintf(state->display.display_buffer,
state->display.display_buffer_size,
"%.99s%lld\n", numericprefix, total_bytes);
}
} else {
(void) pv_snprintf(state->display_buffer,
state->display_buffer_size, "%.99s%ld\n", numericprefix, state->percentage);
(void) pv_snprintf(state->display.display_buffer,
state->display.display_buffer_size, "%.99s%ld\n", numericprefix,
state->display.percentage);
}
return state->display_buffer;
return state->display.display_buffer;
}
/*
@@ -746,46 +750,47 @@ static const char *pv__format(pvstate_t state,
* to be placed in the output buffer.
*/
state->str_transferred[0] = '\0';
state->str_bufpercent[0] = '\0';
state->str_timer[0] = '\0';
state->str_rate[0] = '\0';
state->str_average_rate[0] = '\0';
state->str_progress[0] = '\0';
state->str_lastoutput[0] = '\0';
state->str_eta[0] = '\0';
state->str_fineta[0] = '\0';
state->display.str_transferred[0] = '\0';
state->display.str_bufpercent[0] = '\0';
state->display.str_timer[0] = '\0';
state->display.str_rate[0] = '\0';
state->display.str_average_rate[0] = '\0';
state->display.str_progress[0] = '\0';
state->display.str_lastoutput[0] = '\0';
state->display.str_eta[0] = '\0';
state->display.str_fineta[0] = '\0';
/* If we're showing bytes transferred, set up the display string. */
if ((state->components_used & PV_DISPLAY_BYTES) != 0) {
if (state->bits && !state->linemode) {
pv__sizestr(state->str_transferred,
if ((state->display.components_used & PV_DISPLAY_BYTES) != 0) {
if (state->control.bits && !state->control.linemode) {
pv__sizestr(state->display.str_transferred,
PV_SIZEOF_STR_TRANSFERRED, "%s", (long double) total_bytes * 8, "", _("b"),
PV_TRANSFERCOUNT_BYTES);
} else {
pv__sizestr(state->str_transferred,
pv__sizestr(state->display.str_transferred,
PV_SIZEOF_STR_TRANSFERRED, "%s",
(long double) total_bytes, "", _("B"),
state->linemode ? PV_TRANSFERCOUNT_LINES : PV_TRANSFERCOUNT_BYTES);
state->control.linemode ? PV_TRANSFERCOUNT_LINES : PV_TRANSFERCOUNT_BYTES);
}
}
/* Transfer buffer percentage - set up the display string. */
if ((state->components_used & PV_DISPLAY_BUFPERCENT) != 0) {
if (state->buffer_size > 0)
(void) pv_snprintf(state->str_bufpercent,
if ((state->display.components_used & PV_DISPLAY_BUFPERCENT) != 0) {
if (state->transfer.buffer_size > 0)
(void) pv_snprintf(state->display.str_bufpercent,
PV_SIZEOF_STR_BUFPERCENT,
"{%3ld%%}",
pv__calc_percentage
(state->read_position - state->write_position, state->buffer_size));
(state->transfer.read_position - state->transfer.write_position,
state->transfer.buffer_size));
#ifdef HAVE_SPLICE
if (state->splice_used)
(void) pv_snprintf(state->str_bufpercent, PV_SIZEOF_STR_BUFPERCENT, "{%s}", "----");
if (state->transfer.splice_used)
(void) pv_snprintf(state->display.str_bufpercent, PV_SIZEOF_STR_BUFPERCENT, "{%s}", "----");
#endif
}
/* Timer - set up the display string. */
if ((state->components_used & PV_DISPLAY_TIMER) != 0) {
if ((state->display.components_used & PV_DISPLAY_TIMER) != 0) {
/*
* Bounds check, so we don't overrun the prefix buffer. This
* does mean that the timer will stop at a 100,000 hours,
@@ -799,14 +804,14 @@ static const char *pv__format(pvstate_t state,
* well as hours, minutes, and seconds.
*/
if (elapsed_sec > (long double) 86400.0L) {
(void) pv_snprintf(state->str_timer,
(void) pv_snprintf(state->display.str_timer,
PV_SIZEOF_STR_TIMER,
"%ld:%02ld:%02ld:%02ld",
((long) elapsed_sec) / 86400,
(((long) elapsed_sec) / 3600) %
24, (((long) elapsed_sec) / 60) % 60, ((long) elapsed_sec) % 60);
} else {
(void) pv_snprintf(state->str_timer,
(void) pv_snprintf(state->display.str_timer,
PV_SIZEOF_STR_TIMER,
"%ld:%02ld:%02ld",
((long) elapsed_sec) / 3600,
@@ -815,48 +820,48 @@ static const char *pv__format(pvstate_t state,
}
/* Rate - set up the display string. */
if ((state->components_used & PV_DISPLAY_RATE) != 0) {
if (state->bits && !state->linemode) {
pv__sizestr(state->str_rate, PV_SIZEOF_STR_RATE, "[%s]", 8 * rate, "", _("b/s"),
if ((state->display.components_used & PV_DISPLAY_RATE) != 0) {
if (state->control.bits && !state->control.linemode) {
pv__sizestr(state->display.str_rate, PV_SIZEOF_STR_RATE, "[%s]", 8 * rate, "", _("b/s"),
PV_TRANSFERCOUNT_BYTES);
} else {
pv__sizestr(state->str_rate,
pv__sizestr(state->display.str_rate,
PV_SIZEOF_STR_RATE, "[%s]", rate, _("/s"), _("B/s"),
state->linemode ? PV_TRANSFERCOUNT_LINES : PV_TRANSFERCOUNT_BYTES);
state->control.linemode ? PV_TRANSFERCOUNT_LINES : PV_TRANSFERCOUNT_BYTES);
}
}
/* Average rate - set up the display string. */
if ((state->components_used & PV_DISPLAY_AVERAGERATE) != 0) {
if (state->bits && !state->linemode) {
pv__sizestr(state->str_average_rate,
if ((state->display.components_used & PV_DISPLAY_AVERAGERATE) != 0) {
if (state->control.bits && !state->control.linemode) {
pv__sizestr(state->display.str_average_rate,
PV_SIZEOF_STR_AVERAGE_RATE, "[%s]", 8 * average_rate, "", _("b/s"),
PV_TRANSFERCOUNT_BYTES);
} else {
pv__sizestr(state->str_average_rate,
pv__sizestr(state->display.str_average_rate,
PV_SIZEOF_STR_AVERAGE_RATE,
"[%s]", average_rate, _("/s"), _("B/s"),
state->linemode ? PV_TRANSFERCOUNT_LINES : PV_TRANSFERCOUNT_BYTES);
state->control.linemode ? PV_TRANSFERCOUNT_LINES : PV_TRANSFERCOUNT_BYTES);
}
}
/* Last output bytes - set up the display string. */
if ((state->components_used & PV_DISPLAY_OUTPUTBUF) != 0) {
if ((state->display.components_used & PV_DISPLAY_OUTPUTBUF) != 0) {
int idx;
for (idx = 0; idx < state->lastoutput_length; idx++) {
for (idx = 0; idx < state->display.lastoutput_length; idx++) {
int c;
c = state->lastoutput_buffer[idx];
state->str_lastoutput[idx] = isprint(c) ? c : '.';
c = state->display.lastoutput_buffer[idx];
state->display.str_lastoutput[idx] = isprint(c) ? c : '.';
}
state->str_lastoutput[idx] = '\0';
state->display.str_lastoutput[idx] = '\0';
}
/* ETA (only if size is known) - set up the display string. */
if (((state->components_used & PV_DISPLAY_ETA) != 0)
&& (state->size > 0)) {
if (((state->display.components_used & PV_DISPLAY_ETA) != 0)
&& (state->control.size > 0)) {
eta =
pv__calc_eta(total_bytes - state->initial_offset,
state->size - state->initial_offset, state->current_avg_rate);
pv__calc_eta(total_bytes - state->display.initial_offset,
state->control.size - state->display.initial_offset, state->display.current_avg_rate);
/*
* Bounds check, so we don't overrun the suffix buffer. This
@@ -869,12 +874,12 @@ static const char *pv__format(pvstate_t state,
* well as hours, minutes, and seconds.
*/
if (eta > 86400L) {
(void) pv_snprintf(state->str_eta,
(void) pv_snprintf(state->display.str_eta,
PV_SIZEOF_STR_ETA,
"%.16s %ld:%02ld:%02ld:%02ld",
_("ETA"), eta / 86400, (eta / 3600) % 24, (eta / 60) % 60, eta % 60);
} else {
(void) pv_snprintf(state->str_eta,
(void) pv_snprintf(state->display.str_eta,
PV_SIZEOF_STR_ETA,
"%.16s %ld:%02ld:%02ld", _("ETA"), eta / 3600, (eta / 60) % 60, eta % 60);
}
@@ -885,15 +890,15 @@ static const char *pv__format(pvstate_t state,
*/
if (bytes_since_last < 0) {
unsigned int i;
for (i = 0; i < PV_SIZEOF_STR_ETA && state->str_eta[i] != '\0'; i++) {
state->str_eta[i] = ' ';
for (i = 0; i < PV_SIZEOF_STR_ETA && state->display.str_eta[i] != '\0'; i++) {
state->display.str_eta[i] = ' ';
}
}
}
/* ETA as clock time (as above) - set up the display string. */
if (((state->components_used & PV_DISPLAY_FINETA) != 0)
&& (state->size > 0)) {
if (((state->display.components_used & PV_DISPLAY_FINETA) != 0)
&& (state->control.size > 0)) {
/*
* The ETA may be hidden by a failed ETA string
* generation.
@@ -905,8 +910,8 @@ static const char *pv__format(pvstate_t state,
char *time_format = NULL;
eta =
pv__calc_eta(total_bytes - state->initial_offset,
state->size - state->initial_offset, state->current_avg_rate);
pv__calc_eta(total_bytes - state->display.initial_offset,
state->control.size - state->display.initial_offset, state->display.current_avg_rate);
/*
* Bounds check, so we don't overrun the suffix buffer. This
@@ -935,16 +940,16 @@ static const char *pv__format(pvstate_t state,
* by time functions. */
struct tm time = *time_ptr;
(void) pv_snprintf(state->str_fineta, PV_SIZEOF_STR_FINETA, "%.16s ", _("ETA"));
strftime(state->str_fineta +
strlen(state->str_fineta),
PV_SIZEOF_STR_FINETA - 1 - strlen(state->str_fineta), time_format, &time);
(void) pv_snprintf(state->display.str_fineta, PV_SIZEOF_STR_FINETA, "%.16s ", _("ETA"));
strftime(state->display.str_fineta +
strlen(state->display.str_fineta),
PV_SIZEOF_STR_FINETA - 1 - strlen(state->display.str_fineta), time_format, &time);
}
if (!show_eta) {
unsigned int i;
for (i = 0; i < PV_SIZEOF_STR_FINETA && state->str_fineta[i] != '\0'; i++) {
state->str_fineta[i] = ' ';
for (i = 0; i < PV_SIZEOF_STR_FINETA && state->display.str_fineta[i] != '\0'; i++) {
state->display.str_fineta[i] = ' ';
}
}
}
@@ -955,13 +960,13 @@ static const char *pv__format(pvstate_t state,
* (i.e. the progress bar).
*/
static_portion_size = 0;
for (segment = 0; state->format[segment].string; segment++) {
if (state->format[segment].length < 0) {
for (segment = 0; state->display.format[segment].string; segment++) {
if (state->display.format[segment].length < 0) {
continue;
} else if (state->format[segment].length > 0) {
static_portion_size += state->format[segment].length;
} else if (state->display.format[segment].length > 0) {
static_portion_size += state->display.format[segment].length;
} else {
static_portion_size += strlen(state->format[segment].string);
static_portion_size += strlen(state->display.format[segment].string);
}
}
@@ -970,20 +975,20 @@ static const char *pv__format(pvstate_t state,
/*
* Assemble the progress bar now we know how big it should be.
*/
if ((state->components_used & PV_DISPLAY_PROGRESS) != 0) {
if ((state->display.components_used & PV_DISPLAY_PROGRESS) != 0) {
char pct[16];
int available_width, i;
strcpy(state->str_progress, "[");
strcpy(state->display.str_progress, "[");
if (state->size > 0) {
if (state->percentage < 0)
state->percentage = 0;
if (state->percentage > 100000)
state->percentage = 100000;
(void) pv_snprintf(pct, sizeof(pct), "%3ld%%", state->percentage);
if (state->control.size > 0) {
if (state->display.percentage < 0)
state->display.percentage = 0;
if (state->display.percentage > 100000)
state->display.percentage = 100000;
(void) pv_snprintf(pct, sizeof(pct), "%3ld%%", state->display.percentage);
available_width = state->width - static_portion_size - strlen(pct) - 3;
available_width = state->control.width - static_portion_size - strlen(pct) - 3;
if (available_width < 0)
available_width = 0;
@@ -991,23 +996,23 @@ static const char *pv__format(pvstate_t state,
if (available_width > (int) (PV_SIZEOF_STR_PROGRESS) - 16)
available_width = PV_SIZEOF_STR_PROGRESS - 16;
for (i = 0; i < (available_width * state->percentage) / 100 - 1; i++) {
for (i = 0; i < (available_width * state->display.percentage) / 100 - 1; i++) {
if (i < available_width)
(void) pv_strlcat(state->str_progress, "=", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, "=", PV_SIZEOF_STR_PROGRESS);
}
if (i < available_width) {
(void) pv_strlcat(state->str_progress, ">", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, ">", PV_SIZEOF_STR_PROGRESS);
i++;
}
for (; i < available_width; i++) {
(void) pv_strlcat(state->str_progress, " ", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, " ", PV_SIZEOF_STR_PROGRESS);
}
(void) pv_strlcat(state->str_progress, "] ", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->str_progress, pct, PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, "] ", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, pct, PV_SIZEOF_STR_PROGRESS);
} else {
int p = state->percentage;
int p = state->display.percentage;
available_width = state->width - static_portion_size - 5;
available_width = state->control.width - static_portion_size - 5;
if (available_width < 0)
available_width = 0;
@@ -1021,34 +1026,34 @@ static const char *pv__format(pvstate_t state,
p = 200 - p;
for (i = 0; i < (available_width * p) / 100; i++) {
if (i < available_width)
(void) pv_strlcat(state->str_progress, " ", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, " ", PV_SIZEOF_STR_PROGRESS);
}
(void) pv_strlcat(state->str_progress, "<=>", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, "<=>", PV_SIZEOF_STR_PROGRESS);
for (; i < available_width; i++) {
(void) pv_strlcat(state->str_progress, " ", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, " ", PV_SIZEOF_STR_PROGRESS);
}
(void) pv_strlcat(state->str_progress, "]", PV_SIZEOF_STR_PROGRESS);
(void) pv_strlcat(state->display.str_progress, "]", PV_SIZEOF_STR_PROGRESS);
}
/*
* If the progress bar won't fit, drop it.
*/
if (strlen(state->str_progress) + static_portion_size > state->width)
state->str_progress[0] = '\0';
if (strlen(state->display.str_progress) + static_portion_size > state->control.width)
state->display.str_progress[0] = '\0';
}
/*
* We can now build the output string using the format structure.
*/
state->display_buffer[0] = '\0';
state->display.display_buffer[0] = '\0';
display_string_length = 0;
for (segment = 0; state->format[segment].string; segment++) {
for (segment = 0; state->display.format[segment].string; segment++) {
int segment_length;
if (state->format[segment].length > 0) {
segment_length = state->format[segment].length;
if (state->display.format[segment].length > 0) {
segment_length = state->display.format[segment].length;
} else {
segment_length = strlen(state->format[segment].string);
segment_length = strlen(state->display.format[segment].string);
}
/* Skip empty segments */
if (segment_length == 0)
@@ -1057,14 +1062,14 @@ static const char *pv__format(pvstate_t state,
* Truncate segment if it would make the display string
* overflow the buffer
*/
if (segment_length + display_string_length > state->display_buffer_size - 2)
segment_length = state->display_buffer_size - display_string_length - 2;
if (segment_length + display_string_length > state->display.display_buffer_size - 2)
segment_length = state->display.display_buffer_size - display_string_length - 2;
if (segment_length < 1)
break;
/* Skip segment if it would make the display too wide */
if (segment_length + display_string_length > (int) (state->width))
if (segment_length + display_string_length > (int) (state->control.width))
break;
strncat(state->display_buffer, state->format[segment].string, segment_length);
strncat(state->display.display_buffer, state->display.format[segment].string, segment_length);
display_string_length += segment_length;
}
@@ -1072,12 +1077,12 @@ static const char *pv__format(pvstate_t state,
* If the size of our output shrinks, we need to keep appending
* spaces at the end, so that we don't leave dangling bits behind.
*/
output_length = strlen(state->display_buffer);
if ((output_length < state->prev_length)
&& ((int) (state->width) >= state->prev_width)) {
output_length = strlen(state->display.display_buffer);
if ((output_length < state->display.prev_length)
&& ((int) (state->control.width) >= state->display.prev_width)) {
char spaces[32];
int spaces_to_add;
spaces_to_add = state->prev_length - output_length;
spaces_to_add = state->display.prev_length - output_length;
/* Upper boundary on number of spaces */
if (spaces_to_add > 15) {
spaces_to_add = 15;
@@ -1087,12 +1092,12 @@ static const char *pv__format(pvstate_t state,
while (--spaces_to_add >= 0) {
spaces[spaces_to_add] = ' ';
}
(void) pv_strlcat(state->display_buffer, spaces, state->display_buffer_size);
(void) pv_strlcat(state->display.display_buffer, spaces, state->display.display_buffer_size);
}
state->prev_width = state->width;
state->prev_length = output_length;
state->display.prev_width = state->control.width;
state->display.prev_length = output_length;
return state->display_buffer;
return state->display.display_buffer;
}
@@ -1118,9 +1123,9 @@ void pv_display(pvstate_t state, long double esec, off_t sl, off_t tot)
* If the display options need reparsing, do so to generate new
* formatting parameters.
*/
if (state->reparse_display) {
if (state->flag.reparse_display) {
pv__format_init(state);
state->reparse_display = 0;
state->flag.reparse_display = 0;
}
pv_sig_checkbg();
@@ -1129,18 +1134,18 @@ void pv_display(pvstate_t state, long double esec, off_t sl, off_t tot)
if (NULL == display)
return;
if (state->numeric) {
if (state->control.numeric) {
pv_write_retry(STDERR_FILENO, display, strlen(display));
} else if (state->cursor) {
if (state->force || pv_in_foreground()) {
} else if (state->control.cursor) {
if (state->control.force || pv_in_foreground()) {
pv_crs_update(state, display);
state->display_visible = true;
state->display.display_visible = true;
}
} else {
if (state->force || pv_in_foreground()) {
if (state->control.force || pv_in_foreground()) {
pv_write_retry(STDERR_FILENO, display, strlen(display));
pv_write_retry(STDERR_FILENO, "\r", 1);
state->display_visible = true;
state->display.display_visible = true;
}
}
+44 -44
View File
@@ -45,25 +45,25 @@ static off_t pv_calc_total_bytes(pvstate_t state)
/*
* No files specified - check stdin.
*/
if ((state->input_file_count < 1) || (NULL == state->input_files)) {
if ((state->files.file_count < 1) || (NULL == state->files.filename)) {
if (0 == fstat(STDIN_FILENO, &sb))
total = sb.st_size;
return total;
}
for (file_idx = 0; file_idx < state->input_file_count; file_idx++) {
for (file_idx = 0; file_idx < state->files.file_count; file_idx++) {
int rc;
if (0 == strcmp(state->input_files[file_idx], "-")) {
if (0 == strcmp(state->files.filename[file_idx], "-")) {
rc = fstat(STDIN_FILENO, &sb);
if (rc != 0) {
total = 0;
return total;
}
} else {
rc = stat(state->input_files[file_idx], &sb);
rc = stat(state->files.filename[file_idx], &sb);
if (0 == rc) {
rc = access(state->input_files[file_idx], R_OK); /* flawfinder: ignore */
rc = access(state->files.filename[file_idx], R_OK); /* flawfinder: ignore */
/*
* flawfinder rationale: we're not really
* using access() to do permissions checks,
@@ -79,7 +79,7 @@ static off_t pv_calc_total_bytes(pvstate_t state)
}
if (rc != 0) {
debug("%s: %s", state->input_files[file_idx], strerror(errno));
debug("%s: %s", state->files.filename[file_idx], strerror(errno));
total = 0;
return total;
}
@@ -91,7 +91,7 @@ static off_t pv_calc_total_bytes(pvstate_t state)
* Get the size of block devices by opening
* them and seeking to the end.
*/
if (0 == strcmp(state->input_files[file_idx], "-")) {
if (0 == strcmp(state->files.filename[file_idx], "-")) {
fd = open("/dev/stdin", O_RDONLY); /* flawfinder: ignore */
/*
* flawfinder rationale: "/dev/stdin" may be
@@ -101,7 +101,7 @@ static off_t pv_calc_total_bytes(pvstate_t state)
* be under the control of someone else.
*/
} else {
fd = open(state->input_files[file_idx], O_RDONLY); /* flawfinder: ignore */
fd = open(state->files.filename[file_idx], O_RDONLY); /* flawfinder: ignore */
/* flawfinder - see last open() below. */
}
if (fd >= 0) {
@@ -146,7 +146,7 @@ static off_t pv_calc_total_bytes(pvstate_t state)
if (lseek(STDOUT_FILENO, 0, SEEK_SET) != 0) {
pv_error(state, "%s: %s: %s", "(stdout)",
_("failed to seek to start of output"), strerror(errno));
state->exit_status |= 2;
state->status.exit_status |= 2;
}
/*
* If we worked out a size, then set the
@@ -155,7 +155,7 @@ static off_t pv_calc_total_bytes(pvstate_t state)
* device.
*/
if (total > 0) {
state->stop_at_size = true;
state->control.stop_at_size = true;
}
}
}
@@ -182,11 +182,11 @@ static off_t pv_calc_total_lines(pvstate_t state)
total = 0;
for (file_idx = 0; file_idx < state->input_file_count && NULL != state->input_files; file_idx++) {
for (file_idx = 0; file_idx < state->files.file_count && NULL != state->files.filename; file_idx++) {
int fd = -1;
int rc = 0;
if (0 == strcmp(state->input_files[file_idx], "-")) {
if (0 == strcmp(state->files.filename[file_idx], "-")) {
rc = fstat(STDIN_FILENO, &sb);
if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
total = 0;
@@ -194,17 +194,17 @@ static off_t pv_calc_total_lines(pvstate_t state)
}
fd = dup(STDIN_FILENO);
} else {
rc = stat(state->input_files[file_idx], &sb);
rc = stat(state->files.filename[file_idx], &sb);
if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
total = 0;
return total;
}
fd = open(state->input_files[file_idx], O_RDONLY); /* flawfinder: ignore */
fd = open(state->files.filename[file_idx], O_RDONLY); /* flawfinder: ignore */
/* flawfinder - see last open() below. */
}
if (fd < 0) {
debug("%s: %s", state->input_files[file_idx], strerror(errno));
debug("%s: %s", state->files.filename[file_idx], strerror(errno));
total = 0;
return total;
}
@@ -227,14 +227,14 @@ static off_t pv_calc_total_lines(pvstate_t state)
* OK.
*/
if (numread < 0) {
pv_error(state, "%s: %s", state->input_files[file_idx], strerror(errno));
state->exit_status |= 2;
pv_error(state, "%s: %s", state->files.filename[file_idx], strerror(errno));
state->status.exit_status |= 2;
break;
} else if (0 == numread) {
break;
}
for (buf_idx = 0; buf_idx < numread; buf_idx++) {
if (state->null_terminated_lines) {
if (state->control.null_terminated_lines) {
if ('\0' == scanbuf[buf_idx])
total++;
} else {
@@ -245,8 +245,8 @@ static off_t pv_calc_total_lines(pvstate_t state)
}
if (0 != lseek(fd, 0, SEEK_SET)) {
pv_error(state, "%s: %s", state->input_files[file_idx], strerror(errno));
state->exit_status |= 2;
pv_error(state, "%s: %s", state->files.filename[file_idx], strerror(errno));
state->status.exit_status |= 2;
}
(void) close(fd);
@@ -259,13 +259,13 @@ static off_t pv_calc_total_lines(pvstate_t state)
/*
* Work out the total size of all data by adding up the sizes of all input
* files, using either pv_calc_total_bytes() or pv_calc_total_lines()
* depending on whether state->linemode is true.
* depending on whether state->control.linemode is true.
*
* Returns the total size, or 0 if it is unknown.
*/
off_t pv_calc_total_size(pvstate_t state)
{
if (state->linemode) {
if (state->control.linemode) {
return pv_calc_total_lines(state);
} else {
return pv_calc_total_bytes(state);
@@ -279,7 +279,7 @@ off_t pv_calc_total_size(pvstate_t state)
* error). It is an error if the next input file is the same as the file
* stdout is pointing to.
*
* Updates state->current_input_file in the process.
* Updates state->status.current_input_file in the process.
*/
int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
{
@@ -291,21 +291,21 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
if (oldfd >= 0) {
if (0 != close(oldfd)) {
pv_error(state, "%s: %s", _("failed to close file"), strerror(errno));
state->exit_status |= 8;
state->status.exit_status |= 8;
return -1;
}
}
if (filenum >= state->input_file_count) {
debug("%s: %d >= %d", "filenum too large", filenum, state->input_file_count);
state->exit_status |= 8;
if (filenum >= state->files.file_count) {
debug("%s: %d >= %d", "filenum too large", filenum, state->files.file_count);
state->status.exit_status |= 8;
return -1;
}
if ((NULL == state->input_files) || (0 == strcmp(state->input_files[filenum], "-"))) {
if ((NULL == state->files.filename) || (0 == strcmp(state->files.filename[filenum], "-"))) {
fd = STDIN_FILENO;
} else {
fd = open(state->input_files[filenum], O_RDONLY); /* flawfinder: ignore */
fd = open(state->files.filename[filenum], O_RDONLY); /* flawfinder: ignore */
/*
* flawfinder rationale: the input file list is under the
* control of the operator by its nature, so we can't refuse
@@ -313,24 +313,24 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
*/
if (fd < 0) {
pv_error(state, "%s: %s: %s",
_("failed to read file"), state->input_files[filenum], strerror(errno));
state->exit_status |= 2;
_("failed to read file"), state->files.filename[filenum], strerror(errno));
state->status.exit_status |= 2;
return -1;
}
}
if (0 != fstat(fd, &isb)) {
pv_error(state, "%s: %s: %s", _("failed to stat file"),
NULL == state->input_files ? "-" : state->input_files[filenum], strerror(errno));
NULL == state->files.filename ? "-" : state->files.filename[filenum], strerror(errno));
(void) close(fd);
state->exit_status |= 2;
state->status.exit_status |= 2;
return -1;
}
if (0 != fstat(STDOUT_FILENO, &osb)) {
pv_error(state, "%s: %s", _("failed to stat output file"), strerror(errno));
(void) close(fd);
state->exit_status |= 2;
state->status.exit_status |= 2;
return -1;
}
@@ -351,18 +351,18 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
if (input_file_is_stdout) {
pv_error(state, "%s: %s", _("input file is output file"),
NULL == state->input_files ? "-" : state->input_files[filenum]);
NULL == state->files.filename ? "-" : state->files.filename[filenum]);
(void) close(fd);
state->exit_status |= 4;
state->status.exit_status |= 4;
return -1;
}
state->current_input_file = filenum;
state->status.current_input_file = filenum;
#ifdef O_DIRECT
/*
* Set or clear O_DIRECT on the file descriptor.
*/
if (0 != fcntl(fd, F_SETFL, (state->direct_io ? O_DIRECT : 0) | fcntl(fd, F_GETFL))) {
if (0 != fcntl(fd, F_SETFL, (state->control.direct_io ? O_DIRECT : 0) | fcntl(fd, F_GETFL))) {
/*@-compdef@ */
/*
* splint - passed or returned storage is undefined - but at
@@ -400,7 +400,7 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
/*@-statictrans@ */
/*
* Here we are doing bad things with regards to whether the returned
* string is an allocated string from the state->input_files array,
* string is an allocated string from the state->files.filename array,
* a constant string, or a returned string from gettext(), but it
* has no impact. We explicitly document, above, that the returned
* string expires with the state, and hence switch off the
@@ -418,15 +418,15 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
if (NULL == str_stdin)
str_stdin = "(stdin)";
if (state->current_input_file < 0)
if (state->status.current_input_file < 0)
return str_none;
if ((unsigned int) (state->current_input_file) >= state->input_file_count)
if ((unsigned int) (state->status.current_input_file) >= state->files.file_count)
return str_none;
if (NULL == state->input_files) {
if (NULL == state->files.filename) {
input_file_name = NULL;
} else {
input_file_name = state->input_files[state->current_input_file];
input_file_name = state->files.filename[state->status.current_input_file];
}
if (NULL == input_file_name)
return str_none;
@@ -437,7 +437,7 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
return input_file_name;
/*@+compdef@ */
/*
* splint warns about state->input_files being undefined, but we
* splint warns about state->files.filename being undefined, but we
* know it's been populated fully by the time this function is
* called.
*/
+112 -110
View File
@@ -69,7 +69,7 @@ int pv_main_loop(pvstate_t state)
total_written = 0;
lineswritten = 0;
transferred_since_last = 0;
state->initial_offset = 0;
state->display.initial_offset = 0;
memset(&cur_time, 0, sizeof(cur_time));
memset(&start_time, 0, sizeof(start_time));
@@ -84,11 +84,11 @@ int pv_main_loop(pvstate_t state)
pv_elapsedtime_copy(&next_ratecheck, &cur_time);
pv_elapsedtime_copy(&next_remotecheck, &cur_time);
pv_elapsedtime_copy(&next_update, &cur_time);
if ((state->delay_start > 0)
&& (state->delay_start > state->interval)) {
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->delay_start));
if ((state->control.delay_start > 0)
&& (state->control.delay_start > state->control.interval)) {
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.delay_start));
} else {
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
}
target = 0;
@@ -99,7 +99,7 @@ int pv_main_loop(pvstate_t state)
* Open the first readable input file.
*/
fd = -1;
while (fd < 0 && file_idx < state->input_file_count) {
while (fd < 0 && file_idx < state->files.file_count) {
fd = pv_next_file(state, file_idx, -1);
if (fd < 0)
file_idx++;
@@ -109,9 +109,9 @@ int pv_main_loop(pvstate_t state)
* Exit early if there was no readable input file.
*/
if (fd < 0) {
if (state->cursor)
if (state->control.cursor)
pv_crs_fini(state);
return state->exit_status;
return state->status.exit_status;
}
#if HAVE_POSIX_FADVISE
/* Advise the OS that we will only be reading sequentially. */
@@ -122,10 +122,11 @@ int pv_main_loop(pvstate_t state)
/*
* Set or clear O_DIRECT on the output.
*/
if (0 != fcntl(STDOUT_FILENO, F_SETFL, (state->direct_io ? O_DIRECT : 0) | fcntl(STDOUT_FILENO, F_GETFL))) {
if (0 !=
fcntl(STDOUT_FILENO, F_SETFL, (state->control.direct_io ? O_DIRECT : 0) | fcntl(STDOUT_FILENO, F_GETFL))) {
debug("%s: %s", "fcntl", strerror(errno));
}
state->direct_io_changed = false;
state->control.direct_io_changed = false;
#endif /* O_DIRECT */
#if HAVE_STRUCT_STAT_ST_BLKSIZE
@@ -133,7 +134,7 @@ int pv_main_loop(pvstate_t state)
* Set target buffer size if the initial file's block size can be
* read and we weren't given a target buffer size.
*/
if (0 == state->target_buffer_size) {
if (0 == state->control.target_buffer_size) {
struct stat sb;
memset(&sb, 0, sizeof(sb));
if (0 == fstat(fd, &sb)) {
@@ -142,13 +143,13 @@ int pv_main_loop(pvstate_t state)
if (sz > BUFFER_SIZE_MAX) {
sz = BUFFER_SIZE_MAX;
}
state->target_buffer_size = sz;
state->control.target_buffer_size = sz;
}
}
#endif
if (0 == state->target_buffer_size)
state->target_buffer_size = BUFFER_SIZE;
if (0 == state->control.target_buffer_size)
state->control.target_buffer_size = BUFFER_SIZE;
while ((!(eof_in && eof_out)) || (!final_update)) {
@@ -162,17 +163,17 @@ int pv_main_loop(pvstate_t state)
pv_elapsedtime_add_nsec(&next_remotecheck, REMOTE_INTERVAL);
}
if (1 == state->pv_sig_abort)
if (1 == state->flag.trigger_exit)
break;
if (state->rate_limit > 0) {
if (state->control.rate_limit > 0) {
pv_elapsedtime_read(&cur_time);
if (pv_elapsedtime_compare(&cur_time, &next_ratecheck) > 0) {
target +=
((long double) (state->rate_limit)) / (long double) (1000000000.0 /
(long
double) (RATE_GRANULARITY));
long double burst_max = ((long double) (state->rate_limit * RATE_BURST_WINDOW));
((long double) (state->control.rate_limit)) / (long double) (1000000000.0 /
(long double)
(RATE_GRANULARITY));
long double burst_max = ((long double) (state->control.rate_limit * RATE_BURST_WINDOW));
if (target > burst_max) {
target = burst_max;
}
@@ -185,11 +186,11 @@ int pv_main_loop(pvstate_t state)
* If we have to stop at "size" bytes, make sure we don't
* try to write more than we're allowed to.
*/
if ((0 < state->size) && (state->stop_at_size)) {
if ((state->size < (total_written + cansend))
if ((0 < state->control.size) && (state->control.stop_at_size)) {
if ((state->control.size < (total_written + cansend))
|| ((0 == cansend)
&& (0 == state->rate_limit))) {
cansend = state->size - total_written;
&& (0 == state->control.rate_limit))) {
cansend = state->control.size - total_written;
if (0 >= cansend) {
eof_in = true;
eof_out = true;
@@ -197,7 +198,7 @@ int pv_main_loop(pvstate_t state)
}
}
if ((0 < state->size) && (state->stop_at_size)
if ((0 < state->control.size) && (state->control.stop_at_size)
&& (0 >= cansend) && eof_in && eof_out) {
written = 0;
} else {
@@ -206,27 +207,27 @@ int pv_main_loop(pvstate_t state)
/* End on write error. */
if (written < 0) {
if (state->cursor)
if (state->control.cursor)
pv_crs_fini(state);
return state->exit_status;
return state->status.exit_status;
}
if (state->linemode) {
if (state->control.linemode) {
transferred_since_last += lineswritten;
total_written += lineswritten;
if (state->rate_limit > 0)
if (state->control.rate_limit > 0)
target -= lineswritten;
} else {
transferred_since_last += written;
total_written += written;
if (state->rate_limit > 0)
if (state->control.rate_limit > 0)
target -= written;
}
/*
* EOF, and files remain - advance to the next file.
*/
while (eof_in && eof_out && file_idx < (state->input_file_count - 1)) {
while (eof_in && eof_out && file_idx < (state->files.file_count - 1)) {
file_idx++;
fd = pv_next_file(state, file_idx, fd);
if (fd >= 0) {
@@ -241,14 +242,14 @@ int pv_main_loop(pvstate_t state)
/* If full EOF, final update, and force a display updaate. */
if (eof_in && eof_out) {
final_update = true;
if ((state->display_visible)
|| (state->delay_start < 0.001)) {
if ((state->display.display_visible)
|| (state->control.delay_start < 0.001)) {
pv_elapsedtime_copy(&next_update, &cur_time);
}
}
/* Just go round the loop again if there's no display. */
if (state->no_display)
if (state->control.no_display)
continue;
/*
@@ -257,9 +258,9 @@ int pv_main_loop(pvstate_t state)
* we then count time as if we started when the first byte
* was received.
*/
if (state->wait) {
if (state->control.wait) {
/* Restart the loop if nothing written yet. */
if (state->linemode) {
if (state->control.linemode) {
if (lineswritten < 1)
continue;
} else {
@@ -267,7 +268,7 @@ int pv_main_loop(pvstate_t state)
continue;
}
state->wait = 0;
state->control.wait = 0;
/*
* Reset the timer offset counter now that data
@@ -281,7 +282,7 @@ int pv_main_loop(pvstate_t state)
*/
pv_sig_nopause();
pv_elapsedtime_read(&start_time);
pv_elapsedtime_zero(&(state->pv_sig_toffset));
pv_elapsedtime_zero(&(state->signal.toffset));
pv_sig_allowpause();
/*
@@ -289,7 +290,7 @@ int pv_main_loop(pvstate_t state)
* not immediately.
*/
pv_elapsedtime_copy(&next_update, &start_time);
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
}
/* Restart the loop if it's not time to update the display. */
@@ -297,7 +298,7 @@ int pv_main_loop(pvstate_t state)
continue;
}
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
/* Set the "next update" time to now, if it's in the past. */
if (pv_elapsedtime_compare(&next_update, &cur_time) < 0)
@@ -308,7 +309,7 @@ int pv_main_loop(pvstate_t state)
* started, plus the total time we spent stopped.
*/
memset(&init_time, 0, sizeof(init_time));
pv_elapsedtime_add(&init_time, &start_time, &(state->pv_sig_toffset));
pv_elapsedtime_add(&init_time, &start_time, &(state->signal.toffset));
/*
* Now get the effective elapsed transfer time - current
@@ -323,19 +324,19 @@ int pv_main_loop(pvstate_t state)
transferred_since_last = -1;
/* Resize the display, if a resize signal was received. */
if (1 == state->pv_sig_newsize) {
if (1 == state->flag.terminal_resized) {
unsigned int new_width, new_height;
state->pv_sig_newsize = 0;
state->flag.terminal_resized = 0;
new_width = state->width;
new_height = state->height;
new_width = state->control.width;
new_height = state->control.height;
pv_screensize(&new_width, &new_height);
if (!state->width_set_manually)
state->width = new_width;
if (!state->height_set_manually)
state->height = new_height;
if (!state->control.width_set_manually)
state->control.width = new_width;
if (!state->control.height_set_manually)
state->control.height = new_height;
}
pv_display(state, elapsed_seconds, transferred_since_last, total_written);
@@ -343,27 +344,27 @@ int pv_main_loop(pvstate_t state)
transferred_since_last = 0;
}
if (state->cursor) {
if (state->control.cursor) {
pv_crs_fini(state);
} else {
if ((!state->numeric) && (!state->no_display)
&& (state->display_visible))
if ((!state->control.numeric) && (!state->control.no_display)
&& (state->display.display_visible))
pv_write_retry(STDERR_FILENO, "\n", 1);
}
if (1 == state->pv_sig_abort)
state->exit_status |= 32;
if (1 == state->flag.trigger_exit)
state->status.exit_status |= 32;
if (fd >= 0)
(void) close(fd);
return state->exit_status;
return state->status.exit_status;
}
/*
* Watch the progress of file descriptor state->watch_fd in process
* state->watch_pid and show details about the transfer on standard error
* Watch the progress of file descriptor state->control.watch_fd in process
* state->control.watch_pid and show details about the transfer on standard error
* according to the given options.
*
* Returns nonzero on error.
@@ -379,28 +380,28 @@ int pv_watchfd_loop(pvstate_t state)
int rc;
memset(&info, 0, sizeof(info));
info.watch_pid = state->watch_pid;
info.watch_fd = state->watch_fd;
info.watch_pid = state->control.watch_pid;
info.watch_fd = state->control.watch_fd;
rc = pv_watchfd_info(state, &info, false);
if (0 != rc) {
state->exit_status |= 2;
return state->exit_status;
state->status.exit_status |= 2;
return state->status.exit_status;
}
/*
* Use a size if one was passed, otherwise use the total size
* calculated.
*/
if (0 >= state->size)
state->size = info.size;
if (0 >= state->control.size)
state->control.size = info.size;
if (state->size < 1) {
if (state->control.size < 1) {
char *fmt;
while (NULL != (fmt = strstr(state->default_format, "%e"))) {
while (NULL != (fmt = strstr(state->control.default_format, "%e"))) {
debug("%s", "zero size - removing ETA");
/* strlen-1 here to include trailing NUL */
memmove(fmt, fmt + 2, strlen(fmt) - 1);
state->reparse_display = 1;
state->flag.reparse_display = 1;
}
}
@@ -414,7 +415,7 @@ int pv_watchfd_loop(pvstate_t state)
pv_elapsedtime_copy(&(info.start_time), &cur_time);
pv_elapsedtime_copy(&next_remotecheck, &cur_time);
pv_elapsedtime_copy(&next_update, &cur_time);
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
ended = false;
total_written = 0;
@@ -430,7 +431,7 @@ int pv_watchfd_loop(pvstate_t state)
pv_elapsedtime_add_nsec(&next_remotecheck, REMOTE_INTERVAL);
}
if (1 == state->pv_sig_abort)
if (1 == state->flag.trigger_exit)
break;
position_now = pv_watchfd_position(&info);
@@ -441,7 +442,7 @@ int pv_watchfd_loop(pvstate_t state)
transferred_since_last += position_now - total_written;
total_written = position_now;
if (first_check) {
state->initial_offset = position_now;
state->display.initial_offset = position_now;
first_check = false;
}
}
@@ -462,7 +463,7 @@ int pv_watchfd_loop(pvstate_t state)
continue;
}
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
/* Set the "next update" time to now, if it's in the past. */
if (pv_elapsedtime_compare(&next_update, &cur_time) < 0)
@@ -472,7 +473,7 @@ int pv_watchfd_loop(pvstate_t state)
* Calculate the effective start time: the time we actually
* started, plus the total time we spent stopped.
*/
pv_elapsedtime_add(&init_time, &(info.start_time), &(state->pv_sig_toffset));
pv_elapsedtime_add(&init_time, &(info.start_time), &(state->signal.toffset));
/*
* Now get the effective elapsed transfer time - current
@@ -486,19 +487,19 @@ int pv_watchfd_loop(pvstate_t state)
transferred_since_last = -1;
/* Resize the display, if a resize signal was received. */
if (1 == state->pv_sig_newsize) {
if (1 == state->flag.terminal_resized) {
unsigned int new_width, new_height;
state->pv_sig_newsize = 0;
state->flag.terminal_resized = 0;
new_width = state->width;
new_height = state->height;
new_width = state->control.width;
new_height = state->control.height;
pv_screensize(&new_width, &new_height);
if (!state->width_set_manually)
state->width = new_width;
if (!state->height_set_manually)
state->height = new_height;
if (!state->control.width_set_manually)
state->control.width = new_width;
if (!state->control.height_set_manually)
state->control.height = new_height;
}
pv_display(state, elapsed_seconds, transferred_since_last, total_written);
@@ -506,18 +507,18 @@ int pv_watchfd_loop(pvstate_t state)
transferred_since_last = 0;
}
if (!state->numeric)
if (!state->control.numeric)
pv_write_retry(STDERR_FILENO, "\n", 1);
if (1 == state->pv_sig_abort)
state->exit_status |= 32;
if (1 == state->flag.trigger_exit)
state->status.exit_status |= 32;
return state->exit_status;
return state->status.exit_status;
}
/*
* Watch the progress of all file descriptors in process state->watch_pid
* Watch the progress of all file descriptors in process state->control.watch_pid
* and show details about the transfers on standard error according to the
* given options.
*
@@ -541,9 +542,9 @@ int pv_watchpid_loop(pvstate_t state)
* Make sure the process exists first, so we can give an error if
* it's not there at the start.
*/
if (kill(state->watch_pid, 0) != 0) {
pv_error(state, "%s %u: %s", _("pid"), state->watch_pid, strerror(errno));
state->exit_status |= 2;
if (kill(state->control.watch_pid, 0) != 0) {
pv_error(state, "%s %u: %s", _("pid"), state->control.watch_pid, strerror(errno));
state->status.exit_status |= 2;
return 2;
}
@@ -557,7 +558,8 @@ int pv_watchpid_loop(pvstate_t state)
* Make sure there's a format string, and then insert %N into it if
* it's not present.
*/
original_format_string = state->format_string ? state->format_string : state->default_format;
original_format_string =
state->control.format_string ? state->control.format_string : state->control.default_format;
memset(new_format_string, 0, sizeof(new_format_string));
if (NULL == strstr(original_format_string, "%N")) {
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%%N %s", original_format_string);
@@ -565,9 +567,9 @@ int pv_watchpid_loop(pvstate_t state)
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%s", original_format_string);
}
new_format_string[sizeof(new_format_string) - 1] = '\0';
state_copy.format_string = NULL;
(void) pv_snprintf(state_copy.default_format, PV_SIZEOF_DEFAULT_FORMAT, "%.510s", new_format_string);
state_copy.default_format[PV_SIZEOF_DEFAULT_FORMAT - 1] = '\0';
state_copy.control.format_string = NULL;
(void) pv_snprintf(state_copy.control.default_format, PV_SIZEOF_DEFAULT_FORMAT, "%.510s", new_format_string);
state_copy.control.default_format[PV_SIZEOF_DEFAULT_FORMAT - 1] = '\0';
/*
* Get things ready for the main loop.
@@ -578,7 +580,7 @@ int pv_watchpid_loop(pvstate_t state)
pv_elapsedtime_read(&cur_time);
pv_elapsedtime_copy(&next_update, &cur_time);
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
for (idx = 0; idx < FD_SETSIZE; idx++) {
fd_to_idx[idx] = -1;
@@ -589,15 +591,15 @@ int pv_watchpid_loop(pvstate_t state)
while (true) {
int rc, fd, displayed_lines;
if (1 == state->pv_sig_abort)
if (1 == state->flag.trigger_exit)
break;
pv_elapsedtime_read(&cur_time);
if (kill(state->watch_pid, 0) != 0) {
if (kill(state->control.watch_pid, 0) != 0) {
if (first_pass) {
pv_error(state, "%s %u: %s", _("pid"), state->watch_pid, strerror(errno));
state->exit_status |= 2;
pv_error(state, "%s %u: %s", _("pid"), state->control.watch_pid, strerror(errno));
state->status.exit_status |= 2;
if (NULL != info_array)
free(info_array);
if (NULL != state_array)
@@ -616,30 +618,30 @@ int pv_watchpid_loop(pvstate_t state)
continue;
}
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->interval));
pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval));
/* Set the "next update" time to now, if it's in the past. */
if (pv_elapsedtime_compare(&next_update, &cur_time) < 0)
pv_elapsedtime_copy(&next_update, &cur_time);
/* Resize the display, if a resize signal was received. */
if (1 == state->pv_sig_newsize) {
state->pv_sig_newsize = 0;
pv_screensize(&(state->width), &(state->height));
if (1 == state->flag.terminal_resized) {
state->flag.terminal_resized = 0;
pv_screensize(&(state->control.width), &(state->control.height));
for (idx = 0; idx < array_length; idx++) {
state_array[idx].width = state->width;
state_array[idx].height = state->height;
state_array[idx].control.width = state->control.width;
state_array[idx].control.height = state->control.height;
pv_watchpid_setname(state, &(info_array[idx]));
state_array[idx].reparse_display = 1;
state_array[idx].flag.reparse_display = 1;
}
}
rc = pv_watchpid_scanfds(state, &state_copy,
state->watch_pid, &array_length, &info_array, &state_array, fd_to_idx);
state->control.watch_pid, &array_length, &info_array, &state_array, fd_to_idx);
if (rc != 0) {
if (first_pass) {
pv_error(state, "%s %u: %s", _("pid"), state->watch_pid, strerror(errno));
state->exit_status |= 2;
pv_error(state, "%s %u: %s", _("pid"), state->control.watch_pid, strerror(errno));
state->status.exit_status |= 2;
if (NULL != info_array)
free(info_array);
if (NULL != state_array)
@@ -657,7 +659,7 @@ int pv_watchpid_loop(pvstate_t state)
struct timespec init_time, transfer_elapsed;
long double elapsed_seconds;
if (displayed_lines >= (int) (state->height))
if (displayed_lines >= (int) (state->control.height))
break;
idx = fd_to_idx[fd];
@@ -701,7 +703,7 @@ int pv_watchpid_loop(pvstate_t state)
* Calculate the effective start time: the time we actually
* started, plus the total time we spent stopped.
*/
pv_elapsedtime_add(&init_time, &(info_array[idx].start_time), &(state->pv_sig_toffset));
pv_elapsedtime_add(&init_time, &(info_array[idx].start_time), &(state->signal.toffset));
/*
* Now get the effective elapsed transfer time - current
@@ -737,7 +739,7 @@ int pv_watchpid_loop(pvstate_t state)
unsigned int x;
if (displayed_lines > 0)
pv_write_retry(STDERR_FILENO, "\n", 1);
for (x = 0; x < state->width; x++)
for (x = 0; x < state->control.width; x++)
pv_write_retry(STDERR_FILENO, " ", 1);
pv_write_retry(STDERR_FILENO, "\r", 1);
blank_lines--;
@@ -758,7 +760,7 @@ int pv_watchpid_loop(pvstate_t state)
blank_lines = prev_displayed_lines;
while (blank_lines > 0) {
unsigned int x;
for (x = 0; x < state->width; x++)
for (x = 0; x < state->control.width; x++)
pv_write_retry(STDERR_FILENO, " ", 1);
pv_write_retry(STDERR_FILENO, "\r", 1);
blank_lines--;
+52 -51
View File
@@ -45,7 +45,7 @@ static void pv_sig_ensure_tty_tostop()
if (0 == (terminal_attributes.c_lflag & TOSTOP)) {
terminal_attributes.c_lflag |= TOSTOP;
if (0 == tcsetattr(STDERR_FILENO, TCSANOW, &terminal_attributes)) {
pv_sig_state->pv_tty_tostop_added = true;
pv_sig_state->signal.pv_tty_tostop_added = true;
debug("%s", "set terminal TOSTOP attribute");
} else {
debug("%s: %s", "failed to set terminal TOSTOP attribute", strerror(errno));
@@ -55,8 +55,9 @@ static void pv_sig_ensure_tty_tostop()
* In "-c" mode with IPC, make all "pv -c" instances aware
* that we set TOSTOP, so the last one can clear it on exit.
*/
if (pv_sig_state->cursor && (NULL != pv_sig_state->crs_shared) && (!pv_sig_state->crs_noipc)) {
pv_sig_state->crs_shared->tty_tostop_added = true;
if (pv_sig_state->control.cursor && (NULL != pv_sig_state->cursor.shared)
&& (!pv_sig_state->cursor.noipc)) {
pv_sig_state->cursor.shared->tty_tostop_added = true;
}
#endif
}
@@ -92,8 +93,8 @@ static void pv_sig_ttou( /*@unused@ */ __attribute__((unused))
* stderr while backgrounded.
*/
if (-1 == pv_sig_state->pv_sig_old_stderr)
pv_sig_state->pv_sig_old_stderr = dup(STDERR_FILENO);
if (-1 == pv_sig_state->signal.old_stderr)
pv_sig_state->signal.old_stderr = dup(STDERR_FILENO);
if (dup2(fd, STDERR_FILENO) < 0) {
debug("%s: %s", "failed to replace stderr", strerror(errno));
@@ -114,7 +115,7 @@ static void pv_sig_tstp( /*@unused@ */ __attribute__((unused))
{
if (NULL == pv_sig_state)
return;
pv_elapsedtime_read(&(pv_sig_state->pv_sig_tstp_time));
pv_elapsedtime_read(&(pv_sig_state->signal.tstp_time));
if (0 != raise(SIGSTOP)) {
debug("%s: %s", "raise", strerror(errno));
}
@@ -135,13 +136,13 @@ static void pv_sig_cont( /*@unused@ */ __attribute__((unused))
if (NULL == pv_sig_state)
return;
pv_sig_state->pv_sig_newsize = 1;
pv_sig_state->flag.terminal_resized = 1;
/*
* We can only make the time adjustments if this SIGCONT followed a
* SIGTSTP such that we have a stop time.
*/
if (0 != pv_sig_state->pv_sig_tstp_time.tv_sec) {
if (0 != pv_sig_state->signal.tstp_time.tv_sec) {
memset(&current_time, 0, sizeof(current_time));
memset(&time_spent_stopped, 0, sizeof(time_spent_stopped));
@@ -149,27 +150,27 @@ static void pv_sig_cont( /*@unused@ */ __attribute__((unused))
pv_elapsedtime_read(&current_time);
/* time spent stopped = current time - time SIGTSTP received */
pv_elapsedtime_subtract(&time_spent_stopped, &current_time, &(pv_sig_state->pv_sig_tstp_time));
pv_elapsedtime_subtract(&time_spent_stopped, &current_time, &(pv_sig_state->signal.tstp_time));
/* add time spent stopped the total stopped-time count */
pv_elapsedtime_add(&(pv_sig_state->pv_sig_toffset), &(pv_sig_state->pv_sig_toffset),
pv_elapsedtime_add(&(pv_sig_state->signal.toffset), &(pv_sig_state->signal.toffset),
&time_spent_stopped);
/* reset the SIGTSTP receipt time */
pv_elapsedtime_zero(&(pv_sig_state->pv_sig_tstp_time));
pv_elapsedtime_zero(&(pv_sig_state->signal.tstp_time));
}
/*
* Restore the old stderr, if we had replaced it.
*/
if (pv_sig_state->pv_sig_old_stderr != -1) {
if (dup2(pv_sig_state->pv_sig_old_stderr, STDERR_FILENO) < 0) {
if (pv_sig_state->signal.old_stderr != -1) {
if (dup2(pv_sig_state->signal.old_stderr, STDERR_FILENO) < 0) {
debug("%s: %s", "failed to restore old stderr", strerror(errno));
}
if (0 != close(pv_sig_state->pv_sig_old_stderr)) {
if (0 != close(pv_sig_state->signal.old_stderr)) {
debug("%s: %s", "failed to close duplicate old stderr", strerror(errno));
}
pv_sig_state->pv_sig_old_stderr = -1;
pv_sig_state->signal.old_stderr = -1;
}
pv_sig_ensure_tty_tostop();
@@ -189,7 +190,7 @@ static void pv_sig_winch( /*@unused@ */ __attribute__((unused))
{
if (NULL == pv_sig_state)
return;
pv_sig_state->pv_sig_newsize = 1;
pv_sig_state->flag.terminal_resized = 1;
}
#endif
@@ -202,7 +203,7 @@ static void pv_sig_term( /*@unused@ */ __attribute__((unused))
{
if (NULL == pv_sig_state)
return;
pv_sig_state->pv_sig_abort = 1;
pv_sig_state->flag.trigger_exit = 1;
}
@@ -219,8 +220,8 @@ static void pv_sig_usr2( /*@unused@ */ __attribute__((unused))
return;
if (NULL == info)
return;
pv_sig_state->pv_sig_rxusr2 = 1;
pv_sig_state->pv_sig_sender = info->si_pid;
pv_sig_state->signal.rxusr2 = 1;
pv_sig_state->signal.sender = info->si_pid;
}
@@ -232,11 +233,11 @@ bool pv_sigusr2_received(pvstate_t state, pid_t * pid)
{
if (NULL == state)
return false;
if (0 == state->pv_sig_rxusr2)
if (0 == state->signal.rxusr2)
return false;
if (NULL != pid)
*pid = state->pv_sig_sender;
state->pv_sig_rxusr2 = 0;
*pid = state->signal.sender;
state->signal.rxusr2 = 0;
return true;
}
@@ -261,9 +262,9 @@ void pv_sig_init(pvstate_t state)
pv_sig_state = state;
pv_sig_state->pv_sig_old_stderr = -1;
pv_elapsedtime_zero(&(pv_sig_state->pv_sig_tstp_time));
pv_elapsedtime_zero(&(pv_sig_state->pv_sig_toffset));
pv_sig_state->signal.old_stderr = -1;
pv_elapsedtime_zero(&(pv_sig_state->signal.tstp_time));
pv_elapsedtime_zero(&(pv_sig_state->signal.toffset));
/*
* Note that we cast all sigemptyset() and sigaction() return values
@@ -278,7 +279,7 @@ void pv_sig_init(pvstate_t state)
sa.sa_handler = SIG_IGN;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGPIPE, &sa, &(pv_sig_state->pv_sig_old_sigpipe));
(void) sigaction(SIGPIPE, &sa, &(pv_sig_state->signal.old_sigpipe));
/*
* Handle SIGTTOU by continuing with output switched off, so that we
@@ -287,7 +288,7 @@ void pv_sig_init(pvstate_t state)
sa.sa_handler = pv_sig_ttou;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGTTOU, &sa, &(pv_sig_state->pv_sig_old_sigttou));
(void) sigaction(SIGTTOU, &sa, &(pv_sig_state->signal.old_sigttou));
/*
* Handle SIGTSTP by storing the time the signal happened for later
@@ -296,7 +297,7 @@ void pv_sig_init(pvstate_t state)
sa.sa_handler = pv_sig_tstp;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGTSTP, &sa, &(pv_sig_state->pv_sig_old_sigtstp));
(void) sigaction(SIGTSTP, &sa, &(pv_sig_state->signal.old_sigtstp));
/*
* Handle SIGCONT by adding the elapsed time since the last SIGTSTP
@@ -306,7 +307,7 @@ void pv_sig_init(pvstate_t state)
sa.sa_handler = pv_sig_cont;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGCONT, &sa, &(pv_sig_state->pv_sig_old_sigcont));
(void) sigaction(SIGCONT, &sa, &(pv_sig_state->signal.old_sigcont));
/*
* Handle SIGWINCH by setting a flag to let the main loop know it
@@ -316,7 +317,7 @@ void pv_sig_init(pvstate_t state)
sa.sa_handler = pv_sig_winch;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGWINCH, &sa, &(pv_sig_state->pv_sig_old_sigwinch));
(void) sigaction(SIGWINCH, &sa, &(pv_sig_state->signal.old_sigwinch));
#endif
/*
@@ -326,17 +327,17 @@ void pv_sig_init(pvstate_t state)
sa.sa_handler = pv_sig_term;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGINT, &sa, &(pv_sig_state->pv_sig_old_sigint));
(void) sigaction(SIGINT, &sa, &(pv_sig_state->signal.old_sigint));
sa.sa_handler = pv_sig_term;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGHUP, &sa, &(pv_sig_state->pv_sig_old_sighup));
(void) sigaction(SIGHUP, &sa, &(pv_sig_state->signal.old_sighup));
sa.sa_handler = pv_sig_term;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
(void) sigaction(SIGTERM, &sa, &(pv_sig_state->pv_sig_old_sigterm));
(void) sigaction(SIGTERM, &sa, &(pv_sig_state->signal.old_sigterm));
#ifdef SA_SIGINFO
/*
@@ -349,7 +350,7 @@ void pv_sig_init(pvstate_t state)
/*@-unrecog@ *//* splint doesn't know about SA_SIGINFO */
sa.sa_flags = SA_SIGINFO;
/*@+unrecog@ */
(void) sigaction(SIGUSR2, &sa, &(pv_sig_state->pv_sig_old_sigusr2));
(void) sigaction(SIGUSR2, &sa, &(pv_sig_state->signal.old_sigusr2));
memset(&sa, 0, sizeof(sa));
#endif
@@ -375,23 +376,23 @@ void pv_sig_fini( /*@unused@ */ __attribute__((unused)) pvstate_t state)
if (NULL == pv_sig_state)
return;
(void) sigaction(SIGPIPE, &(pv_sig_state->pv_sig_old_sigpipe), NULL);
(void) sigaction(SIGTTOU, &(pv_sig_state->pv_sig_old_sigttou), NULL);
(void) sigaction(SIGTSTP, &(pv_sig_state->pv_sig_old_sigtstp), NULL);
(void) sigaction(SIGCONT, &(pv_sig_state->pv_sig_old_sigcont), NULL);
(void) sigaction(SIGPIPE, &(pv_sig_state->signal.old_sigpipe), NULL);
(void) sigaction(SIGTTOU, &(pv_sig_state->signal.old_sigttou), NULL);
(void) sigaction(SIGTSTP, &(pv_sig_state->signal.old_sigtstp), NULL);
(void) sigaction(SIGCONT, &(pv_sig_state->signal.old_sigcont), NULL);
#ifdef SIGWINCH
(void) sigaction(SIGWINCH, &(pv_sig_state->pv_sig_old_sigwinch), NULL);
(void) sigaction(SIGWINCH, &(pv_sig_state->signal.old_sigwinch), NULL);
#endif
(void) sigaction(SIGINT, &(pv_sig_state->pv_sig_old_sigint), NULL);
(void) sigaction(SIGHUP, &(pv_sig_state->pv_sig_old_sighup), NULL);
(void) sigaction(SIGTERM, &(pv_sig_state->pv_sig_old_sigterm), NULL);
(void) sigaction(SIGINT, &(pv_sig_state->signal.old_sigint), NULL);
(void) sigaction(SIGHUP, &(pv_sig_state->signal.old_sighup), NULL);
(void) sigaction(SIGTERM, &(pv_sig_state->signal.old_sigterm), NULL);
#ifdef SA_SIGINFO
(void) sigaction(SIGUSR2, &(pv_sig_state->pv_sig_old_sigusr2), NULL);
(void) sigaction(SIGUSR2, &(pv_sig_state->signal.old_sigusr2), NULL);
#endif
need_to_clear_tostop = pv_sig_state->pv_tty_tostop_added;
need_to_clear_tostop = pv_sig_state->signal.pv_tty_tostop_added;
if (pv_sig_state->cursor) {
if (pv_sig_state->control.cursor) {
#ifdef HAVE_IPC
/*
* We won't clear TOSTOP if other "pv -c" instances
@@ -400,7 +401,7 @@ void pv_sig_fini( /*@unused@ */ __attribute__((unused)) pvstate_t state)
* TODO: we need a better way to determine if we're the last
* "pv" left.
*/
if (pv_sig_state->cursor && pv_sig_state->crs_pvcount > 1) {
if (pv_sig_state->control.cursor && pv_sig_state->cursor.pvcount > 1) {
need_to_clear_tostop = false;
}
#else /* !HAVE_IPC */
@@ -430,7 +431,7 @@ void pv_sig_fini( /*@unused@ */ __attribute__((unused)) pvstate_t state)
}
}
pv_sig_state->pv_tty_tostop_added = false;
pv_sig_state->signal.pv_tty_tostop_added = false;
}
}
@@ -495,18 +496,18 @@ void pv_sig_checkbg(void)
next_check = time(NULL) + 1;
if (-1 == pv_sig_state->pv_sig_old_stderr)
if (-1 == pv_sig_state->signal.old_stderr)
return;
if (dup2(pv_sig_state->pv_sig_old_stderr, STDERR_FILENO) < 0) {
if (dup2(pv_sig_state->signal.old_stderr, STDERR_FILENO) < 0) {
debug("%s: %s", "failed to restore old stderr", strerror(errno));
}
if (0 != close(pv_sig_state->pv_sig_old_stderr)) {
if (0 != close(pv_sig_state->signal.old_stderr)) {
debug("%s: %s", "failed to close duplicate old stderr", strerror(errno));
}
pv_sig_state->pv_sig_old_stderr = -1;
pv_sig_state->signal.old_stderr = -1;
pv_sig_ensure_tty_tostop();
#ifdef HAVE_IPC
+111 -110
View File
@@ -20,26 +20,26 @@
/* alloc / realloc history buffer */
static void pv_alloc_history(pvstate_t state)
{
if (NULL != state->history)
free(state->history);
state->history = NULL;
if (NULL != state->display.history)
free(state->display.history);
state->display.history = NULL;
state->history = calloc((size_t) (state->history_len), sizeof(state->history[0]));
if (NULL == state->history) {
state->display.history = calloc((size_t) (state->display.history_len), sizeof(state->display.history[0]));
if (NULL == state->display.history) {
/*@-mustfreefresh@ */
/*
* splint note: the gettext calls made by _() cause memory
* leak warnings, but in this case it's unavoidable, and
* mitigated by the fact we only translate each string once.
*/
fprintf(stderr, "%s: %s: %s\n", state->program_name,
fprintf(stderr, "%s: %s: %s\n", state->status.program_name,
_("history structure allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
state->history_first = state->history_last = 0;
state->history[0].elapsed_sec = 0.0; /* to be safe, memset() not recommended for doubles */
state->display.history_first = state->display.history_last = 0;
state->display.history[0].elapsed_sec = 0.0; /* to be safe, memset() not recommended for doubles */
}
/*
@@ -55,44 +55,44 @@ pvstate_t pv_state_alloc(const char *program_name)
memset(state, 0, sizeof(*state));
/* splint 3.1.2 thinks this is required for some reason. */
if (NULL != state->program_name) {
free(state->program_name);
if (NULL != state->status.program_name) {
free(state->status.program_name);
}
state->program_name = pv_strdup(program_name);
if (NULL == state->program_name) {
state->status.program_name = pv_strdup(program_name);
if (NULL == state->status.program_name) {
free(state);
return NULL;
}
state->watch_pid = 0;
state->watch_fd = -1;
state->control.watch_pid = 0;
state->control.watch_fd = -1;
#ifdef HAVE_IPC
state->crs_shmid = -1;
state->crs_pvcount = 1;
state->cursor.shmid = -1;
state->cursor.pvcount = 1;
#endif /* HAVE_IPC */
state->crs_lock_fd = -1;
state->cursor.lock_fd = -1;
state->reparse_display = 1;
state->current_input_file = -1;
state->flag.reparse_display = 1;
state->status.current_input_file = -1;
#ifdef HAVE_SPLICE
state->splice_failed_fd = -1;
state->transfer.splice_failed_fd = -1;
#endif /* HAVE_SPLICE */
state->display_visible = false;
state->display.display_visible = false;
/*
* Get the current working directory, if possible, as a base for
* showing relative filenames with --watchfd.
*/
if (NULL == getcwd(state->cwd, PV_SIZEOF_CWD - 1)) {
if (NULL == getcwd(state->status.cwd, PV_SIZEOF_CWD - 1)) {
/* failed - will always show full path */
state->cwd[0] = '\0';
state->status.cwd[0] = '\0';
}
if ('\0' == state->cwd[1]) {
if ('\0' == state->status.cwd[1]) {
/* CWD is root directory - always show full path */
state->cwd[0] = '\0';
state->status.cwd[0] = '\0';
}
state->cwd[PV_SIZEOF_CWD - 1] = '\0';
state->status.cwd[PV_SIZEOF_CWD - 1] = '\0';
return state;
}
@@ -106,45 +106,45 @@ void pv_state_free(pvstate_t state)
if (0 == state)
return;
if (NULL != state->program_name)
free(state->program_name);
state->program_name = NULL;
if (NULL != state->status.program_name)
free(state->status.program_name);
state->status.program_name = NULL;
if (NULL != state->display_buffer)
free(state->display_buffer);
state->display_buffer = NULL;
if (NULL != state->display.display_buffer)
free(state->display.display_buffer);
state->display.display_buffer = NULL;
if (NULL != state->name) {
free(state->name);
state->name = NULL;
if (NULL != state->control.name) {
free(state->control.name);
state->control.name = NULL;
}
if (NULL != state->format_string) {
free(state->format_string);
state->format_string = NULL;
if (NULL != state->control.format_string) {
free(state->control.format_string);
state->control.format_string = NULL;
}
/*@-keeptrans@ */
if (NULL != state->transfer_buffer)
free(state->transfer_buffer);
state->transfer_buffer = NULL;
if (NULL != state->transfer.transfer_buffer)
free(state->transfer.transfer_buffer);
state->transfer.transfer_buffer = NULL;
/*@+keeptrans@ */
/* splint - explicitly freeing this structure, so free() here is OK. */
if (NULL != state->history)
free(state->history);
state->history = NULL;
if (NULL != state->display.history)
free(state->display.history);
state->display.history = NULL;
if (NULL != state->input_files) {
if (NULL != state->files.filename) {
unsigned int file_idx;
for (file_idx = 0; file_idx < state->input_file_count; file_idx++) {
for (file_idx = 0; file_idx < state->files.file_count; file_idx++) {
/*@-unqualifiedtrans@ */
free(state->input_files[file_idx]);
free(state->files.filename[file_idx]);
/*@+unqualifiedtrans@ */
/* splint: see similar code below. */
}
free(state->input_files);
state->input_files = NULL;
free(state->files.filename);
state->files.filename = NULL;
}
free(state);
@@ -160,12 +160,12 @@ void pv_state_set_format(pvstate_t state, bool progress, bool timer, bool eta, b
const char *name)
{
#define PV_ADDFORMAT(x,y) if (x) { \
if (state->default_format[0] != '\0') \
(void) pv_strlcat(state->default_format, " ", sizeof(state->default_format)); \
(void) pv_strlcat(state->default_format, y, sizeof(state->default_format)); \
if (state->control.default_format[0] != '\0') \
(void) pv_strlcat(state->control.default_format, " ", sizeof(state->control.default_format)); \
(void) pv_strlcat(state->control.default_format, y, sizeof(state->control.default_format)); \
}
state->default_format[0] = '\0';
state->control.default_format[0] = '\0';
PV_ADDFORMAT(name, "%N");
PV_ADDFORMAT(bytes, "%b");
PV_ADDFORMAT(bufpercent, "%T");
@@ -187,159 +187,159 @@ void pv_state_set_format(pvstate_t state, bool progress, bool timer, bool eta, b
*/
}
if (NULL != state->name) {
free(state->name);
state->name = NULL;
if (NULL != state->control.name) {
free(state->control.name);
state->control.name = NULL;
}
if (NULL != name)
state->name = pv_strdup(name);
state->control.name = pv_strdup(name);
state->reparse_display = 1;
state->flag.reparse_display = 1;
}
void pv_state_force_set(pvstate_t state, bool val)
{
state->force = val;
state->control.force = val;
}
void pv_state_cursor_set(pvstate_t state, bool val)
{
state->cursor = val;
state->control.cursor = val;
}
void pv_state_numeric_set(pvstate_t state, bool val)
{
state->numeric = val;
state->control.numeric = val;
}
void pv_state_wait_set(pvstate_t state, bool val)
{
state->wait = val;
state->control.wait = val;
}
void pv_state_delay_start_set(pvstate_t state, double val)
{
state->delay_start = val;
state->control.delay_start = val;
}
void pv_state_linemode_set(pvstate_t state, bool val)
{
state->linemode = val;
state->control.linemode = val;
}
void pv_state_bits_set(pvstate_t state, bool bits)
{
state->bits = bits;
state->control.bits = bits;
}
void pv_state_null_terminated_lines_set(pvstate_t state, bool val)
{
state->null_terminated_lines = val;
state->control.null_terminated_lines = val;
}
void pv_state_no_display_set(pvstate_t state, bool val)
{
state->no_display = val;
state->control.no_display = val;
}
void pv_state_skip_errors_set(pvstate_t state, unsigned int val)
{
state->skip_errors = val;
state->control.skip_errors = val;
}
void pv_state_error_skip_block_set(pvstate_t state, off_t val)
{
state->error_skip_block = val;
state->control.error_skip_block = val;
}
void pv_state_stop_at_size_set(pvstate_t state, bool val)
{
state->stop_at_size = val;
state->control.stop_at_size = val;
}
void pv_state_sync_after_write_set(pvstate_t state, bool val)
{
state->sync_after_write = val;
state->control.sync_after_write = val;
}
void pv_state_direct_io_set(pvstate_t state, bool val)
{
state->direct_io = val;
state->direct_io_changed = true;
state->control.direct_io = val;
state->control.direct_io_changed = true;
}
void pv_state_discard_input_set(pvstate_t state, bool val)
{
state->discard_input = val;
state->control.discard_input = val;
}
void pv_state_rate_limit_set(pvstate_t state, off_t val)
{
state->rate_limit = val;
state->control.rate_limit = val;
}
void pv_state_target_buffer_size_set(pvstate_t state, size_t val)
{
state->target_buffer_size = val;
state->control.target_buffer_size = val;
}
void pv_state_no_splice_set(pvstate_t state, bool val)
{
state->no_splice = val;
state->control.no_splice = val;
}
void pv_state_size_set(pvstate_t state, off_t val)
{
state->size = val;
state->control.size = val;
}
void pv_state_interval_set(pvstate_t state, double val)
{
state->interval = val;
state->control.interval = val;
}
void pv_state_width_set(pvstate_t state, unsigned int val, bool was_set_manually)
{
state->width = val;
state->width_set_manually = was_set_manually;
state->control.width = val;
state->control.width_set_manually = was_set_manually;
}
void pv_state_height_set(pvstate_t state, unsigned int val, bool was_set_manually)
{
state->height = val;
state->height_set_manually = was_set_manually;
state->control.height = val;
state->control.height_set_manually = was_set_manually;
}
void pv_state_name_set(pvstate_t state, /*@null@ */ const char *val)
{
if (NULL != state->name) {
free(state->name);
state->name = NULL;
if (NULL != state->control.name) {
free(state->control.name);
state->control.name = NULL;
}
if (NULL != val)
state->name = pv_strdup(val);
state->control.name = pv_strdup(val);
}
void pv_state_format_string_set(pvstate_t state, /*@null@ */ const char *val)
{
if (NULL != state->format_string) {
free(state->format_string);
state->format_string = NULL;
if (NULL != state->control.format_string) {
free(state->control.format_string);
state->control.format_string = NULL;
}
if (NULL != val)
state->format_string = pv_strdup(val);
state->control.format_string = pv_strdup(val);
}
void pv_state_watch_pid_set(pvstate_t state, pid_t val)
{
state->watch_pid = val;
state->control.watch_pid = val;
}
void pv_state_watch_fd_set(pvstate_t state, int val)
{
state->watch_fd = val;
state->control.watch_fd = val;
}
void pv_state_average_rate_window_set(pvstate_t state, unsigned int val)
@@ -347,11 +347,11 @@ void pv_state_average_rate_window_set(pvstate_t state, unsigned int val)
if (val < 1)
val = 1;
if (val >= 20) {
state->history_len = val / 5 + 1;
state->history_interval = 5;
state->display.history_len = val / 5 + 1;
state->display.history_interval = 5;
} else {
state->history_len = val + 1;
state->history_interval = 1;
state->display.history_len = val + 1;
state->display.history_interval = 1;
}
pv_alloc_history(state);
}
@@ -364,10 +364,10 @@ void pv_state_inputfiles(pvstate_t state, unsigned int input_file_count, const c
{
unsigned int file_idx;
if (NULL != state->input_files) {
for (file_idx = 0; file_idx < state->input_file_count; file_idx++) {
if (NULL != state->files.filename) {
for (file_idx = 0; file_idx < state->files.file_count; file_idx++) {
/*@-unqualifiedtrans@ */
free(state->input_files[file_idx]);
free(state->files.filename[file_idx]);
/*@+unqualifiedtrans@ */
/*
* TODO: find a way to tell splint the array
@@ -375,29 +375,30 @@ void pv_state_inputfiles(pvstate_t state, unsigned int input_file_count, const c
* array itself.
*/
}
free(state->input_files);
state->input_files = NULL;
state->input_file_count = 0;
free(state->files.filename);
state->files.filename = NULL;
state->files.file_count = 0;
}
state->input_files = calloc((size_t) (input_file_count + 1), sizeof(char *));
if (NULL == state->input_files) {
state->files.filename = calloc((size_t) (input_file_count + 1), sizeof(char *));
if (NULL == state->files.filename) {
/*@-mustfreefresh@ *//* see similar _() issue above */
fprintf(stderr, "%s: %s: %s\n", state->program_name, _("file list allocation failed"), strerror(errno));
fprintf(stderr, "%s: %s: %s\n", state->status.program_name, _("file list allocation failed"),
strerror(errno));
/*@+mustfreefresh@ */
return;
}
for (file_idx = 0; file_idx < input_file_count; file_idx++) {
/*@-nullstate@ */
state->input_files[file_idx] = pv_strdup(input_files[file_idx]);
if (NULL == state->input_files[file_idx]) {
state->files.filename[file_idx] = pv_strdup(input_files[file_idx]);
if (NULL == state->files.filename[file_idx]) {
/*@-mustfreefresh@ *//* see similar _() issue above */
fprintf(stderr, "%s: %s: %s\n", state->program_name,
fprintf(stderr, "%s: %s: %s\n", state->status.program_name,
_("file list allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
}
state->input_file_count = input_file_count;
state->files.file_count = input_file_count;
}
/*@+nullstate@*/
+138 -129
View File
@@ -293,21 +293,21 @@ static ssize_t pv__transfer_write_repeated(int fd, void *buf, size_t count, bool
* returns 1.
*
* At most, the number of bytes read will be the number of bytes remaining
* in the input buffer. If state->rate_limit is >0, and/or "allowed" is >0,
* in the input buffer. If state->control.rate_limit is >0, and/or "allowed" is >0,
* then the maximum number of bytes read will be the number remaining unused
* in the input buffer or the value of "allowed", whichever is smaller.
*
* If splice() was successfully used, sets state->splice_used to true; if it
* failed, then state->splice_failed_fd is updated to the current fd so
* If splice() was successfully used, sets state->transfer.splice_used to true; if it
* failed, then state->transfer.splice_failed_fd is updated to the current fd so
* splice() won't be tried again until the next input file.
*
* Updates state->read_position by the number of bytes read, unless splice()
* Updates state->transfer.read_position by the number of bytes read, unless splice()
* was used, in which case it does not since there's nothing in the buffer
* (and it also adds the bytes to state->written since they've been written
* (and it also adds the bytes to state->transfer.written since they've been written
* to the output).
*
* On read error, updates state->exit_status, and if allowed by
* state->skip_errors, tries to skip past the problem.
* On read error, updates state->status.exit_status, and if allowed by
* state->control.skip_errors, tries to skip past the problem.
*
* If the end of the input file is reached or the error is unrecoverable,
* sets *eof_in to true. If all data in the buffer has been written at this
@@ -324,18 +324,18 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
#endif /* HAVE_SPLICE */
do_not_skip_errors = false;
if (0 == state->skip_errors)
if (0 == state->control.skip_errors)
do_not_skip_errors = true;
bytes_can_read = state->buffer_size - state->read_position;
bytes_can_read = state->transfer.buffer_size - state->transfer.read_position;
nread = 0;
#ifdef HAVE_SPLICE
state->splice_used = false;
if ((!state->linemode) && (!state->no_splice)
&& (fd != state->splice_failed_fd)
&& (0 == state->to_write)) {
if (state->rate_limit > 0 || allowed != 0) {
state->transfer.splice_used = false;
if ((!state->control.linemode) && (!state->control.no_splice)
&& (fd != state->transfer.splice_failed_fd)
&& (0 == state->transfer.to_write)) {
if (state->control.rate_limit > 0 || allowed != 0) {
bytes_to_splice = (size_t) allowed;
} else {
bytes_to_splice = bytes_can_read;
@@ -348,18 +348,18 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
/*@+type@ */
/*@+nullpass@ */
state->splice_used = true;
state->transfer.splice_used = true;
if ((nread < 0) && (EINVAL == errno)) {
debug("%s %d: %s", "fd", fd, "splice failed with EINVAL - disabling");
state->splice_failed_fd = fd;
state->splice_used = false;
state->transfer.splice_failed_fd = fd;
state->transfer.splice_used = false;
/*
* Fall through to read() below.
*/
} else if (nread > 0) {
state->written = nread;
state->transfer.written = nread;
#ifdef HAVE_FDATASYNC
if (state->sync_after_write) {
if (state->control.sync_after_write) {
/*
* Ignore non IO errors, such as EBADFD (bad file
* descriptor), EINVAL (non syncable fd, such as a
@@ -380,14 +380,18 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
/* nothing read yet - do nothing */
} else {
/* EOF might not really be EOF, it seems */
state->splice_used = false;
state->transfer.splice_used = false;
}
}
if (!state->splice_used) {
nread = pv__transfer_read_repeated(fd, state->transfer_buffer + state->read_position, bytes_can_read);
if (!state->transfer.splice_used) {
nread =
pv__transfer_read_repeated(fd, state->transfer.transfer_buffer + state->transfer.read_position,
bytes_can_read);
}
#else
nread = pv__transfer_read_repeated(fd, state->transfer_buffer + state->read_position, bytes_can_read);
nread =
pv__transfer_read_repeated(fd, state->transfer.transfer_buffer + state->transfer.read_position,
bytes_can_read);
#endif /* HAVE_SPLICE */
@@ -399,7 +403,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* move on to the next input file.
*/
*eof_in = true;
if (state->write_position >= state->read_position)
if (state->transfer.write_position >= state->transfer.read_position)
*eof_out = true;
return 1;
} else if (nread > 0) {
@@ -408,16 +412,16 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* the error counter and update our record of how much data
* we've got in the buffer.
*/
state->read_errors_in_a_row = 0;
state->transfer.read_errors_in_a_row = 0;
#ifdef HAVE_SPLICE
/*
* If we used splice(), there isn't any more data in the
* buffer than there was before.
*/
if (!state->splice_used)
state->read_position += nread;
if (!state->transfer.splice_used)
state->transfer.read_position += nread;
#else
state->read_position += nread;
state->transfer.read_position += nread;
#endif /* HAVE_SPLICE */
return 1;
}
@@ -441,8 +445,8 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* exit status, regardless of whether we're skipping errors, and
* increment the error counter.
*/
state->exit_status |= 16;
state->read_errors_in_a_row++;
state->status.exit_status |= 16;
state->transfer.read_errors_in_a_row++;
/*
* If we aren't skipping errors, show the error and pretend we
@@ -459,7 +463,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* TODO: investigate and fix the reason for this.
*/
*eof_in = true;
if (state->write_position >= state->read_position) {
if (state->transfer.write_position >= state->transfer.read_position) {
*eof_out = true;
}
return 1;
@@ -471,13 +475,13 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
amount_skipped = -1;
if (!state->read_error_warning_shown) {
if (!state->transfer.read_error_warning_shown) {
/*@-compdef@ */
pv_error(state, "%s: %s: %s", pv_current_file_name(state), _("warning: read errors detected"),
strerror(errno));
/*@+compdef@ */
/* splint - see previous pv_current_file_name() call. */
state->read_error_warning_shown = true;
state->transfer.read_error_warning_shown = true;
}
orig_offset = (off_t) lseek(fd, 0, SEEK_CUR);
@@ -493,7 +497,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
/*@+compdef@ */
/* splint - see previous pv_current_file_name() calls. */
*eof_in = true;
if (state->write_position >= state->read_position) {
if (state->transfer.write_position >= state->transfer.read_position) {
*eof_out = true;
}
return 1;
@@ -504,13 +508,13 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* otherwise start small and ramp up based on the number of errors
* in a row.
*/
if (state->error_skip_block > 0) {
amount_to_skip = state->error_skip_block;
if (state->control.error_skip_block > 0) {
amount_to_skip = state->control.error_skip_block;
} else {
if (state->read_errors_in_a_row < 10) {
amount_to_skip = (off_t) (state->read_errors_in_a_row < 5 ? 1 : 2);
} else if (state->read_errors_in_a_row < 20) {
unsigned int shift_by = (unsigned int) (state->read_errors_in_a_row - 10);
if (state->transfer.read_errors_in_a_row < 10) {
amount_to_skip = (off_t) (state->transfer.read_errors_in_a_row < 5 ? 1 : 2);
} else if (state->transfer.read_errors_in_a_row < 20) {
unsigned int shift_by = (unsigned int) (state->transfer.read_errors_in_a_row - 10);
amount_to_skip = (off_t) (1 << shift_by);
} else {
amount_to_skip = 512;
@@ -581,9 +585,9 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* of the transfer buffer, and update the buffer position.
*/
if (amount_skipped > 0) {
memset(state->transfer_buffer + state->read_position, 0, (size_t) amount_skipped);
state->read_position += amount_skipped;
if (state->skip_errors < 2) {
memset(state->transfer.transfer_buffer + state->transfer.read_position, 0, (size_t) amount_skipped);
state->transfer.read_position += amount_skipped;
if (state->control.skip_errors < 2) {
/*@-compdef@ */
pv_error(state, "%s: %s: %ld - %ld (%ld %s)",
pv_current_file_name(state),
@@ -597,7 +601,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* Failed to skip - mark file as ended.
*/
*eof_in = true;
if (state->write_position >= state->read_position) {
if (state->transfer.write_position >= state->transfer.read_position) {
*eof_out = true;
}
}
@@ -607,47 +611,48 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
/*
* Write state->to_write bytes of data from the transfer buffer to stdout.
* Write state->transfer.to_write bytes of data from the transfer buffer to stdout.
* Returns zero if there was a transient error and we need to return 0 from
* pv_transfer, otherwise returns 1.
*
* Updates state->write_position by moving it on by the number of bytes
* written; adds the number of bytes written to state->written; sets
* Updates state->transfer.write_position by moving it on by the number of bytes
* written; adds the number of bytes written to state->transfer.written; sets
* *eof_out to true, on stdout EOF, or when the write position catches up
* with the read position AND *eof_in is true (meaning we've reached the end
* of data).
*
* On error, sets *eof_out to true, sets state->written to -1, and updates
* state->exit_status.
* On error, sets *eof_out to true, sets state->transfer.written to -1, and updates
* state->status.exit_status.
*
* If state->discard_input is true, does not actually write anything.
* If state->control.discard_input is true, does not actually write anything.
*/
static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long *lineswritten)
{
ssize_t nwritten;
if (NULL == state->transfer_buffer) {
if (NULL == state->transfer.transfer_buffer) {
pv_error(state, "%s", _("no transfer buffer allocated"));
state->exit_status |= 64;
state->status.exit_status |= 64;
*eof_out = true;
state->written = -1;
state->transfer.written = -1;
return 1;
}
nwritten = 0;
if (state->discard_input) {
nwritten = state->to_write;
} else if (state->to_write > 0) {
if (state->control.discard_input) {
nwritten = state->transfer.to_write;
} else if (state->transfer.to_write > 0) {
if (signal(SIGALRM, SIG_IGN) == SIG_ERR) {
pv_error(state, "%s: %s", _("failed to set alarm signal handler"), strerror(errno));
} else {
(void) alarm(1);
}
nwritten = pv__transfer_write_repeated(STDOUT_FILENO,
state->transfer_buffer +
state->write_position, (size_t) (state->to_write),
state->sync_after_write);
state->transfer.transfer_buffer +
state->transfer.write_position,
(size_t) (state->transfer.to_write),
state->control.sync_after_write);
(void) alarm(0);
}
@@ -661,20 +666,21 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
/*
* Write returned >0 - data successfully written.
*/
if ((state->linemode) && (lineswritten != NULL)) {
if ((state->control.linemode) && (lineswritten != NULL)) {
char separator;
char *ptr;
long lines = 0;
if (state->null_terminated_lines) {
if (state->control.null_terminated_lines) {
separator = '\0';
} else {
separator = '\n';
}
ptr = (char *) (state->transfer_buffer + state->write_position - 1);
ptr = (char *) (state->transfer.transfer_buffer + state->transfer.write_position - 1);
for (ptr++;
ptr - (char *) state->transfer_buffer - state->write_position < (size_t) nwritten; ptr++) {
ptr - (char *) state->transfer.transfer_buffer - state->transfer.write_position <
(size_t) nwritten; ptr++) {
if (*ptr == separator)
++lines;
}
@@ -682,37 +688,38 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
*lineswritten += lines;
}
state->write_position += nwritten;
state->written += nwritten;
state->transfer.write_position += nwritten;
state->transfer.written += nwritten;
/*
* If we're monitoring the output, update our copy of the
* last few bytes we've written.
*/
if (((state->components_used & PV_DISPLAY_OUTPUTBUF) != 0)
if (((state->display.components_used & PV_DISPLAY_OUTPUTBUF) != 0)
&& (nwritten > 0)) {
size_t new_portion_length, old_portion_length;
new_portion_length = (size_t) nwritten;
if (new_portion_length > state->lastoutput_length)
new_portion_length = state->lastoutput_length;
if (new_portion_length > state->display.lastoutput_length)
new_portion_length = state->display.lastoutput_length;
old_portion_length = state->lastoutput_length - new_portion_length;
old_portion_length = state->display.lastoutput_length - new_portion_length;
/*
* Make room for the new portion.
*/
if (old_portion_length > 0) {
memmove(state->lastoutput_buffer,
state->lastoutput_buffer + new_portion_length, old_portion_length);
memmove(state->display.lastoutput_buffer,
state->display.lastoutput_buffer + new_portion_length, old_portion_length);
}
/*
* Copy the new data in.
*/
memcpy(state->lastoutput_buffer + /* flawfinder: ignore */
memcpy(state->display.lastoutput_buffer + /* flawfinder: ignore */
old_portion_length,
state->transfer_buffer + state->write_position - new_portion_length, new_portion_length);
state->transfer.transfer_buffer + state->transfer.write_position - new_portion_length,
new_portion_length);
/*
* flawfinder rationale: calculations above ensure
* that old_portion_length + new_portion_length is
@@ -731,9 +738,9 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
* EOF, set eof_out as well to indicate that we've written
* everything for this input file.
*/
if (state->write_position >= state->read_position) {
state->write_position = 0;
state->read_position = 0;
if (state->transfer.write_position >= state->transfer.read_position) {
state->transfer.write_position = 0;
state->transfer.read_position = 0;
if (*eof_in)
*eof_out = true;
}
@@ -766,9 +773,9 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
}
pv_error(state, "%s: %s", _("write failed"), strerror(errno));
state->exit_status |= 16;
state->status.exit_status |= 16;
*eof_out = true;
state->written = -1;
state->transfer.written = -1;
return 1;
}
@@ -841,13 +848,13 @@ static char *pv__allocate_aligned_buffer(int fd, size_t target_size)
/*
* Transfer some data from "fd" to standard output, timing out after 9/100
* of a second. If state->rate_limit is >0, and/or "allowed" is >0, only up
* of a second. If state->control.rate_limit is >0, and/or "allowed" is >0, only up
* to "allowed" bytes can be written. The variables that "eof_in" and
* "eof_out" point to are used to flag that we've finished reading and
* writing respectively.
*
* Returns the number of bytes written, or negative on error (in which case
* state->exit_status is updated). In line mode, the number of lines written
* state->status.exit_status is updated). In line mode, the number of lines written
* will be put into *lineswritten.
*/
ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t allowed, long *lineswritten)
@@ -864,9 +871,9 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* Set or clear O_DIRECT on the input and output file descriptors,
* if the setting has changed.
*/
if (state->direct_io_changed) {
if (state->control.direct_io_changed) {
if (!(*eof_in)) {
if (0 != fcntl(fd, F_SETFL, (state->direct_io ? O_DIRECT : 0) | fcntl(fd, F_GETFL))) {
if (0 != fcntl(fd, F_SETFL, (state->control.direct_io ? O_DIRECT : 0) | fcntl(fd, F_GETFL))) {
/*@-compdef@ */
debug("%s: %s: %s", pv_current_file_name(state), "fcntl", strerror(errno));
/*@+compdef@ */
@@ -875,11 +882,11 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
}
if (!(*eof_out)) {
if (0 != fcntl(STDOUT_FILENO, F_SETFL,
(state->direct_io ? O_DIRECT : 0) | fcntl(STDOUT_FILENO, F_GETFL))) {
(state->control.direct_io ? O_DIRECT : 0) | fcntl(STDOUT_FILENO, F_GETFL))) {
debug("%s: %s: %s", "(stdout)", "fcntl", strerror(errno));
}
}
state->direct_io_changed = false;
state->control.direct_io_changed = false;
}
#endif /* O_DIRECT */
@@ -887,24 +894,25 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* Reinitialise the error skipping variables if the file descriptor
* has changed since the last time we were called.
*/
if (fd != state->last_read_skip_fd) {
state->last_read_skip_fd = fd;
state->read_errors_in_a_row = 0;
state->read_error_warning_shown = false;
if (fd != state->transfer.last_read_skip_fd) {
state->transfer.last_read_skip_fd = fd;
state->transfer.read_errors_in_a_row = 0;
state->transfer.read_error_warning_shown = false;
}
/*
* Allocate a new buffer, aligned appropriately for the input file
* (important if using O_DIRECT).
*/
if (NULL == state->transfer_buffer) {
state->transfer_buffer = pv__allocate_aligned_buffer(fd, state->target_buffer_size + 32);
if (NULL == state->transfer_buffer) {
if (NULL == state->transfer.transfer_buffer) {
state->transfer.transfer_buffer =
pv__allocate_aligned_buffer(fd, state->control.target_buffer_size + 32);
if (NULL == state->transfer.transfer_buffer) {
pv_error(state, "%s: %s", _("buffer allocation failed"), strerror(errno));
state->exit_status |= 64;
state->status.exit_status |= 64;
return -1;
}
state->buffer_size = state->target_buffer_size;
state->transfer.buffer_size = state->control.target_buffer_size;
}
/*
@@ -914,37 +922,37 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* memory) because the buffer may need to be aligned for O_DIRECT,
* and we can't realloc() an aligned buffer.
*/
if (state->buffer_size < state->target_buffer_size) {
if (state->transfer.buffer_size < state->control.target_buffer_size) {
char *newptr;
newptr = pv__allocate_aligned_buffer(fd, state->target_buffer_size + 32);
newptr = pv__allocate_aligned_buffer(fd, state->control.target_buffer_size + 32);
if (NULL == newptr) {
/*
* Reset target if realloc failed so we don't keep
* trying to realloc over and over.
*/
debug("realloc: %s", strerror(errno));
state->target_buffer_size = state->buffer_size;
state->control.target_buffer_size = state->transfer.buffer_size;
} else {
debug("%s: %ld", "buffer resized", state->buffer_size);
debug("%s: %ld", "buffer resized", state->transfer.buffer_size);
/*
* Copy the old buffer contents into the new buffer,
* and free the old one.
*/
if (state->buffer_size > 0) {
memcpy(newptr, state->transfer_buffer, state->buffer_size); /* flawfinder: ignore */
if (state->transfer.buffer_size > 0) {
memcpy(newptr, state->transfer.transfer_buffer, state->transfer.buffer_size); /* flawfinder: ignore */
}
/*
* flawfinder rationale: number of bytes copied is
* definitely always smaller than the new buffer
* size.
*/
free(state->transfer_buffer);
state->transfer_buffer = newptr;
state->buffer_size = state->target_buffer_size;
free(state->transfer.transfer_buffer);
state->transfer.transfer_buffer = newptr;
state->transfer.buffer_size = state->control.target_buffer_size;
}
}
if ((state->linemode) && (lineswritten != NULL))
if ((state->control.linemode) && (lineswritten != NULL))
*lineswritten = 0;
if ((*eof_in) && (*eof_out))
@@ -957,7 +965,7 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* If the input file is not at EOF and there's room in the buffer,
* look for incoming data from it.
*/
if ((!(*eof_in)) && (state->read_position < state->buffer_size)) {
if ((!(*eof_in)) && (state->transfer.read_position < state->transfer.buffer_size)) {
check_read_fd = fd;
}
@@ -967,10 +975,10 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* is >0, then this puts an upper limit on how much we're allowed to
* write.
*/
state->to_write = (ssize_t) (state->read_position - state->write_position);
if ((state->rate_limit > 0) || (allowed > 0)) {
if ((off_t) (state->to_write) > allowed) {
state->to_write = (ssize_t) allowed;
state->transfer.to_write = (ssize_t) (state->transfer.read_position - state->transfer.write_position);
if ((state->control.rate_limit > 0) || (allowed > 0)) {
if ((off_t) (state->transfer.to_write) > allowed) {
state->transfer.to_write = (ssize_t) allowed;
}
}
@@ -978,7 +986,7 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* If we don't think we've finished writing and there's anything
* we're allowed to write, look for the stdout becoming writable.
*/
if ((!(*eof_out)) && (state->to_write > 0)) {
if ((!(*eof_out)) && (state->transfer.to_write > 0)) {
check_write_fd = STDOUT_FILENO;
}
@@ -1002,18 +1010,18 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
/*@+compdef@ */
/* splint - see previous pv_current_file_name() calls. */
state->exit_status |= 16;
state->status.exit_status |= 16;
return -1;
}
state->written = 0;
state->transfer.written = 0;
/*
* If there is data to read, try to read some in. Return early if
* there was a transient read error.
*
* NB this can update state->written because of splice().
* NB this can update state->transfer.written because of splice().
*/
if (ready_to_read) {
if (pv__transfer_read(state, fd, eof_in, eof_out, allowed) == 0)
@@ -1024,15 +1032,15 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* In line mode, only write up to and including the last newline,
* so that we're writing output line-by-line.
*/
if ((state->to_write > 0) && (state->linemode) && !(state->null_terminated_lines)) {
if ((state->transfer.to_write > 0) && (state->control.linemode) && !(state->control.null_terminated_lines)) {
char *start;
char *end;
start = (char *) (state->transfer_buffer + state->write_position);
end = pv_memrchr(start, (int) '\n', (size_t) (state->to_write));
start = (char *) (state->transfer.transfer_buffer + state->transfer.write_position);
end = pv_memrchr(start, (int) '\n', (size_t) (state->transfer.to_write));
if (NULL != end) {
state->to_write = (ssize_t) ((end - start) + 1);
state->transfer.to_write = (ssize_t) ((end - start) + 1);
}
}
@@ -1043,10 +1051,10 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
*/
if (ready_to_write
#ifdef HAVE_SPLICE
&& (!state->splice_used)
&& (!state->transfer.splice_used)
#endif /* HAVE_SPLICE */
&& (state->read_position > state->write_position)
&& (state->to_write > 0)
&& (state->transfer.read_position > state->transfer.write_position)
&& (state->transfer.to_write > 0)
&& (NULL != lineswritten)) {
if (pv__transfer_write(state, eof_in, eof_out, lineswritten) == 0)
return 0;
@@ -1056,21 +1064,22 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* Rotate the written bytes out of the buffer so that it can be
* filled up completely by the next read.
*/
if (state->write_position > 0) {
if (state->write_position < state->read_position) {
memmove(state->transfer_buffer,
state->transfer_buffer +
state->write_position, state->read_position - state->write_position);
state->read_position -= state->write_position;
state->write_position = 0;
if (state->transfer.write_position > 0) {
if (state->transfer.write_position < state->transfer.read_position) {
memmove(state->transfer.transfer_buffer,
state->transfer.transfer_buffer +
state->transfer.write_position,
state->transfer.read_position - state->transfer.write_position);
state->transfer.read_position -= state->transfer.write_position;
state->transfer.write_position = 0;
} else {
state->write_position = 0;
state->read_position = 0;
state->transfer.write_position = 0;
state->transfer.read_position = 0;
}
}
#endif /* MAXIMISE_BUFFER_FILL */
return state->written;
return state->transfer.written;
}
/* EOF */
+13 -13
View File
@@ -385,8 +385,8 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
*array_length_ptr = array_length;
for (check_idx = 0; check_idx < array_length; check_idx++) {
state_array[check_idx].name = info_array[check_idx].display_name;
state_array[check_idx].reparse_display = 1;
state_array[check_idx].control.name = info_array[check_idx].display_name;
state_array[check_idx].flag.reparse_display = 1;
}
}
@@ -427,31 +427,31 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
info_array[use_idx].watch_fd = -1;
}
state_array[use_idx].size = info_array[use_idx].size;
if (state_array[use_idx].size < 1) {
state_array[use_idx].control.size = info_array[use_idx].size;
if (state_array[use_idx].control.size < 1) {
char *fmt;
while (NULL != (fmt = strstr(state_array[use_idx].default_format, "%e"))) {
while (NULL != (fmt = strstr(state_array[use_idx].control.default_format, "%e"))) {
debug("%s", "zero size - removing ETA");
/* strlen-1 here to include trailing NUL */
memmove(fmt, fmt + 2, strlen(fmt) - 1);
state_array[use_idx].reparse_display = 1;
state_array[use_idx].flag.reparse_display = 1;
}
}
state_array[use_idx].name = info_array[use_idx].display_name;
state_array[use_idx].control.name = info_array[use_idx].display_name;
pv_watchpid_setname(state, &(info_array[use_idx]));
state_array[use_idx].reparse_display = 1;
state_array[use_idx].flag.reparse_display = 1;
pv_elapsedtime_read(&(info_array[use_idx].start_time));
state_array[use_idx].initial_offset = 0;
state_array[use_idx].display.initial_offset = 0;
info_array[use_idx].position = 0;
position_now = pv_watchfd_position(&(info_array[use_idx]));
if (position_now >= 0) {
state_array[use_idx].initial_offset = position_now;
state_array[use_idx].display.initial_offset = position_now;
info_array[use_idx].position = position_now;
}
}
@@ -482,15 +482,15 @@ void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
memset(info->display_name, 0, PV_SIZEOF_DISPLAY_NAME);
path_length = strlen(info->file_fdpath);
cwd_length = strlen(state->cwd);
cwd_length = strlen(state->status.cwd);
if (cwd_length > 0 && path_length > cwd_length) {
if (0 == strncmp(info->file_fdpath, state->cwd, cwd_length)) {
if (0 == strncmp(info->file_fdpath, state->status.cwd, cwd_length)) {
file_fdpath += cwd_length + 1;
path_length -= cwd_length + 1;
}
}
max_display_length = (state->width / 2) - 6;
max_display_length = (state->control.width / 2) - 6;
if (max_display_length >= path_length) {
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME, "%4d:%.498s", info->watch_fd, file_fdpath);