295 lines
10 KiB
C
295 lines
10 KiB
C
/*
|
|
* Functions internal to the PV library.
|
|
*/
|
|
|
|
#ifndef _PV_INTERNAL_H
|
|
#define _PV_INTERNAL_H 1
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifndef _PV_H
|
|
#include "pv.h"
|
|
#endif /* _PV_H */
|
|
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
|
|
/*
|
|
* Since macOS 10.6, stat64 variants are equivalent to plain stat, and the
|
|
* suffixed versions have been removed in macOS 11. See stat(2).
|
|
*/
|
|
#if defined(__APPLE__) || defined(APPLE)
|
|
#define stat64 stat
|
|
#define fstat64 fstat
|
|
#define lstat64 lstat
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define PV_DISPLAY_PROGRESS 1
|
|
#define PV_DISPLAY_TIMER 2
|
|
#define PV_DISPLAY_ETA 4
|
|
#define PV_DISPLAY_RATE 8
|
|
#define PV_DISPLAY_AVERAGERATE 16
|
|
#define PV_DISPLAY_BYTES 32
|
|
#define PV_DISPLAY_NAME 64
|
|
#define PV_DISPLAY_BUFPERCENT 128
|
|
#define PV_DISPLAY_OUTPUTBUF 256
|
|
#define PV_DISPLAY_FINETA 512
|
|
|
|
#define RATE_GRANULARITY 100000 /* usec between -L rate chunks */
|
|
#define RATE_BURST_WINDOW 5 /* rate burst window (multiples of rate) */
|
|
#define REMOTE_INTERVAL 100000 /* usec between checks for -R */
|
|
#define BUFFER_SIZE 409600 /* default transfer buffer size */
|
|
#define BUFFER_SIZE_MAX 524288 /* max auto transfer buffer size */
|
|
#define MAX_READ_AT_ONCE 524288 /* max to read() in one go */
|
|
#define MAX_WRITE_AT_ONCE 524288 /* max to write() in one go */
|
|
#define TRANSFER_READ_TIMEOUT 90000 /* usec to time reads out at */
|
|
#define TRANSFER_WRITE_TIMEOUT 900000 /* usec to time writes out at */
|
|
|
|
#define MAXIMISE_BUFFER_FILL 1
|
|
|
|
|
|
typedef struct pvhistory {
|
|
long long total_bytes;
|
|
long double elapsed_sec;
|
|
} pvhistory_t;
|
|
|
|
|
|
/*
|
|
* Structure for holding PV internal state. Opaque outside the PV library.
|
|
*/
|
|
struct pvstate_s {
|
|
/***************
|
|
* Input files *
|
|
***************/
|
|
int input_file_count; /* number of input files */
|
|
const char **input_files; /* input files (0=first) */
|
|
|
|
/*******************
|
|
* 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; /* lines are null-terminated */
|
|
bool no_op; /* do nothing other than pipe data */
|
|
unsigned int skip_errors; /* skip read errors counter */
|
|
bool stop_at_size; /* set if we stop at "size" bytes */
|
|
bool no_splice; /* never use splice() */
|
|
unsigned long long rate_limit; /* rate limit, in bytes per second */
|
|
unsigned long long target_buffer_size; /* buffer size (0=default) */
|
|
unsigned long long size; /* total size of data */
|
|
double interval; /* interval between updates */
|
|
double delay_start; /* delay before first display */
|
|
unsigned int watch_pid; /* process to watch fds of */
|
|
int watch_fd; /* fd to watch */
|
|
unsigned int width; /* screen width */
|
|
unsigned int height; /* screen height */
|
|
const char *name; /* display name */
|
|
char default_format[512]; /* default format string */
|
|
const char *format_string; /* output format string */
|
|
|
|
/******************
|
|
* Program status *
|
|
******************/
|
|
const char *program_name; /* program name for error reporting */
|
|
char cwd[4096]; /* current working directory for relative path */
|
|
const char *current_file; /* current file being read */
|
|
int exit_status; /* exit status to give (0=OK) */
|
|
|
|
/*******************
|
|
* Signal handling *
|
|
*******************/
|
|
int pv_sig_old_stderr; /* see pv_sig_ttou() */
|
|
struct timeval pv_sig_tstp_time; /* see pv_sig_tstp() / __cont() */
|
|
struct timeval 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 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;
|
|
|
|
/*****************
|
|
* 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. */
|
|
pvhistory_t *history; /* state at previous intervals (circular buffer) */
|
|
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 */
|
|
|
|
unsigned long long initial_offset;
|
|
char *display_buffer;
|
|
long display_buffer_size;
|
|
int lastoutput_length; /* number of last-output bytes to show */
|
|
unsigned char lastoutput_buffer[256];
|
|
int prev_width; /* screen width last time we were called */
|
|
int prev_length; /* length of last string we output */
|
|
char str_name[512];
|
|
char str_transferred[128];
|
|
char str_bufpercent[128];
|
|
char str_timer[128];
|
|
char str_rate[128];
|
|
char str_average_rate[128];
|
|
char str_progress[1024];
|
|
char str_lastoutput[512];
|
|
char str_eta[128];
|
|
char str_fineta[128];
|
|
unsigned long components_used; /* bitmask of components used */
|
|
struct {
|
|
const char *string;
|
|
int length;
|
|
} format[100];
|
|
bool display_visible; /* set once anything written to terminal */
|
|
|
|
/********************
|
|
* Cursor/IPC state *
|
|
********************/
|
|
#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 */
|
|
int *crs_y_top; /* pointer to Y coord of topmost `pv' */
|
|
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 */
|
|
#endif /* HAVE_IPC */
|
|
int crs_lock_fd; /* fd of lockfile, -1 if none open */
|
|
char crs_lock_file[1024];
|
|
int crs_y_start; /* our initial Y coordinate */
|
|
|
|
/*******************
|
|
* Transfer state *
|
|
*******************/
|
|
/*
|
|
* The transfer buffer is used for moving data from the input files
|
|
* to the output when splice() is not available.
|
|
*
|
|
* If buffer_size is smaller than pv__target_bufsize, then
|
|
* pv_transfer will try to reallocate transfer_buffer to make
|
|
* buffer_size equal to pv__target_bufsize.
|
|
*
|
|
* Data from the input files is read into the buffer; read_position
|
|
* is the offset in the buffer that we've read data up to.
|
|
*
|
|
* Data is written to the output from the buffer, and write_position
|
|
* is the offset in the buffer that we've written data up to. It
|
|
* will always be less than or equal to read_position.
|
|
*/
|
|
unsigned char *transfer_buffer; /* data transfer buffer */
|
|
unsigned long long buffer_size; /* size of buffer */
|
|
unsigned long read_position; /* amount of data in buffer */
|
|
unsigned long 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 and
|
|
* read_error_warning_shown to 0 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;
|
|
unsigned long read_errors_in_a_row;
|
|
int 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 1 if splice() was
|
|
* used this time within pv_transfer().
|
|
*/
|
|
int splice_failed_fd;
|
|
int splice_used;
|
|
#endif
|
|
long to_write; /* max to write this time around */
|
|
long written; /* bytes sent to stdout this time */
|
|
};
|
|
|
|
|
|
struct pvwatchfd_s {
|
|
unsigned int watch_pid; /* PID to watch */
|
|
int watch_fd; /* fd to watch, -1 = not displayed */
|
|
#ifdef __APPLE__
|
|
#else
|
|
char file_fdinfo[4096]; /* path to /proc fdinfo file */
|
|
char file_fd[4096]; /* path to /proc fd symlink */
|
|
#endif
|
|
char file_fdpath[4096]; /* path to file that was opened */
|
|
char display_name[512]; /* name to show on progress bar */
|
|
struct stat64 sb_fd; /* stat of fd symlink */
|
|
struct stat64 sb_fd_link; /* lstat of fd symlink */
|
|
unsigned long long size; /* size of whole file, 0 if unknown */
|
|
long long position; /* position last seen at */
|
|
struct timeval start_time; /* time we started watching the fd */
|
|
};
|
|
typedef struct pvwatchfd_s *pvwatchfd_t;
|
|
|
|
void pv_error(pvstate_t, char *, ...);
|
|
|
|
int pv_main_loop(pvstate_t);
|
|
void pv_display(pvstate_t, long double, long long, long long);
|
|
long pv_transfer(pvstate_t, int, int *, int *, unsigned long long, long *);
|
|
void pv_set_buffer_size(unsigned long long, int);
|
|
int pv_next_file(pvstate_t, int, int);
|
|
|
|
void pv_crs_fini(pvstate_t);
|
|
void pv_crs_init(pvstate_t);
|
|
void pv_crs_update(pvstate_t, char *);
|
|
#ifdef HAVE_IPC
|
|
void pv_crs_needreinit(pvstate_t);
|
|
#endif
|
|
|
|
void pv_sig_allowpause(void);
|
|
void pv_sig_checkbg(void);
|
|
void pv_sig_nopause(void);
|
|
|
|
void pv_remote_init(pvstate_t);
|
|
void pv_remote_check(pvstate_t);
|
|
void pv_remote_fini(pvstate_t);
|
|
int pv_remote_set(pvstate_t);
|
|
|
|
int pv_watchfd_info(pvstate_t, pvwatchfd_t, int);
|
|
int pv_watchfd_changed(pvwatchfd_t);
|
|
long long pv_watchfd_position(pvwatchfd_t);
|
|
int pv_watchpid_scanfds(pvstate_t, pvstate_t, unsigned int, int *, pvwatchfd_t *, pvstate_t *, int *);
|
|
void pv_watchpid_setname(pvstate_t, pvwatchfd_t);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* _PV_INTERNAL_H */
|
|
|
|
/* EOF */
|