Merge branch 'main' into eta_fix

This commit is contained in:
Andrew Wood
2023-07-16 11:41:50 +01:00
committed by GitHub
17 changed files with 710 additions and 756 deletions
+5
View File
@@ -34,6 +34,7 @@ extern "C" {
#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 */
@@ -91,6 +92,7 @@ struct pvstate_s {
* 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) */
@@ -227,8 +229,11 @@ struct pvstate_s {
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 */
+30 -2
View File
@@ -8,11 +8,13 @@
#include "options.h"
#include "library/getopt.h"
#include "pv.h"
#include "pv-internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -140,6 +142,9 @@ opts_t opts_parse(int argc, char **argv)
*/
switch (c) {
case 's':
/* "-s @" is valid, so allow it. */
if ('@' == *optarg)
break;
case 'A':
case 'w':
case 'H':
@@ -260,7 +265,29 @@ opts_t opts_parse(int argc, char **argv)
opts->delay_start = pv_getnum_d(optarg);
break;
case 's':
opts->size = pv_getnum_ull(optarg);
/* Permit "@<filename>" as well as just a number. */
if ('@' == *optarg) {
const char *size_file = 1 + optarg;
struct stat64 sb;
int rc;
rc = 0;
memset(&sb, 0, sizeof(sb));
rc = stat64(size_file, &sb);
if (0 == rc) {
opts->size = sb.st_size;
} else {
fprintf(stderr, "%s: %s %s: %s\n",
opts->program_name,
_("failed to stat file"),
size_file,
strerror(errno));
opts_free(opts);
return NULL;
}
} else {
opts->size = pv_getnum_ull(optarg);
}
break;
case 'l':
opts->linemode = true;
@@ -367,7 +394,7 @@ opts_t opts_parse(int argc, char **argv)
opts_free(opts);
return NULL;
}
#ifndef __APPLE__
if (0 != access("/proc/self/fdinfo", X_OK)) {
fprintf(stderr, "%s: -d: %s\n", opts->program_name,
_
@@ -375,6 +402,7 @@ opts_t opts_parse(int argc, char **argv)
opts_free(opts);
return NULL;
}
#endif
}
/*
+4
View File
@@ -48,6 +48,10 @@ bool pv_in_foreground(void)
our_process_group = getpgrp();
tty_process_group = tcgetpgrp(STDERR_FILENO);
if (tty_process_group == -1 && errno == ENOTTY)
return true;
if (our_process_group == tty_process_group)
return true;
+5
View File
@@ -151,10 +151,15 @@ int pv_main_loop(pvstate_t state)
|| (cur_time.tv_sec == next_ratecheck.tv_sec
&& cur_time.tv_usec >=
next_ratecheck.tv_usec)) {
target +=
((long double) (state->rate_limit)) /
(long double) (1000000 /
RATE_GRANULARITY);
long double burstMax = ((long double) (state->rate_limit * RATE_BURST_WINDOW));
if (target > burstMax) {
target = burstMax;
}
pv_timeval_add_usec(&next_ratecheck,
RATE_GRANULARITY);
}
+14
View File
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
/* alloc / realloc history buffer */
@@ -51,6 +52,19 @@ pvstate_t pv_state_alloc(const char *program_name)
#endif /* HAVE_SPLICE */
state->display_visible = false;
/*
* Get the current working directory, if possible, as a base for
* showing relative filenames with --watchfd.
*/
if (NULL == getcwd(state->cwd, sizeof(state->cwd))) {
/* failed - will always show full path */
state->cwd[0] = '\0';
}
if ('\0' == state->cwd[1]) {
/* CWD is root directory - always show full path */
state->cwd[0] = '\0';
}
return state;
}
+201 -28
View File
@@ -20,6 +20,100 @@
#include <sys/types.h>
#include <dirent.h>
#ifdef __APPLE__
#include <libproc.h>
#include <sys/proc_info.h>
#endif
int filesize(pvwatchfd_t info)
{
if (S_ISBLK(info->sb_fd.st_mode)) {
int fd;
/*
* Get the size of block devices by opening
* them and seeking to the end.
*/
fd = open64(info->file_fdpath, O_RDONLY);
if (fd >= 0) {
info->size = lseek64(fd, 0, SEEK_END);
close(fd);
} else {
info->size = 0;
}
} else if (S_ISREG(info->sb_fd.st_mode)) {
if ((info->sb_fd_link.st_mode & S_IWUSR) == 0) {
info->size = info->sb_fd.st_size;
}
} else {
return 4;
}
return 0;
}
#ifdef __APPLE__
int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, int automatic)
{
struct vnode_fdinfowithpath vnodeInfo = { };
if (NULL == state)
return -1;
if (NULL == info)
return -1;
if (kill(info->watch_pid, 0) != 0) {
if (!automatic)
pv_error(state, "%s %u: %s",
_("pid"),
info->watch_pid, strerror(errno));
return 1;
}
int32_t proc_fd = (int32_t) info->watch_fd;
int size = proc_pidfdinfo(info->watch_pid, proc_fd,
PROC_PIDFDVNODEPATHINFO, &vnodeInfo,
PROC_PIDFDVNODEPATHINFO_SIZE);
if (size != PROC_PIDFDVNODEPATHINFO_SIZE) {
pv_error(state, "%s %u: %s %d: %s",
_("pid"),
info->watch_pid,
_("fd"), info->watch_fd, strerror(errno));
return 3;
}
strlcpy(info->file_fdpath, vnodeInfo.pvip.vip_path,
sizeof(info->file_fdpath));
info->size = 0;
if (!(0 == stat64(info->file_fdpath, &(info->sb_fd)))) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
_("pid"),
info->watch_pid,
_("fd"),
info->watch_fd, info->file_fdpath,
strerror(errno));
return 3;
}
if (filesize(info) != 0) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
_("pid"),
info->watch_pid,
_("fd"),
info->watch_fd,
info->file_fdpath,
_("not a regular file or block device"));
return 4;
}
return 0;
}
#else
/*
* Fill in the given information structure with the file paths and stat
@@ -91,25 +185,8 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, int automatic)
info->size = 0;
if (S_ISBLK(info->sb_fd.st_mode)) {
int fd;
/*
* Get the size of block devices by opening
* them and seeking to the end.
*/
fd = open64(info->file_fdpath, O_RDONLY);
if (fd >= 0) {
info->size = lseek64(fd, 0, SEEK_END);
close(fd);
} else {
info->size = 0;
}
} else if (S_ISREG(info->sb_fd.st_mode)) {
if ((info->sb_fd_link.st_mode & S_IWUSR) == 0) {
info->size = info->sb_fd.st_size;
}
} else {
int ret = filesize(info);
if (ret != 0) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
_("pid"),
@@ -118,13 +195,19 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, int automatic)
info->watch_fd,
info->file_fdpath,
_("not a regular file or block device"));
return 4;
return ret;
}
return 0;
}
#endif
#ifdef __APPLE__
int pv_watchfd_changed(pvwatchfd_t info)
{
return 1;
}
#else
/*
* Return nonzero if the given file descriptor has changed in some way since
* we started looking at it (i.e. changed destination or permissions).
@@ -147,8 +230,28 @@ int pv_watchfd_changed(pvwatchfd_t info)
return 0;
}
#endif
#ifdef __APPLE__
long long pv_watchfd_position(pvwatchfd_t info)
{
long long position;
struct vnode_fdinfowithpath vnodeInfo = { };
int32_t proc_fd = (int32_t) info->watch_fd;
int size = proc_pidfdinfo(info->watch_pid, proc_fd,
PROC_PIDFDVNODEPATHINFO, &vnodeInfo,
PROC_PIDFDVNODEPATHINFO_SIZE);
if (size != PROC_PIDFDVNODEPATHINFO_SIZE) {
return -1;
}
position = (long long) vnodeInfo.pfi.fi_offset;
return position;
}
#else
/*
* Return the current file position of the given file descriptor, or -1 if
* the fd has closed or has changed in some way.
@@ -170,8 +273,35 @@ long long pv_watchfd_position(pvwatchfd_t info)
return position;
}
#endif
#ifdef __APPLE__
int pidfds(pvstate_t state, unsigned int pid, struct proc_fdinfo **fds,
int *count)
{
int size_needed = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, 0, 0);
if (size_needed == -1) {
pv_error(state, "%s: unable to list pid fds: %s", _("pid"),
strerror(errno));
return -1;
}
*count = size_needed / PROC_PIDLISTFD_SIZE;
*fds = (struct proc_fdinfo *) malloc(size_needed);
if (*fds == NULL) {
pv_error(state, "%s: alloc failed: %s", _("pid"),
strerror(errno));
return -1;
}
proc_pidinfo(pid, PROC_PIDLISTFDS, 0, *fds, size_needed);
return 0;
}
#endif
/*
* Scan the given process and update the arrays with any new file
* descriptors.
@@ -185,8 +315,6 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
pvstate_t * state_array_ptr, int *fd_to_idx)
{
char fd_dir[512] = { 0, };
DIR *dptr;
struct dirent *d;
int array_length = 0;
struct pvwatchfd_s *info_array = NULL;
struct pvstate_s *state_array = NULL;
@@ -196,24 +324,47 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
#else
sprintf(fd_dir, "/proc/%u/fd", watch_pid);
#endif
#ifdef __APPLE__
struct proc_fdinfo *fd_infos = NULL;
int fd_infos_count = 0;
if (pidfds(state, watch_pid, &fd_infos, &fd_infos_count) != 0) {
pv_error(state, "%s: pidfds failed", _("pid"));
return -1;
}
#else
DIR *dptr;
struct dirent *d;
dptr = opendir(fd_dir);
if (NULL == dptr)
return 1;
#endif
array_length = *array_length_ptr;
info_array = *info_array_ptr;
state_array = *state_array_ptr;
#ifdef __APPLE__
if (fd_infos_count < 1) {
pv_error(state, "%s: no fds found", _("pid"));
return -1;
}
for (int i = 0; i < fd_infos_count; i++) {
#else
while ((d = readdir(dptr)) != NULL) {
#endif
int fd, check_idx, use_idx, rc;
long long position_now;
fd = -1;
#ifdef __APPLE__
fd = fd_infos[i].proc_fd;
#else
if (sscanf(d->d_name, "%d", &fd) != 1)
continue;
if ((fd < 0) || (fd >= FD_SETSIZE))
continue;
#endif
/*
* Skip if this fd is already known to us.
*/
@@ -296,6 +447,11 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
info_array[use_idx].watch_pid = watch_pid;
info_array[use_idx].watch_fd = fd;
#ifdef __APPLE__
if (fd_infos[i].proc_fdtype != PROX_FDTYPE_VNODE) {
continue;
}
#endif
rc = pv_watchfd_info(state, &(info_array[use_idx]), 1);
/*
@@ -354,7 +510,12 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
}
}
#ifdef __APPLE__
free(fd_infos);
#else
closedir(dptr);
#endif
return 0;
}
@@ -363,14 +524,26 @@ int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
/*
* Set the display name for the given watched file descriptor, truncating at
* the relevant places according to the current screen width.
*
* If the file descriptor is pointing to a file under the current working
* directory, show its relative path, not the full path.
*/
void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
{
int path_length, max_display_length;
int path_length, cwd_length, max_display_length;
char *file_fdpath = info->file_fdpath;
memset(info->display_name, 0, sizeof(info->display_name));
path_length = strlen(info->file_fdpath);
cwd_length = strlen(state->cwd);
if (cwd_length > 0 && path_length > cwd_length) {
if (0 ==
strncmp(info->file_fdpath, state->cwd, cwd_length)) {
file_fdpath += cwd_length + 1;
path_length -= cwd_length + 1;
}
}
max_display_length = (state->width / 2) - 6;
if (max_display_length >= path_length) {
@@ -380,7 +553,7 @@ void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
#else
sprintf(info->display_name,
#endif
"%4d:%.498s", info->watch_fd, info->file_fdpath);
"%4d:%.498s", info->watch_fd, file_fdpath);
} else {
int prefix_length, suffix_length;
@@ -394,9 +567,9 @@ void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
sprintf(info->display_name,
#endif
"%4d:%.*s...%.*s",
info->watch_fd, prefix_length, info->file_fdpath,
info->watch_fd, prefix_length, file_fdpath,
suffix_length,
info->file_fdpath + path_length - suffix_length);
file_fdpath + path_length - suffix_length);
}
debug("%s: %d: [%s]", "set name for fd", info->watch_fd,