95 Commits
Author SHA1 Message Date
Andrew Wood 3f6dc99aa5 Change the release process to build packages with parmo. 2025-10-11 22:01:59 +01:00
Andrew Wood d939d45c27 Commit to the release date. 2025-10-11 21:31:26 +01:00
Andrew Wood fc8326a2b4 Message position updates. 2025-10-11 16:00:44 +01:00
Andrew Wood 8d939c9b99 Provisional version bump. 2025-10-11 16:00:13 +01:00
Andrew Wood 72d9efc993 More specific TODOs for one way of implementing #81. 2025-10-07 22:17:10 +01:00
Andrew Wood 64c4e8efb9 Add TODO markers for one way of implementing #81. 2025-10-06 18:03:46 +01:00
Andrew Wood 25dadb2bfd Add a comment describing what this structure is for. 2025-10-06 18:01:57 +01:00
Andrew Wood 80b68a73ee Include -C in the test, since splice can have an effect (#166). 2025-10-05 21:50:09 +01:00
Andrew Wood 3437b75256 Position updates and new strings. 2025-10-05 21:41:51 +01:00
Andrew Wood 462415a88a Note the Turkish translation updates. 2025-10-05 21:40:52 +01:00
Andrew Wood d23a7e929e Acknowledge Turkish translation updates (#168). 2025-10-05 21:40:25 +01:00
Andrew Wood f18fa637c6 Merge pull request 'Translations update from Codeberg Translate' (#168) from translate/pv:weblate-pv-pv into main
Reviewed-on: https://codeberg.org/ivarch/pv/pulls/168
2025-10-05 22:34:50 +02:00
Oğuz ErsenandCodeberg Translate 9bff7f0bb5 Translated using Weblate (Turkish)
Currently translated at 100.0% (134 of 134 strings)

Translation: pv/pv
Translate-URL: https://translate.codeberg.org/projects/pv/pv/tr/
2025-10-05 20:33:46 +00:00
Andrew Wood 771b61db30 Add test for over-read when using stop-at-size (#166). 2025-10-05 21:33:32 +01:00
Andrew Wood 615c1d5321 Explicitly cast both sides of the comparison to "long long", otherwise there is an overflow on 32-bit systems and stop-at-size stops at the wrong point (#166). 2025-10-05 21:20:27 +01:00
Andrew Wood 3442d7651a Use a void *, not a char *, so the types are consistent throughout. 2025-10-05 21:16:34 +01:00
Andrew Wood 7982badb65 Write a debugging line when truncating transfers for stop-at-size. 2025-10-05 21:15:58 +01:00
Andrew Wood a83a549de5 Correct the value size in the debug statement, otherwise it overflows on 32-bits systems. 2025-10-05 21:02:27 +01:00
Andrew Wood b1797c51e6 Note the new "=NAME" and "@LISTFILE" syntax additions to --watchfd. 2025-10-05 18:10:41 +01:00
Andrew Wood 8504964f1a Remove old non-functional code relating to ETAs and --size in the --watchfd loop. 2025-10-05 18:07:02 +01:00
Andrew Wood f83aa2272b Fix incorrect usage of "optarg". 2025-10-04 21:51:26 +01:00
Andrew Wood fb7c05c262 Implement the "pgrep" call for --watchfd =NAME (#95). 2025-10-04 21:50:25 +01:00
Andrew Wood e6f611f4de Adjust formatting. 2025-10-04 20:27:24 +01:00
Andrew Wood bd4ca7301c Document the new "=NAME" (#95) and "@FILE" (#12) syntax for --watchfd options. 2025-10-04 20:17:46 +01:00
Andrew Wood 242297a3c6 Partial draft of "-d @filename" (#12) and "-d =processname" syntax (#95). 2025-10-04 17:46:43 +01:00
Andrew Wood 0a658f99bb In --watchfd, when deciding whether to insert %N into the format, check for %{name} in the current format as well as the existing check for %N. 2025-10-04 14:49:06 +01:00
Andrew Wood 8df1c29c37 Note the addition of an empty Finnish translation file. 2025-10-04 00:54:48 +01:00
Andrew Wood a8b7cd19bd Add an empty translation file for Finnish. 2025-10-03 23:03:38 +01:00
Andrew Wood b4f525fd79 Merge pull request 'Translations update from Codeberg Translate' (#167) from translate/pv:weblate-pv-pv into main
Reviewed-on: https://codeberg.org/ivarch/pv/pulls/167
Reviewed-by: Andrew Wood <a-j-wood@noreply.codeberg.org>
2025-10-02 22:31:05 +02:00
Coral PinkandCodeberg Translate 8caa977a35 Translated using Weblate (Polish)
Currently translated at 100.0% (134 of 134 strings)

Translation: pv/pv
Translate-URL: https://translate.codeberg.org/projects/pv/pv/pl/
2025-10-02 13:23:16 +00:00
Andrew Wood f6d398738e Note the behaviour change of --stop-at-size with a zero size. 2025-10-01 22:09:33 +01:00
Andrew Wood 11dc25966d If stop_at_size is true, do not read more than control.size even if that is 0 (#166). 2025-10-01 18:06:59 +01:00
Andrew Wood efc8b33e81 Position updates. 2025-09-30 22:30:36 +01:00
Andrew Wood be066f6c8c Restrict the amount to read when --stop-at-size is active so that reads, as well as writes, never go past --size bytes (#166). 2025-09-30 22:27:25 +01:00
Andrew Wood 6a1ad7d374 Note the improvement to the control of a --watchfd with a remote -R. 2025-09-29 22:05:47 +01:00
Andrew Wood 751263376b Adjust the format and reparse the display, if a remote update -R was received while in the --watchfd loop. 2025-09-29 21:42:48 +01:00
Andrew Wood d903a7d188 Add a return value to pv_remote_check() so its caller can know whether a message was received. 2025-09-29 21:31:05 +01:00
Andrew Wood a4e2243102 Position updates. 2025-09-29 17:55:39 +01:00
Andrew Wood 9fe604df1a Move the declaration of changes_made outside the conditional, so as to not break on macOS. 2025-09-29 17:53:56 +01:00
Andrew Wood 64cd9cd85c Move the watchfd %N format insertion into its own function, so it can be called separately elsewhere in future, and to make it easier to extend the %N detection to find %{name} later as well. 2025-09-28 17:22:56 +01:00
Andrew Wood 10ef5a8596 If watching more than one distinct PID with --watchfd, display the PID as well as the FD number (#12). 2025-09-28 16:36:06 +01:00
Andrew Wood 77ed2e5989 Another minor issue noted as a TODO. 2025-09-27 18:32:27 +01:00
Andrew Wood 8ae549c47f Mention the --watchfd multiple arguments feature (#12). 2025-09-27 18:31:24 +01:00
Andrew Wood 284ceba52b Add TODO marker after some testing showed an issue. 2025-09-27 18:24:59 +01:00
Andrew Wood 3ea19829d7 Merge pv_watchpid_loop into pv_watchfd_loop, and allow multiple PID / PID:FD sets to be watched at once (#12). 2025-09-27 17:55:18 +01:00
Andrew Wood c49fc4aa57 Eliminate the fd_to_idx array in --watchfd, so that file descriptors aren't constrained to FD_SETSIZE and so we don't have to track another array. 2025-09-26 23:40:39 +01:00
Andrew Wood 7fdb6716e1 In the pvwatchfd_s structure, use booleans "displayable" and "unused" instead of having values of watch_pid=0 for unused and watch_fd=-1 for not displayable, so that each item only means one thing. 2025-09-26 23:01:07 +01:00
Andrew Wood c61c589378 Typo correction in the comment. 2025-09-26 22:29:36 +01:00
Andrew Wood c688987087 Adjust the --watchfd documentation to say that multiple PID/PID:FD arguments are allowed (#12). 2025-09-25 06:21:55 +01:00
Andrew Wood 0b2f9ec397 Only call pv_watchfd_loop() from main, so that eventually pv_watchpid_loop() can be removed and multiple "-d" values supported (#12). 2025-09-24 22:11:44 +01:00
Andrew Wood 8a8e6d71a4 Reinstate the previously removed "cannot transfer files" message for "-d". 2025-09-23 05:46:53 +01:00
Andrew Wood a0a9d682ca Reject "-o" when using "-d". 2025-09-23 05:45:43 +01:00
Andrew Wood 05a72bf75e Position updates, two new strings, one old message removed. 2025-09-23 05:39:43 +01:00
Andrew Wood 22bf08f8e4 Accept additional arguments when -d is specified, expecting them to be more pid[:fd] values (#12). 2025-09-22 21:50:35 +01:00
Andrew Wood b5fbd1978e Replace watch_pid, watch_fd with arrays, though for now only use the first item in the arrays (#12). 2025-09-21 19:50:56 +01:00
Andrew Wood db80f838ff Explicitly set an action variable to say which action to perform, instead of inferring it from other settings like whether a watch PID was set (#12). 2025-09-18 06:18:18 +01:00
Andrew Wood 8c2e934768 Add a TODO marker for the next step to take. 2025-09-18 05:47:15 +01:00
Andrew Wood dbce5b355e Add --watchfd option values to an array in the main state, as well as to the currently used variables (#12). 2025-09-17 23:12:13 +01:00
Andrew Wood 12cc996d32 Add --watchfd option values to an array as well as to the currently used variables (#12). 2025-09-17 22:12:45 +01:00
Andrew Wood 4a0f9e713c Define struct pvwatchspec_s for future use in an array for --watchfd, and add a comment defining nullable_string_t. 2025-09-16 23:05:41 +01:00
Andrew Wood 8771b901d9 Add TODO markers as part of looking at supporting multiple "-d" options (#12). 2025-09-15 20:12:55 +01:00
Andrew Wood 48ac509af7 Line number updates. 2025-09-14 16:42:42 +01:00
Andrew Wood f70627c031 Pass through indent. 2025-09-14 16:42:08 +01:00
Andrew Wood 1e6c9704b1 Adjustments to remove the need for the unqualifiedtrans and nullstate splint workarounds. 2025-09-14 16:39:47 +01:00
Andrew Wood a629a488d7 Add TODO marker for the planned next step. 2025-07-28 20:39:05 +01:00
Andrew Wood ad1d0e1c9a In the watchfd info array, instead of using copies of the global state, each fd has its own flags, transfer, calc, and display sub-structures (#165). 2025-07-28 00:25:14 +01:00
Andrew Wood 4f9d746823 Split the state reset functions into smaller pieces, so sub-structures can be reset individually (#165). 2025-07-27 23:24:56 +01:00
Andrew Wood 9fc9b6a8ed Carry the fd info_array "size" into the global "control" structure just before calling pv_display() so it gets used without having to have a per-fd copy of "control" (#165). 2025-07-27 21:39:36 +01:00
Andrew Wood 9ab82cde1e Use the original info_aray size for comparison as the "control" structure may be made irrelevant here soon (#165). 2025-07-27 21:38:55 +01:00
Andrew Wood a7f392e3c3 Address splint warnings about setting and clearing state->control.name (#165). 2025-07-27 21:34:46 +01:00
Andrew Wood 574ea04502 Instead of adding an aliased display name and having to maintain it and treat it differently, go back to keeping the name only in the "control" sub-structure of the state, but share the global state "control" across all watched fds, and just change it before each pv_display() call so it points to the relevant fd display_name when needed (#165). 2025-07-27 21:23:41 +01:00
Andrew Wood 5282a521b5 Pass only the relevant sub-structure to pv_alloc_history (#165). 2025-07-27 20:59:21 +01:00
Andrew Wood 52634f01f9 Do not call pv_state_name_set when adjusting an fd display_name, but instead set the alias state->display.name ourselves. Since the fd display_name we are pointing to is within the info_array, if we extend info_array with realloc we then have to also reset those aliases since display_name may move if realloc rebases the array. (#165) 2025-07-27 20:51:00 +01:00
Andrew Wood a0f2d9c9c7 Use status, cursor from main state, and a null extra_display, to reduce the dependency on the per-watched-fd state (#165). 2025-07-27 20:46:51 +01:00
Andrew Wood 8386c05978 Explicitly check for non-NULL rather than treating NULL as boolean false. 2025-07-27 20:43:52 +01:00
Andrew Wood 6a2b9a2788 Add an alias for the name for %N to the display sub-structure, so that the name can be varied between displays without having to alter the control value (#165). 2025-07-27 19:53:28 +01:00
Andrew Wood e04f50f0dc Change all cursor positioning functions to use sub-structures rather than the whole state structure, and if turning off cursor positioning, do so via a new flag "cursor->disable" rather than changing the operator-supplied options in "control" (#165). 2025-07-27 17:05:04 +01:00
Andrew Wood 021dc6e054 Pass individual sub-structures to pv_display, but still keep state for now, until the functions cursor.c have been updated to take sub-structures rather than the whole state (#165). 2025-07-27 15:56:03 +01:00
Andrew Wood 7d7efac7c6 Move the terminal_supports_utf8, terminal_supports_colour, and checked_colour_support flags out of "control" and into "status", as they are not operator-supplied options, but are program-generated status flags; this will allow "control" to remain read-only for larger parts of the program (#165). 2025-07-27 15:37:16 +01:00
Andrew Wood f79bed3cb8 Rename "can_display_colour" and "can_display_utf8" to "terminal_supports_colour" and "terminal_supports_utf8" to make it clearer that these are not operator-supplied option settings, they are derived from terminal capabilities (colour) and the environment (UTF-8). 2025-07-27 15:20:05 +01:00
Andrew Wood 2171f40703 Address the splint warning. 2025-07-27 00:34:09 +01:00
Andrew Wood 960ff1572f Pass state->status, rather than state itself, to pv_format (#165). 2025-07-27 00:31:45 +01:00
Andrew Wood da2a2e6fd2 Remove the state from the pv_error arguments, by adding a new function pv_set_error_prefix to call on startup, eliminating the need for a state program_name string; and add a private boolean to track whether there has been any output which means errors need preceding by a newline, which is updated by pv_display directly (#165). 2025-07-27 00:22:57 +01:00
Andrew Wood 005bc2f841 Pass the sub-structures separately to pv_format and pv__format_init rather than the whole state; but still pass state for now, as pv_error needs it (#165). 2025-07-26 22:49:29 +01:00
Andrew Wood ecc0c0e414 Adjust the readonly structure pointer types so the pointer itself is not read-only but the thing it points to is; and change the display formatters to use pointers to control, transfer, and calc structures instead of the whole state, with read-only access enforced at compile time (#165). 2025-07-26 22:28:39 +01:00
Andrew Wood 18548d217b Rename struct pvipcstate_s to pvcursorstate_s since it is for cursor positioning, not for IPC (#165). 2025-07-26 21:30:16 +01:00
Andrew Wood 653326ca9b Rename struct pvcursorstate_s to pvipccursorstate_s for clarity since it is only for IPC (#165). 2025-07-26 21:29:20 +01:00
Andrew Wood 0cf8902d9b Rename display structure member "display_visible" to "output_produced" for clarity. 2025-07-26 21:25:54 +01:00
Andrew Wood 762676f4e1 Make pv_tty_write take only the transient flags part of the state rather than the whole state, and rename the "flag" part of the state to "flags" for better readability (#165). 2025-07-26 21:18:13 +01:00
Andrew Wood 3bd49a0c3f Ensure the current average rate calculation can't accidentally divide by zero. 2025-07-26 20:53:22 +01:00
Andrew Wood 870dfad9fd Introduce read-only structure pointer typedefs for each of the state sub-structures, so the compiler will catch anywhere that a function would alter a structure it isn't expected to (#165). 2025-07-26 20:51:28 +01:00
Andrew Wood 3b0891b128 Pass more specific structures to pv_calculate_transfer_rate rather than the whole state (#165). 2025-07-26 19:22:07 +01:00
Andrew Wood b3c854b27a Add typedefs for the pointers to the sub-structures within struct pvstate_s, so they can be used as types in function declarations (#165). 2025-07-26 18:33:24 +01:00
Andrew Wood a923bdaca4 Give struct names to each of the sub-structures within struct pvstate_s, so they can be used as types in function declarations (#165). 2025-07-26 18:24:47 +01:00
Andrew Wood 0070a74390 Correct a minor typo in a comment. 2025-07-26 17:57:46 +01:00
45 changed files with 3967 additions and 2267 deletions
+1
View File
@@ -99,6 +99,7 @@ tests/Terminal_-_Detect_width.test \
tests/Transfer_-_--rate-limit.test \
tests/Transfer_-_--remote.test \
tests/Transfer_-_--stop-at-size.test \
tests/Transfer_-_--stop-at-size_reads.test \
tests/Watchfd_-_Multiple_descriptors.test \
tests/Watchfd_-_Single_descriptor.test
+1 -1
View File
@@ -4,7 +4,7 @@ dnl Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
dnl
dnl License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
AC_INIT([pv], [1.9.34], [https://codeberg.org/ivarch/pv/issues], [pv], [https://ivarch.com/p/pv])
AC_INIT([pv], [1.9.42], [https://codeberg.org/ivarch/pv/issues], [pv], [https://ivarch.com/p/pv])
AC_CONFIG_SRCDIR([src/include/config.h.in])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([src/include/config.h])
+1
View File
@@ -129,5 +129,6 @@ Translations provided through [Codeberg Weblate](https://translate.codeberg.org/
* [0ko](https://translate.codeberg.org/user/0ko/) (157)
* **Turkish**
* [omerdduran](https://translate.codeberg.org/user/omerdduran/) (129)
* [Oğuz Ersen](https://codeberg.org/ersen) (8)
---
+11
View File
@@ -1,3 +1,14 @@
### 1.9.42 - 11 October 2025
* *feature:* permit multiple arguments to **--watchfd** ([#12](https://codeberg.org/ivarch/pv/issues/12))
* *feature:* new "**=NAME**" syntax for **--watchfd** to watch processes by name using **pgrep**(1) ([#95](https://codeberg.org/ivarch/pv/issues/95))
* *feature:* new "**@LISTFILE**" syntax for **--watchfd** to watch processes listed in a file
* *fix:* improve support for changing the format of a **--watchfd** process with **--remote**
* *fix:* don't read more than **--size** bytes when using **--stop-at-size** ([#166](https://codeberg.org/ivarch/pv/issues/166))
* *fix:* transfer nothing if **--stop-at-size** is given a **--size** of 0 ([#166](https://codeberg.org/ivarch/pv/issues/166))
* *i18n:* Finnish translation stub added
* *i18n:* Turkish translations updated
### 1.9.34 - 26 July 2025
* *fix:* prevent tight loop consuming CPU when waiting for a partially filled output pipe to be drained ([#164](https://codeberg.org/ivarch/pv/issues/164))
+22 -9
View File
@@ -1,4 +1,4 @@
.TH PV 1 2025-07-26 pv-1.9.34 "User Commands"
.TH PV 1 2025-10-11 pv-1.9.42 "User Commands"
.\"
.SH NAME
pv \- monitor the progress of data through a pipe
@@ -7,7 +7,8 @@ pv \- monitor the progress of data through a pipe
.B pv
[\fIOPTION\fR]... [\fIFILE\fR]...
.PP
\fBpv\fR \fB\-d\fR|\fB\-\-watchfd\fR \fIPID\fR[:\fIFD\fR] [\fIOPTION\fR]...
\fBpv\fR [\fIOPTION\fR]... \fB\-d\fR|\fB\-\-watchfd\fR
\fIPID\fR[:\fIFD\fR]|=\fINAME\fR|@\fILISTFILE\fR...
.PP
\fBpv\fR \fB\-R\fR|\fB\-\-remote\fR \fIPID\fR [\fIOPTION\fR]...
.\"
@@ -349,16 +350,28 @@ doesn't affect the progress display.
.\"
.SS "Alternative operating modes"
.TP
.BI \-d\ PID\fR[\fB:\fR\fIFD\fR],\ \fB\-\-watchfd\ PID\fR[\fB:\fR\fIFD\fR]
\fB\-d\fR, \fB\-\-watchfd\fR \fIPID\fR[:\fIFD\fR]|=\fINAME\fR|@\fILISTFILE\fR...
Instead of transferring data, watch file descriptor \fIFD\fR of process
\fIPID\fR, and show its progress.
The \fBpv\fR process will exit when \fIFD\fR either changes to a different
file, changes read/write mode, or is closed; other data transfer modifiers -
and remote control - may not be used with this option.
Other data transfer modifiers - and remote control - may not be used with
this option.
.IP
If only a \fIPID\fR is specified, then that process will be watched, and all
regular files and block devices it opens will be shown with a progress bar.
The \fBpv\fR process will exit when process \fIPID\fR exits.
If a \fIPID\fR is specified without an \fIFD\fR, then that process will be
watched, and all regular files and block devices it opens will be shown with
a progress bar.
.IP
If a \fINAME\fR is specified, prefixed with "=", then processes with that
name will be found with \fBpgrep\fR(1), and as watched described above.
.IP
If a \fILISTFILE\fR is specified, prefixed with "@", the lines in that file
will be used as additional arguments.
.IP
All remaining non-option arguments will also be treated as additional
arguments.
.IP
The \fBpv\fR process will exit when all \fIFD\fRs have either changed to a
different file, changed read/write mode, or have closed, and all \fIPID\fRs
(without a specific \fIFD\fR) have exited.
.TP
.BI \-R\ PID \fR,\ \fB\-\-remote\ PID
Remotely control another instance of \fBpv\fR with process ID \fIPID\fR,
+22 -9
View File
@@ -6,7 +6,8 @@ pv - monitor the progress of data through a pipe
**pv** \[*OPTION*\]\... \[*FILE*\]\...
**pv** **-d**\|**\--watchfd** *PID*\[:*FD*\] \[*OPTION*\]\...
**pv** \[*OPTION*\]\... **-d**\|**\--watchfd**
*PID*\[:*FD*\]\|=*NAME*\|@*LISTFILE*\...
**pv** **-R**\|**\--remote** *PID* \[*OPTION*\]\...
@@ -361,17 +362,29 @@ are explicitly switched on will be shown.
## Alternative operating modes
**-d PID\[:FD\], \--watchfd PID\[:FD\]**
**-d**, **\--watchfd** *PID*\[:*FD*\]\|=*NAME*\|@*LISTFILE*\...
: Instead of transferring data, watch file descriptor *FD* of process
*PID*, and show its progress. The **pv** process will exit when *FD*
either changes to a different file, changes read/write mode, or is
closed; other data transfer modifiers - and remote control - may not
be used with this option.
*PID*, and show its progress. Other data transfer modifiers - and
remote control - may not be used with this option.
If only a *PID* is specified, then that process will be watched, and
all regular files and block devices it opens will be shown with a
progress bar. The **pv** process will exit when process *PID* exits.
If a *PID* is specified without an *FD*, then that process will be
watched, and all regular files and block devices it opens will be
shown with a progress bar.
If a *NAME* is specified, prefixed with \"=\", then processes with
that name will be found with **pgrep**(1), and as watched described
above.
If a *LISTFILE* is specified, prefixed with \"@\", the lines in that
file will be used as additional arguments.
All remaining non-option arguments will also be treated as
additional arguments.
The **pv** process will exit when all *FD*s have either changed to a
different file, changed read/write mode, or have closed, and all
*PID*s (without a specific *FD*) have exited.
**-R PID, \--remote PID**
+41 -32
View File
@@ -4,22 +4,19 @@
# build directory, such as one in which "configure" has been run, i.e.
# there should be a Makefile present.
#
# If ~/.config/packaging-hosts exists, then build-package.sh is run on each
# one and the resultant packages (RPMs, DEBs, etc) are copied back.
# Requires "parmo" (https://ivarch.com/p/parmo); builds for all targets that
# parmo supports.
#
# All of the release artefacts are placed in a "RELEASE-x" directory, where
# "x" is the version.
# All of the release artefacts are placed in a "PV-RELEASE-x" directory,
# where "x" is the version.
#
# Copyright 2024-2025 Andrew Wood
# License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
#
# Version: 0.0.2 / 16 Dec 2024
srcdir="$(awk '/^VPATH/{print $NF}' < Makefile | sed -n 1p)"
manuals="$(find "${srcdir}/docs" -mindepth 1 -maxdepth 1 -type f -name "*.[0-9]" -printf "%f\n")"
mainProgram="$(awk '/^[a-z]+_PROGRAMS/{print $3}' Makefile |cut -d '$' -f 1 | sed -n 1p)"
labTestScript="${srcdir}/docs/test-on-vm-lab.sh"
packageBuildScript="${srcdir}/docs/build-package.sh"
status () {
test -n "$*" && printf "\n"
@@ -43,7 +40,6 @@ possiblyDie () {
}
test -e "${labTestScript}" || labTestScript=""
test -e "${packageBuildScript}" || packageBuildScript=""
# The checklist is re-ordered a little so that we defer making changes (like
# "make indent") until as late as possible, in case any checks fail.
@@ -72,6 +68,7 @@ make analyse || possiblyDie "failed 'make analyse'"
status "Version checks"
# * Check that _docs/NEWS.md_ is up to date
sed -n 1p docs/NEWS.md | grep -Fqi unreleased && possiblyDie "NEWS.md says 'unreleased' on line 1"
versionInNews="$(awk 'FNR==1{print $2}' "${srcdir}/docs/NEWS.md")"
printf "%s\n" "${versionInNews}" | grep -Eq '^[0-9]' || possiblyDie "version in NEWS.md (${versionInNews}) is not numeric"
@@ -158,44 +155,56 @@ fi
# * Copy the release _.tar.gz_, _.txt_, and _.asc_ files to the web site
# * Use "_pandoc --from markdown --to html_" to convert the news and manual to HTML
status "Release dir"
rm -rf "RELEASE-${versionInNews}"
mkdir "RELEASE-${versionInNews}"
cp "${sourceArchive}" "${sourceArchive}.asc" "${sourceArchive}.txt" "RELEASE-${versionInNews}/" || possiblyDie "failed to copy release files"
releaseDir="PV-RELEASE-${versionInNews}"
rm -rf "${releaseDir}"
mkdir "${releaseDir}"
cp "${sourceArchive}" "${sourceArchive}.asc" "${sourceArchive}.txt" "${releaseDir}/" || possiblyDie "failed to copy release files"
status "HTML docs"
for manPage in ${manuals}; do
pandoc --from markdown --to html --shift-heading-level-by=1 < "${srcdir}/docs/${manPage}.md" > "RELEASE-${versionInNews}/${manPage}.html"
pandoc --from markdown --to html --shift-heading-level-by=1 < "${srcdir}/docs/${manPage}.md" > "${releaseDir}/${manPage}.html"
done
pandoc --from markdown --to html < "${srcdir}/docs/NEWS.md" > "RELEASE-${versionInNews}/news.html"
pandoc --from markdown --to html < "${srcdir}/docs/NEWS.md" > "${releaseDir}/news.html"
# Build OS packages.
packagingHosts="$(cat ~/.config/packaging-hosts 2>/dev/null)"
test -n "${packageBuildScript}" || packagingHosts=""
for buildHost in ${packagingHosts}; do
remoteWorkDir="$(ssh "${buildHost}" "mktemp -d")" || continue
test -n "${remoteWorkDir}" || continue
status "Package: ${buildHost}"
buildTargets=$(parmo targets)
if test -n "${MAINTAINER}"; then
gpg --export-secret-key --armor "${MAINTAINER}" > "${workDir}/signing-key" \
|| possiblyDie 'failed to export signing key'
fi
for buildTarget in ${buildTargets}; do
status "Package: ${buildTarget}"
buildOK=true
scp "${packageBuildScript}" "${buildHost}:${remoteWorkDir}/build-package.sh" || buildOK=false
${buildOK} && scp "${sourceArchive}" "${buildHost}:${remoteWorkDir}/" || buildOK=false
# shellcheck disable=SC2029
${buildOK} && ssh -t "${buildHost}" "cd \"${remoteWorkDir}\" && SKIP_VALGRIND_TESTS=\"${SKIP_VALGRIND_TESTS}\" MAINTAINER=\"${MAINTAINER}\" sh ./build-package.sh ./*gz" || buildOK=false
# shellcheck disable=SC2029
${buildOK} && ssh "${buildHost}" "rm \"${remoteWorkDir}\"/${sourceArchive##*/} \"${remoteWorkDir}/build-package.sh\""
${buildOK} && mkdir -p "RELEASE-${versionInNews}/${buildHost}"
${buildOK} && scp "${buildHost}:${remoteWorkDir}/*" "RELEASE-${versionInNews}/${buildHost}/"
# shellcheck disable=SC2029
ssh "${buildHost}" "rm -rf \"${remoteWorkDir}\""
rm -rf "${workDir}/package"
mkdir "${workDir}/package"
if test -s "${workDir}/signing-key"; then
parmo --key "${workDir}/signing-key" --source "${sourceArchive}" --destination "${workDir}/package" --target "${buildTarget}" build-package \
|| possiblyDie "${buildTarget}: build failed"
else
parmo --source "${sourceArchive}" --destination "${workDir}/package" --target "${buildTarget}" build-package \
|| possiblyDie "${buildTarget}: build failed"
fi
find "${workDir}/package" -type f \
| while read -r packageFile; do
destinationFile="${releaseDir}/${packageFile##*/}"
case "${destinationFile}" in
*.deb) destinationFile="${destinationFile%.deb}_${buildTarget}.deb" ;;
*.txt) destinationFile="" ;;
esac
test -n "${destinationFile}" || continue
cp "${packageFile}" "${destinationFile}"
chmod 644 "${destinationFile}"
done
done
find "RELEASE-${versionInNews}/" -type f -exec chmod 644 '{}' ';'
find "RELEASE-${versionInNews}/" -type d -exec chmod 755 '{}' ';'
find "${releaseDir}/" -type f -exec chmod 644 '{}' ';'
find "${releaseDir}/" -type d -exec chmod 755 '{}' ';'
status "Done"
cat <<EOF
Files are under: RELEASE-${versionInNews}/
Files are under: ${releaseDir}/
Still to do:
* Update the news and manual on the web site
+1
View File
@@ -1,6 +1,7 @@
cs
de
es
fi
fr
pl
pt
+161 -136
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"PO-Revision-Date: 2024-10-13 20:43+0000\n"
"Last-Translator: mmatous <mmatous@users.noreply.translate.codeberg.org>\n"
"Language-Team: Czech <https://translate.codeberg.org/projects/pv/pv/cs/>\n"
@@ -281,73 +281,85 @@ msgstr "Prosím, hlašte veškeré chyby na: %s"
msgid "(input)"
msgstr "(vstup)"
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr "selhala alokace stavu"
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "nebylo možné zjistit informace o souboru"
#: src/main/options.c:160
msgid "is a directory"
msgstr "je adresář"
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr "selhalo vytváření jména pro soubor v sysfs"
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr "selhalo čtení velikosti souboru v sysfs"
#: src/main/options.c:231
msgid "failed to open block device"
msgstr "selhalo otevření blokového zařízení"
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr "selhalo zjištění velikosti blokového zařízení"
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "selhala alokace struktury pro volby"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "selhala alokace struktury pro argv"
#: src/main/options.c:419
msgid "numeric value not understood"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "očekáván celočíselný argument"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "očekáván číselný argument"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "očekáváno ID procesu nebo dvojice PID:DS"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "neplatné ID procesu"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "nebylo možné zjistit informace o souboru"
#: src/main/options.c:462
msgid "is a directory"
msgstr "je adresář"
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr "selhalo vytváření jména pro soubor v sysfs"
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr "selhalo čtení velikosti souboru v sysfs"
#: src/main/options.c:533
msgid "failed to open block device"
msgstr "selhalo otevření blokového zařízení"
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr "selhalo zjištění velikosti blokového zařízení"
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "selhala alokace struktury pro volby"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "selhala alokace struktury pro argv"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr ""
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "očekáván celočíselný argument"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "očekáván číselný argument"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "Zkuste `%s --help' pro více informací."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "Zkuste `%s --h' pro více informací."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
@@ -355,19 +367,19 @@ msgstr ""
"při sledování deskriptorů souborů nelze použít řádkový mód nebo volby pro "
"modifikaci přenosu"
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr "při sledování deskriptorů souborů nelze pozicování kurzoru použít"
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr "při sledování deskriptorů souborů nelze použít vzdálené ovládání"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr "při sledování deskriptorů souborů nelze použít přenos souborů"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "není dostupné na systémech bez /proc/self/fdinfo"
@@ -375,7 +387,7 @@ msgstr "není dostupné na systémech bez /proc/self/fdinfo"
msgid "message not received"
msgstr "zpráva nepřijata"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "SA_SIGINFO není na tomto systému podporováno"
@@ -411,150 +423,163 @@ msgstr "selhal pokus o uzamčení"
msgid "failed to open terminal"
msgstr "selhalo otevření terminálu"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr "yzafpnum kMGTPEZY"
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr "yzafpnum KMGTPEZY"
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "selhala alokace vyrovnávací paměti"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr "selhalo posunutí za začátek výstupu"
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "selhalo zavření souboru"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "selhalo čtení ze souboru"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "selhalo zjištění informací o výstupním souboru"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "vstupní soubor je výstupní soubor"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr "(žádný)"
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr "(stdin)"
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr "b/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr "/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "B/s"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr "b"
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr "B"
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ETA"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr "FIN"
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr "rychlost min/avg/max/std"
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr "rychlost neměřena"
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr "pid"
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr "selhala alokace struktury historie"
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr "selhala alokace seznamu souborů"
#: src/pv/transfer.c:463
msgid "read failed"
msgstr "čtení selhalo"
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr "varování: detekovány chyby při čtení"
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr "souborem nelze procházet"
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr "selhal skok za chybu"
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr "chyba přeskočena"
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr "vyrovnávací paměť není alokována"
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr "selhalo nastavení intervalového časovače"
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr "selhalo vynulování intervalového časovače"
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr "selhala alokace vyrovnávací paměti pro pozici v řádcích"
#: src/pv/transfer.c:918
msgid "write failed"
msgstr "zápis selhal"
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr "selhalo volání select"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr "ds"
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr "selhala alokace struktury historie"
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr "selhala alokace seznamu souborů"
#: src/pv/state.c:731
#, fuzzy
#| msgid "file list allocation failed"
msgid "process list allocation failed"
msgstr "selhala alokace seznamu souborů"
#: src/pv/state.c:739
#, fuzzy
#| msgid "file list allocation failed"
msgid "file descriptor list allocation failed"
msgstr "selhala alokace seznamu souborů"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "čtení selhalo"
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "varování: detekovány chyby při čtení"
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr "souborem nelze procházet"
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr "selhal skok za chybu"
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr "chyba přeskočena"
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr "vyrovnávací paměť není alokována"
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr "selhalo nastavení intervalového časovače"
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr "selhalo vynulování intervalového časovače"
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr "selhala alokace vyrovnávací paměti pro pozici v řádcích"
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "zápis selhal"
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "selhalo volání select"
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "není obyčejný soubor nebo blokové zařízení"
+162 -137
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"PO-Revision-Date: 2025-01-14 20:39+0000\n"
"Last-Translator: Benny <benny@users.noreply.translate.codeberg.org>\n"
"Language-Team: German <https://translate.codeberg.org/projects/pv/pv/de/>\n"
@@ -299,73 +299,85 @@ msgstr "Bitte senden Sie Fehlerberichte an %s"
msgid "(input)"
msgstr "(eingabe)"
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr "Speicherzuweisung für `state' fehlgeschlagen"
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "konnte Dateiinformationen nicht lesen"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:160
msgid "is a directory"
msgstr "ist ein Verzeichnis"
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr "konnte Sysfs-Dateinamen nicht erzeugen"
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr "konnte Größe der Sysfs-Datei nicht lesen"
#: src/main/options.c:231
msgid "failed to open block device"
msgstr "konnte Blockgerät nicht öffnen"
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr "konnte Größe des Blockgeräts nicht ermitteln"
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "Speicherzuweisung für `option' fehlgeschlagen"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "Speicherzuweisung für `argv' der Option fehlgeschlagen"
#: src/main/options.c:419
msgid "numeric value not understood"
msgstr "numerischen Wert nicht verstanden"
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "Ganzzahliges Argument erwartet"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "numerisches Argument erwartet"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "Prozess-ID oder PID:FD-Paar erwartet"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "ungültige Prozess-ID"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "konnte Dateiinformationen nicht lesen"
#: src/main/options.c:462
msgid "is a directory"
msgstr "ist ein Verzeichnis"
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr "konnte Sysfs-Dateinamen nicht erzeugen"
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr "konnte Größe der Sysfs-Datei nicht lesen"
#: src/main/options.c:533
msgid "failed to open block device"
msgstr "konnte Blockgerät nicht öffnen"
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr "konnte Größe des Blockgeräts nicht ermitteln"
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "Speicherzuweisung für `option' fehlgeschlagen"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "Speicherzuweisung für `argv' der Option fehlgeschlagen"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr "numerischen Wert nicht verstanden"
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "Ganzzahliges Argument erwartet"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "numerisches Argument erwartet"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "`%s --help' zeigt weitere Informationen an."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "`%s -h' zeigt weitere Informationen an."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
@@ -373,24 +385,24 @@ msgstr ""
"Beim Beobachten von Dateideskriptoren können keine Optionen für den "
"Zeilenmodus oder den Übertragungsmodifikator verwendet werden"
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
"Beim Beobachten von Dateideskriptoren kann Cursor-Positionierung nicht "
"verwendet werden"
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr ""
"Beim Beobachten von Dateideskriptoren kann die Fernbedienung nicht verwenden "
"werden"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr ""
"Beim Beobachten von Dateideskriptoren können Dateien nicht übertragen werden"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "Nicht verfügbar auf Systemen ohne /proc/self/fdinfo"
@@ -398,7 +410,7 @@ msgstr "Nicht verfügbar auf Systemen ohne /proc/self/fdinfo"
msgid "message not received"
msgstr "Nachricht nicht empfangen"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "SA_SIGINFO wird auf diesem System nicht unterstützt"
@@ -434,150 +446,163 @@ msgstr "Sperrversuch fehlgeschlagen"
msgid "failed to open terminal"
msgstr "konnte Terminal nicht öffnen"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr "yzafpnµm kMGTPEZY"
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr "yzafpnµm KMGTPEZY"
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "Speicherzuweisung für den Puffer fehlgeschlagen"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr "Konnte nicht zum Anfang der Ausgabe springen"
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "konnte Datei nicht schließen"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "konnte Datei nicht lesen"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "konnte Dateiinformationen für Ausgabe-Datei nicht lesen"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "Eingabe-Datei ist Ausgabe-Datei"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr "(keine)"
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr "(stdin)"
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr "b/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr "/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "B/s"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr "b"
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr "B"
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ETA"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr "Endzeit"
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr "Rate min/mittel/max/abweichung"
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr "Übertragungsrate nicht gemessen"
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr "pid"
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr "Speicherzuweisung für `history' fehlgeschlagen"
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr "Speicherzuweisung für die Dateiliste fehlgeschlagen"
#: src/pv/transfer.c:463
msgid "read failed"
msgstr "read-Aufruf fehlgeschlagen"
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr "warnung: lesefehler erkannt"
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr "Datei ist nicht durchsuchbar"
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr "konnte den Fehler nicht überwinden"
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr "über den Lesefehler hinaus verschoben"
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr "Speicherzuweisung für den Transferpuffer fehlgeschlagen"
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr "konnte Intervall-Timer nicht setzen"
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr "konnte Intervall-Timer nicht löschen"
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr "Zuweisung des Zeilenpuffers fehlgeschlagen"
#: src/pv/transfer.c:918
msgid "write failed"
msgstr "write-Aufruf fehlgeschlagen"
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr "select-Aufruf fehlgeschlagen"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr "fd"
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr "Speicherzuweisung für `history' fehlgeschlagen"
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr "Speicherzuweisung für die Dateiliste fehlgeschlagen"
#: src/pv/state.c:731
#, fuzzy
#| msgid "file list allocation failed"
msgid "process list allocation failed"
msgstr "Speicherzuweisung für die Dateiliste fehlgeschlagen"
#: src/pv/state.c:739
#, fuzzy
#| msgid "file list allocation failed"
msgid "file descriptor list allocation failed"
msgstr "Speicherzuweisung für die Dateiliste fehlgeschlagen"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "read-Aufruf fehlgeschlagen"
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "warnung: lesefehler erkannt"
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr "Datei ist nicht durchsuchbar"
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr "konnte den Fehler nicht überwinden"
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr "über den Lesefehler hinaus verschoben"
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr "Speicherzuweisung für den Transferpuffer fehlgeschlagen"
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr "konnte Intervall-Timer nicht setzen"
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr "konnte Intervall-Timer nicht löschen"
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr "Zuweisung des Zeilenpuffers fehlgeschlagen"
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "write-Aufruf fehlgeschlagen"
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "select-Aufruf fehlgeschlagen"
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "ist weder eine normale Datei noch ein Blockgerät"
+157 -136
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -275,91 +275,103 @@ msgstr ""
msgid "(input)"
msgstr ""
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr ""
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:160
msgid "is a directory"
msgstr ""
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr ""
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr ""
#: src/main/options.c:231
msgid "failed to open block device"
msgstr ""
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr ""
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr ""
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr ""
#: src/main/options.c:419
msgid "numeric value not understood"
msgstr ""
#: src/main/options.c:437
msgid "integer argument expected"
msgstr ""
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr ""
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr ""
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr ""
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr ""
#: src/main/options.c:462
msgid "is a directory"
msgstr ""
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr ""
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr ""
#: src/main/options.c:533
msgid "failed to open block device"
msgstr ""
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr ""
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr ""
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr ""
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr ""
#: src/main/options.c:738
msgid "integer argument expected"
msgstr ""
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr ""
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr ""
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr ""
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
msgstr ""
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr ""
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr ""
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr ""
@@ -367,7 +379,7 @@ msgstr ""
msgid "message not received"
msgstr ""
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr ""
@@ -403,150 +415,159 @@ msgstr ""
msgid "failed to open terminal"
msgstr ""
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr ""
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr ""
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr ""
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr ""
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr ""
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr ""
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr ""
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr ""
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr ""
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr ""
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr ""
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr ""
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr ""
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr ""
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr ""
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr ""
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr ""
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr ""
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr ""
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr ""
#: src/pv/transfer.c:463
msgid "read failed"
msgstr ""
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr ""
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr ""
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr ""
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr ""
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr ""
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr ""
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:918
msgid "write failed"
msgstr ""
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr ""
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr ""
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr ""
#: src/pv/state.c:731
msgid "process list allocation failed"
msgstr ""
#: src/pv/state.c:739
msgid "file descriptor list allocation failed"
msgstr ""
#: src/pv/transfer.c:490
msgid "read failed"
msgstr ""
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr ""
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr ""
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr ""
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr ""
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr ""
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr ""
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:944
msgid "write failed"
msgstr ""
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr ""
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr ""
+578
View File
@@ -0,0 +1,578 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pv 1.9.34\n"
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-10-11 16:00+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"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/main/help.c:236
msgid "show progress bar"
msgstr ""
#: src/main/help.c:239
msgid "show elapsed time"
msgstr ""
#: src/main/help.c:242
msgid "show estimated time of arrival (completion)"
msgstr ""
#: src/main/help.c:245
msgid "show absolute estimated time of arrival (completion)"
msgstr ""
#: src/main/help.c:248
msgid "show data transfer rate counter"
msgstr ""
#: src/main/help.c:251
msgid "show data transfer average rate counter"
msgstr ""
#: src/main/help.c:254
msgid "show number of bytes transferred"
msgstr ""
#: src/main/help.c:257
msgid "show percentage of transfer buffer in use"
msgstr ""
#: src/main/help.c:259
msgid "NUM"
msgstr ""
#: src/main/help.c:260
msgid "show NUM bytes last written"
msgstr ""
#: src/main/help.c:262
msgid "FORMAT"
msgstr ""
#: src/main/help.c:263
msgid "set output format to FORMAT"
msgstr ""
#: src/main/help.c:266
msgid "output percentages, not visual information"
msgstr ""
#: src/main/help.c:269
msgid "do not output any transfer information at all"
msgstr ""
#: src/main/help.c:273
msgid "show number of bits transferred"
msgstr ""
#: src/main/help.c:276
msgid "treat suffixes as multiples of 1000 rather than 1024"
msgstr ""
#: src/main/help.c:279
msgid "display nothing until first byte transferred"
msgstr ""
#: src/main/help.c:281 src/main/help.c:296 src/main/help.c:299
msgid "SEC"
msgstr ""
#: src/main/help.c:282
msgid "display nothing until SEC seconds have passed"
msgstr ""
#: src/main/help.c:284
msgid "SIZE"
msgstr ""
#: src/main/help.c:285
msgid "set estimated data size to SIZE bytes"
msgstr ""
#: src/main/help.c:288
msgid "if size unknown, show rate vs max rate"
msgstr ""
#: src/main/help.c:291
msgid "count lines instead of bytes"
msgstr ""
#: src/main/help.c:294
msgid "lines are null-terminated"
msgstr ""
#: src/main/help.c:297
msgid "update every SEC seconds"
msgstr ""
#: src/main/help.c:300
msgid "compute average rate over past SEC seconds (default 30s)"
msgstr ""
#: src/main/help.c:302
msgid "WIDTH"
msgstr ""
#: src/main/help.c:303
msgid "assume terminal is WIDTH characters wide"
msgstr ""
#: src/main/help.c:305
msgid "HEIGHT"
msgstr ""
#: src/main/help.c:306
msgid "assume terminal is HEIGHT rows high"
msgstr ""
#: src/main/help.c:308
msgid "NAME"
msgstr ""
#: src/main/help.c:309
msgid "prefix visual information with NAME"
msgstr ""
#: src/main/help.c:311
msgid "STYLE"
msgstr ""
#: src/main/help.c:312
msgid "set default bar style to NAME"
msgstr ""
#: src/main/help.c:314
msgid "SPEC"
msgstr ""
#: src/main/help.c:315
msgid "also send progress to SPEC"
msgstr ""
#: src/main/help.c:318
msgid "output transfer statistics at the end"
msgstr ""
#: src/main/help.c:321
msgid "output even if standard error is not a terminal"
msgstr ""
#: src/main/help.c:324
msgid "use cursor positioning escape sequences"
msgstr ""
#: src/main/help.c:327 src/main/help.c:357 src/main/help.c:369
#: src/main/help.c:379
msgid "FILE"
msgstr ""
#: src/main/help.c:328
msgid "write output to FILE instead of stdout"
msgstr ""
#: src/main/help.c:330
msgid "RATE"
msgstr ""
#: src/main/help.c:331
msgid "limit transfer to RATE bytes per second"
msgstr ""
#: src/main/help.c:333 src/main/help.c:342
msgid "BYTES"
msgstr ""
#: src/main/help.c:334
msgid "use a buffer size of BYTES"
msgstr ""
#: src/main/help.c:337
msgid "never use splice(), always use read/write"
msgstr ""
#: src/main/help.c:340
msgid "skip read errors in input"
msgstr ""
#: src/main/help.c:343
msgid "skip errors in BYTES blocks at a time"
msgstr ""
#: src/main/help.c:346
msgid "stop after --size bytes have been transferred"
msgstr ""
#: src/main/help.c:349
msgid "flush cache to disk after every write"
msgstr ""
#: src/main/help.c:352
msgid "use direct I/O to bypass cache"
msgstr ""
#: src/main/help.c:355
msgid "discard input instead of writing to output"
msgstr ""
#: src/main/help.c:358
msgid "write all input to FILE before writing to output"
msgstr ""
#: src/main/help.c:360
msgid "PID[:FD]"
msgstr ""
#: src/main/help.c:361
msgid "watch file FD opened by process PID"
msgstr ""
#: src/main/help.c:364
msgid "PID"
msgstr ""
#: src/main/help.c:365
msgid "update settings of process PID"
msgstr ""
#: src/main/help.c:370
msgid "save process ID in FILE"
msgstr ""
#: src/main/help.c:373
msgid "show this help and exit"
msgstr ""
#: src/main/help.c:376
msgid "show version information and exit"
msgstr ""
#: src/main/help.c:380
msgid "write debug logs to FILE"
msgstr ""
#: src/main/help.c:406
#, c-format
msgid "Usage: %s [OPTION] [FILE]..."
msgstr ""
#: src/main/help.c:417
msgid ""
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
msgstr ""
#: src/main/help.c:555
msgid "Supported format sequences:"
msgstr ""
#: src/main/help.c:569
#, c-format
msgid "Please report any bugs to: %s"
msgstr ""
#: src/main/main.c:232
msgid "(input)"
msgstr ""
#: src/main/main.c:334
msgid "state allocation failed"
msgstr ""
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr ""
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr ""
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr ""
#: src/main/options.c:462
msgid "is a directory"
msgstr ""
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr ""
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr ""
#: src/main/options.c:533
msgid "failed to open block device"
msgstr ""
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr ""
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr ""
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr ""
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr ""
#: src/main/options.c:738
msgid "integer argument expected"
msgstr ""
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr ""
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr ""
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr ""
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
msgstr ""
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr ""
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr ""
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr ""
#: src/main/remote.c:309
msgid "message not received"
msgstr ""
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr ""
#: src/main/version.c:28
msgid "License: GPLv3+ <https://www.gnu.org/licenses/gpl-3.0.html>"
msgstr ""
#: src/main/version.c:29
msgid "This is free software: you are free to change and redistribute it."
msgstr ""
#: src/main/version.c:30
msgid "There is NO WARRANTY, to the extent permitted by law."
msgstr ""
#: src/main/version.c:32
msgid "Project web site"
msgstr ""
#: src/pv/cursor.c:61
msgid "failed to get terminal name"
msgstr ""
#: src/pv/cursor.c:106
msgid "failed to open lock file"
msgstr ""
#: src/pv/cursor.c:139
msgid "lock attempt failed"
msgstr ""
#: src/pv/cursor.c:400
msgid "failed to open terminal"
msgstr ""
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr ""
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr ""
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr ""
#: src/pv/file.c:303
msgid "failed to close file"
msgstr ""
#: src/pv/file.c:335
msgid "failed to read file"
msgstr ""
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr ""
#: src/pv/file.c:372
msgid "input file is output file"
msgstr ""
#: src/pv/file.c:429
msgid "(none)"
msgstr ""
#: src/pv/file.c:431
msgid "(stdin)"
msgstr ""
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr ""
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr ""
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr ""
#: src/pv/format/bytes.c:35
msgid "b"
msgstr ""
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr ""
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr ""
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr ""
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr ""
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr ""
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr ""
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr ""
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr ""
#: src/pv/state.c:731
msgid "process list allocation failed"
msgstr ""
#: src/pv/state.c:739
msgid "file descriptor list allocation failed"
msgstr ""
#: src/pv/transfer.c:490
msgid "read failed"
msgstr ""
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr ""
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr ""
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr ""
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr ""
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr ""
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr ""
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:944
msgid "write failed"
msgstr ""
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr ""
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr ""
+162 -137
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"PO-Revision-Date: 2025-05-31 08:58+0000\n"
"Last-Translator: milimarg <milimarg@noreply.codeberg.org>\n"
"Language-Team: French <https://translate.codeberg.org/projects/pv/pv/fr/>\n"
@@ -300,73 +300,85 @@ msgstr "SVP rapporter tous bogues à %s"
msgid "(input)"
msgstr "(entrée)"
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr "échec de l'allocation de mémoire de condition"
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "échec à statuer sur le fichier"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:160
msgid "is a directory"
msgstr "est un répertoire"
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr "échec de génération du nom de fichier sysfs"
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr "échec de la lecture de la taille du fichier sysfs"
#: src/main/options.c:231
msgid "failed to open block device"
msgstr "échec de l'ouverture du périphérique de bloc"
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr "échec de l'évaluation de la taille du périphérique de bloc"
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "l'allocation pour la structure d'une option a échoué"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "l'allocation pour la structure de l'option argv a échoué"
#: src/main/options.c:419
msgid "numeric value not understood"
msgstr "valeur numérique non comprise"
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "Valeur entière attendue"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "Valeur numérique attendue"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "ID de processus ou paire pid:fd attendue"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "ID de processus non valide"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "échec à statuer sur le fichier"
#: src/main/options.c:462
msgid "is a directory"
msgstr "est un répertoire"
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr "échec de génération du nom de fichier sysfs"
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr "échec de la lecture de la taille du fichier sysfs"
#: src/main/options.c:533
msgid "failed to open block device"
msgstr "échec de l'ouverture du périphérique de bloc"
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr "échec de l'évaluation de la taille du périphérique de bloc"
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "l'allocation pour la structure d'une option a échoué"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "l'allocation pour la structure de l'option argv a échoué"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr "valeur numérique non comprise"
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "Valeur entière attendue"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "Valeur numérique attendue"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "Essayez `%s --help' pour plus d'informations."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "Essayez `%s -h' pour plus d'informations."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
@@ -374,25 +386,25 @@ msgstr ""
"impossible d'utiliser le mode ligne ou les options de modificateur de "
"transfert lors de la visualisation des descripteurs de fichiers"
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
"impossible d'utiliser le positionnement du curseur lors de la visualisation "
"des descripteurs de fichier"
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr ""
"impossible d'utiliser la télécommande lors de la visualisation des "
"descripteurs de fichiers"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr ""
"impossible de transférer des fichiers lorsque vous regardez des descripteurs "
"de fichiers"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "non disponible sur les systèmes sans /proc/self/fdinfo"
@@ -400,7 +412,7 @@ msgstr "non disponible sur les systèmes sans /proc/self/fdinfo"
msgid "message not received"
msgstr "message non reçu"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "SA_SIGINFO non pris en charge sur ce système"
@@ -438,151 +450,164 @@ msgstr "échec de la tentative de verrouillage"
msgid "failed to open terminal"
msgstr "échec de l'ouverture du terminal"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr "yzafpnum kMGTPEZY"
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr "yzafpnum KMGTPEZY"
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "échec de l'allocation de mémoire tampon"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr "ne peut pas passer au début de la sortie"
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "la fermeture du fichier a échoué"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "la lecture du fichier a échoué"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "échec à statuer sur le fichier de sortie"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "fichiers d'entré et de sortie sont les mêmes"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr "(aucun)"
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr "(stdin)"
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr "b/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr "/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "O/s"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr "b"
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr "O"
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ETA"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr "FIN"
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr "taux min/moy/max/écart-type"
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr "taux non mesuré"
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr "pid"
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr "l'allocation de la structure de l'historique a échoué"
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr "échec de l'allocation de la liste de fichiers"
#: src/pv/transfer.c:463
msgid "read failed"
msgstr "la lecture a échoué"
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr "avertissement : erreurs de lecture détectées"
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr "ne peut pas se déplacer dans le fichier"
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr "n'a pas réussi à dépasser l'erreur"
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr "erreur de lecture dépassée"
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr "aucun tampon de transfert alloué"
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr "La définition de l'intervalle du minuteur a échoué"
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr "La réinitialisation des intervalles du minuteur a échoué"
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr "L'allocation de la position de la ligne de la mémoire tampon a échoué"
#: src/pv/transfer.c:918
msgid "write failed"
msgstr "l'écriture a échoué"
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr "l'appel de sélection a échoué"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr "fd"
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr "l'allocation de la structure de l'historique a échoué"
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr "échec de l'allocation de la liste de fichiers"
#: src/pv/state.c:731
#, fuzzy
#| msgid "file list allocation failed"
msgid "process list allocation failed"
msgstr "échec de l'allocation de la liste de fichiers"
#: src/pv/state.c:739
#, fuzzy
#| msgid "file list allocation failed"
msgid "file descriptor list allocation failed"
msgstr "échec de l'allocation de la liste de fichiers"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "la lecture a échoué"
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "avertissement : erreurs de lecture détectées"
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr "ne peut pas se déplacer dans le fichier"
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr "n'a pas réussi à dépasser l'erreur"
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr "erreur de lecture dépassée"
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr "aucun tampon de transfert alloué"
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr "La définition de l'intervalle du minuteur a échoué"
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr "La réinitialisation des intervalles du minuteur a échoué"
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr "L'allocation de la position de la ligne de la mémoire tampon a échoué"
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "l'écriture a échoué"
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "l'appel de sélection a échoué"
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "pas un fichier ordinaire ou un périphérique de bloc"
+125 -104
View File
@@ -6,9 +6,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"PO-Revision-Date: 2025-01-15 19:08+0000\n"
"Last-Translator: coralpink <coralpink@users.noreply.translate.codeberg.org>\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"PO-Revision-Date: 2025-10-02 13:23+0000\n"
"Last-Translator: Coral Pink <coralpink@noreply.codeberg.org>\n"
"Language-Team: Polish <https://translate.codeberg.org/projects/pv/pv/pl/>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.9.2\n"
"X-Generator: Weblate 5.13.2\n"
#: src/main/help.c:236
msgid "show progress bar"
@@ -294,73 +294,85 @@ msgstr "Proszę przesyłać zgłoszenia błędów do %s"
msgid "(input)"
msgstr "(wejście)"
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr "alokacja stanu programu nie powiodła się"
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "nie udało się wykonać operacji stat na pliku"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:160
msgid "is a directory"
msgstr "jest katalogiem"
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr "nie udało się wygenerować nazwy pliku dla sysfs"
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr "nie udało się odczytać rozmiaru pliku sysfs"
#: src/main/options.c:231
msgid "failed to open block device"
msgstr "nie udało się otworzyć urządzenia blokowego"
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr "nie udało się ustalić rozmiaru urządzenia blokowego"
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "nie udało się zaalokować struktur opcji"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "nie udało się zaalokować struktur opcji argv"
#: src/main/options.c:419
msgid "numeric value not understood"
msgstr "wartość liczbowa niezrozumiana"
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "oczekiwany argument typu liczby całkowitej"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "oczekiwany argument liczbowy"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "oczekiwany proces ID lub para PID:FD"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "niepoprawne ID procesu"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "nie udało się wykonać operacji stat na pliku"
#: src/main/options.c:462
msgid "is a directory"
msgstr "jest katalogiem"
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr "nie udało się wygenerować nazwy pliku dla sysfs"
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr "nie udało się odczytać rozmiaru pliku sysfs"
#: src/main/options.c:533
msgid "failed to open block device"
msgstr "nie udało się otworzyć urządzenia blokowego"
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr "nie udało się ustalić rozmiaru urządzenia blokowego"
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "nie udało się zaalokować struktur opcji"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "nie udało się zaalokować struktur opcji argv"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr "wartość liczbowa niezrozumiana"
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "oczekiwany argument typu liczby całkowitej"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "oczekiwany argument liczbowy"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "Spróbuj `%s --help' by uzyskać więcej informacji."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "Spróbuj `%s -h' by uzyskać więcej informacji."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
@@ -368,23 +380,23 @@ msgstr ""
"nie można użyć trybu zliczania linii lub opcji modyfikujących przesył "
"łącznie z opcją obserwowania deskryptorów plików"
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
"nie można użyć pozycjonowania kursora łącznie z opcją obserwowania "
"deskryptorów plików"
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr ""
"nie można użyć opcji zaktualizowania ustawień procesu łącznie z opcją "
"obserwowania deskryptorów plików"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr "nie można przesyłać plików z opcją obserwowania deskryptorów plików"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "niedostępne na systemach bez /proc/self/fdinfo"
@@ -392,7 +404,7 @@ msgstr "niedostępne na systemach bez /proc/self/fdinfo"
msgid "message not received"
msgstr "wiadomość nieodebrana"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "SA_SIGINFO nie jest wspierane na tym systemie"
@@ -429,152 +441,161 @@ msgstr "blokada zasobów nie powiodła się"
msgid "failed to open terminal"
msgstr "nie udało się otworzyć terminala"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr "yzafpnum kMGTPEZY"
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr "yzafpnum KMGTPEZY"
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "nie udało się zaalokować bufora"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr "nie udało się przewinąć wyjścia do początku"
# "Przewidywany czas ukończenia" for ETA is too long
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "nie udało się zamknąć pliku"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "nie udało się odczytać pliku"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "nie udało się wykonać operacji stat na pliku wyjściowym"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "plik wejściowy jest zarazem plikiem wyjściowym"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr "(brak)"
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr "(stdin)"
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr "b/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr "/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "B/s"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr "b"
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr "B"
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ETA"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr "FIN"
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr "prędkość min/śr/max/odch"
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr "prędkość niezmierzona"
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr "pid"
#: src/pv/state.c:40
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr "fd"
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr "nie udało się zaalokować struktury historii"
#: src/pv/state.c:617 src/pv/state.c:628
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr "nie udało się zaalokować listy plików"
#: src/pv/transfer.c:463
#: src/pv/state.c:731
msgid "process list allocation failed"
msgstr "nie udało się zaalokować listy procesów"
#: src/pv/state.c:739
msgid "file descriptor list allocation failed"
msgstr "nie udało się zaalokować listy deskryptorów plików"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "błąd odczytu"
#: src/pv/transfer.c:479
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "ostrzeżenie: błędy odczytu wykryte"
#: src/pv/transfer.c:495
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr "pliku nie da się przewijać"
#: src/pv/transfer.c:573
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr "nie udało się przewinąć za błąd"
#: src/pv/transfer.c:593
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr "pominięto błąd odczytu"
#: src/pv/transfer.c:634
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr "brak zaalokowanego bufora transferu"
#: src/pv/transfer.c:676
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr "nie udało się ustawić interwału czasowego"
# "Przewidywany czas ukończenia" for ETA is too long
#: src/pv/transfer.c:702
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr "nie udało się wyczyścić interwału czasowego"
#: src/pv/transfer.c:744
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr "alokacja buforu pozycji linii nie powiodła się"
#: src/pv/transfer.c:918
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "błąd zapisu"
#: src/pv/transfer.c:1159
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "nie udało się wywołać funkcji select"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
msgid "fd"
msgstr "fd"
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "plik nie jest plikiem regularnym lub urządzeniem blokowym"
+161 -136
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"POT-Creation-Date: 2025-10-11 16:00+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"
@@ -285,73 +285,85 @@ msgstr "Por favor, reporte quaisquer defeitos para %s"
msgid "(input)"
msgstr ""
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr "alocação de memória de status falhou"
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "erro obtendo informações do arquivo"
#: src/main/options.c:160
msgid "is a directory"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr ""
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr ""
#: src/main/options.c:231
msgid "failed to open block device"
msgstr ""
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr ""
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "erro na alocação da estrutura de opções"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "erro na alocação da estrutura de opções argv"
#: src/main/options.c:419
msgid "numeric value not understood"
msgstr ""
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "argumento inteiro esperado"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "argumento numérico esperado"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "ID do processo ou par pid:fd esperado"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "ID de processo inválido"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "erro obtendo informações do arquivo"
#: src/main/options.c:462
msgid "is a directory"
msgstr ""
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr ""
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr ""
#: src/main/options.c:533
msgid "failed to open block device"
msgstr ""
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr ""
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "erro na alocação da estrutura de opções"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "erro na alocação da estrutura de opções argv"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr ""
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "argumento inteiro esperado"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "argumento numérico esperado"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "Tente `%s --help' para maiores informações."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "Tente `%s -h' para maiores informações."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
@@ -359,21 +371,21 @@ msgstr ""
"não pode usar o modo de linha ou opções de modificador de transferência ao "
"assistir os descritores de arquivo"
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
"não pode usar o posicionamento do cursor ao observar os descritores de "
"arquivo"
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr "não pode usar o controle remoto ao assistir os descritores de arquivo"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr "não pode transferir arquivos ao assistir descritores de arquivo"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "não disponível em sistemas sem /proc/self/fdinfo"
@@ -381,7 +393,7 @@ msgstr "não disponível em sistemas sem /proc/self/fdinfo"
msgid "message not received"
msgstr "mensagem não recebida"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "SA_SIGINFO não suportado neste sistema"
@@ -417,150 +429,163 @@ msgstr "tentativa de bloqueio falhou"
msgid "failed to open terminal"
msgstr "erro abrindo o terminal"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr ""
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "erro alocando o buffer"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr "não pode mover para o início da produção"
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "erro fechando o arquivo"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "erro lendo o arquivo"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "erro obtendo informações do arquivo de saída"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "os arquivos de entrada e saída são o mesmo"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr ""
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr ""
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr ""
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr ""
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "B/s"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr ""
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr ""
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ETA"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr ""
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr ""
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr ""
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr ""
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr ""
#: src/pv/transfer.c:463
msgid "read failed"
msgstr "erro de leitura"
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr "aviso: erros de leitura detectados"
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr "não pode mover dentro do arquivo"
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr "não pode ir além do erro"
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr "ignorado erro de leitura"
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr ""
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr ""
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:918
msgid "write failed"
msgstr "erro de gravação"
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr "erro na chamada da função select"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr ""
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr ""
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr ""
#: src/pv/state.c:731
#, fuzzy
#| msgid "state allocation failed"
msgid "process list allocation failed"
msgstr "alocação de memória de status falhou"
#: src/pv/state.c:739
#, fuzzy
#| msgid "state allocation failed"
msgid "file descriptor list allocation failed"
msgstr "alocação de memória de status falhou"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "erro de leitura"
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "aviso: erros de leitura detectados"
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr "não pode mover dentro do arquivo"
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr "não pode ir além do erro"
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr "ignorado erro de leitura"
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr ""
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr ""
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr ""
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "erro de gravação"
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "erro na chamada da função select"
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "não é um arquivo regular ou dispositivo de bloqueio"
+162 -137
View File
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"PO-Revision-Date: 2025-01-15 19:08+0000\n"
"Last-Translator: 0ko <0ko@users.noreply.translate.codeberg.org>\n"
"Language-Team: Russian <https://translate.codeberg.org/projects/pv/pv/ru/>\n"
@@ -282,91 +282,103 @@ msgstr "Сообщайте о проблемах на: %s"
msgid "(input)"
msgstr "(ввод)"
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr ""
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "не удалось получить информацию о файле"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:160
msgid "is a directory"
msgstr "является каталогом"
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr "не удалось создать имя файла sysfs"
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr "не удалось узнать размер файла sysfs"
#: src/main/options.c:231
msgid "failed to open block device"
msgstr "не удалось открыть блочное устройство"
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr "не удалось определить размер блочного устройства"
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "не удалось выделить память для структуры опций"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "не удалось выделить память для структуры опций argv"
#: src/main/options.c:419
msgid "numeric value not understood"
msgstr "число не распознано"
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "ожидалось целое число"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "ожидалось число"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "ожидался ИД процесса или пара ИДпр:ДФ"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "неправильный ИД процесса"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "не удалось получить информацию о файле"
#: src/main/options.c:462
msgid "is a directory"
msgstr "является каталогом"
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr "не удалось создать имя файла sysfs"
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr "не удалось узнать размер файла sysfs"
#: src/main/options.c:533
msgid "failed to open block device"
msgstr "не удалось открыть блочное устройство"
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr "не удалось определить размер блочного устройства"
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "не удалось выделить память для структуры опций"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "не удалось выделить память для структуры опций argv"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr "число не распознано"
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "ожидалось целое число"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "ожидалось число"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "Выполните `%s --help' для получения подробностей."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "Выполните `%s -h' для получения подробностей."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
msgstr ""
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr ""
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr "удалённое управление невозможно при отслеживании дескрипторов файлов"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr "передача файлов невозможна при отслеживании дескрипторов файлов"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "невозможно на системах без /proc/self/fdinfo"
@@ -374,7 +386,7 @@ msgstr "невозможно на системах без /proc/self/fdinfo"
msgid "message not received"
msgstr "сообщение не получено"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "Этой системой не поддерживается SA_SIGINFO"
@@ -412,150 +424,163 @@ msgstr "попытка блокировки не удалась"
msgid "failed to open terminal"
msgstr "не удалось открыть терминал"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr ""
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr ""
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "не удалось выделить память для буфера"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr ""
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "не удалось закрыть файл"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "не удалось прочесть файл"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "не удалось получить информацию о выходном файле"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "пути исходного и выходного файлов одинаковы"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr "(нет)"
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr "(стд. ввод)"
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr "бит/с"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr "/с"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "байт/с"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr "бит"
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr "байт"
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ОЖИД"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr "ЗАВЕРШ"
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr "скор. мин/сред/макс/дев"
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr "скорость не изменяется"
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr "ИДпр"
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr "не удалось выделить память для структуры истории"
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr "не удалось выделить память для списка файлов"
#: src/pv/transfer.c:463
msgid "read failed"
msgstr "чтение не удалось"
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr "внимание: замечены ошибки чтения"
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr ""
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr ""
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr ""
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr "не выделена память для буфера передачи"
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr "не удалось задать измеритель временного промежутка"
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr "не удалось очистить измеритель временного промежутка"
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:918
msgid "write failed"
msgstr "запись не удалась"
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr "запрос выборки не удался"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr "дф"
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr "не удалось выделить память для структуры истории"
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr "не удалось выделить память для списка файлов"
#: src/pv/state.c:731
#, fuzzy
#| msgid "file list allocation failed"
msgid "process list allocation failed"
msgstr "не удалось выделить память для списка файлов"
#: src/pv/state.c:739
#, fuzzy
#| msgid "file list allocation failed"
msgid "file descriptor list allocation failed"
msgstr "не удалось выделить память для списка файлов"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "чтение не удалось"
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "внимание: замечены ошибки чтения"
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr ""
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr ""
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr ""
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr "не выделена память для буфера передачи"
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr "не удалось задать измеритель временного промежутка"
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr "не удалось очистить измеритель временного промежутка"
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr ""
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "запись не удалась"
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "запрос выборки не удался"
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "не является обычным файлом или блочным устройством"
+165 -144
View File
@@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Project-Id-Version: pv 1.8.14\n"
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
"POT-Creation-Date: 2025-07-26 14:50+0100\n"
"PO-Revision-Date: 2024-10-12 23:51+0000\n"
"Last-Translator: a-j-wood <a-j-wood@users.noreply.translate.codeberg.org>\n"
"POT-Creation-Date: 2025-10-11 16:00+0100\n"
"PO-Revision-Date: 2025-10-05 20:09+0000\n"
"Last-Translator: Oğuz Ersen <ersen@noreply.codeberg.org>\n"
"Language-Team: Turkish <https://translate.codeberg.org/projects/pv/pv/tr/>\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.7.2\n"
"X-Generator: Weblate 5.13.2\n"
#: src/main/help.c:236
msgid "show progress bar"
@@ -143,19 +143,19 @@ msgstr "görsel bilgiyi İSİM ile öne ekle"
#: src/main/help.c:311
msgid "STYLE"
msgstr ""
msgstr "BİÇİM"
#: src/main/help.c:312
msgid "set default bar style to NAME"
msgstr ""
msgstr "öntanımlı çubuk biçimini İSİM olarak ayarla"
#: src/main/help.c:314
msgid "SPEC"
msgstr ""
msgstr "BELİRT"
#: src/main/help.c:315
msgid "also send progress to SPEC"
msgstr ""
msgstr "ilerlemeyi BELİRT ögesine de gönder"
#: src/main/help.c:318
msgid "output transfer statistics at the end"
@@ -271,7 +271,7 @@ msgstr ""
#: src/main/help.c:555
msgid "Supported format sequences:"
msgstr ""
msgstr "Desteklenen biçim dizileri:"
#: src/main/help.c:569
#, c-format
@@ -282,73 +282,85 @@ msgstr "Lütfen hataları şu adrese bildirin: %s"
msgid "(input)"
msgstr "(giriş)"
#: src/main/main.c:328
#: src/main/main.c:334
msgid "state allocation failed"
msgstr "durum tahsisi başarısız oldu"
#: src/main/options.c:146 src/pv/file.c:324
msgid "failed to stat file"
msgstr "dosya statüsünde başarısız oldu"
#: src/main/options.c:160
msgid "is a directory"
msgstr "bir dizindir"
#: src/main/options.c:189
msgid "failed to generate sysfs filename"
msgstr "sysfs dosya adı oluşturulamadı"
#: src/main/options.c:211
msgid "failed to read sysfs size file"
msgstr "sysfs boyut dosyası okunamadı"
#: src/main/options.c:231
msgid "failed to open block device"
msgstr "blok aygıtı açılamadı"
#: src/main/options.c:241
msgid "failed to determine size of block device"
msgstr "blok aygıtının boyutu belirlenemedi"
#: src/main/options.c:347
msgid "option structure allocation failed"
msgstr "seçenek yapısı tahsisi başarısız oldu"
#: src/main/options.c:366
msgid "option structure argv allocation failed"
msgstr "seçenek yapısı argv tahsisi başarısız oldu"
#: src/main/options.c:419
msgid "numeric value not understood"
#: src/main/options.c:370
msgid "list files may not contain @ lines"
msgstr ""
#: src/main/options.c:437
msgid "integer argument expected"
msgstr "tamsayı bağımsız değişkeni bekleniyor"
#: src/main/options.c:449
msgid "numeric argument expected"
msgstr "sayısal bağımsız değişken bekleniyor"
#: src/main/options.c:460
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:802
msgid "process ID or pid:fd pair expected"
msgstr "süreç kimliği (ID) veya pid:fd çifti bekleniyor"
#: src/main/options.c:467
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:809
msgid "invalid process ID"
msgstr "geçersiz süreç kimliği (ID)"
#: src/main/options.c:700
#: src/main/options.c:448 src/pv/file.c:342
msgid "failed to stat file"
msgstr "dosya statüsünde başarısız oldu"
#: src/main/options.c:462
msgid "is a directory"
msgstr "bir dizindir"
#: src/main/options.c:491
msgid "failed to generate sysfs filename"
msgstr "sysfs dosya adı oluşturulamadı"
#: src/main/options.c:513
msgid "failed to read sysfs size file"
msgstr "sysfs boyut dosyası okunamadı"
#: src/main/options.c:533
msgid "failed to open block device"
msgstr "blok aygıtı açılamadı"
#: src/main/options.c:543
msgid "failed to determine size of block device"
msgstr "blok aygıtının boyutu belirlenemedi"
#: src/main/options.c:649
msgid "option structure allocation failed"
msgstr "seçenek yapısı tahsisi başarısız oldu"
#: src/main/options.c:668
msgid "option structure argv allocation failed"
msgstr "seçenek yapısı argv tahsisi başarısız oldu"
#: src/main/options.c:720
msgid "numeric value not understood"
msgstr "sayısal değer anlaşılmadı"
#: src/main/options.c:738
msgid "integer argument expected"
msgstr "tamsayı bağımsız değişkeni bekleniyor"
#: src/main/options.c:750
msgid "numeric argument expected"
msgstr "sayısal bağımsız değişken bekleniyor"
#: src/main/options.c:762
msgid "missing filename"
msgstr ""
#: src/main/options.c:790
msgid "missing process name"
msgstr ""
#: src/main/options.c:1042
#, c-format
msgid "Try `%s --help' for more information."
msgstr "Daha fazla bilgi için `%s --help' seçeneğini deneyin."
#: src/main/options.c:702
#: src/main/options.c:1044
#, c-format
msgid "Try `%s -h' for more information."
msgstr "Daha fazla bilgi için `%s -h' seçeneğini deneyin."
#: src/main/options.c:733
#: src/main/options.c:1075
msgid ""
"cannot use line mode or transfer modifier options when watching file "
"descriptors"
@@ -356,19 +368,19 @@ msgstr ""
"dosya tanımlayıcılarını izlerken satır modu veya aktarım değiştirici "
"seçeneklerini kullanamaz"
#: src/main/options.c:742
#: src/main/options.c:1084
msgid "cannot use cursor positioning when watching file descriptors"
msgstr "dosya tanımlayıcılarını izlerken imleç konumlandırmayı kullanamaz"
#: src/main/options.c:751
#: src/main/options.c:1093
msgid "cannot use remote control when watching file descriptors"
msgstr "dosya tanımlayıcılarını izlerken uzaktan kumandayı kullanamaz"
#: src/main/options.c:760
#: src/main/options.c:1102
msgid "cannot transfer files when watching file descriptors"
msgstr "dosya tanımlayıcıları izlenirken dosya aktarılamıyor"
#: src/main/options.c:775
#: src/main/options.c:1127
msgid "not available on systems without /proc/self/fdinfo"
msgstr "/proc/self/fdinfo olmayan sistemlerde kullanılamaz"
@@ -376,7 +388,7 @@ msgstr "/proc/self/fdinfo olmayan sistemlerde kullanılamaz"
msgid "message not received"
msgstr "mesaj alınamadı"
#: src/main/remote.c:440
#: src/main/remote.c:444
msgid "SA_SIGINFO not supported on this system"
msgstr "SA_SIGINFO bu sistemde desteklenmiyor"
@@ -413,150 +425,159 @@ msgstr "kilit denemesi başarısız oldu"
msgid "failed to open terminal"
msgstr "terminal açılamadı"
#: src/pv/display.c:249
#: src/pv/display.c:285
msgid "yzafpnum kMGTPEZY"
msgstr "yzafpnum kMGTPEZY"
#: src/pv/display.c:267
#: src/pv/display.c:303
msgid "yzafpnum KMGTPEZY"
msgstr "yzafpnum KMGTPEZY"
#: src/pv/display.c:989 src/pv/transfer.c:1057
#: src/pv/display.c:1053 src/pv/loop.c:747 src/pv/transfer.c:1083
msgid "buffer allocation failed"
msgstr "arabellek tahsisi başarısız oldu"
#: src/pv/file.c:149
#: src/pv/file.c:153
msgid "failed to seek to start of output"
msgstr "çıktının başlangıcına ulaşılamadı"
#: src/pv/file.c:294
#: src/pv/file.c:303
msgid "failed to close file"
msgstr "dosya kapatılamadı"
#: src/pv/file.c:317
#: src/pv/file.c:335
msgid "failed to read file"
msgstr "dosya okunamadı"
#: src/pv/file.c:332
#: src/pv/file.c:350
msgid "failed to stat output file"
msgstr "çıktı dosyası stat edilemedi"
#: src/pv/file.c:354
#: src/pv/file.c:372
msgid "input file is output file"
msgstr "girdi dosyası çıktı dosyasıdır"
#: src/pv/file.c:412
#: src/pv/file.c:429
msgid "(none)"
msgstr "(yok)"
#: src/pv/file.c:414
#: src/pv/file.c:431
msgid "(stdin)"
msgstr "(stdin)"
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:93
#: src/pv/format/rate.c:37 src/pv/loop.c:562
#: src/pv/format/averagerate.c:34 src/pv/format/progressbar.c:92
#: src/pv/format/rate.c:36 src/pv/loop.c:565
msgid "b/s"
msgstr "b/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40
msgid "/s"
msgstr "/s"
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:97
#: src/pv/format/rate.c:41 src/pv/loop.c:562
#: src/pv/format/averagerate.c:38 src/pv/format/progressbar.c:96
#: src/pv/format/rate.c:40 src/pv/loop.c:565
msgid "B/s"
msgstr "B/s"
#: src/pv/format/bytes.c:37
#: src/pv/format/bytes.c:35
msgid "b"
msgstr "b"
#: src/pv/format/bytes.c:41 src/pv/transfer.c:594
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
msgid "B"
msgstr "B"
#: src/pv/format/eta.c:53 src/pv/format/eta.c:57
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
msgid "ETA"
msgstr "ETA"
#: src/pv/format/fineta.c:81
#: src/pv/format/fineta.c:80
msgid "FIN"
msgstr "FIN"
#: src/pv/loop.c:561
#: src/pv/loop.c:564
msgid "rate min/avg/max/mdev"
msgstr "oran min/ortalama/maks/standart sapma"
#: src/pv/loop.c:573
#: src/pv/loop.c:576
msgid "rate not measured"
msgstr "oran ölçülmedi"
#: src/pv/loop.c:783 src/pv/loop.c:834 src/pv/loop.c:887 src/pv/watchpid.c:99
#: src/pv/watchpid.c:109 src/pv/watchpid.c:120 src/pv/watchpid.c:128
#: src/pv/watchpid.c:165 src/pv/watchpid.c:184 src/pv/watchpid.c:192
#: src/pv/watchpid.c:202 src/pv/watchpid.c:300 src/pv/watchpid.c:308
#: src/pv/watchpid.c:385 src/pv/watchpid.c:406
#: src/pv/loop.c:768 src/pv/loop.c:784 src/pv/loop.c:802 src/pv/watchpid.c:99
#: src/pv/watchpid.c:108 src/pv/watchpid.c:119 src/pv/watchpid.c:127
#: src/pv/watchpid.c:164 src/pv/watchpid.c:183 src/pv/watchpid.c:191
#: src/pv/watchpid.c:201 src/pv/watchpid.c:299 src/pv/watchpid.c:307
#: src/pv/watchpid.c:439 src/pv/watchpid.c:462
msgid "pid"
msgstr "pid"
#: src/pv/state.c:40
msgid "history structure allocation failed"
msgstr "geçmiş yapısı tahsisi başarısız oldu"
#: src/pv/state.c:617 src/pv/state.c:628
msgid "file list allocation failed"
msgstr "dosya listesi tahsisi başarısız oldu"
#: src/pv/transfer.c:463
msgid "read failed"
msgstr "okuma başarısız"
#: src/pv/transfer.c:479
msgid "warning: read errors detected"
msgstr "uyarı: okuma hataları tespit edildi"
#: src/pv/transfer.c:495
msgid "file is not seekable"
msgstr "dosya aranabilir değil"
#: src/pv/transfer.c:573
msgid "failed to seek past error"
msgstr "geçmiş hatayı aramakta başarısız oldu"
#: src/pv/transfer.c:593
msgid "skipped past read error"
msgstr "geçmiş okuma hatası atlandı"
#: src/pv/transfer.c:634
msgid "no transfer buffer allocated"
msgstr "aktarım arabelleği ayrılmamış"
#: src/pv/transfer.c:676
msgid "failed to set interval timer"
msgstr "aralık zamanlayıcısı ayarlanamadı"
#: src/pv/transfer.c:702
msgid "failed to clear interval timer"
msgstr "aralık zamanlayıcısı temizlenemedi"
#: src/pv/transfer.c:744
msgid "line position buffer allocation failed"
msgstr "satır konumu arabellek tahsisi başarısız oldu"
#: src/pv/transfer.c:918
msgid "write failed"
msgstr "yazma başarısız"
#: src/pv/transfer.c:1159
msgid "select call failed"
msgstr "seçme çağrısı başarısız oldu"
#: src/pv/watchpid.c:109 src/pv/watchpid.c:121 src/pv/watchpid.c:130
#: src/pv/watchpid.c:184 src/pv/watchpid.c:193 src/pv/watchpid.c:204
#: src/pv/loop.c:802 src/pv/watchpid.c:108 src/pv/watchpid.c:120
#: src/pv/watchpid.c:129 src/pv/watchpid.c:183 src/pv/watchpid.c:192
#: src/pv/watchpid.c:203
msgid "fd"
msgstr "fd"
#: src/pv/watchpid.c:130 src/pv/watchpid.c:204
#: src/pv/state.c:42
msgid "history structure allocation failed"
msgstr "geçmiş yapısı tahsisi başarısız oldu"
#: src/pv/state.c:685 src/pv/state.c:697
msgid "file list allocation failed"
msgstr "dosya listesi tahsisi başarısız oldu"
#: src/pv/state.c:731
msgid "process list allocation failed"
msgstr "işlem listesi tahsisi başarısız oldu"
#: src/pv/state.c:739
msgid "file descriptor list allocation failed"
msgstr "dosya tanımlayıcı listesi tahsisi başarısız oldu"
#: src/pv/transfer.c:490
msgid "read failed"
msgstr "okuma başarısız"
#: src/pv/transfer.c:506
msgid "warning: read errors detected"
msgstr "uyarı: okuma hataları tespit edildi"
#: src/pv/transfer.c:522
msgid "file is not seekable"
msgstr "dosya aranabilir değil"
#: src/pv/transfer.c:599
msgid "failed to seek past error"
msgstr "geçmiş hatayı aramakta başarısız oldu"
#: src/pv/transfer.c:619
msgid "skipped past read error"
msgstr "geçmiş okuma hatası atlandı"
#: src/pv/transfer.c:660
msgid "no transfer buffer allocated"
msgstr "aktarım arabelleği ayrılmamış"
#: src/pv/transfer.c:702
msgid "failed to set interval timer"
msgstr "aralık zamanlayıcısı ayarlanamadı"
#: src/pv/transfer.c:728
msgid "failed to clear interval timer"
msgstr "aralık zamanlayıcısı temizlenemedi"
#: src/pv/transfer.c:770
msgid "line position buffer allocation failed"
msgstr "satır konumu arabellek tahsisi başarısız oldu"
#: src/pv/transfer.c:944
msgid "write failed"
msgstr "yazma başarısız"
#: src/pv/transfer.c:1185
msgid "select call failed"
msgstr "seçme çağrısı başarısız oldu"
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
msgid "not a regular file or block device"
msgstr "normal bir dosya veya blok aygıtı değil"
+15 -3
View File
@@ -23,6 +23,16 @@ extern "C" {
struct opts_s;
typedef struct opts_s *opts_t;
/*
* Overall program actions to select.
*/
typedef enum {
PV_ACTION_NOTHING, /* do nothing, and exit */
PV_ACTION_TRANSFER, /* transfer data */
PV_ACTION_STORE_AND_FORWARD, /* store to file, then output from it */
PV_ACTION_WATCHFD /* watch process file descriptors */
} pvaction_t;
/*
* Structure describing run-time options.
*
@@ -39,6 +49,8 @@ struct opts_s {
/*@keep@*/ /*@null@*/ char *pidfile; /* PID file, if any */
/*@keep@*/ /*@null@*/ char *store_and_forward_file; /* store and forward file, if any */
/*@keep@*/ /*@null@*/ char *extra_display; /* extra display specifier, if any */
/*@keep@*/ /*@null@*/ pid_t *watchfd_pid; /* array of processes to watch fds of */
/*@keep@*/ /*@null@*/ int *watchfd_fd; /* array of fds to watch in each one (0=all) */
/*@keep@*/ /*@null@*/ const char **argv; /* array of non-option arguments */
size_t lastwritten; /* show N bytes last written */
off_t rate_limit; /* rate limit, in bytes per second */
@@ -47,14 +59,14 @@ struct opts_s {
off_t error_skip_block; /* skip block size, 0 for adaptive */
pid_t remote; /* PID of pv to update settings of */
unsigned int skip_errors; /* skip read errors counter */
pid_t watch_pid; /* process to watch fds of */
int watch_fd; /* fd to watch */
unsigned int average_rate_window; /* time window in seconds for average rate calculations */
unsigned int width; /* screen width */
unsigned int height; /* screen height */
unsigned int argc; /* number of non-option arguments */
unsigned int argv_length; /* allocated array size */
bool do_nothing; /* exit-without-doing-anything flag */
unsigned int watchfd_count; /* number of watchfd items */
unsigned int watchfd_length; /* allocated array size */
pvaction_t action; /* the program action to perform */
bool progress; /* progress bar flag */
bool timer; /* timer flag */
bool eta; /* ETA flag */
+99 -35
View File
@@ -60,7 +60,7 @@ extern "C" {
/*
* Structure for data shared between multiple "pv -c" instances.
*/
struct pvcursorstate_s {
struct pvipccursorstate_s {
int y_topmost; /* terminal row of topmost "pv" instance */
bool tty_tostop_added; /* whether any instance had to set TOSTOP on the terminal */
};
@@ -131,6 +131,8 @@ typedef uint16_t pvdisplay_bytecount_t;
typedef uint16_t pvdisplay_width_t;
#define PVDISPLAY_WIDTH_MAX (65535) /* UINT16_MAX */
/* String pointer, that is the only pointer to this resource, that can be null. */
typedef /*@only@*/ /*@null@*/ char * nullable_string_t;
/*
* Structure for holding PV internal state. Opaque outside the PV library.
@@ -141,25 +143,37 @@ struct pvstate_s {
/******************
* Program status *
******************/
struct {
/*@only@*/ char *program_name; /* program name for error reporting */
struct pvprogramstatus_s {
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) */
bool terminal_supports_utf8; /* whether the terminal supports UTF-8 */
bool terminal_supports_colour; /* whether the terminal supports colour */
bool checked_colour_support; /* whether we have checked colour support yet */
} status;
/***************
* Input files *
***************/
struct {
/*@only@*/ /*@null@*/ char **filename; /* input filenames */
struct pvinputfiles_s {
/*@only@*/ /*@null@*/ nullable_string_t *filename; /* input filenames */
unsigned int file_count; /* number of input files */
} files;
/*********************************
* Items to watch with --watchfd *
*********************************/
struct pvwatchspec_s {
/*@only@*/ /*@null@*/ pid_t *pid; /* array of processes to watch fds of */
/*@only@*/ /*@null@*/ int *fd; /* array of fds to watch in each one (0=all) */
unsigned int count; /* number of items in these arrays */
bool multiple_pids; /* true if more than one distinct PID */
} watchfd;
/*******************
* Program control *
*******************/
struct {
struct pvcontrol_s {
char default_format[PV_SIZEOF_DEFAULT_FORMAT]; /* default format string */
double interval; /* interval between updates */
double delay_start; /* delay before first display */
@@ -172,9 +186,7 @@ struct pvstate_s {
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 */
pid_t watch_pid; /* process to watch fds of */
unsigned int skip_errors; /* skip read errors counter */
int watch_fd; /* fd to watch */
int output_fd; /* fd to write output to */
unsigned int average_rate_window; /* time window in seconds for average rate calculations */
unsigned int history_interval; /* seconds between each average rate calc history entry */
@@ -198,9 +210,6 @@ struct pvstate_s {
bool no_splice; /* never use splice() */
bool discard_input; /* write nothing to stdout */
bool show_stats; /* show statistics on exit */
bool can_display_utf8; /* whether UTF-8 output is permitted */
bool can_display_colour; /* whether the terminal supports colour */
bool checked_colour_support; /* whether we have checked colour support yet */
bool width_set_manually; /* width was set manually, not detected */
bool height_set_manually; /* height was set manually, not detected */
} control;
@@ -208,7 +217,7 @@ struct pvstate_s {
/*******************
* Signal handling *
*******************/
struct {
struct pvsignal_s {
/* old signal handlers to restore in pv_sig_fini(). */
struct sigaction old_sigpipe;
struct sigaction old_sigttou;
@@ -233,7 +242,7 @@ struct pvstate_s {
/*******************
* Transient flags *
*******************/
struct {
struct pvtransientflags_s {
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 */
@@ -241,7 +250,7 @@ struct pvstate_s {
volatile sig_atomic_t suspend_stderr; /* whether writing to stderr is suspended */
volatile sig_atomic_t skip_next_sigcont; /* whether to ignore the next SIGCONT */
volatile sig_atomic_t pipe_closed; /* whether the output pipe was closed */
} flag;
} flags;
/*****************
* Display state *
@@ -295,7 +304,7 @@ struct pvstate_s {
bool colour_permitted; /* whether colour is permitted for this display */
bool sgr_code_active; /* set while SGR code is active in a display line */
bool final_update; /* set internally on the final update */
bool display_visible; /* set once anything written to terminal */
bool output_produced; /* set once anything written to terminal */
} display;
@@ -305,7 +314,7 @@ struct pvstate_s {
/************************************
* Calculated state of the transfer *
************************************/
struct {
struct pvtransfercalc_s {
long double transfer_rate; /* calculated transfer rate */
long double average_rate; /* calculated average transfer rate */
@@ -337,10 +346,10 @@ struct pvstate_s {
/********************
* Cursor/IPC state *
********************/
struct {
struct pvcursorstate_s {
char lock_file[PV_SIZEOF_CRS_LOCK_FILE];
#ifdef HAVE_IPC
/*@keep@*/ /*@null@*/ struct pvcursorstate_s *shared; /* data shared between instances */
/*@keep@*/ /*@null@*/ struct pvipccursorstate_s *shared; /* data shared between instances */
int shmid; /* ID of our shared memory segment */
int pvcount; /* number of `pv' processes in total */
int pvmax; /* highest number of `pv's seen */
@@ -353,6 +362,7 @@ struct pvstate_s {
#ifdef HAVE_IPC
bool noipc; /* set if we can't use IPC */
#endif /* HAVE_IPC */
bool disable; /* set if cursor positioning can't be used */
} cursor;
/*******************
@@ -373,7 +383,7 @@ 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.
*/
struct {
struct pvtransferstate_s {
long double elapsed_seconds; /* how long we have been transferring data for */
/*@only@*/ /*@null@*/ char *transfer_buffer; /* data transfer buffer */
size_t buffer_size; /* size of buffer */
@@ -385,6 +395,7 @@ struct pvstate_s {
size_t written_but_not_consumed; /* bytes in the output pipe, unread */
off_t total_bytes_read; /* total bytes read */
off_t total_written; /* total bytes or lines written */
off_t transferred; /* amount transferred (written - unconsumed) */
@@ -429,16 +440,43 @@ struct pvstate_s {
} transfer;
};
typedef struct pvprogramstatus_s *pvprogramstatus_t;
typedef struct pvinputfiles_s *pvinputfiles_t;
typedef struct pvcontrol_s *pvcontrol_t;
typedef struct pvsignal_s *pvsignal_t;
typedef struct pvtransientflags_s *pvtransientflags_t;
typedef struct pvdisplay_s *pvdisplay_t;
typedef struct pvdisplay_segment_s *pvdisplay_segment_t;
typedef struct pvtransfercalc_s *pvtransfercalc_t;
typedef struct pvcursorstate_s *pvcursorstate_t;
typedef struct pvtransferstate_s *pvtransferstate_t;
/*
* Read-only counterparts to the above structure pointers, to be used in
* function declarations where the function definitely shouldn't be altering
* the contents of the structure.
*/
typedef const struct pvprogramstatus_s * readonly_pvprogramstatus_t;
typedef const struct pvinputfiles_s * readonly_pvinputfiles_t;
typedef const struct pvcontrol_s * readonly_pvcontrol_t;
typedef const struct pvsignal_s * readonly_pvsignal_t;
typedef const struct pvtransientflags_s * readonly_pvtransientflags_t;
typedef const struct pvdisplay_s * readonly_pvdisplay_t;
typedef const struct pvdisplay_segment_s * readonly_pvdisplay_segment_t;
typedef const struct pvtransfercalc_s * readonly_pvtransfercalc_t;
typedef const struct pvcursorstate_s * readonly_pvcursorstate_t;
typedef const struct pvtransferstate_s * readonly_pvtransferstate_t;
/*
* Structure containing the parameters used by formatters.
*/
struct pvformatter_args_s {
/*@dependent@*/ pvstate_t state; /* overall state */
/*@dependent@*/ pvdisplay_t display; /* the display being updated */
/*@dependent@*/ pvdisplay_segment_t segment; /* the segment of the display */
/*@dependent@*/ readonly_pvprogramstatus_t status; /* program status */
/*@dependent@*/ readonly_pvcontrol_t control; /* control settings */
/*@dependent@*/ readonly_pvtransferstate_t transfer; /* transfer state */
/*@dependent@*/ readonly_pvtransfercalc_t calc; /* calculated transfer state */
/*@dependent@*/ char *buffer; /* buffer to write formatted segments into */
pvdisplay_bytecount_t buffer_size; /* size of the buffer */
pvdisplay_bytecount_t offset; /* current write position in the buffer */
@@ -460,29 +498,39 @@ struct pvdisplay_component_s {
};
/*
* Structure defining the current state of a single watched file descriptor.
*/
struct pvwatchfd_s {
struct pvtransientflags_s flags; /* transient flags */
struct pvtransferstate_s transfer; /* transfer state */
struct pvtransfercalc_s calc; /* calculated transfer state */
struct pvdisplay_s display; /* display data */
#ifdef __APPLE__
#else
char file_fdinfo[PV_SIZEOF_FILE_FDINFO]; /* path to /proc fdinfo file */
char file_fd[PV_SIZEOF_FILE_FD]; /* path to /proc fd symlink */
#endif
char file_fdpath[PV_SIZEOF_FILE_FDPATH]; /* path to file that was opened */
char display_name[PV_SIZEOF_DISPLAY_NAME]; /* name to show on progress bar */
/*@keep@ */ char display_name[PV_SIZEOF_DISPLAY_NAME]; /* name to show on progress bar */
struct stat sb_fd; /* stat of fd symlink */
struct stat sb_fd_link; /* lstat of fd symlink */
off_t size; /* size of whole file, 0 if unknown */
off_t position; /* position last seen at */
struct timespec start_time; /* time we started watching the fd */
/*@null@*/ pvstate_t state; /* state object for flags and display */
struct timespec last_active; /* time the fd was last seen open (TODO, #81) */
pid_t watch_pid; /* PID to watch */
int watch_fd; /* fd to watch, -1 = not displayed */
int watch_fd; /* fd to watch */
bool displayable; /* false if not displayable */
bool inactive; /* true if the fd is now closed (TODO, #81) */
bool unused; /* true if free for re-use */
};
typedef struct pvwatchfd_s *pvwatchfd_t;
void pv_error(pvstate_t, char *, ...);
void pv_error(char *, ...);
int pv_main_loop(pvstate_t);
void pv_calculate_transfer_rate(pvstate_t, bool);
void pv_calculate_transfer_rate(pvtransfercalc_t, readonly_pvtransferstate_t, readonly_pvcontrol_t, readonly_pvdisplay_t, bool);
long pv_bound_long(long, long, long);
long pv_seconds_remaining(const off_t, const off_t, const long double);
@@ -534,20 +582,36 @@ pvdisplay_bytecount_t pv_formatter_previous_line(pvformatter_args_t);
pvdisplay_bytecount_t pv_formatter_name(pvformatter_args_t);
pvdisplay_bytecount_t pv_formatter_sgr(pvformatter_args_t);
bool pv_format(pvstate_t, /*@null@*/ const char *, pvdisplay_t, bool, bool);
void pv_display(pvstate_t, bool);
bool pv_format (pvprogramstatus_t, readonly_pvcontrol_t,
readonly_pvtransferstate_t, readonly_pvtransfercalc_t,
/*@null@ */ const char *, pvdisplay_t, bool, bool);
void pv_display (pvprogramstatus_t, readonly_pvcontrol_t, pvtransientflags_t,
readonly_pvtransferstate_t, pvtransfercalc_t,
pvcursorstate_t, pvdisplay_t, /*@null@ */ pvdisplay_t, bool);
ssize_t pv_transfer(pvstate_t, int, bool *, bool *, off_t, long *);
int pv_next_file(pvstate_t, unsigned int, int);
/*@keep@*/ const char *pv_current_file_name(pvstate_t);
void pv_write_retry(int, const char *, size_t);
void pv_tty_write(pvstate_t, const char *, size_t);
unsigned int pv_update_calc_average_rate_window(pvtransfercalc_t, unsigned int);
void pv_reset_calc(pvtransfercalc_t);
void pv_reset_transfer(pvtransferstate_t);
void pv_reset_flags(pvtransientflags_t);
void pv_reset_display(pvdisplay_t);
void pv_reset_watchfd(pvwatchfd_t);
void pv_freecontents_display(pvdisplay_t);
void pv_freecontents_transfer(pvtransferstate_t);
void pv_freecontents_calc(pvtransfercalc_t);
void pv_freecontents_watchfd(pvwatchfd_t);
void pv_crs_fini(pvstate_t);
void pv_crs_init(pvstate_t);
void pv_crs_update(pvstate_t, const char *);
void pv_write_retry(int, const char *, size_t);
void pv_tty_write(readonly_pvtransientflags_t, const char *, size_t);
void pv_crs_fini(pvcursorstate_t, readonly_pvcontrol_t, pvtransientflags_t);
void pv_crs_init(pvcursorstate_t, readonly_pvcontrol_t, pvtransientflags_t);
void pv_crs_update(pvcursorstate_t, readonly_pvcontrol_t, pvtransientflags_t, const char *);
#ifdef HAVE_IPC
void pv_crs_needreinit(pvstate_t);
void pv_crs_needreinit(pvcursorstate_t);
#endif
void pv_sig_allowpause(void);
@@ -555,14 +619,14 @@ void pv_sig_checkbg(void);
void pv_sig_nopause(void);
void pv_remote_init(pvstate_t);
void pv_remote_check(pvstate_t);
bool 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, bool);
bool pv_watchfd_changed(pvwatchfd_t);
off_t pv_watchfd_position(pvwatchfd_t);
int pv_watchpid_scanfds(pvstate_t, pid_t, int *, pvwatchfd_t *, int *);
int pv_watchpid_scanfds(pvstate_t, pid_t, int, int *, pvwatchfd_t *);
void pv_watchpid_setname(pvstate_t, pvwatchfd_t);
#ifdef __cplusplus
+9 -10
View File
@@ -175,10 +175,15 @@ void pv_nanosleep(long long);
* Main PV functions.
*/
/*
* Set the prefix (program name) for any PV error messages.
*/
extern void pv_set_error_prefix(/*@unique@ */ const char *);
/*
* Create a new state structure, and return it, or 0 (NULL) on error.
*/
extern /*@null@*/ /*@only@*/ pvstate_t pv_state_alloc(const char *);
extern /*@null@*/ /*@only@*/ pvstate_t pv_state_alloc(void);
/*
* Clear the calculated parts of a state structure.
@@ -228,13 +233,12 @@ extern void pv_state_name_set(pvstate_t, /*@null@*/ const char *);
extern void pv_state_default_bar_style_set(pvstate_t, /*@null@ */ const char *);
extern void pv_state_format_string_set(pvstate_t, /*@null@*/ const char *);
extern void pv_state_extra_display_set(pvstate_t, /*@null@*/ const char *);
extern void pv_state_watch_pid_set(pvstate_t, pid_t);
extern void pv_state_watch_fd_set(pvstate_t, int);
extern void pv_state_output_set(pvstate_t, int, const char *);
extern void pv_state_average_rate_window_set(pvstate_t, unsigned int);
extern void pv_state_set_can_display_utf8(pvstate_t, bool);
extern void pv_state_set_terminal_supports_utf8(pvstate_t, bool);
extern void pv_state_inputfiles(pvstate_t, unsigned int, const char **);
extern void pv_state_watchfds(pvstate_t, unsigned int, const pid_t *, const int *);
/*
* Work out whether we are in the foreground.
@@ -269,15 +273,10 @@ extern bool pv_sigusr2_received(pvstate_t, pid_t *);
extern int pv_main_loop(pvstate_t);
/*
* Watch the selected file descriptor of the selected process.
* Watch the selected file descriptors of the selected processes.
*/
extern int pv_watchfd_loop(pvstate_t);
/*
* Watch the selected process.
*/
extern int pv_watchpid_loop(pvstate_t);
/*
* Shut down signal handlers after running the main loop.
*/
+30 -16
View File
@@ -281,7 +281,7 @@ int main(int argc, char **argv)
/*@only@ */ pvstate_t state = NULL;
int retcode = 0;
bool can_have_eta = true;
bool can_display_utf8 = false;
bool terminal_supports_utf8 = false;
#if ! HAVE_SETPROCTITLE
initproctitle(argc, argv);
@@ -295,7 +295,7 @@ int main(int argc, char **argv)
#ifdef HAVE_LANGINFO_H
/*@-mustfreefresh@ *//* splint thinks nl_langinfo() leaks memory */
if (0 == strcmp(nl_langinfo(CODESET), "UTF-8"))
can_display_utf8 = true;
terminal_supports_utf8 = true;
/*@+mustfreefresh@ */
#endif
#endif
@@ -308,16 +308,22 @@ int main(int argc, char **argv)
}
/* Early exit if necessary, such as with "-h". */
if (opts->do_nothing) {
if (PV_ACTION_NOTHING == opts->action) {
debug("%s", "nothing to do - exiting with status 0");
opts_free(opts);
return 0;
}
/* Set the error message prefix. */
/*@-keeptrans@ */
pv_set_error_prefix(opts->program_name);
/* splint - this function doesn't add an alias or release it. */
/*@+keeptrans@ */
/*
* Allocate our internal state buffer.
*/
state = pv_state_alloc(opts->program_name);
state = pv_state_alloc();
if (NULL == state) {
/*@-mustfreefresh@ */
/*
@@ -381,6 +387,13 @@ int main(int argc, char **argv)
pv_state_inputfiles(state, opts->argc, (const char **) (opts->argv));
}
/*
* Put the list of watchfd items into the PV internal state.
*/
if ((opts->watchfd_count > 0) && (NULL != opts->watchfd_pid) && (NULL != opts->watchfd_fd)) {
pv_state_watchfds(state, opts->watchfd_count, opts->watchfd_pid, opts->watchfd_fd);
}
/*
* If stderr is not a terminal and we're neither forcing output nor
* outputting numerically, we will have nothing to display at all.
@@ -452,7 +465,7 @@ int main(int argc, char **argv)
pv_state_stop_at_size_set(state, opts->stop_at_size);
/* Total size calculation, in normal transfer mode. */
if (0 == opts->watch_pid) {
if (PV_ACTION_TRANSFER == opts->action) {
/*
* If no size was given, try to calculate the total size.
*/
@@ -505,37 +518,38 @@ int main(int argc, char **argv)
pv_state_default_bar_style_set(state, opts->default_bar_style);
pv_state_format_string_set(state, opts->format);
pv_state_extra_display_set(state, opts->extra_display);
pv_state_watch_pid_set(state, opts->watch_pid);
pv_state_watch_fd_set(state, opts->watch_fd);
pv_state_average_rate_window_set(state, opts->average_rate_window);
pv_state_set_format(state, opts->progress, opts->timer, can_have_eta ? opts->eta : false,
can_have_eta ? opts->fineta : false, opts->rate, opts->average_rate,
opts->bytes, opts->bufpercent, opts->lastwritten, opts->name);
debug("%s: %s", "can_display_utf8", can_display_utf8 ? "true" : "false");
pv_state_set_can_display_utf8(state, can_display_utf8);
debug("%s: %s", "terminal_supports_utf8", terminal_supports_utf8 ? "true" : "false");
pv_state_set_terminal_supports_utf8(state, terminal_supports_utf8);
/* Initialise the signal handling. */
pv_sig_init(state);
/* Run the appropriate main loop. */
if (0 == opts->watch_pid && NULL == opts->store_and_forward_file) {
switch (opts->action) {
case PV_ACTION_NOTHING:
break;
case PV_ACTION_TRANSFER:
/* Normal "transfer data" mode. */
pv_remote_init();
retcode = pv_main_loop(state);
pv_remote_fini();
} else if (0 == opts->watch_pid && NULL != opts->store_and_forward_file) {
break;
case PV_ACTION_STORE_AND_FORWARD:
/* Store-and-forward transfer mode. */
pv_remote_init();
retcode = pv__store_and_forward(state, opts, can_have_eta);
pv_remote_fini();
} else if (0 != opts->watch_pid && -1 == opts->watch_fd) {
/* "Watch all file descriptors of another process" mode. */
retcode = pv_watchpid_loop(state);
} else if (0 != opts->watch_pid && -1 != opts->watch_fd) {
/* "Watch a specific file descriptor of another process" mode. */
break;
case PV_ACTION_WATCHFD:
/* "Watch file descriptor(s) of another process" mode. */
retcode = pv_watchfd_loop(state);
break;
}
/* Clear up the PID file, if one was written. */
+373 -21
View File
@@ -27,6 +27,7 @@
#endif
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
@@ -34,6 +35,14 @@
void display_help(void);
void display_version(void);
static bool opts_watchfd_parse(opts_t, const char *, /*@null@ */ const char *, unsigned int);
/*
* splint note about mustfreefresh: the gettext calls made by _() cause
* memory leak warnings, but in these cases it's unavoidable, and mitigated
* by the fact we only translate each string once.
*/
/*
@@ -63,6 +72,10 @@ void opts_free( /*@only@ */ opts_t opts)
free(opts->store_and_forward_file);
if (NULL != opts->extra_display)
free(opts->extra_display);
if (NULL != opts->watchfd_pid)
free(opts->watchfd_pid);
if (NULL != opts->watchfd_fd)
free(opts->watchfd_fd);
if (NULL != opts->argv)
free(opts->argv);
/*@+keeptrans@ */
@@ -104,6 +117,300 @@ bool opts_add_file(opts_t opts, const char *filename)
return true;
}
/*
* Add a process ID and file descriptor to the list of items to watch with
* --watchfd, returning false on error.
*/
static bool opts_watchfd_add_item(opts_t opts, pid_t pid, int fd)
{
/*@-branchstate@ */
if ((opts->watchfd_count >= opts->watchfd_length) || (NULL == opts->watchfd_pid)) {
opts->watchfd_length = opts->watchfd_count + 10;
/*@-keeptrans@ */
opts->watchfd_pid = realloc(opts->watchfd_pid, opts->watchfd_length * sizeof(pid_t));
opts->watchfd_fd = realloc(opts->watchfd_fd, opts->watchfd_length * sizeof(int));
/*@+keeptrans@ */
if ((NULL == opts->watchfd_pid) || (NULL == opts->watchfd_fd)) {
fprintf(stderr, "%s: %s\n", opts->program_name, strerror(errno));
opts->watchfd_length = 0;
opts->watchfd_count = 0;
return false;
}
}
/*@+branchstate@ */
/*
* splint notes: we turned off "branchstate" and "keeptrans" above
* because of the same reason as in opts_add_file().
*/
opts->watchfd_pid[opts->watchfd_count] = pid;
opts->watchfd_fd[opts->watchfd_count] = fd;
opts->watchfd_count++;
return true;
}
/*
* Look for processes with the given name, and add all of them to the list
* of watched PIDs. Returns false on error.
*/
static bool opts_watchfd_processname(opts_t opts, const char *process_name)
{
int fds[2];
pid_t pid;
FILE *fptr;
char buffer[1024]; /* flawfinder: ignore */
pid_t waited_pid;
int pid_status;
bool ok;
/*
* flawfinder: buffer is zeroed before each use, and fgets() is
* passed one less than its size so the string functions in the loop
* always find a null byte at the end.
*/
/* Pipe for communicating with pgrep. */
if (pipe(fds) < 0) {
fprintf(stderr, "%s: %s\n", opts->program_name, strerror(errno));
return false;
}
/* Subprocess in which to run pgrep. */
pid = (pid_t) fork();
if (pid < 0) {
fprintf(stderr, "%s: %s\n", opts->program_name, strerror(errno));
(void) close(fds[0]);
(void) close(fds[1]);
return false;
} else if (0 == pid) {
int nullfd;
/* Child process - close stdin, set up stdout, run pgrep. */
/* Replace stdin with /dev/null. */
nullfd = open("/dev/null", O_RDONLY); /* flawfinder: ignore */
/* flawfinder: /dev/null is trusted. */
if (nullfd < 0) {
fprintf(stderr, "%s: %s: %s\n", opts->program_name, "/dev/null", strerror(errno));
exit(EXIT_FAILURE);
}
if (dup2(nullfd, STDIN_FILENO) < 0) {
perror("dup2");
exit(EXIT_FAILURE);
}
(void) close(nullfd);
/* Replace stdout with the write end of the pipe. */
if (dup2(fds[1], STDOUT_FILENO) < 0) {
perror("dup2");
exit(EXIT_FAILURE);
}
(void) close(fds[1]);
/* Close the read end of the pipe. */
(void) close(fds[0]);
/* Run pgrep. */
if (execlp("pgrep", "pgrep", process_name, NULL) < 0) { /* flawfinder: ignore */
perror("pgrep");
}
/*
* flawfinder: deliberately calling pgrep as there isn't a
* portable library to use instead.
*/
exit(EXIT_FAILURE);
}
/* Close the write end of the pipe. */
(void) close(fds[1]);
/* Open a file stream on the read end of the pipe. */
fptr = fdopen(fds[0], "r");
if (NULL == fptr) {
perror("fdopen");
(void) close(fds[0]);
return false;
}
/* Read the lines of output from the child process. */
ok = true;
memset(buffer, 0, sizeof(buffer));
while ((0 == feof(fptr)) && (NULL != fgets(buffer, (int) (sizeof(buffer) - 1), fptr))) {
unsigned int watch_pid;
/* Skip all lines if we've hit any errors. */
if (!ok) {
memset(buffer, 0, sizeof(buffer));
continue;
}
/* Skip lines without valid PID. */
watch_pid = 0;
if (sscanf(buffer, "%u", &watch_pid) < 1)
continue;
if (watch_pid < 1)
continue;
if (!opts_watchfd_parse(opts, buffer, NULL, 0))
ok = false;
memset(buffer, 0, sizeof(buffer));
}
/* Close the stream from the read end of the pipe. */
(void) fclose(fptr);
/* Wait for the child process to exit. */
do {
/*@-type@ */
/* splint disagreement about __pid_t vs pid_t. */
pid_status = 0;
waited_pid = waitpid(pid, &pid_status, 0);
/*@+type@ */
} while (-1 == waited_pid && errno == EINTR);
return ok;
}
/*
* Read additional "-d" values from the given file, returning false on
* failure.
*/
static bool opts_watchfd_listfile(opts_t opts, const char *filename)
{
FILE *fptr;
char buffer[1024]; /* flawfinder: ignore */
unsigned int linenumber;
/*
* flawfinder: buffer is zeroed before each use, and fgets() is
* passed one less than its size so the string functions in the loop
* always find a null byte at the end.
*/
fptr = fopen(filename, "r"); /* flawfinder: ignore */
/*
* flawfinder note: caller directly controls filename, and we're
* opening the file read-only.
*/
if (NULL == fptr) {
fprintf(stderr, "%s: -d @: %s: %s\n", opts->program_name, filename, strerror(errno));
return false;
}
linenumber = 0;
memset(buffer, 0, sizeof(buffer));
while ((0 == feof(fptr)) && (NULL != fgets(buffer, (int) (sizeof(buffer) - 1), fptr))) {
char *argument;
char *nlptr;
linenumber++;
/* Remove trailing carriage returns or newlines. */
nlptr = strchr(buffer, '\r');
if (NULL != nlptr)
nlptr[0] = '\0';
nlptr = strchr(buffer, '\n');
if (NULL != nlptr)
nlptr[0] = '\0';
/* Ignore leading spaces. */
argument = buffer;
while (argument[0] != '\0' && (argument[0] == ' ' || argument[0] == '\t'))
argument++;
/* Ignore blank lines or comment lines. */
if ((argument[0] == '\0') || (argument[0] == '#')) {
memset(buffer, 0, sizeof(buffer));
continue;
}
/* Reject "@" lines. */
if (argument[0] == '@') {
(void) fclose(fptr);
return false;
}
if (!opts_watchfd_parse(opts, argument, filename, linenumber)) {
(void) fclose(fptr);
return false;
}
memset(buffer, 0, sizeof(buffer));
}
(void) fclose(fptr);
return true;
}
/*
* Parse a "-d" option value and make the appropriate additions to the list
* of watchfd items, returning false on failure.
*/
static bool opts_watchfd_parse(opts_t opts, const char *argument, /*@null@ */ const char *filename, unsigned int line)
{
unsigned int parse_pid;
int parse_fd;
if ('@' == argument[0]) {
/* "-d @FILE" syntax - read more values from FILE. */
/* Don't allow this syntax in a list file. */
if (NULL != filename) {
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: -d @: %s:%u: %s\n",
opts->program_name, filename, line, _("list files may not contain @ lines"));
return false;
/*@+mustfreefresh@ */
}
return opts_watchfd_listfile(opts, argument + 1);
} else if ('=' == argument[0]) {
/* "-d =NAME" syntax - find processes named NAME. */
return opts_watchfd_processname(opts, argument + 1);
}
/* "-d PID[:FD]" syntax. */
parse_pid = 0;
parse_fd = -1;
if (sscanf(argument, "%u:%d", &parse_pid, &parse_fd) < 1) {
/*@-mustfreefresh@ *//* see above */
if (NULL != filename) {
fprintf(stderr, "%s: -d: %s:%u: %s\n",
opts->program_name, filename, line, _("process ID or pid:fd pair expected"));
} else {
fprintf(stderr, "%s: -d: %s\n", opts->program_name, _("process ID or pid:fd pair expected"));
}
return false;
/*@+mustfreefresh@ */
}
if (parse_pid < 1) {
/*@-mustfreefresh@ *//* see above */
if (NULL != filename) {
fprintf(stderr, "%s: -d: %s:%u: %u: %s\n",
opts->program_name, filename, line, parse_pid, _("invalid process ID"));
} else {
fprintf(stderr, "%s: -d: %u: %s\n", opts->program_name, parse_pid, _("invalid process ID"));
}
return false;
/*@+mustfreefresh@ */
}
return opts_watchfd_add_item(opts, (pid_t) parse_pid, parse_fd);
}
/*
* Set opts->size from the size of the file whose name is size_file,
@@ -136,12 +443,7 @@ static bool opts_use_size_of_file(opts_t opts, const char *size_file)
stat_rc = stat(size_file, &sb);
if (0 != stat_rc) {
/*@-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.
*/
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: %s: %s: %s\n",
opts->program_name, size_file, _("failed to stat file"), strerror(errno));
return false;
@@ -331,8 +633,8 @@ opts_t opts_parse(unsigned int argc, char **argv)
#endif
;
int c, numopts;
unsigned int check_pid, parse_pid;
int check_fd, parse_fd;
unsigned int check_pid;
int check_fd;
opts_t opts;
char *leafptr;
@@ -372,10 +674,9 @@ opts_t opts_parse(unsigned int argc, char **argv)
numopts = 0;
opts->action = PV_ACTION_TRANSFER;
opts->interval = 1;
opts->delay_start = 0;
opts->watch_pid = 0;
opts->watch_fd = -1;
opts->average_rate_window = 30;
opts->width_set_manually = false;
@@ -453,8 +754,49 @@ opts_t opts_parse(unsigned int argc, char **argv)
}
break;
case 'd':
if ('@' == optarg[0]) {
/* "-d @FILE" syntax - check FILE exists. */
if (optarg[1] == '\0') {
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: -%c @: %s\n",
opts->program_name, c, _("missing filename"));
opts_free(opts);
return NULL;
/*@+mustfreefresh@ */
} else if (0 != access(optarg + 1, R_OK)) { /* flawfinder: ignore */
/*
* flawfinder rationale: we're not
* using access() to check
* permissions, only to help give a
* usable error message, so there's
* no TOCTOU issue.
*/
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: -%c @: %s: %s\n",
opts->program_name, c, optarg + 1, strerror(errno));
opts_free(opts);
return NULL;
/*@+mustfreefresh@ */
}
break;
} else if ('=' == optarg[0]) {
/*
* "-d =NAME" syntax - check NAME is not
* blank.
*/
if (optarg[1] == '\0') {
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: -%c %c: %s\n",
opts->program_name, c, optarg[0], _("missing process name"));
opts_free(opts);
return NULL;
/*@+mustfreefresh@ */
}
break;
}
if (sscanf(optarg, "%u:%d", &check_pid, &check_fd)
< 1) {
/* "-d PID[:FD]" syntax - check numbers. */
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: -%c: %s\n",
opts->program_name, c, _("process ID or pid:fd pair expected"));
@@ -480,11 +822,11 @@ opts_t opts_parse(unsigned int argc, char **argv)
switch (c) {
case 'h':
display_help();
opts->do_nothing = true;
opts->action = PV_ACTION_NOTHING;
return opts; /* early return */
case 'V':
display_version();
opts->do_nothing = true;
opts->action = PV_ACTION_NOTHING;
return opts; /* early return */
case 'p':
opts->progress = true;
@@ -641,6 +983,7 @@ opts_t opts_parse(unsigned int argc, char **argv)
opts_free(opts);
return NULL;
}
opts->action = PV_ACTION_STORE_AND_FORWARD;
break;
case 'R':
opts->remote = (pid_t) pv_getnum_count(optarg, false);
@@ -670,12 +1013,11 @@ opts_t opts_parse(unsigned int argc, char **argv)
}
break;
case 'd':
parse_pid = 0;
parse_fd = -1;
/* No syntax check here, already done earlier */
(void) sscanf(optarg, "%u:%d", &parse_pid, &parse_fd);
opts->watch_pid = (pid_t) parse_pid;
opts->watch_fd = parse_fd;
if (!opts_watchfd_parse(opts, optarg, NULL, 0)) {
opts_free(opts);
return NULL;
}
opts->action = PV_ACTION_WATCHFD;
break;
case 'o':
opts->output = pv_strdup(optarg);
@@ -724,7 +1066,7 @@ opts_t opts_parse(unsigned int argc, char **argv)
if (NULL == opts)
return NULL;
if (0 != opts->watch_pid) {
if (PV_ACTION_WATCHFD == opts->action) {
if (opts->linemode || opts->null_terminated_lines || opts->stop_at_size
|| (opts->skip_errors > 0) || (opts->buffer_size > 0)
|| (opts->rate_limit > 0)) {
@@ -754,14 +1096,24 @@ opts_t opts_parse(unsigned int argc, char **argv)
/*@+mustfreefresh@ */
}
if (optind < (int) argc) {
if (NULL != opts->output) {
/*@-mustfreefresh@ *//* see above */
fprintf(stderr, "%s: %s\n", opts->program_name,
fprintf(stderr, "%s: -o: %s\n", opts->program_name,
_("cannot transfer files when watching file descriptors"));
opts_free(opts);
return NULL;
/*@+mustfreefresh@ */
}
/* Accept additional watchfd arguments. */
while (optind < (int) argc) {
if (!opts_watchfd_parse(opts, argv[optind], NULL, 0)) {
opts_free(opts);
return NULL;
}
optind++;
}
#ifndef __APPLE__
if (0 != access("/proc/self/fdinfo", X_OK)) { /* flawfinder: ignore */
/*
+20 -16
View File
@@ -22,7 +22,7 @@
#include <sys/stat.h>
#ifdef PV_REMOTE_CONTROL
void pv_error(pvstate_t, char *, ...);
void pv_error(char *, ...);
struct remote_msg {
bool progress; /* progress bar flag */
@@ -161,7 +161,7 @@ int pv_remote_set(opts_t opts, pvstate_t state)
* Check that the remote process exists.
*/
if (kill((pid_t) (opts->remote), 0) != 0) {
pv_error(state, "%u: %s", opts->remote, strerror(errno));
pv_error("%u: %s", opts->remote, strerror(errno));
return PV_ERROREXIT_REMOTE_OR_PID;
}
@@ -225,7 +225,7 @@ int pv_remote_set(opts_t opts, pvstate_t state)
memset(control_filename, 0, sizeof(control_filename));
control_fptr = pv__control_file(control_filename, sizeof(control_filename), (pid_t) getpid(), true);
if (NULL == control_fptr) {
pv_error(state, "%s", strerror(errno));
pv_error("%s", strerror(errno));
return PV_ERROREXIT_REMOTE_OR_PID;
}
@@ -234,14 +234,14 @@ int pv_remote_set(opts_t opts, pvstate_t state)
* it.
*/
if (1 != fwrite(&msgbuf, sizeof(msgbuf), 1, control_fptr)) {
pv_error(state, "%s", strerror(errno));
pv_error("%s", strerror(errno));
(void) fclose(control_fptr);
(void) remove(control_filename);
return PV_ERROREXIT_REMOTE_OR_PID;
}
if (0 != fclose(control_fptr)) {
pv_error(state, "%s", strerror(errno));
pv_error("%s", strerror(errno));
(void) remove(control_filename);
return PV_ERROREXIT_REMOTE_OR_PID;
}
@@ -253,7 +253,7 @@ int pv_remote_set(opts_t opts, pvstate_t state)
signal_sender = 0;
(void) pv_sigusr2_received(state, &signal_sender);
if (kill((pid_t) (opts->remote), SIGUSR2) != 0) {
pv_error(state, "%u: %s", opts->remote, strerror(errno));
pv_error("%u: %s", opts->remote, strerror(errno));
(void) remove(control_filename);
return PV_ERROREXIT_REMOTE_OR_PID;
}
@@ -291,7 +291,7 @@ int pv_remote_set(opts_t opts, pvstate_t state)
* Remove the remote control file.
*/
if (0 != remove(control_filename)) {
pv_error(state, "%s", strerror(errno));
pv_error("%s", strerror(errno));
}
/*
@@ -306,7 +306,7 @@ int pv_remote_set(opts_t opts, pvstate_t state)
* warnings, but in this case it's unavoidable, and mitigated by the
* fact we only translate each string once.
*/
pv_error(state, "%u: %s", opts->remote, _("message not received"));
pv_error("%u: %s", opts->remote, _("message not received"));
return PV_ERROREXIT_REMOTE_OR_PID;
/*@+mustfreefresh @ */
}
@@ -318,8 +318,10 @@ int pv_remote_set(opts_t opts, pvstate_t state)
*
* NB relies on pv_state_set_format() causing the output format to be
* reparsed.
*
* Returns true if something was received, false otherwise.
*/
void pv_remote_check(pvstate_t state)
bool pv_remote_check(pvstate_t state)
{
pid_t signal_sender;
char control_filename[4096]; /* flawfinder: ignore */
@@ -333,13 +335,13 @@ void pv_remote_check(pvstate_t state)
*/
signal_sender = 0;
if (!pv_sigusr2_received(state, &signal_sender))
return;
return false;
memset(control_filename, 0, sizeof(control_filename));
control_fptr = pv__control_file(control_filename, sizeof(control_filename), signal_sender, false);
if (NULL == control_fptr) {
pv_error(state, "%s: %s", control_filename, strerror(errno));
return;
pv_error("%s: %s", control_filename, strerror(errno));
return false;
}
/*
@@ -347,14 +349,14 @@ void pv_remote_check(pvstate_t state)
* it.
*/
if (1 != fread(&msgbuf, sizeof(msgbuf), 1, control_fptr)) {
pv_error(state, "%s", strerror(errno));
pv_error("%s", strerror(errno));
(void) fclose(control_fptr);
return;
return false;
}
if (0 != fclose(control_fptr)) {
pv_error(state, "%s", strerror(errno));
return;
pv_error("%s", strerror(errno));
return false;
}
/*
@@ -398,6 +400,8 @@ void pv_remote_check(pvstate_t state)
pv_state_format_string_set(state, msgbuf.format);
if (msgbuf.extra_display[0] != '\0')
pv_state_extra_display_set(state, msgbuf.extra_display);
return true;
}
+72 -61
View File
@@ -17,23 +17,24 @@
* rate, otherwise calulate the average rate from the difference between the
* current position + elapsed time pair, and the oldest pair in the buffer.
*/
static void pv__update_average_rate_history(pvstate_t state, long double rate)
static void pv__update_average_rate_history(pvtransfercalc_t calc, readonly_pvtransferstate_t transfer,
unsigned int history_interval, long double rate)
{
size_t first = state->calc.history_first;
size_t last = state->calc.history_last;
size_t first = calc->history_first;
size_t last = calc->history_last;
long double last_elapsed;
if (NULL == state->calc.history)
if (NULL == calc->history)
return;
last_elapsed = state->calc.history[last].elapsed_sec;
last_elapsed = calc->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)
&& (state->transfer.elapsed_seconds < (last_elapsed + state->control.history_interval)))
&& (transfer->elapsed_seconds < (last_elapsed + history_interval)))
return;
/*
@@ -41,53 +42,62 @@ static void pv__update_average_rate_history(pvstate_t state, long double rate)
* buffer.
*/
if (last_elapsed > 0.0) {
size_t len = state->calc.history_len;
size_t len = calc->history_len;
last = (last + 1) % len;
state->calc.history_last = last;
calc->history_last = last;
if (last == first) {
first = (first + 1) % len;
state->calc.history_first = first;
calc->history_first = first;
}
}
state->calc.history[last].elapsed_sec = state->transfer.elapsed_seconds;
state->calc.history[last].transferred = state->transfer.transferred;
calc->history[last].elapsed_sec = transfer->elapsed_seconds;
calc->history[last].transferred = transfer->transferred;
if (first == last) {
state->calc.current_avg_rate = rate;
calc->current_avg_rate = rate;
} else {
off_t bytes = (state->calc.history[last].transferred - state->calc.history[first].transferred);
long double sec = (state->calc.history[last].elapsed_sec - state->calc.history[first].elapsed_sec);
state->calc.current_avg_rate = (long double) bytes / sec;
off_t bytes = (calc->history[last].transferred - calc->history[first].transferred);
long double sec = (calc->history[last].elapsed_sec - calc->history[first].elapsed_sec);
/* Safety check to avoid division by zero. */
if (sec < 0.000001 && sec > -0.000001)
sec = 0.000001;
calc->current_avg_rate = (long double) bytes / sec;
}
}
/*
* Update all calculated transfer state (state->calc).
* Update all calculated transfer state in calc (usually from state->calc).
*
* If "final" is true, this is the final update, so
* state->calc.transfer_rate and state->calc.average_rate are given as an
* average over the whole transfer; otherwise they are the current transfer
* rate and current average rate.
* If "final" is true, this is the final update, so calc->transfer_rate and
* calc->average_rate are given as an average over the whole transfer;
* otherwise they are the current transfer rate and current average rate.
*
* The value of state->calc.percentage will reflect the percentage
* completion if state->control.size is greater than zero, otherwise it will
* increase by 2 each call and wrap at 200.
* The value of calc->percentage will reflect the percentage completion if
* control->size is greater than zero, otherwise it will increase by 2 each
* call and wrap at 200.
*/
void pv_calculate_transfer_rate(pvstate_t state, bool final)
void pv_calculate_transfer_rate(pvtransfercalc_t calc, readonly_pvtransferstate_t transfer,
readonly_pvcontrol_t control, readonly_pvdisplay_t display, bool final)
{
off_t bytes_since_last;
long double time_since_last, transfer_rate, average_rate;
/* Quick safety check - state must exist. */
if (NULL == state)
/* Quick safety checks for null pointers. */
if (NULL == calc)
return;
if (NULL == transfer)
return;
if (NULL == control)
return;
if (NULL == display)
return;
bytes_since_last = 0;
if (state->transfer.transferred >= 0) {
bytes_since_last = state->transfer.transferred - state->calc.prev_transferred;
state->calc.prev_transferred = state->transfer.transferred;
if (transfer->transferred >= 0) {
bytes_since_last = transfer->transferred - calc->prev_transferred;
calc->prev_transferred = transfer->transferred;
}
/*
@@ -96,37 +106,37 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final)
* adding to that until a reasonable amount of time has passed to
* avoid rate spikes or division by zero.
*/
time_since_last = state->transfer.elapsed_seconds - state->calc.prev_elapsed_sec;
time_since_last = transfer->elapsed_seconds - calc->prev_elapsed_sec;
if (time_since_last <= 0.01) {
transfer_rate = state->calc.prev_rate;
state->calc.prev_trans += bytes_since_last;
transfer_rate = calc->prev_rate;
calc->prev_trans += bytes_since_last;
} else {
long double measured_rate;
transfer_rate = ((long double) bytes_since_last + state->calc.prev_trans) / time_since_last;
transfer_rate = ((long double) bytes_since_last + calc->prev_trans) / time_since_last;
measured_rate = transfer_rate;
state->calc.prev_elapsed_sec = state->transfer.elapsed_seconds;
state->calc.prev_trans = 0;
calc->prev_elapsed_sec = transfer->elapsed_seconds;
calc->prev_trans = 0;
if (state->control.bits)
if (control->bits)
measured_rate = 8.0 * measured_rate;
if ((state->calc.measurements_taken < 1) || (measured_rate < state->calc.rate_min)) {
state->calc.rate_min = measured_rate;
if ((calc->measurements_taken < 1) || (measured_rate < calc->rate_min)) {
calc->rate_min = measured_rate;
}
if (measured_rate > state->calc.rate_max) {
state->calc.rate_max = measured_rate;
if (measured_rate > calc->rate_max) {
calc->rate_max = measured_rate;
}
state->calc.rate_sum += measured_rate;
state->calc.ratesquared_sum += (measured_rate * measured_rate);
state->calc.measurements_taken++;
calc->rate_sum += measured_rate;
calc->ratesquared_sum += (measured_rate * measured_rate);
calc->measurements_taken++;
}
state->calc.prev_rate = transfer_rate;
calc->prev_rate = transfer_rate;
/* Update history and current average rate for ETA. */
pv__update_average_rate_history(state, transfer_rate);
average_rate = state->calc.current_avg_rate;
pv__update_average_rate_history(calc, transfer, control->history_interval, transfer_rate);
average_rate = calc->current_avg_rate;
/*
* If this is the final update at the end of the transfer, we
@@ -134,19 +144,20 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final)
* period of the transfer.
*/
if (final) {
long double total_elapsed_seconds = (long double) (transfer->elapsed_seconds);
/* Safety check to avoid division by zero. */
if (state->transfer.elapsed_seconds < 0.000001)
state->transfer.elapsed_seconds = 0.000001;
if (total_elapsed_seconds < 0.000001)
total_elapsed_seconds = 0.000001;
average_rate =
(((long double) (state->transfer.transferred)) -
((long double) state->display.initial_offset)) / (long double) (state->transfer.elapsed_seconds);
(((long double) (transfer->transferred)) -
((long double) display->initial_offset)) / total_elapsed_seconds;
transfer_rate = average_rate;
}
state->calc.transfer_rate = transfer_rate;
state->calc.average_rate = average_rate;
calc->transfer_rate = transfer_rate;
calc->average_rate = average_rate;
if (state->control.size <= 0) {
if (control->size <= 0) {
/*
* If we don't know the total size of the incoming data,
* then for a percentage, we gradually increase the
@@ -156,16 +167,16 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final)
* 0%-100%, 100%-0%, 0%-100%, and so on.
*/
if (transfer_rate > 0)
state->calc.percentage += 2;
if (state->calc.percentage > 199)
state->calc.percentage = 0;
calc->percentage += 2;
if (calc->percentage > 199)
calc->percentage = 0;
} else {
state->calc.percentage = pv_percentage(state->transfer.transferred, state->control.size);
calc->percentage = pv_percentage(transfer->transferred, control->size);
}
/* Ensure the percentage is never negative or huge. */
if (state->calc.percentage < 0.0)
state->calc.percentage = 0.0;
if (state->calc.percentage > 100000.0)
state->calc.percentage = 100000.0;
if (calc->percentage < 0.0)
calc->percentage = 0.0;
if (calc->percentage > 100000.0)
calc->percentage = 100000.0;
}
+146 -139
View File
@@ -47,24 +47,24 @@
* Create a per-euid, per-tty, lockfile in ${TMPDIR:-${TMP:-/tmp}} for the
* tty on the given file descriptor.
*/
static void pv_crs_open_lockfile(pvstate_t state, int fd)
static void pv_crs_open_lockfile(pvcursorstate_t cursor, readonly_pvcontrol_t control, int fd)
{
char *ttydev;
char *tmpdir;
int openflags;
state->cursor.lock_fd = -1;
cursor->lock_fd = -1;
ttydev = ttyname(fd);
if (!ttydev) {
if (!state->control.force) {
pv_error(state, "%s: %s", _("failed to get terminal name"), strerror(errno));
if (!control->force) {
pv_error("%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->control.cursor = 0;
cursor->disable = true;
debug("%s", "ttyname failed - cursor positioning disabled");
return;
}
@@ -80,8 +80,8 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
* $TMP are rejected, and the destination buffer is bounded.
*/
memset(state->cursor.lock_file, 0, PV_SIZEOF_CRS_LOCK_FILE);
(void) pv_snprintf(state->cursor.lock_file,
memset(cursor->lock_file, 0, PV_SIZEOF_CRS_LOCK_FILE);
(void) pv_snprintf(cursor->lock_file,
PV_SIZEOF_CRS_LOCK_FILE, "%s/pv-%s-%i.lock", tmpdir, basename(ttydev), (int) geteuid());
/*
@@ -93,7 +93,7 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
openflags = O_RDWR | O_CREAT;
#endif
state->cursor.lock_fd = open(state->cursor.lock_file, openflags, 0600); /* flawfinder: ignore */
cursor->lock_fd = open(cursor->lock_file, openflags, 0600); /* flawfinder: ignore */
/*
* flawfinder rationale: we aren't truncating the lock file, we
@@ -102,9 +102,9 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
* open() is as safe as we can make it.
*/
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;
if (cursor->lock_fd < 0) {
pv_error("%s: %s: %s", cursor->lock_file, _("failed to open lock file"), strerror(errno));
cursor->disable = true;
return;
}
}
@@ -114,14 +114,14 @@ static void pv_crs_open_lockfile(pvstate_t state, int fd)
* Lock the terminal on the given file descriptor, falling back to using a
* lockfile if the terminal itself cannot be locked.
*/
static void pv_crs_lock(pvstate_t state, int fd)
static void pv_crs_lock(pvcursorstate_t cursor, readonly_pvcontrol_t control, int fd)
{
struct flock lock;
int lock_fd;
lock_fd = fd;
if (state->cursor.lock_fd >= 0)
lock_fd = state->cursor.lock_fd;
if (cursor->lock_fd >= 0)
lock_fd = cursor->lock_fd;
memset(&lock, 0, sizeof(lock));
lock.l_type = (short) F_WRLCK;
@@ -130,20 +130,20 @@ 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->cursor.lock_fd == -2) {
pv_crs_open_lockfile(state, fd);
if (state->cursor.lock_fd >= 0) {
lock_fd = state->cursor.lock_fd;
if (cursor->lock_fd == -2) {
pv_crs_open_lockfile(cursor, control, fd);
if (cursor->lock_fd >= 0) {
lock_fd = cursor->lock_fd;
}
} else {
pv_error(state, "%s: %s", _("lock attempt failed"), strerror(errno));
pv_error("%s: %s", _("lock attempt failed"), strerror(errno));
return;
}
}
}
if (state->cursor.lock_fd >= 0) {
debug("%s: %s", state->cursor.lock_file, "terminal lockfile acquired");
if (cursor->lock_fd >= 0) {
debug("%s: %s", cursor->lock_file, "terminal lockfile acquired");
} else {
debug("%s", "terminal lock acquired");
}
@@ -154,14 +154,14 @@ static void pv_crs_lock(pvstate_t state, int fd)
* Unlock the terminal on the given file descriptor. If pv_crs_lock used
* lockfile locking, unlock the lockfile.
*/
static void pv_crs_unlock(pvstate_t state, int fd)
static void pv_crs_unlock(pvcursorstate_t cursor, int fd)
{
struct flock lock;
int lock_fd;
lock_fd = fd;
if (state->cursor.lock_fd >= 0)
lock_fd = state->cursor.lock_fd;
if (cursor->lock_fd >= 0)
lock_fd = cursor->lock_fd;
memset(&lock, 0, sizeof(lock));
lock.l_type = (short) F_UNLCK;
@@ -170,8 +170,8 @@ static void pv_crs_unlock(pvstate_t state, int fd)
lock.l_len = 1;
(void) fcntl(lock_fd, F_SETLK, &lock);
if (state->cursor.lock_fd >= 0) {
debug("%s: %s", state->cursor.lock_file, "terminal lockfile released");
if (cursor->lock_fd >= 0) {
debug("%s: %s", cursor->lock_file, "terminal lockfile released");
} else {
debug("%s", "terminal lock released");
}
@@ -185,20 +185,20 @@ static void pv_crs_unlock(pvstate_t state, int fd)
* cursor mode (including us), and store it in pv_crs_pvcount. If this is
* larger than pv_crs_pvmax, update pv_crs_pvmax.
*/
static void pv_crs_ipccount(pvstate_t state)
static void pv_crs_ipccount(pvcursorstate_t cursor)
{
struct shmid_ds buf;
memset(&buf, 0, sizeof(buf));
buf.shm_nattch = 0;
(void) shmctl(state->cursor.shmid, IPC_STAT, &buf);
state->cursor.pvcount = (int) (buf.shm_nattch);
(void) shmctl(cursor->shmid, IPC_STAT, &buf);
cursor->pvcount = (int) (buf.shm_nattch);
if (state->cursor.pvcount > state->cursor.pvmax)
state->cursor.pvmax = state->cursor.pvcount;
if (cursor->pvcount > cursor->pvmax)
cursor->pvmax = cursor->pvcount;
debug("%s: %d", "pvcount", state->cursor.pvcount);
debug("%s: %d", "pvcount", cursor->pvcount);
}
#endif /* HAVE_IPC */
@@ -294,7 +294,7 @@ static int pv_crs_get_ypos(int terminalfd)
* count" of one, and so no initialisation occurs. So, we lock the terminal
* with pv_crs_lock() while we are attaching and checking.
*/
static int pv_crs_ipcinit(pvstate_t state, char *ttyfile, int terminalfd)
static int pv_crs_ipcinit(pvcursorstate_t cursor, readonly_pvcontrol_t control, char *ttyfile, int terminalfd)
{
key_t key;
@@ -309,25 +309,25 @@ static int pv_crs_ipcinit(pvstate_t state, char *ttyfile, int terminalfd)
return 1;
}
pv_crs_lock(state, terminalfd);
if (!state->control.cursor) {
pv_crs_lock(cursor, control, terminalfd);
if ((!control->cursor) || (cursor->disable)) {
debug("%s", "early return - cursor has been disabled");
return 1;
}
state->cursor.shmid = shmget(key, sizeof(struct pvcursorstate_s), 0600 | IPC_CREAT);
if (state->cursor.shmid < 0) {
cursor->shmid = shmget(key, sizeof(struct pvipccursorstate_s), 0600 | IPC_CREAT);
if (cursor->shmid < 0) {
debug("%s: %s", "shmget failed", strerror(errno));
pv_crs_unlock(state, terminalfd);
pv_crs_unlock(cursor, terminalfd);
return 1;
}
/*@-nullpass@ */
/* splint doesn't know shmaddr can be NULL */
state->cursor.shared = shmat(state->cursor.shmid, NULL, 0);
cursor->shared = shmat(cursor->shmid, NULL, 0);
/*@+nullpass@ */
pv_crs_ipccount(state);
pv_crs_ipccount(cursor);
/*
* If nobody else is attached to the shared memory segment, we're
@@ -335,29 +335,29 @@ 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->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;
if (cursor->pvcount < 2) {
cursor->y_start = pv_crs_get_ypos(terminalfd);
cursor->shared->y_topmost = cursor->y_start;
cursor->shared->tty_tostop_added = false;
cursor->y_lastread = cursor->y_start;
debug("%s", "we are the first to attach");
}
state->cursor.y_offset = state->cursor.pvcount - 1;
if (state->cursor.y_offset < 0)
state->cursor.y_offset = 0;
cursor->y_offset = cursor->pvcount - 1;
if (cursor->y_offset < 0)
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->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);
if (cursor->pvcount > 1) {
cursor->y_start = cursor->shared->y_topmost;
cursor->y_lastread = cursor->y_start;
debug("%s: %d", "not the first to attach - got top y", cursor->y_start);
}
pv_crs_unlock(state, terminalfd);
pv_crs_unlock(cursor, terminalfd);
return 0;
}
@@ -367,15 +367,15 @@ static int pv_crs_ipcinit(pvstate_t state, char *ttyfile, int terminalfd)
/*
* Initialise the terminal for cursor positioning.
*/
void pv_crs_init(pvstate_t state)
void pv_crs_init(pvcursorstate_t cursor, readonly_pvcontrol_t control, pvtransientflags_t flags)
{
char *ttyfile;
int terminalfd;
state->cursor.lock_fd = -2;
state->cursor.lock_file[0] = '\0';
cursor->lock_fd = -2;
cursor->lock_file[0] = '\0';
if (!state->control.cursor)
if ((!control->cursor) || (cursor->disable))
return;
debug("%s", "init");
@@ -383,7 +383,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->control.cursor = false;
cursor->disable = true;
return;
}
@@ -397,23 +397,23 @@ void pv_crs_init(pvstate_t state)
*/
if (terminalfd < 0) {
pv_error(state, "%s: %s: %s", _("failed to open terminal"), ttyfile, strerror(errno));
state->control.cursor = false;
pv_error("%s: %s: %s", _("failed to open terminal"), ttyfile, strerror(errno));
cursor->disable = true;
return;
}
#ifdef HAVE_IPC
if (pv_crs_ipcinit(state, ttyfile, terminalfd) != 0) {
if (pv_crs_ipcinit(cursor, control, ttyfile, terminalfd) != 0) {
debug("%s", "ipcinit failed, setting noipc flag");
state->cursor.noipc = true;
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->cursor.noipc) && (1 == state->flag.clear_tty_tostop_on_exit) && (NULL != state->cursor.shared)) {
if ((!cursor->noipc) && (1 == flags->clear_tty_tostop_on_exit) && (NULL != cursor->shared)) {
debug("%s", "propagating local clear_tty_tostop_on_exit true value to shared tty_tostop_added flag");
state->cursor.shared->tty_tostop_added = true;
cursor->shared->tty_tostop_added = true;
}
/*
@@ -421,26 +421,26 @@ 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->cursor.noipc) {
if (cursor->noipc) {
#else /* ! HAVE_IPC */
if (1) {
#endif /* HAVE_IPC */
/*
* Get current cursor position + 1.
*/
pv_crs_lock(state, terminalfd);
state->cursor.y_start = pv_crs_get_ypos(terminalfd);
pv_crs_lock(cursor, control, terminalfd);
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->cursor.y_start > 0)
pv_tty_write(state, "\n", 1);
pv_crs_unlock(state, terminalfd);
if (cursor->y_start > 0)
pv_tty_write(flags, "\n", 1);
pv_crs_unlock(cursor, terminalfd);
if (state->cursor.y_start < 1)
state->control.cursor = 0;
if (cursor->y_start < 1)
cursor->disable = true;
}
(void) close(terminalfd);
@@ -451,11 +451,11 @@ void pv_crs_init(pvstate_t state)
/*
* Set the "we need to reinitialise cursor positioning" flag.
*/
void pv_crs_needreinit(pvstate_t state)
void pv_crs_needreinit(pvcursorstate_t cursor)
{
state->cursor.needreinit += 2;
if (state->cursor.needreinit > 3)
state->cursor.needreinit = 3;
cursor->needreinit += 2;
if (cursor->needreinit > 3)
cursor->needreinit = 3;
}
#endif
@@ -465,36 +465,36 @@ void pv_crs_needreinit(pvstate_t state)
* Reinitialise the cursor positioning code (called if we are backgrounded
* then foregrounded again).
*/
static void pv_crs_reinit(pvstate_t state)
static void pv_crs_reinit(pvcursorstate_t cursor, readonly_pvcontrol_t control, pvtransientflags_t flags)
{
debug("%s", "reinit");
if (1 == state->flag.suspend_stderr) {
if (1 == flags->suspend_stderr) {
debug("%s", "reinit abandoned - stderr is suspended");
return;
}
pv_crs_lock(state, STDERR_FILENO);
pv_crs_lock(cursor, control, STDERR_FILENO);
state->cursor.needreinit--;
if (state->cursor.y_offset < 1)
state->cursor.needreinit = 0;
cursor->needreinit--;
if (cursor->y_offset < 1)
cursor->needreinit = 0;
if (state->cursor.needreinit > 0) {
pv_crs_unlock(state, STDERR_FILENO);
if (cursor->needreinit > 0) {
pv_crs_unlock(cursor, STDERR_FILENO);
return;
}
debug("%s", "reinit full");
state->cursor.y_start = pv_crs_get_ypos(STDERR_FILENO);
cursor->y_start = pv_crs_get_ypos(STDERR_FILENO);
if ((state->cursor.y_offset < 1) && (NULL != state->cursor.shared)) {
state->cursor.shared->y_topmost = state->cursor.y_start;
if ((cursor->y_offset < 1) && (NULL != cursor->shared)) {
cursor->shared->y_topmost = cursor->y_start;
}
state->cursor.y_lastread = state->cursor.y_start;
cursor->y_lastread = cursor->y_start;
pv_crs_unlock(state, STDERR_FILENO);
pv_crs_unlock(cursor, STDERR_FILENO);
}
#endif
@@ -503,12 +503,17 @@ static void pv_crs_reinit(pvstate_t state)
* Output a single-line update (\0-terminated), using the ECMA-48 CSI "CUP"
* sequence to move the cursor to the correct position to do so.
*/
void pv_crs_update(pvstate_t state, const char *output_line)
void pv_crs_update(pvcursorstate_t cursor, readonly_pvcontrol_t control, pvtransientflags_t flags,
const char *output_line)
{
char cup_cmd[32]; /* flawfinder: ignore */
size_t cup_cmd_length, output_line_length;
int y;
/* Early return if cursor positioning was disabled. */
if (cursor->disable)
return;
/*
* flawfinder rationale: the "cup_cmd" buffer is always zeroed
* before each use, and is only written to by pv_snprintf() bounded
@@ -520,24 +525,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->cursor.noipc) {
if (state->cursor.needreinit > 0)
pv_crs_reinit(state);
if (!cursor->noipc) {
if (cursor->needreinit > 0)
pv_crs_reinit(cursor, control, flags);
pv_crs_ipccount(state);
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;
pv_crs_ipccount(cursor);
if (NULL != cursor->shared) {
if (cursor->y_lastread != cursor->shared->y_topmost) {
cursor->y_start = cursor->shared->y_topmost;
cursor->y_lastread = cursor->y_start;
}
}
if (state->cursor.needreinit > 0)
if (cursor->needreinit > 0)
return;
}
#endif /* HAVE_IPC */
y = state->cursor.y_start;
y = cursor->y_start;
#ifdef HAVE_IPC
/*
@@ -546,41 +551,41 @@ 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->cursor.y_start + state->cursor.pvmax) > (int) (state->control.height))
&& (!state->cursor.noipc)
if (((cursor->y_start + cursor->pvmax) > (int) (control->height))
&& (!cursor->noipc)
) {
int offs;
offs = ((state->cursor.y_start + state->cursor.pvmax) - state->control.height);
offs = ((cursor->y_start + cursor->pvmax) - control->height);
state->cursor.y_start -= offs;
if (state->cursor.y_start < 1)
state->cursor.y_start = 1;
cursor->y_start -= offs;
if (cursor->y_start < 1)
cursor->y_start = 1;
debug("%s: %d", "scroll offset", offs);
/*
* Scroll the screen if we're the first `pv'.
*/
if (0 == state->cursor.y_offset) {
pv_crs_lock(state, STDERR_FILENO);
if (0 == cursor->y_offset) {
pv_crs_lock(cursor, control, STDERR_FILENO);
memset(cup_cmd, 0, sizeof(cup_cmd));
(void) pv_snprintf(cup_cmd, sizeof(cup_cmd), "\033[%u;1H", state->control.height);
(void) pv_snprintf(cup_cmd, sizeof(cup_cmd), "\033[%u;1H", control->height);
cup_cmd_length = strlen(cup_cmd); /* flawfinder: ignore */
pv_tty_write(state, cup_cmd, cup_cmd_length);
pv_tty_write(flags, cup_cmd, cup_cmd_length);
for (; offs > 0; offs--) {
pv_tty_write(state, "\n", 1);
pv_tty_write(flags, "\n", 1);
}
pv_crs_unlock(state, STDERR_FILENO);
pv_crs_unlock(cursor, STDERR_FILENO);
debug("%s", "we are the first - scrolled screen");
}
}
if (!state->cursor.noipc)
y = state->cursor.y_start + state->cursor.y_offset;
if (!cursor->noipc)
y = cursor->y_start + cursor->y_offset;
#endif /* HAVE_IPC */
/*
@@ -601,19 +606,19 @@ void pv_crs_update(pvstate_t state, const char *output_line)
* pv_snprintf() fails to run the string will be of zero length.
*/
pv_crs_lock(state, STDERR_FILENO);
pv_crs_lock(cursor, control, STDERR_FILENO);
pv_tty_write(state, cup_cmd, cup_cmd_length);
pv_tty_write(state, output_line, output_line_length);
pv_tty_write(flags, cup_cmd, cup_cmd_length);
pv_tty_write(flags, output_line, output_line_length);
pv_crs_unlock(state, STDERR_FILENO);
pv_crs_unlock(cursor, STDERR_FILENO);
}
/*
* Reposition the cursor to a final position.
*/
void pv_crs_fini(pvstate_t state)
void pv_crs_fini(pvcursorstate_t cursor, readonly_pvcontrol_t control, pvtransientflags_t flags)
{
char cup_cmd[32]; /* flawfinder: ignore */
unsigned int y;
@@ -622,15 +627,15 @@ void pv_crs_fini(pvstate_t state)
debug("%s", "fini");
y = (unsigned int) (state->cursor.y_start);
y = (unsigned int) (cursor->y_start);
#ifdef HAVE_IPC
if ((state->cursor.pvmax > 0) && (!state->cursor.noipc))
y += state->cursor.pvmax - 1;
if ((cursor->pvmax > 0) && (!cursor->noipc))
y += cursor->pvmax - 1;
#endif /* HAVE_IPC */
if (y > state->control.height)
y = state->control.height;
if (y > control->height)
y = control->height;
/*
* Absolute bounds check.
@@ -641,9 +646,11 @@ void pv_crs_fini(pvstate_t state)
memset(cup_cmd, 0, sizeof(cup_cmd));
(void) pv_snprintf(cup_cmd, sizeof(cup_cmd), "\033[%u;1H\n", y);
pv_crs_lock(state, STDERR_FILENO);
pv_crs_lock(cursor, control, STDERR_FILENO);
pv_tty_write(state, cup_cmd, strlen(cup_cmd)); /* flawfinder: ignore */
if (!cursor->disable) {
pv_tty_write(flags, cup_cmd, strlen(cup_cmd)); /* flawfinder: ignore */
}
/* flawfinder - pv_snprintf() always \0-terminates (see above). */
#ifdef HAVE_IPC
@@ -652,40 +659,40 @@ void pv_crs_fini(pvstate_t state)
* attribute, set our local flag so pv_sig_fini() will know about
* it.
*/
if ((!state->cursor.noipc) && (NULL != state->cursor.shared) && state->cursor.shared->tty_tostop_added) {
if (0 == state->flag.clear_tty_tostop_on_exit) {
if ((!cursor->noipc) && (NULL != cursor->shared) && cursor->shared->tty_tostop_added) {
if (0 == flags->clear_tty_tostop_on_exit) {
debug("%s",
"propagating shared tty_tostop_added true value to local clear_tty_tostop_on_exit flag");
state->flag.clear_tty_tostop_on_exit = 1;
flags->clear_tty_tostop_on_exit = 1;
}
}
pv_crs_ipccount(state);
if (NULL != state->cursor.shared) {
(void) shmdt(state->cursor.shared);
pv_crs_ipccount(cursor);
if (NULL != cursor->shared) {
(void) shmdt(cursor->shared);
}
state->cursor.shared = NULL;
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->cursor.pvcount < 2) {
if (cursor->pvcount < 2) {
struct shmid_ds shm_buf;
memset(&shm_buf, 0, sizeof(shm_buf));
(void) shmctl(state->cursor.shmid, IPC_RMID, &shm_buf);
(void) shmctl(cursor->shmid, IPC_RMID, &shm_buf);
}
#endif /* HAVE_IPC */
pv_crs_unlock(state, STDERR_FILENO);
pv_crs_unlock(cursor, STDERR_FILENO);
if (state->cursor.lock_fd >= 0) {
(void) close(state->cursor.lock_fd);
if (cursor->lock_fd >= 0) {
(void) close(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->cursor.lock_file);
(void) remove(cursor->lock_file);
}
}
+166 -82
View File
@@ -49,17 +49,53 @@
#include <sys/ioctl.h>
#endif
/*
* The error prefix for messages (the program name); whether it has been
* set; and whether any output has been displayed yet, indicating whether
* any errors must be preceded by a newline.
*/
static char pv__error_prefix[64]; /* flawfinder: ignore */
static bool pv__error_prefix_set = false;
static bool pv__output_produced = false;
/*
* flawfinder rationale: zeroed before use, string copy is bounded to 1 less
* than size so it always has \0 termination. Not used unless initialised,
* by checking pv__error_prefix_set.
*/
/*
* Set the error message prefix.
*/
void pv_set_error_prefix( /*@unique@ */ const char *prefix)
{
if (NULL == prefix)
return;
memset(pv__error_prefix, 0, sizeof(pv__error_prefix));
strncpy(pv__error_prefix, prefix, sizeof(pv__error_prefix) - 1); /* flawfinder: ignore */
pv__error_prefix_set = true;
/*
* flawfinder rationale: strncpy's pointers are as valid as we can
* make them since the first is a static buffer and the second is
* caller-supplied. The caller must \0-terminate the string but in
* any case it is bounded to 1 less than the size of the
* destination. The destination is zeroed before use so the result
* is guaranteed to be \0-terminated.
*/
}
/*
* Output an error message. If we've displayed anything to the terminal
* already, then put a newline before our error so we don't write over what
* we've written.
*/
void pv_error(pvstate_t state, char *format, ...)
void pv_error(char *format, ...)
{
va_list ap;
if (state->display.display_visible)
if (pv__output_produced)
fprintf(stderr, "\n");
fprintf(stderr, "%s: ", state->status.program_name);
if (pv__error_prefix_set)
fprintf(stderr, "%s: ", pv__error_prefix);
va_start(ap, format);
(void) vfprintf(stderr, format, ap); /* flawfinder: ignore */
va_end(ap);
@@ -140,9 +176,9 @@ void pv_write_retry(int fd, const char *buf, size_t count)
* Write the given buffer to the terminal, like pv_write_retry(), unless
* stderr is suspended.
*/
void pv_tty_write(pvstate_t state, const char *buf, size_t count)
void pv_tty_write(readonly_pvtransientflags_t flags, const char *buf, size_t count)
{
while (0 == state->flag.suspend_stderr && count > 0) {
while (0 == flags->suspend_stderr && count > 0) {
ssize_t nwritten;
nwritten = write(STDERR_FILENO, buf, count);
@@ -553,15 +589,26 @@ char *pv_format_sequences(void)
/*
* Initialise the output format structure, based on the current options.
*
* May update status->checked_colour_support and
* status->terminal_supports_colour.
*/
static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supplied, pvdisplay_t display)
static void pv__format_init(pvprogramstatus_t status, readonly_pvcontrol_t control, readonly_pvtransferstate_t transfer,
readonly_pvtransfercalc_t calc,
/*@null@ */ const char *format_supplied, pvdisplay_t display)
{
struct pvdisplay_component_s *format_component_array;
const char *display_format;
size_t strpos;
size_t segment;
if (NULL == state)
if (NULL == status)
return;
if (NULL == control)
return;
if (NULL == transfer)
return;
if (NULL == calc)
return;
if (NULL == display)
return;
@@ -578,7 +625,7 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
display->showing_previous_line = false;
display->format_uses_colour = false;
display_format = NULL == format_supplied ? state->control.default_format : format_supplied;
display_format = NULL == format_supplied ? control->default_format : format_supplied;
if (NULL == display_format)
return;
@@ -779,9 +826,12 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
memset(&formatter_info, 0, sizeof(formatter_info));
dummy_buffer[0] = '\0';
formatter_info.state = state;
formatter_info.display = display;
formatter_info.segment = &(display->format[segment]);
formatter_info.status = status;
formatter_info.control = control;
formatter_info.transfer = transfer;
formatter_info.calc = calc;
formatter_info.buffer = dummy_buffer;
formatter_info.buffer_size = 0;
formatter_info.offset = 0;
@@ -801,16 +851,16 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
display->format_segment_count++;
}
if (display->format_uses_colour && !state->control.checked_colour_support) {
state->control.checked_colour_support = true;
if (display->format_uses_colour && !status->checked_colour_support) {
status->checked_colour_support = true;
#ifdef ENABLE_NCURSES
/*
* If we have terminal info support, check whether the
* current terminal supports colour - or just assume it's
* supported if we're forcing output.
*/
if (true == state->control.force) {
state->control.can_display_colour = true;
if (true == control->force) {
status->terminal_supports_colour = true;
debug("%s", "force mode - assuming terminal supports colour");
} else {
char *term_env = NULL;
@@ -820,22 +870,22 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
* flawfinder - here we pass responsibility to the
* ncurses library to behave OK with $TERM.
*/
state->control.can_display_colour = false;
status->terminal_supports_colour = false;
if (NULL != term_env) {
int setup_err = 0;
if ((0 == setupterm(term_env, STDERR_FILENO, &setup_err))
&& (tigetnum("colors") > 1)
) {
state->control.can_display_colour = true;
status->terminal_supports_colour = true;
debug("%s: %s", term_env, "terminal supports colour");
} else {
state->control.can_display_colour = false;
status->terminal_supports_colour = false;
debug("%s: %s", term_env, "terminal does not support colour");
}
} else {
/* If TERM is unset, disable colour. */
state->control.can_display_colour = false;
status->terminal_supports_colour = false;
debug("%s", "no TERM variable - disabling colour support");
}
}
@@ -846,8 +896,8 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
* to determine whether colour is available, unless --force
* was supplied, in which case colour support is assumed.
*/
if (true == state->control.force) {
state->control.can_display_colour = true;
if (true == control->force) {
status->terminal_supports_colour = true;
debug("%s", "force mode - assuming terminal supports colour");
} else {
FILE *command_fptr;
@@ -863,21 +913,21 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
*/
if (NULL == command_fptr) {
state->control.can_display_colour = false;
status->terminal_supports_colour = false;
debug("%s (%s)", "popen failed - disabling colour support", strerror(errno));
} else {
int colour_count;
if (1 == fscanf(command_fptr, "%d", &colour_count)) {
if (colour_count > 1) {
state->control.can_display_colour = true;
status->terminal_supports_colour = true;
debug("%s (%d)", "terminal supports colour", colour_count);
} else {
state->control.can_display_colour = false;
status->terminal_supports_colour = false;
debug("%s (%d)",
"fewer than 2 colours available - disabling colour support");
}
} else {
state->control.can_display_colour = false;
status->terminal_supports_colour = false;
debug("%s", "tput did not produce a number - disabling colour support");
}
/*@-unrecog@ *//* splint doesn't know pclose(). */
@@ -890,7 +940,7 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
* Without terminal info support, just assume colour is
* available.
*/
state->control.can_display_colour = true;
status->terminal_supports_colour = true;
debug("%s", "terminal info support not compiled in - assuming colour support");
#endif /* (! ENABLE_NCURSES) && (! USE_POPEN_TPUTS) */
#endif /* ! ENABLE_NCURSES */
@@ -900,7 +950,7 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
/*
* Update display->display_buffer with status information formatted
* according to the state held within the given structure.
* according to the state held within the given structures.
*
* If "reinitialise" is true, the format string is reparsed first. This
* should be true for the first call, and true whenever the format is
@@ -914,9 +964,14 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp
* When returning true, this function will have also set
* display->display_string_len to the length of the string in
* display->display_buffer, in bytes.
*
* Updates status->exit_status if buffer allocation fails.
*
* See pv__format_init for the adjustments that may be made to "status".
*/
bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdisplay_t display, bool reinitialise,
bool final)
bool pv_format(pvprogramstatus_t status, readonly_pvcontrol_t control, readonly_pvtransferstate_t transfer,
readonly_pvtransfercalc_t calc, /*@null@ */ const char *format_supplied, pvdisplay_t display,
bool reinitialise, bool final)
{
struct pvdisplay_component_s *format_component_array;
char display_segments[PV_SIZEOF_FORMAT_SEGMENTS_BUF]; /* flawfinder: ignore - always bounded */
@@ -930,17 +985,26 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
memset(&formatter_info, 0, sizeof(formatter_info));
display_segments[0] = '\0';
/* Quick safety check - state and display must exist. */
if (NULL == state)
/* Quick safety check for null pointers. */
if (NULL == status)
return false;
if (NULL == control)
return false;
if (NULL == transfer)
return false;
if (NULL == calc)
return false;
if (NULL == display)
return false;
formatter_info.state = state;
formatter_info.display = display;
formatter_info.buffer = display_segments;
formatter_info.buffer_size = sizeof(display_segments);
formatter_info.offset = 0;
formatter_info.status = status;
formatter_info.control = control;
formatter_info.transfer = transfer;
formatter_info.calc = calc;
format_component_array = pv__format_components();
@@ -949,24 +1013,24 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
/* Reinitialise if we were asked to. */
if (reinitialise)
pv__format_init(state, format_supplied, display);
pv__format_init(status, control, transfer, calc, format_supplied, display);
/* The format string is needed for the static segments. */
display_format = NULL == format_supplied ? state->control.default_format : format_supplied;
display_format = NULL == format_supplied ? control->default_format : format_supplied;
if (NULL == display_format)
return false;
/* Determine the type of thing being counted for transfer, rate, etc. */
display->count_type = PV_TRANSFERCOUNT_BYTES;
if (state->control.linemode)
if (control->linemode)
display->count_type = PV_TRANSFERCOUNT_LINES;
else if (state->control.decimal_units)
else if (control->decimal_units)
display->count_type = PV_TRANSFERCOUNT_DECBYTES;
/*
* Reallocate the output buffer if the display width changes.
*/
if (display->display_buffer != NULL && display->display_buffer_size < (size_t) ((state->control.width * 4))) {
if (display->display_buffer != NULL && display->display_buffer_size < (size_t) ((control->width * 4))) {
free(display->display_buffer);
display->display_buffer = NULL;
display->display_buffer_size = 0;
@@ -979,15 +1043,15 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
char *new_buffer;
size_t new_size;
new_size = (size_t) ((4 * state->control.width) + 80);
if (NULL != state->control.name)
new_size += strlen(state->control.name); /* flawfinder: ignore */
new_size = (size_t) ((4 * control->width) + 80);
if (NULL != control->name)
new_size += strlen(control->name); /* flawfinder: ignore */
/* flawfinder: name is always set by pv_strdup(), which bounds with a \0. */
new_buffer = malloc(new_size + 16);
if (NULL == new_buffer) {
pv_error(state, "%s: %s", _("buffer allocation failed"), strerror(errno));
state->status.exit_status |= PV_ERROREXIT_MEMORY;
pv_error("%s: %s", _("buffer allocation failed"), strerror(errno));
status->exit_status |= PV_ERROREXIT_MEMORY;
display->display_buffer = NULL;
return false;
}
@@ -1054,8 +1118,8 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
*/
dynamic_segment_width = 0;
if (state->control.width > static_portion_width)
dynamic_segment_width = state->control.width - static_portion_width;
if (control->width > static_portion_width)
dynamic_segment_width = control->width - static_portion_width;
/*
* Divide the total remaining screen space by the number of dynamic
@@ -1064,8 +1128,8 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
if (dynamic_segment_count > 1)
dynamic_segment_width /= dynamic_segment_count;
debug("control.width=%d static_portion_width=%d dynamic_segment_width=%d dynamic_segment_count=%d",
state->control.width, static_portion_width, dynamic_segment_width, dynamic_segment_count);
debug("control->width=%d static_portion_width=%d dynamic_segment_width=%d dynamic_segment_count=%d",
control->width, static_portion_width, dynamic_segment_width, dynamic_segment_count);
for (segment_idx = 0; segment_idx < display->format_segment_count; segment_idx++) {
pvdisplay_segment_t segment;
@@ -1153,7 +1217,7 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
* spaces at the end, so that we don't leave dangling bits behind.
*/
if ((new_display_string_width < display->display_string_width)
&& (state->control.width >= display->prev_screen_width)) {
&& (control->width >= display->prev_screen_width)) {
char spaces[32]; /* flawfinder: ignore - terminated, bounded */
int spaces_to_add;
@@ -1173,7 +1237,7 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
display->display_string_bytes = new_display_string_bytes;
display->display_string_width = new_display_string_width;
display->prev_screen_width = state->control.width;
display->prev_screen_width = control->width;
return true;
}
@@ -1185,78 +1249,98 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl
* If "final" is true, this is the final update, so the rate is given as an
* an average over the whole transfer; otherwise the current rate is shown.
*/
void pv_display(pvstate_t state, bool final)
void pv_display(pvprogramstatus_t status, readonly_pvcontrol_t control, pvtransientflags_t flags,
readonly_pvtransferstate_t transfer, pvtransfercalc_t calc, pvcursorstate_t cursor, pvdisplay_t display,
/*@null@ */ pvdisplay_t extra_display, bool final)
{
bool reinitialise = false;
if (NULL == state)
if (NULL == status)
return;
if (NULL == control)
return;
if (NULL == flags)
return;
if (NULL == transfer)
return;
if (NULL == calc)
return;
if (NULL == cursor)
return;
if (NULL == display)
return;
pv_sig_checkbg();
pv_calculate_transfer_rate(state, final);
pv_calculate_transfer_rate(calc, transfer, control, display, final);
/*
* Enable colour on the main display, and disable it on the extra
* display (process title, window title).
*/
state->display.colour_permitted = true;
state->extra_display.colour_permitted = false;
display->colour_permitted = true;
if (NULL != extra_display)
extra_display->colour_permitted = false;
/*
* If the display options need reparsing, do so to generate new
* formatting parameters.
*/
if (0 != state->flag.reparse_display) {
if (0 != flags->reparse_display) {
reinitialise = true;
state->flag.reparse_display = 0;
flags->reparse_display = 0;
}
if (!pv_format(state, state->control.format_string, &(state->display), reinitialise, final))
if (!pv_format(status, control, transfer, calc, control->format_string, display, reinitialise, final))
return;
if (0 != state->control.extra_displays) {
if (!pv_format(state, state->control.extra_format_string, &(state->extra_display), reinitialise, final))
if ((NULL != extra_display) && (0 != control->extra_displays)) {
if (!pv_format
(status, control, transfer, calc, control->extra_format_string, extra_display, reinitialise, final))
return;
}
if (NULL == state->display.display_buffer)
if (NULL == display->display_buffer)
return;
if (state->control.numeric) {
pv_tty_write(state, state->display.display_buffer, state->display.display_string_bytes);
pv_tty_write(state, "\n", 1);
} else if (state->control.cursor) {
if (state->control.force || pv_in_foreground()) {
pv_crs_update(state, state->display.display_buffer);
state->display.display_visible = true;
if (control->numeric) {
pv_tty_write(flags, display->display_buffer, display->display_string_bytes);
pv_tty_write(flags, "\n", 1);
} else if (control->cursor) {
if (control->force || pv_in_foreground()) {
pv_crs_update(cursor, control, flags, display->display_buffer);
display->output_produced = true;
pv__output_produced = true;
}
} else {
if (state->control.force || pv_in_foreground()) {
pv_tty_write(state, state->display.display_buffer, state->display.display_string_bytes);
pv_tty_write(state, "\r", 1);
state->display.display_visible = true;
if (control->force || pv_in_foreground()) {
pv_tty_write(flags, display->display_buffer, display->display_string_bytes);
pv_tty_write(flags, "\r", 1);
display->output_produced = true;
pv__output_produced = true;
}
}
debug("%s: [%s]", "display", state->display.display_buffer);
debug("%s: [%s]", "display", display->display_buffer);
if ((0 != (PV_DISPLAY_WINDOWTITLE & state->control.extra_displays))
&& (state->control.force || pv_in_foreground())
&& (NULL != state->extra_display.display_buffer)
if ((0 != (PV_DISPLAY_WINDOWTITLE & control->extra_displays))
&& (control->force || pv_in_foreground())
&& (NULL != extra_display)
&& (NULL != extra_display->display_buffer)
) {
pv_tty_write(state, "\033]2;", 4);
pv_tty_write(state, state->extra_display.display_buffer, state->extra_display.display_string_bytes);
pv_tty_write(state, "\033\\", 2);
state->extra_display.display_visible = true;
debug("%s: [%s]", "windowtitle display", state->extra_display.display_buffer);
pv_tty_write(flags, "\033]2;", 4);
pv_tty_write(flags, extra_display->display_buffer, extra_display->display_string_bytes);
pv_tty_write(flags, "\033\\", 2);
extra_display->output_produced = true;
debug("%s: [%s]", "windowtitle display", extra_display->display_buffer);
}
if ((0 != (PV_DISPLAY_PROCESSTITLE & state->control.extra_displays))
&& (NULL != state->extra_display.display_buffer)
if ((0 != (PV_DISPLAY_PROCESSTITLE & control->extra_displays))
&& (NULL != extra_display)
&& (NULL != extra_display->display_buffer)
) {
setproctitle("%s", state->extra_display.display_buffer);
state->extra_display.display_visible = true;
debug("%s: [%s]", "processtitle display", state->extra_display.display_buffer);
setproctitle("%s", extra_display->display_buffer);
extra_display->output_produced = true;
debug("%s: [%s]", "processtitle display", extra_display->display_buffer);
}
}
+30 -13
View File
@@ -54,6 +54,10 @@ static off_t pv_calc_total_bytes(pvstate_t state)
for (file_idx = 0; file_idx < state->files.file_count; file_idx++) {
int rc;
/* Skip any NULL entries, though they should be impossible. */
if (NULL == state->files.filename[file_idx])
continue;
if (0 == strcmp(state->files.filename[file_idx], "-")) {
rc = fstat(STDIN_FILENO, &sb);
if (rc != 0) {
@@ -144,7 +148,7 @@ static off_t pv_calc_total_bytes(pvstate_t state)
total = end_position;
}
if (lseek(state->control.output_fd, 0, SEEK_SET) != 0) {
pv_error(state, "%s: %s: %s",
pv_error("%s: %s: %s",
NULL == state->control.output_name ? "(null)" : state->control.output_name,
_("failed to seek to start of output"), strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
@@ -187,6 +191,10 @@ static off_t pv_calc_total_lines(pvstate_t state)
int fd = -1;
int rc = 0;
/* Skip any NULL entries, though they should be impossible. */
if (NULL == state->files.filename[file_idx])
continue;
if (0 == strcmp(state->files.filename[file_idx], "-")) {
rc = fstat(STDIN_FILENO, &sb);
if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
@@ -228,7 +236,7 @@ static off_t pv_calc_total_lines(pvstate_t state)
* OK.
*/
if (numread < 0) {
pv_error(state, "%s: %s", state->files.filename[file_idx], strerror(errno));
pv_error("%s: %s", state->files.filename[file_idx], strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
break;
} else if (0 == numread) {
@@ -246,7 +254,7 @@ static off_t pv_calc_total_lines(pvstate_t state)
}
if (0 != lseek(fd, 0, SEEK_SET)) {
pv_error(state, "%s: %s", state->files.filename[file_idx], strerror(errno));
pv_error("%s: %s", state->files.filename[file_idx], strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
}
@@ -288,10 +296,11 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
struct stat osb;
int fd;
bool input_file_is_output;
char *next_filename;
if (oldfd >= 0) {
if (0 != close(oldfd)) {
pv_error(state, "%s: %s", _("failed to close file"), strerror(errno));
pv_error("%s: %s", _("failed to close file"), strerror(errno));
state->status.exit_status |= PV_ERROREXIT_TRANSITION;
return -1;
}
@@ -303,33 +312,42 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
return -1;
}
if ((NULL == state->files.filename) || (0 == strcmp(state->files.filename[filenum], "-"))) {
next_filename = NULL;
if (NULL != state->files.filename) {
next_filename = state->files.filename[filenum];
if (NULL == next_filename) {
debug("%s: @%d, max %d", "unexpected null filename", filenum, state->files.file_count);
state->status.exit_status |= PV_ERROREXIT_TRANSITION;
return -1;
}
}
if ((NULL == next_filename) || (0 == strcmp(next_filename, "-"))) {
fd = STDIN_FILENO;
} else {
fd = open(state->files.filename[filenum], O_RDONLY); /* flawfinder: ignore */
fd = open(next_filename, 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
* to open symlinks etc as that would be counterintuitive.
*/
if (fd < 0) {
pv_error(state, "%s: %s: %s",
_("failed to read file"), state->files.filename[filenum], strerror(errno));
pv_error("%s: %s: %s", _("failed to read file"), next_filename, strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
return -1;
}
}
if (0 != fstat(fd, &isb)) {
pv_error(state, "%s: %s: %s", _("failed to stat file"),
NULL == state->files.filename ? "-" : state->files.filename[filenum], strerror(errno));
pv_error("%s: %s: %s", _("failed to stat file"),
NULL == next_filename ? "-" : next_filename, strerror(errno));
(void) close(fd);
state->status.exit_status |= PV_ERROREXIT_ACCESS;
return -1;
}
if (0 != fstat(state->control.output_fd, &osb)) {
pv_error(state, "%s: %s", _("failed to stat output file"), strerror(errno));
pv_error("%s: %s", _("failed to stat output file"), strerror(errno));
(void) close(fd);
state->status.exit_status |= PV_ERROREXIT_ACCESS;
return -1;
@@ -351,8 +369,7 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd)
input_file_is_output = false;
if (input_file_is_output) {
pv_error(state, "%s: %s", _("input file is output file"),
NULL == state->files.filename ? "-" : state->files.filename[filenum]);
pv_error("%s: %s", _("input file is output file"), NULL == next_filename ? "-" : next_filename);
(void) close(fd);
state->status.exit_status |= PV_ERROREXIT_OUROBOROS;
return -1;
+5 -5
View File
@@ -24,18 +24,18 @@ pvdisplay_bytecount_t pv_formatter_average_rate(pvformatter_args_t args)
return 0;
/*@-mustfreefresh@ */
if (args->state->control.numeric) {
if (args->control->numeric) {
/* numeric - raw value without suffix. */
(void) pv_snprintf(content, sizeof(content),
"%.4Lf", ((args->state->control.bits ? 8.0 : 1.0) * args->state->calc.average_rate));
} else if (args->state->control.bits && !args->state->control.linemode) {
"%.4Lf", ((args->control->bits ? 8.0 : 1.0) * args->calc->average_rate));
} else if (args->control->bits && !args->control->linemode) {
/* bits per second */
pv_describe_amount(content, sizeof(content),
"(%s)", 8 * args->state->calc.average_rate, "", _("b/s"), args->display->count_type);
"(%s)", 8 * args->calc->average_rate, "", _("b/s"), args->display->count_type);
} else {
/* bytes or lines per second */
pv_describe_amount(content,
sizeof(content), "(%s)", args->state->calc.average_rate, _("/s"), _("B/s"),
sizeof(content), "(%s)", args->calc->average_rate, _("/s"), _("B/s"),
args->display->count_type);
}
/*@+mustfreefresh@ *//* splint: see above. */
+4 -4
View File
@@ -44,7 +44,7 @@ static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char
memset(style, 0, sizeof(*style));
if (args->state->control.can_display_utf8 && 0 == strcmp(name, "block")) {
if (args->status->terminal_supports_utf8 && 0 == strcmp(name, "block")) {
style->style_id = 2;
@@ -58,7 +58,7 @@ static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char
return true;
} else if (args->state->control.can_display_utf8 && 0 == strcmp(name, "granular")) {
} else if (args->status->terminal_supports_utf8 && 0 == strcmp(name, "granular")) {
style->style_id = 3;
@@ -79,7 +79,7 @@ static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char
return true;
} else if (args->state->control.can_display_utf8 && 0 == strcmp(name, "shaded")) {
} else if (args->status->terminal_supports_utf8 && 0 == strcmp(name, "shaded")) {
style->style_id = 4;
@@ -164,7 +164,7 @@ pvdisplay_bytecount_t pv_formatter_bar_default(pvformatter_args_t args)
{
if (0 == args->segment->parameter) {
const char *default_name;
default_name = args->state->control.default_bar_style;
default_name = args->control->default_bar_style;
/*@-branchstate@ */
if (NULL == default_name)
default_name = "plain";
+4 -5
View File
@@ -23,16 +23,15 @@ pvdisplay_bytecount_t pv_formatter_buffer_percent(pvformatter_args_t args)
if (0 == args->buffer_size)
return 0;
if (args->state->transfer.buffer_size > 0) {
if (args->transfer->buffer_size > 0) {
double pct_used = pv_percentage((off_t)
(args->state->transfer.read_position -
args->state->transfer.write_position),
(args->transfer->read_position - args->transfer->write_position),
(off_t)
(args->state->transfer.buffer_size));
(args->transfer->buffer_size));
(void) pv_snprintf(content, sizeof(content), "{%3.0f%%}", pct_used);
}
#ifdef HAVE_SPLICE
if (args->state->transfer.splice_used)
if (args->transfer->splice_used)
(void) pv_snprintf(content, sizeof(content), "{%s}", "----");
#endif
+5 -8
View File
@@ -26,20 +26,17 @@ pvdisplay_bytecount_t pv_formatter_bytes(pvformatter_args_t args)
content[0] = '\0';
/*@-mustfreefresh@ */
if (args->state->control.numeric) {
if (args->control->numeric) {
/* Numeric mode - raw values only, no suffix. */
(void) pv_snprintf(content, sizeof(content),
"%lld",
(long long) ((args->state->control.bits ? 8 : 1) *
args->state->transfer.transferred));
} else if (args->state->control.bits && !args->state->control.linemode) {
"%lld", (long long) ((args->control->bits ? 8 : 1) * args->transfer->transferred));
} else if (args->control->bits && !args->control->linemode) {
pv_describe_amount(content, sizeof(content), "%s",
(long double) (args->state->transfer.transferred * 8), "", _("b"),
(long double) (args->transfer->transferred * 8), "", _("b"),
args->display->count_type);
} else {
pv_describe_amount(content, sizeof(content), "%s",
(long double) (args->state->transfer.transferred), "", _("B"),
args->display->count_type);
(long double) (args->transfer->transferred), "", _("B"), args->display->count_type);
}
/*@+mustfreefresh@ *//* splint - false positive from gettext(). */
+3 -4
View File
@@ -24,16 +24,15 @@ pvdisplay_bytecount_t pv_formatter_eta(pvformatter_args_t args)
/*
* Don't try to calculate this if the size is not known.
*/
if (args->state->control.size < 1)
if (args->control->size < 1)
return 0;
if (0 == args->buffer_size)
return 0;
eta =
pv_seconds_remaining((args->state->transfer.transferred - args->display->initial_offset),
args->state->control.size - args->display->initial_offset,
args->state->calc.current_avg_rate);
pv_seconds_remaining((args->transfer->transferred - args->display->initial_offset),
args->control->size - args->display->initial_offset, args->calc->current_avg_rate);
/*
* Bounds check, so we don't overrun the suffix buffer. This means
+3 -4
View File
@@ -32,7 +32,7 @@ pvdisplay_bytecount_t pv_formatter_fineta(pvformatter_args_t args)
/*
* Don't try to calculate this if the size is not known.
*/
if (args->state->control.size < 1)
if (args->control->size < 1)
return 0;
if (0 == args->buffer_size)
@@ -47,9 +47,8 @@ pvdisplay_bytecount_t pv_formatter_fineta(pvformatter_args_t args)
* lookup.
*/
eta = pv_seconds_remaining(args->state->transfer.transferred - args->display->initial_offset,
args->state->control.size - args->display->initial_offset,
args->state->calc.current_avg_rate);
eta = pv_seconds_remaining(args->transfer->transferred - args->display->initial_offset,
args->control->size - args->display->initial_offset, args->calc->current_avg_rate);
/* Bounds check - see pv_formatter_eta(). */
eta = pv_bound_long(eta, 0, (long) 360000000L);
+2 -2
View File
@@ -35,8 +35,8 @@ pvdisplay_bytecount_t pv_formatter_name(pvformatter_args_t args)
(void) pv_snprintf(string_format, sizeof(string_format), "%%%d.500s:", field_width);
content[0] = '\0';
if (args->state->control.name) {
(void) pv_snprintf(content, sizeof(content), string_format, args->state->control.name);
if (NULL != args->control->name) {
(void) pv_snprintf(content, sizeof(content), string_format, args->control->name);
}
return pv_formatter_segmentcontent(content, args);
+15 -17
View File
@@ -74,28 +74,26 @@ static pvdisplay_bytecount_t pv_formatter_progress_knownsize(pvformatter_args_t
memset(after_bar, 0, sizeof(after_bar));
if (args->state->control.size > 0) {
if (args->control->size > 0) {
/* Percentage of data transferred. */
bar_percentage = (double) (args->state->calc.percentage);
bar_percentage = (double) (args->calc->percentage);
(void) pv_snprintf(after_bar, sizeof(after_bar), " %3ld%%", (int) bar_percentage);
} else {
/* Current rate vs max rate. */
bar_percentage = 0.0;
if (args->state->calc.rate_max > 0) {
bar_percentage =
(double) (100.0 * args->state->calc.transfer_rate / args->state->calc.rate_max);
if (args->calc->rate_max > 0) {
bar_percentage = (double) (100.0 * args->calc->transfer_rate / args->calc->rate_max);
}
/*@-mustfreefresh@ */
if (args->state->control.bits && !args->state->control.linemode) {
if (args->control->bits && !args->control->linemode) {
/* bits per second */
pv_describe_amount(after_bar, sizeof(after_bar), "/%s",
8.0 * args->state->calc.rate_max, "", _("b/s"), args->display->count_type);
8.0 * args->calc->rate_max, "", _("b/s"), args->display->count_type);
} else {
/* bytes or lines per second */
pv_describe_amount(after_bar, sizeof(after_bar),
"/%s", args->state->calc.rate_max, _("/s"), _("B/s"),
args->display->count_type);
"/%s", args->calc->rate_max, _("/s"), _("B/s"), args->display->count_type);
}
/*@+mustfreefresh@ *//* splint: see above about gettext(). */
}
@@ -247,7 +245,7 @@ static pvdisplay_bytecount_t pv_formatter_progress_unknownsize(pvformatter_args_
* here we make values above 100 send the indicator back down again,
* so it moves back and forth.
*/
indicator_position = args->state->calc.percentage;
indicator_position = args->calc->percentage;
if (indicator_position > 200.0)
#if HAVE_FMOD
indicator_position = fmod(indicator_position, 200.0);
@@ -316,7 +314,7 @@ pvdisplay_bytecount_t pv_formatter_progress(pvformatter_args_t args)
if (0 == args->segment->parameter) {
const char *default_name;
default_name = args->state->control.default_bar_style;
default_name = args->control->default_bar_style;
/*@-branchstate@ */
if (NULL == default_name)
default_name = "plain";
@@ -328,7 +326,7 @@ pvdisplay_bytecount_t pv_formatter_progress(pvformatter_args_t args)
if (0 == args->buffer_size)
return 0;
if (args->state->control.size > 0 || args->state->control.rate_gauge) {
if (args->control->size > 0 || args->control->rate_gauge) {
/* Known size or rate gauge - bar with percentage. */
bytes = pv_formatter_progress_knownsize(args, content, sizeof(content), true, true, true);
} else {
@@ -354,7 +352,7 @@ pvdisplay_bytecount_t pv_formatter_progress_bar_only(pvformatter_args_t args)
if (0 == args->segment->parameter) {
const char *default_name;
default_name = args->state->control.default_bar_style;
default_name = args->control->default_bar_style;
/*@-branchstate@ */
if (NULL == default_name)
default_name = "plain";
@@ -366,7 +364,7 @@ pvdisplay_bytecount_t pv_formatter_progress_bar_only(pvformatter_args_t args)
if (0 == args->buffer_size)
return 0;
if (args->state->control.size > 0 || args->state->control.rate_gauge) {
if (args->control->size > 0 || args->control->rate_gauge) {
/* Known size or rate gauge - bar with percentage. */
bytes = pv_formatter_progress_knownsize(args, content, sizeof(content), false, true, false);
} else {
@@ -393,12 +391,12 @@ pvdisplay_bytecount_t pv_formatter_progress_amount_only(pvformatter_args_t args)
if (0 == args->buffer_size)
return 0;
if (args->state->control.numeric) {
if (args->control->numeric) {
/* Numeric mode - percentage as a rounded integer with no suffix. */
(void) pv_snprintf(content, sizeof(content), "%.0f", args->state->calc.percentage);
(void) pv_snprintf(content, sizeof(content), "%.0f", args->calc->percentage);
bytes = strlen(content); /* flawfinder: ignore */
/* flawfinder: always \0-terminated by pv_snprintf() and the earlier memset(). */
} else if (args->state->control.size > 0 || args->state->control.rate_gauge) {
} else if (args->control->size > 0 || args->control->rate_gauge) {
/* Known size or rate gauge - percentage or rate. */
bytes = pv_formatter_progress_knownsize(args, content, sizeof(content), false, false, true);
} else {
+5 -7
View File
@@ -26,20 +26,18 @@ pvdisplay_bytecount_t pv_formatter_rate(pvformatter_args_t args)
return 0;
/*@-mustfreefresh@ */
if (args->state->control.numeric) {
if (args->control->numeric) {
/* numeric - raw value without suffix. */
(void) pv_snprintf(content, sizeof(content),
"%.4Lf",
((args->state->control.bits ? 8.0 : 1.0) * args->state->calc.transfer_rate));
} else if (args->state->control.bits && !args->state->control.linemode) {
"%.4Lf", ((args->control->bits ? 8.0 : 1.0) * args->calc->transfer_rate));
} else if (args->control->bits && !args->control->linemode) {
/* bits per second */
pv_describe_amount(content, sizeof(content), "[%s]",
8 * args->state->calc.transfer_rate, "", _("b/s"), args->display->count_type);
8 * args->calc->transfer_rate, "", _("b/s"), args->display->count_type);
} else {
/* bytes or lines per second */
pv_describe_amount(content, sizeof(content),
"[%s]", args->state->calc.transfer_rate, _("/s"), _("B/s"),
args->display->count_type);
"[%s]", args->calc->transfer_rate, _("/s"), _("B/s"), args->display->count_type);
}
/*@+mustfreefresh@ *//* splint: see above. */
+1 -1
View File
@@ -109,7 +109,7 @@ pvdisplay_bytecount_t pv_formatter_sgr(pvformatter_args_t args)
args->display->format_uses_colour = true;
if (!args->state->control.can_display_colour)
if (!args->status->terminal_supports_colour)
return 0;
if (NULL == args->segment->string_parameter)
return 0;
+15 -14
View File
@@ -17,6 +17,7 @@
pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t args)
{
char content[128]; /* flawfinder: ignore - always bounded */
long double elapsed_seconds;
args->display->showing_timer = true;
@@ -25,22 +26,24 @@ pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t args)
if (0 == args->buffer_size)
return 0;
elapsed_seconds = args->transfer->elapsed_seconds;
/*
* Bounds check, so we don't overrun the prefix buffer. This does
* mean that the timer will stop at a 100,000 hours, but since
* that's 11 years, it shouldn't be a problem.
*/
if (args->state->transfer.elapsed_seconds > (long double) 360000000.0L)
args->state->transfer.elapsed_seconds = (long double) 360000000.0L;
if (elapsed_seconds > (long double) 360000000.0L)
elapsed_seconds = (long double) 360000000.0L;
/* Also check it's not negative. */
if (args->state->transfer.elapsed_seconds < 0.0)
args->state->transfer.elapsed_seconds = 0.0;
if (elapsed_seconds < 0.0)
elapsed_seconds = 0.0;
if (args->state->control.numeric) {
if (args->control->numeric) {
/* Numeric mode - show the number of seconds, unformatted. */
(void) pv_snprintf(content, sizeof(content), "%.4Lf", args->state->transfer.elapsed_seconds);
} else if (args->state->transfer.elapsed_seconds > (long double) 86400.0L) {
(void) pv_snprintf(content, sizeof(content), "%.4Lf", elapsed_seconds);
} else if (elapsed_seconds > (long double) 86400.0L) {
/*
* If the elapsed time is more than a day, include a day count as
* well as hours, minutes, and seconds.
@@ -48,17 +51,15 @@ pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t args)
(void) pv_snprintf(content,
sizeof(content),
"%ld:%02ld:%02ld:%02ld",
((long) (args->state->transfer.elapsed_seconds)) / 86400,
(((long) (args->state->transfer.elapsed_seconds)) / 3600) %
24, (((long) (args->state->transfer.elapsed_seconds)) / 60) % 60,
((long) (args->state->transfer.elapsed_seconds)) % 60);
((long) (elapsed_seconds)) / 86400,
(((long) (elapsed_seconds)) / 3600) %
24, (((long) (elapsed_seconds)) / 60) % 60, ((long) (elapsed_seconds)) % 60);
} else {
(void) pv_snprintf(content,
sizeof(content),
"%ld:%02ld:%02ld",
((long) (args->state->transfer.elapsed_seconds)) / 3600,
(((long) (args->state->transfer.elapsed_seconds)) / 60) % 60,
((long) (args->state->transfer.elapsed_seconds)) % 60);
((long) (elapsed_seconds)) / 3600,
(((long) (elapsed_seconds)) / 60) % 60, ((long) (elapsed_seconds)) % 60);
}
return pv_formatter_segmentcontent(content, args);
+449 -350
View File
@@ -118,7 +118,7 @@ int pv_main_loop(pvstate_t state)
* don't need to.
*/
pv_crs_init(state);
pv_crs_init(&(state->cursor), &(state->control), &(state->flags));
eof_in = false;
eof_out = false;
@@ -166,7 +166,7 @@ int pv_main_loop(pvstate_t state)
*/
if (input_fd < 0) {
if (state->control.cursor)
pv_crs_fini(state);
pv_crs_fini(&(state->cursor), &(state->control), &(state->flags));
return state->status.exit_status;
}
#if HAVE_POSIX_FADVISE
@@ -219,11 +219,11 @@ int pv_main_loop(pvstate_t state)
* Check for remote messages from -R every short while.
*/
if (pv_elapsedtime_compare(&cur_time, &next_remotecheck) > 0) {
pv_remote_check(state);
(void) pv_remote_check(state);
pv_elapsedtime_add_nsec(&next_remotecheck, REMOTE_INTERVAL);
}
if (1 == state->flag.trigger_exit)
if (1 == state->flags.trigger_exit)
break;
if (state->control.rate_limit > 0) {
@@ -270,7 +270,7 @@ int pv_main_loop(pvstate_t state)
if (written < 0) {
debug("%s: %s", "write error from pv_transfer", strerror(errno));
if (state->control.cursor)
pv_crs_fini(state);
pv_crs_fini(&(state->cursor), &(state->control), &(state->flags));
return state->status.exit_status;
}
@@ -292,7 +292,7 @@ int pv_main_loop(pvstate_t state)
if (output_is_pipe) {
int nbytes;
nbytes = 0;
if (0 != state->flag.pipe_closed) {
if (0 != state->flags.pipe_closed) {
if (0 != state->transfer.written_but_not_consumed)
debug("%s",
"clearing written_but_not_consumed because the output pipe was closed");
@@ -394,7 +394,7 @@ int pv_main_loop(pvstate_t state)
*/
if (eof_in && eof_out && 0 == state->transfer.written_but_not_consumed) {
final_update = true;
if ((state->display.display_visible)
if ((state->display.output_produced)
|| (state->control.delay_start < 0.001)) {
pv_elapsedtime_copy(&next_update, &cur_time);
}
@@ -487,10 +487,10 @@ int pv_main_loop(pvstate_t state)
state->transfer.elapsed_seconds = pv_elapsedtime_seconds(&transfer_elapsed);
/* Resize the display, if a resize signal was received. */
if (1 == state->flag.terminal_resized) {
if (1 == state->flags.terminal_resized) {
unsigned int new_width, new_height;
state->flag.terminal_resized = 0;
state->flags.terminal_resized = 0;
new_width = (unsigned int) (state->control.width);
new_height = state->control.height;
@@ -506,10 +506,13 @@ int pv_main_loop(pvstate_t state)
if (state->control.no_display) {
/* If there's no display, calculate rate for the statistics. */
pv_calculate_transfer_rate(state, final_update);
pv_calculate_transfer_rate(&(state->calc), &(state->transfer), &(state->control),
&(state->display), final_update);
} else {
/* Produce the display. */
pv_display(state, final_update);
pv_display(&(state->status), &(state->control), &(state->flags), &(state->transfer),
&(state->calc), &(state->cursor), &(state->display), &(state->extra_display),
final_update);
}
}
@@ -517,14 +520,14 @@ int pv_main_loop(pvstate_t state)
eof_out ? "true" : "false");
if (state->control.cursor) {
pv_crs_fini(state);
pv_crs_fini(&(state->cursor), &(state->control), &(state->flags));
} else {
if ((!state->control.numeric) && (!state->control.no_display)
&& (state->display.display_visible))
pv_tty_write(state, "\n", 1);
&& (state->display.output_produced))
pv_tty_write(&(state->flags), "\n", 1);
}
if (1 == state->flag.trigger_exit)
if (1 == state->flags.trigger_exit)
state->status.exit_status |= PV_ERROREXIT_SIGNAL;
if (input_fd >= 0)
@@ -562,7 +565,7 @@ int pv_main_loop(pvstate_t state)
rate_deviation, state->control.bits ? _("b/s") : _("B/s"));
if (stats_size > 0 && stats_size < (int) (sizeof(stats_buf)))
pv_tty_write(state, stats_buf, (size_t) stats_size);
pv_tty_write(&(state->flags), stats_buf, (size_t) stats_size);
} else if (state->control.show_stats && state->calc.measurements_taken < 1) {
char msg_buf[256]; /* flawfinder: ignore */
int msg_size;
@@ -573,7 +576,7 @@ int pv_main_loop(pvstate_t state)
msg_size = pv_snprintf(msg_buf, sizeof(msg_buf), "%s\n", _("rate not measured"));
if (msg_size > 0 && msg_size < (int) (sizeof(msg_buf)))
pv_tty_write(state, msg_buf, (size_t) msg_size);
pv_tty_write(&(state->flags), msg_buf, (size_t) msg_size);
}
return state->status.exit_status;
@@ -581,193 +584,60 @@ int pv_main_loop(pvstate_t state)
/*
* 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.
* Return true if the given string contains a "%N" or "%{name}" format
* sequence.
*/
int pv_watchfd_loop(pvstate_t state)
static bool format_contains_name(const char *format_string)
{
struct pvwatchfd_s info;
off_t position_now;
struct timespec next_update, cur_time;
struct timespec init_time, next_remotecheck, transfer_elapsed;
bool ended, first_check;
int rc;
memset(&info, 0, sizeof(info));
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->status.exit_status |= PV_ERROREXIT_ACCESS;
/*@-compdestroy@ */
return state->status.exit_status;
/*@+compdestroy@ */
/* splint: no leak of info.state as it is unused so far. */
}
/*
* Use a size if one was passed, otherwise use the total size
* calculated.
*/
if (0 >= state->control.size)
state->control.size = info.size;
if (state->control.size < 1) {
char *fmt;
while (NULL != (fmt = strstr(state->control.default_format, "%e"))) {
debug("%s", "zero size - removing ETA");
/* strlen-1 here to include trailing \0 */
memmove(fmt, fmt + 2, strlen(fmt) - 1); /* flawfinder: ignore */
/* flawfinder: default_format is always \0 terminated */
state->flag.reparse_display = 1;
}
}
memset(&cur_time, 0, sizeof(cur_time));
memset(&next_remotecheck, 0, sizeof(next_remotecheck));
memset(&next_update, 0, sizeof(next_update));
memset(&init_time, 0, sizeof(init_time));
memset(&transfer_elapsed, 0, sizeof(transfer_elapsed));
pv_elapsedtime_read(&cur_time);
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->control.interval));
ended = false;
first_check = true;
while (!ended) {
/*
* Check for remote messages from -R every short while.
*/
if (pv_elapsedtime_compare(&cur_time, &next_remotecheck) > 0) {
pv_remote_check(state);
pv_elapsedtime_add_nsec(&next_remotecheck, REMOTE_INTERVAL);
}
if (1 == state->flag.trigger_exit)
break;
position_now = pv_watchfd_position(&info);
if (position_now < 0) {
ended = true;
} else {
if (first_check) {
state->display.initial_offset = position_now;
first_check = false;
}
state->transfer.transferred = position_now;
state->transfer.total_written = position_now;
}
pv_elapsedtime_read(&cur_time);
/* Ended - force a display update. */
if (ended) {
pv_elapsedtime_copy(&next_update, &cur_time);
}
/*
* Restart the loop after a brief delay, if it's not time to
* update the display.
*/
if (pv_elapsedtime_compare(&cur_time, &next_update) < 0) {
pv_nanosleep(50000000);
while ('\0' != format_string[0]) {
/* If we're not on a '%' character, move on. */
if ('%' != format_string[0]) {
format_string++;
continue;
}
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);
/*
* 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->signal.toffset));
/*
* Now get the effective elapsed transfer time - current
* time minus effective start time.
*/
pv_elapsedtime_subtract(&transfer_elapsed, &cur_time, &init_time);
state->transfer.elapsed_seconds = pv_elapsedtime_seconds(&transfer_elapsed);
/* Resize the display, if a resize signal was received. */
if (1 == state->flag.terminal_resized) {
unsigned int new_width, new_height;
state->flag.terminal_resized = 0;
new_width = (unsigned int) (state->control.width);
new_height = state->control.height;
pv_screensize(&new_width, &new_height);
if (new_width > PVDISPLAY_WIDTH_MAX)
new_width = PVDISPLAY_WIDTH_MAX;
if (!state->control.width_set_manually)
state->control.width = (pvdisplay_width_t) new_width;
if (!state->control.height_set_manually)
state->control.height = new_height;
/* Move past the '%'. */
format_string++;
/* Early return if we've run out of string. */
if ('\0' == format_string[0])
return false;
/* If we've found "%N", return true. */
if ('N' == format_string[0])
return true;
/* If we've found "%%", move on and go back round the loop. */
if ('%' == format_string[0]) {
format_string++;
continue;
}
pv_display(state, ended);
/* Move past any digits, for the "%123{name}" syntax. */
while ('\0' != format_string[0] && (format_string[0] >= '0' && format_string[0] <= '9'))
format_string++;
/*
* If the next character isn't '{', this isn't a valid
* "%{xyz}" sequence, so go back to the top of the loop to
* skip to the next '%'.
*/
if ('{' != format_string[0])
continue;
/*
* If the next part is "{name}", forming "%{name}", return
* true.
*/
if (0 == strncmp(format_string, "{name}", 6))
return true;
/* Loop round again to keep looking. */
}
if (!state->control.numeric)
pv_tty_write(state, "\n", 1);
if (1 == state->flag.trigger_exit)
state->status.exit_status |= PV_ERROREXIT_SIGNAL;
/*
* Free the state structure specific to this file descriptor.
* Uunused so far - this is so that in future we could watch
* multiple file descriptors similar to pv_watchpid_loop().
*/
if (NULL != info.state) {
pv_state_free(info.state);
info.state = NULL;
}
/*@-compdestroy@ */
return state->status.exit_status;
/*@+compdestroy@ */
/* splint: no leak of info.state as we just freed it above. */
return false;
}
/*
* 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.
*
* Replaces format_string in "state" so that starts with "%N " if it doesn't
* already do so.
*
* Returns nonzero on error.
* Update the main format string for use with --watchfd, such that if
* necessary, it starts with "%N " if it doesn't already.
*/
int pv_watchpid_loop(pvstate_t state)
static void pv_watchfd_update_format_string(pvstate_t state)
{
const char *original_format_string;
char new_format_string[512]; /* flawfinder: ignore */
struct pvwatchfd_s *info_array = NULL;
int array_length = 0;
int fd_to_idx[FD_SETSIZE];
struct timespec next_update, cur_time;
int idx;
int prev_displayed_lines, blank_lines;
bool first_pass = true;
/*
* flawfinder rationale (new_format_string): zeroed with memset(),
@@ -775,71 +645,229 @@ int pv_watchpid_loop(pvstate_t state)
* explicitly terminated with \0.
*/
/*
* Make sure the process exists first, so we can give an error if
* it's not there at the start.
*/
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 |= PV_ERROREXIT_ACCESS;
return PV_ERROREXIT_ACCESS;
}
/* If there's nothing to watch, do nothing. */
if (state->watchfd.count < 1)
return;
if (NULL == state->watchfd.pid)
return;
if (NULL == state->watchfd.fd)
return;
/*
* Make sure there's a format string, and then insert %N into it if
* it's not present.
* it's not present AND we're either watching more than one item, or
* the item we're watching is a whole PID, not a single FD.
*/
original_format_string =
NULL != state->control.format_string ? state->control.format_string : state->control.default_format;
original_format_string = state->control.format_string;
if (NULL == original_format_string)
original_format_string = state->control.default_format;
if (NULL == original_format_string)
return;
memset(new_format_string, 0, sizeof(new_format_string));
if (NULL == original_format_string) {
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%%N");
} else if (NULL == strstr(original_format_string, "%N")) {
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%%N %s", original_format_string);
if (state->watchfd.count > 1 || -1 == state->watchfd.fd[0]) {
/* Watching more than one single FD; need %N. */
if (!format_contains_name(original_format_string)) {
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%%N %s",
original_format_string);
} else {
/* If the format string is set, nothing to do. */
if (NULL != state->control.format_string)
return;
/* Prepare a copy of the default format. */
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%s", original_format_string);
}
} else {
/* Watching only one FD; don't prepend %N. */
/* If the format string is set, nothing to do. */
if (NULL != state->control.format_string)
return;
/* Prepare a copy of the default format. */
(void) pv_snprintf(new_format_string, sizeof(new_format_string), "%s", original_format_string);
}
new_format_string[sizeof(new_format_string) - 1] = '\0';
if (NULL != state->control.format_string)
free(state->control.format_string);
state->control.format_string = pv_strdup(new_format_string);
}
/*
* Watch the progress of the PID:FD pairs, or of all FDs under PIDs, as
* specified in state->watchfd, showing details on standard error according
* to the given options.
*
* Replaces format_string in "state" so that starts with "%N " if it doesn't
* already do so.
*
* Returns nonzero on error.
*/
int pv_watchfd_loop(pvstate_t state)
{
struct { /* details for each PID:FD specified by operator */
pid_t pid; /* watched PID */
int fd; /* watched fd, or -1 for all */
pvwatchfd_t info_array; /* watch information for each fd */
int array_length; /* length of watch info array */
/* TODO: "finished but not time to stop showing" flag for #81 */
bool finished; /* "PID:FD": fd closed; or PID gone */
} *watching;
unsigned int watch_idx;
bool all_watching_finished;
struct timespec next_update, next_remotecheck, cur_time;
int prev_displayed_lines, blank_lines;
/* If there's nothing to watch, do nothing at all. */
if (state->watchfd.count < 1)
return 0;
if (NULL == state->watchfd.pid)
return PV_ERROREXIT_MEMORY;
if (NULL == state->watchfd.fd)
return PV_ERROREXIT_MEMORY;
/*
* Get things ready for the main loop.
* Make sure there's no name set.
*/
if (NULL != state->control.name) {
free(state->control.name);
state->control.name = NULL;
}
/* Adjust the format string so PID:FD or FD prefixes are shown. */
pv_watchfd_update_format_string(state);
/*
* Allocate the watching array.
*/
watching = malloc(state->watchfd.count * sizeof(*watching));
if (NULL == watching) {
pv_error("%s: %s", _("buffer allocation failed"), strerror(errno));
return PV_ERROREXIT_MEMORY;
}
memset(watching, 0, state->watchfd.count * sizeof(*watching));
/*
* Populate the watching array. In the process of doing so, raise
* errors if any of the initially specified PIDs or PID:FD pairs
* don't exist or aren't readable.
*/
for (watch_idx = 0; watch_idx < state->watchfd.count; watch_idx++) {
int rc;
watching[watch_idx].pid = state->watchfd.pid[watch_idx];
watching[watch_idx].fd = state->watchfd.fd[watch_idx];
watching[watch_idx].info_array = NULL;
watching[watch_idx].array_length = 0;
watching[watch_idx].finished = false;
if (kill(watching[watch_idx].pid, 0) != 0) {
/* Inaccessible PID - error, mark as finished. */
pv_error("%s %u: %s", _("pid"), watching[watch_idx].pid, strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
watching[watch_idx].finished = true;
continue;
}
if (-1 == watching[watch_idx].fd) {
/*
* If this is a whole-PID watch, do the initial FD
* scan to list all the FDs under that PID.
*/
rc = pv_watchpid_scanfds(state, watching[watch_idx].pid, -1,
&(watching[watch_idx].array_length),
&(watching[watch_idx].info_array));
if (rc != 0) {
/* Scan failed - error, mark as finished. */
pv_error("%s %u: %s", _("pid"), watching[watch_idx].pid, strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
watching[watch_idx].finished = true;
}
} else {
/*
* Scan the PID for the one specific FD given.
*/
rc = pv_watchpid_scanfds(state, watching[watch_idx].pid, watching[watch_idx].fd,
&(watching[watch_idx].array_length),
&(watching[watch_idx].info_array));
if (rc != 0) {
/* Scan failed - mark as finished. */
state->status.exit_status |= PV_ERROREXIT_ACCESS;
watching[watch_idx].finished = true;
} else if (0 == watching[watch_idx].array_length) {
/* FD not found - error, mark as finished. */
pv_error("%s %u: %s %d: %s",
_("pid"), watching[watch_idx].pid, _("fd"), watching[watch_idx].fd,
strerror(ENOENT));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
watching[watch_idx].finished = true;
} else if (!watching[watch_idx].info_array[0].displayable) {
/* FD not displayable - mark as finished. */
state->status.exit_status |= PV_ERROREXIT_ACCESS;
watching[watch_idx].finished = true;
}
}
}
/*
* Skip to the end if none of the items to watch can be watched.
*/
all_watching_finished = true;
for (watch_idx = 0; watch_idx < state->watchfd.count; watch_idx++) {
if (watching[watch_idx].finished)
continue;
all_watching_finished = false;
break;
}
if (all_watching_finished)
goto end_pv_watchfd_loop;
/*
* Prepare timing structures for the main loop.
*/
memset(&cur_time, 0, sizeof(cur_time));
memset(&next_remotecheck, 0, sizeof(next_remotecheck));
memset(&next_update, 0, sizeof(next_update));
pv_elapsedtime_read(&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->control.interval));
for (idx = 0; idx < FD_SETSIZE; idx++) {
fd_to_idx[idx] = -1;
}
/*
* Main loop - continually check each watching[] item and display
* progress until all watched items have finished or an exit signal
* is received.
*/
prev_displayed_lines = 0;
all_watching_finished = false;
while (true) {
int rc, fd, displayed_lines;
while (!all_watching_finished) {
int displayed_lines;
bool terminal_resized;
if (1 == state->flag.trigger_exit)
break;
pv_elapsedtime_read(&cur_time);
if (kill(state->control.watch_pid, 0) != 0) {
if (first_pass) {
pv_error(state, "%s %u: %s", _("pid"), state->control.watch_pid, strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
if (NULL != info_array)
free(info_array);
return PV_ERROREXIT_ACCESS;
/* Check for remote messages from -R every short while. */
if (pv_elapsedtime_compare(&cur_time, &next_remotecheck) > 0) {
if (pv_remote_check(state)) {
/* Message received - ensure format has %N. */
pv_watchfd_update_format_string(state);
/* Fake a resize, to force a reparse. */
state->flags.terminal_resized = 1;
}
break;
pv_elapsedtime_add_nsec(&next_remotecheck, REMOTE_INTERVAL);
}
/* End the loop if a signal handler has set the exit flag. */
if (1 == state->flags.trigger_exit)
break;
/* Get the current time. */
pv_elapsedtime_read(&cur_time);
/*
* Restart the loop after a brief delay, if it's not time to
* update the display.
@@ -849,17 +877,25 @@ int pv_watchpid_loop(pvstate_t state)
continue;
}
/* Set the time of the next display update. */
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->flag.terminal_resized) {
/*
* Resize the display, if a resize signal was received.
*
* We also set a local flag to tell the display loop below
* to trigger a name reset and display reparse for every FD
* output line, to inherit the size change.
*/
terminal_resized = false;
if (1 == state->flags.terminal_resized) {
unsigned int new_width, new_height;
state->flag.terminal_resized = 0;
state->flags.terminal_resized = 0;
new_width = (unsigned int) (state->control.width);
new_height = state->control.height;
@@ -871,124 +907,158 @@ int pv_watchpid_loop(pvstate_t state)
state->control.width = (pvdisplay_width_t) new_width;
state->control.height = new_height;
for (idx = 0; NULL != info_array && idx < array_length; idx++) {
if (NULL == info_array[idx].state)
continue;
info_array[idx].state->control.width = state->control.width;
info_array[idx].state->control.height = state->control.height;
pv_watchpid_setname(state, &(info_array[idx]));
info_array[idx].state->flag.reparse_display = 1;
}
terminal_resized = true;
}
rc = pv_watchpid_scanfds(state, state->control.watch_pid, &array_length, &info_array, fd_to_idx);
if (rc != 0) {
if (first_pass) {
pv_error(state, "%s %u: %s", _("pid"), state->control.watch_pid, strerror(errno));
state->status.exit_status |= PV_ERROREXIT_ACCESS;
if (NULL != info_array)
free(info_array);
return PV_ERROREXIT_ACCESS;
}
break;
}
first_pass = false;
/*
* Run through each watched item.
*/
displayed_lines = 0;
for (watch_idx = 0; NULL != watching && watch_idx < state->watchfd.count; watch_idx++) {
int info_idx;
for (fd = 0; fd < FD_SETSIZE && NULL != info_array; fd++) {
off_t position_now;
struct timespec init_time, transfer_elapsed;
if (displayed_lines >= (int) (state->control.height))
break;
idx = fd_to_idx[fd];
if (idx < 0)
/* Skip watched items that have finished. */
if (watching[watch_idx].finished)
continue;
if (info_array[idx].watch_fd < 0) {
if (-1 == watching[watch_idx].fd) {
int rc;
/*
* Non-displayable fd - just remove if
* changed
* If this watched item is a whole PID,
* rescan that PID's FDs.
*/
if (pv_watchfd_changed(&(info_array[idx]))) {
fd_to_idx[fd] = -1;
info_array[idx].watch_pid = 0;
if (NULL != info_array[idx].state)
pv_state_free(info_array[idx].state);
/*@-mustfreeonly@ *//* not a leak - we've just free()d it. */
info_array[idx].state = NULL;
/*@+mustfreeonly@ */
debug("%s %d: %s", "fd", fd, "removing");
rc = pv_watchpid_scanfds(state, watching[watch_idx].pid, -1,
&(watching[watch_idx].array_length),
&(watching[watch_idx].info_array));
if (rc != 0) {
/*
* PID now inaccessible - mark it as
* finished and skip over it.
*/
watching[watch_idx].finished = true;
continue;
}
continue;
}
if (NULL == info_array[idx].state) {
debug("%s %d: %s", "fd", fd, "null state - skipping");
continue;
}
/*
* Displayable fd - display, or remove if changed
*/
position_now = pv_watchfd_position(&(info_array[idx]));
if (position_now < 0) {
fd_to_idx[fd] = -1;
info_array[idx].watch_pid = 0;
if (NULL != info_array[idx].state)
pv_state_free(info_array[idx].state);
/*@-mustfreeonly@ *//* not a leak - we've just free()d it. */
info_array[idx].state = NULL;
/*@+mustfreeonly@ */
debug("%s %d: %s", "fd", fd, "removing");
continue;
}
info_array[idx].position = position_now;
memset(&init_time, 0, sizeof(init_time));
memset(&transfer_elapsed, 0, sizeof(transfer_elapsed));
/*
* 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->signal.toffset));
/*
* Now get the effective elapsed transfer time - current
* time minus effective start time.
*/
pv_elapsedtime_subtract(&transfer_elapsed, &cur_time, &init_time);
if (NULL != info_array[idx].state) {
info_array[idx].state->transfer.elapsed_seconds =
pv_elapsedtime_seconds(&transfer_elapsed);
}
if (displayed_lines > 0) {
debug("%s", "adding newline");
pv_tty_write(state, "\n", 1);
}
if (NULL == info_array[idx].state) {
debug("%s %d [%d]: %s / %Ld", "fd", fd, idx, "(null state)", position_now);
} else {
debug("%s %d [%d]: %Lf / %Ld", "fd", fd, idx,
info_array[idx].state->transfer.elapsed_seconds, position_now);
/*
* It this watched item is a single FD, and
* that FD is no longer usable, mark the
* item as finished and move on.
*/
if ((NULL == watching[watch_idx].info_array) || (0 == watching[watch_idx].array_length)
|| (watching[watch_idx].info_array[0].unused)
|| (!watching[watch_idx].info_array[0].displayable)) {
watching[watch_idx].finished = true;
continue;
}
}
if (NULL != info_array[idx].state) {
info_array[idx].state->transfer.transferred = position_now;
info_array[idx].state->transfer.total_written = position_now;
pv_display(info_array[idx].state, false);
/*
* Run through the info array of this item.
*/
for (info_idx = 0;
NULL != watching[watch_idx].info_array && info_idx < watching[watch_idx].array_length;
info_idx++) {
off_t position_now;
struct timespec init_time, transfer_elapsed;
pvwatchfd_t info_item = &(watching[watch_idx].info_array[info_idx]);
/* Skip unused array entries. */
if (info_item->unused)
continue;
/* No more lines if we've filled the display. */
if (displayed_lines >= (int) (state->control.height))
break;
if (!info_item->displayable) {
/*
* Non-displayable fd - just remove if
* changed.
*/
if (pv_watchfd_changed(info_item)) {
debug("%s %d: %s", "fd", info_item->watch_fd, "removing");
info_item->unused = true;
info_item->displayable = false;
pv_freecontents_watchfd(info_item);
}
continue;
}
if (info_item->watch_fd < 0) {
debug("%s %d: %s", "fd", info_item->watch_fd, "negative fd - skipping");
continue;
}
/*
* Displayable fd - display, or remove if
* changed.
*/
position_now = pv_watchfd_position(info_item);
if (position_now < 0) {
debug("%s %d: %s", "fd", info_item->watch_fd, "removing");
info_item->unused = true;
info_item->displayable = false;
pv_freecontents_watchfd(info_item);
continue;
}
info_item->position = position_now;
memset(&init_time, 0, sizeof(init_time));
memset(&transfer_elapsed, 0, sizeof(transfer_elapsed));
/*
* Calculate the effective start time: the time we actually
* started, plus the total time we spent stopped.
*/
pv_elapsedtime_add(&init_time, &(info_item->start_time), &(state->signal.toffset));
/*
* Now get the effective elapsed transfer time - current
* time minus effective start time.
*/
pv_elapsedtime_subtract(&transfer_elapsed, &cur_time, &init_time);
info_item->transfer.elapsed_seconds = pv_elapsedtime_seconds(&transfer_elapsed);
if (displayed_lines > 0) {
debug("%s", "adding newline");
pv_tty_write(&(state->flags), "\n", 1);
}
debug("%s %d, %s %d [%d/%d]: %Lf / %Ld", "pid", (int) (info_item->watch_pid), "fd",
info_item->watch_fd, watch_idx, info_idx, info_item->transfer.elapsed_seconds,
position_now);
if (terminal_resized) {
pv_watchpid_setname(state, info_item);
info_item->flags.reparse_display = 1;
}
info_item->transfer.transferred = position_now;
info_item->transfer.total_written = position_now;
state->control.name = info_item->display_name;
state->control.size = info_item->size;
pv_display(&(state->status),
&(state->control), &(info_item->flags),
&(info_item->transfer), &(info_item->calc),
&(state->cursor), &(info_item->display), NULL, false);
/*@-mustfreeonly@ */
state->control.name = NULL;
/*
* splint warns of a memory leak, but we'd
* set name to be an alias of display_name,
* so nothing is lost here.
*/
/*@+mustfreeonly@ */
displayed_lines++;
}
}
/*
@@ -1004,10 +1074,10 @@ int pv_watchpid_loop(pvstate_t state)
while (blank_lines > 0) {
pvdisplay_width_t blank_count;
if (displayed_lines > 0)
pv_tty_write(state, "\n", 1);
pv_tty_write(&(state->flags), "\n", 1);
for (blank_count = 0; blank_count < state->control.width; blank_count++)
pv_tty_write(state, " ", 1);
pv_tty_write(state, "\r", 1);
pv_tty_write(&(state->flags), " ", 1);
pv_tty_write(&(state->flags), "\r", 1);
blank_lines--;
displayed_lines++;
}
@@ -1015,41 +1085,70 @@ int pv_watchpid_loop(pvstate_t state)
debug("%s: %d", "displayed lines", displayed_lines);
while (displayed_lines > 1) {
pv_tty_write(state, "\033[A", 3);
pv_tty_write(&(state->flags), "\033[A", 3);
displayed_lines--;
}
/* Check whether all watched items have finished. */
all_watching_finished = true;
for (watch_idx = 0; watch_idx < state->watchfd.count; watch_idx++) {
if (watching[watch_idx].finished)
continue;
all_watching_finished = false;
break;
}
}
if (!state->control.numeric)
pv_tty_write(&(state->flags), "\n", 1);
/*
* Clean up our displayed lines on exit.
* Clean up our displayed lines after the display loop.
*/
blank_lines = prev_displayed_lines;
while (blank_lines > 0) {
pvdisplay_width_t blank_count;
for (blank_count = 0; blank_count < state->control.width; blank_count++)
pv_tty_write(state, " ", 1);
pv_tty_write(state, "\r", 1);
pv_tty_write(&(state->flags), " ", 1);
pv_tty_write(&(state->flags), "\r", 1);
blank_lines--;
if (blank_lines > 0)
pv_tty_write(state, "\n", 1);
pv_tty_write(&(state->flags), "\n", 1);
}
while (prev_displayed_lines > 1) {
pv_tty_write(state, "\033[A", 3);
pv_tty_write(&(state->flags), "\033[A", 3);
prev_displayed_lines--;
}
/*
* Free the per-fd state.
* If a signal caused the end of the loop, reflect that in the
* return code.
*/
for (idx = 0; NULL != info_array && idx < array_length; idx++) {
if (NULL == info_array[idx].state)
if (1 == state->flags.trigger_exit)
state->status.exit_status |= PV_ERROREXIT_SIGNAL;
end_pv_watchfd_loop:
/* Free all allocated memory. */
/*@-compdestroy@ */
for (watch_idx = 0; NULL != watching && watch_idx < state->watchfd.count; watch_idx++) {
int info_idx;
if (NULL == watching[watch_idx].info_array)
continue;
pv_state_free(info_array[idx].state);
info_array[idx].state = NULL;
for (info_idx = 0; info_idx < watching[watch_idx].array_length; info_idx++) {
pv_freecontents_watchfd(&(watching[watch_idx].info_array[info_idx]));
}
free(watching[watch_idx].info_array);
watching[watch_idx].info_array = NULL;
watching[watch_idx].array_length = 0;
}
free(watching);
watching = NULL;
if (NULL != info_array)
free(info_array);
return 0;
return state->status.exit_status;
/*@+compdestroy @ */
/*
* splint warns that watching[].info_array->transfer.transfer_buffer
* and other deep structures may not be deallocated and so leak
* memory, but that's what pv_freecontents_watchfd() takes care of.
*/
}
+1 -1
View File
@@ -160,7 +160,7 @@ off_t pv_getnum_size(const char *str, bool decimal_units)
fractional_part = fractional_part / fractional_divisor;
integral_part += fractional_part;
debug("%s [%s] = %ld", str, decimal_units ? "decimal" : "binary", integral_part);
debug("%s [%s] = %lld", str, decimal_units ? "decimal" : "binary", (long long) integral_part);
return integral_part;
}
+27 -27
View File
@@ -19,7 +19,7 @@
#include <fcntl.h>
#ifdef HAVE_IPC
void pv_crs_needreinit(pvstate_t);
void pv_crs_needreinit(pvcursorstate_t);
#endif
/*@null@*/ static pvstate_t pv_sig_state = NULL;
@@ -43,7 +43,7 @@ static void pv_sig_ensure_tty_tostop()
return;
/* Can't look at terminal flags if backgrounded. */
if (1 == pv_sig_state->flag.suspend_stderr)
if (1 == pv_sig_state->flags.suspend_stderr)
return;
if (0 != tcgetattr(STDERR_FILENO, &terminal_attributes)) {
@@ -52,13 +52,13 @@ static void pv_sig_ensure_tty_tostop()
}
/* Can't set terminal flags if backgrounded. */
if (1 == pv_sig_state->flag.suspend_stderr)
if (1 == pv_sig_state->flags.suspend_stderr)
return;
if (0 == (terminal_attributes.c_lflag & TOSTOP)) {
terminal_attributes.c_lflag |= TOSTOP;
if (0 == tcsetattr(STDERR_FILENO, TCSANOW, &terminal_attributes)) {
pv_sig_state->flag.clear_tty_tostop_on_exit = 1;
pv_sig_state->flags.clear_tty_tostop_on_exit = 1;
debug("%s", "set terminal TOSTOP attribute");
#if HAVE_IPC
/*
@@ -95,11 +95,11 @@ static void pv_sig_ttou( /*@unused@ */ __attribute__((unused))
if (NULL == pv_sig_state)
return;
if (1 != pv_sig_state->flag.suspend_stderr) {
if (1 != pv_sig_state->flags.suspend_stderr) {
debug("%s", "SIGTTOU - suspending stderr");
pv_sig_state->flag.suspend_stderr = 1;
pv_sig_state->flags.suspend_stderr = 1;
/* Also tell the SIGCONT handler to do nothing next time. */
pv_sig_state->flag.skip_next_sigcont++;
pv_sig_state->flags.skip_next_sigcont++;
/* Raise an immediate SIGCONT to bring the rest of the pipeline back up. */
/*@-unrecog@ *//* splint doesn't know about killpg() */
if (0 != killpg(getpgrp(), SIGCONT)) {
@@ -142,19 +142,19 @@ static void pv_sig_cont( /*@unused@ */ __attribute__((unused))
if (NULL == pv_sig_state)
return;
if (pv_sig_state->flag.skip_next_sigcont > 0) {
if (pv_sig_state->flags.skip_next_sigcont > 0) {
debug("%s: %d", "SIGCONT received but ignored - current value of skip_next_sigcont",
pv_sig_state->flag.skip_next_sigcont);
pv_sig_state->flag.skip_next_sigcont--;
pv_sig_state->flags.skip_next_sigcont);
pv_sig_state->flags.skip_next_sigcont--;
return;
} else if (pv_sig_state->flag.skip_next_sigcont < 0) {
pv_sig_state->flag.skip_next_sigcont = 0;
} else if (pv_sig_state->flags.skip_next_sigcont < 0) {
pv_sig_state->flags.skip_next_sigcont = 0;
debug("%s", "skip_next_sigcont underrun cleared");
}
debug("%s: %d", "SIGCONT received - current value of suspend_stderr", pv_sig_state->flag.suspend_stderr);
debug("%s: %d", "SIGCONT received - current value of suspend_stderr", pv_sig_state->flags.suspend_stderr);
pv_sig_state->flag.terminal_resized = 1;
pv_sig_state->flags.terminal_resized = 1;
/*
* We can only make the time adjustments if this SIGCONT followed a
@@ -182,19 +182,19 @@ static void pv_sig_cont( /*@unused@ */ __attribute__((unused))
* Try resuming our use of stderr, if we had suspended it, but only
* if we're now in the foreground.
*/
if (1 == pv_sig_state->flag.suspend_stderr) {
if (1 == pv_sig_state->flags.suspend_stderr) {
if (pv_in_foreground()) {
debug("%s", "SIGCONT - resuming stderr");
pv_sig_state->flag.suspend_stderr = 0;
pv_sig_state->flags.suspend_stderr = 0;
} else {
debug("%s", "SIGCONT but still in background - not resuming stderr");
}
}
if (0 == pv_sig_state->flag.suspend_stderr) {
if (0 == pv_sig_state->flags.suspend_stderr) {
pv_sig_ensure_tty_tostop();
#ifdef HAVE_IPC
pv_crs_needreinit(pv_sig_state);
pv_crs_needreinit(&(pv_sig_state->cursor));
#endif
}
}
@@ -209,7 +209,7 @@ static void pv_sig_winch( /*@unused@ */ __attribute__((unused))
{
if (NULL == pv_sig_state)
return;
pv_sig_state->flag.terminal_resized = 1;
pv_sig_state->flags.terminal_resized = 1;
}
#endif
@@ -222,7 +222,7 @@ static void pv_sig_term( /*@unused@ */ __attribute__((unused))
{
if (NULL == pv_sig_state)
return;
pv_sig_state->flag.trigger_exit = 1;
pv_sig_state->flags.trigger_exit = 1;
}
@@ -297,7 +297,7 @@ void pv_sig_init(pvstate_t state)
pv_sig_state = state;
pv_sig_state->flag.suspend_stderr = 0;
pv_sig_state->flags.suspend_stderr = 0;
pv_elapsedtime_zero(&(pv_sig_state->signal.tstp_time));
pv_elapsedtime_zero(&(pv_sig_state->signal.toffset));
@@ -320,7 +320,7 @@ void pv_sig_init(pvstate_t state)
* Handle SIGTTOU by continuing with output switched off, so that we
* can be stopped and backgrounded without messing up the terminal.
*/
pv_sig_state->flag.skip_next_sigcont = 0;
pv_sig_state->flags.skip_next_sigcont = 0;
sa.sa_handler = pv_sig_ttou;
(void) sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
@@ -436,7 +436,7 @@ void pv_sig_fini( /*@unused@ */ __attribute__((unused)) pvstate_t state)
#endif
(void) sigaction(SIGALRM, &(pv_sig_state->signal.old_sigalrm), NULL);
need_to_clear_tostop = (1 == pv_sig_state->flag.clear_tty_tostop_on_exit) ? true : false;
need_to_clear_tostop = (1 == pv_sig_state->flags.clear_tty_tostop_on_exit) ? true : false;
if (pv_sig_state->control.cursor) {
#ifdef HAVE_IPC
@@ -477,7 +477,7 @@ void pv_sig_fini( /*@unused@ */ __attribute__((unused)) pvstate_t state)
}
}
pv_sig_state->flag.clear_tty_tostop_on_exit = 0;
pv_sig_state->flags.clear_tty_tostop_on_exit = 0;
}
}
@@ -537,17 +537,17 @@ void pv_sig_checkbg(void)
next_check = time(NULL) + 1;
if (0 == pv_sig_state->flag.suspend_stderr)
if (0 == pv_sig_state->flags.suspend_stderr)
return;
if (!pv_in_foreground())
return;
debug("%s: %s", "pv_sig_checkbg", "attempting to resume stderr");
pv_sig_state->flag.suspend_stderr = 0;
pv_sig_state->flags.suspend_stderr = 0;
pv_sig_ensure_tty_tostop();
#ifdef HAVE_IPC
pv_crs_needreinit(pv_sig_state);
pv_crs_needreinit(&(pv_sig_state->cursor));
#endif
}
+257 -138
View File
@@ -21,29 +21,139 @@
#include <fcntl.h>
/* alloc / realloc history buffer */
static void pv_alloc_history(pvstate_t state)
/*
* Allocate or reallocate the history buffer for calculating average
* transfer rate.
*/
static void pv_alloc_calc_history(pvtransfercalc_t calc)
{
if (NULL != state->calc.history)
free(state->calc.history);
state->calc.history = NULL;
if (NULL != calc->history)
free(calc->history);
calc->history = NULL;
state->calc.history = calloc((size_t) (state->calc.history_len), sizeof(state->calc.history[0]));
if (NULL == state->calc.history) {
calc->history = calloc((size_t) (calc->history_len), sizeof(calc->history[0]));
if (NULL == calc->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->status.program_name,
_("history structure allocation failed"), strerror(errno));
pv_error("%s: %s", _("history structure allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
state->calc.history_first = state->calc.history_last = 0;
state->calc.history[0].elapsed_sec = 0.0; /* to be safe, memset() not recommended for doubles */
calc->history_first = calc->history_last = 0;
calc->history[0].elapsed_sec = 0.0; /* to be safe, memset() not recommended for doubles */
}
/*
* Set the "calc" state sub-structure's history length appropriately for the
* given average rate window setting, allocate an appropriate history, and
* return the appropriate history interval to use.
*/
unsigned int pv_update_calc_average_rate_window(pvtransfercalc_t calc, unsigned int val)
{
unsigned int history_interval;
if (val < 1)
val = 1;
if (val >= 20) {
calc->history_len = (size_t) (val / 5 + 1);
history_interval = 5;
} else {
calc->history_len = (size_t) (val + 1);
history_interval = 1;
}
pv_alloc_calc_history(calc);
return history_interval;
}
/*
* Clear the "calc" part of a state structure.
*/
void pv_reset_calc(pvtransfercalc_t calc)
{
if (NULL == calc)
return;
/*
* Explicitly set important floating point values to 0, as memset()
* is not recommended for this.
*/
calc->transfer_rate = 0.0;
calc->average_rate = 0.0;
calc->prev_elapsed_sec = 0.0;
calc->prev_rate = 0.0;
calc->prev_trans = 0.0;
calc->current_avg_rate = 0.0;
calc->rate_min = 0.0;
calc->rate_max = 0.0;
calc->rate_sum = 0.0;
calc->ratesquared_sum = 0.0;
calc->measurements_taken = 0;
calc->prev_transferred = 0;
calc->percentage = 0.0;
calc->history_first = calc->history_last = 0;
if (NULL != calc->history) {
calc->history[0].elapsed_sec = 0.0;
}
}
/*
* Clear the "transfer" part of a state structure.
*/
void pv_reset_transfer(pvtransferstate_t transfer)
{
if (NULL == transfer)
return;
transfer->elapsed_seconds = 0.0;
transfer->read_position = 0;
transfer->write_position = 0;
transfer->to_write = 0;
transfer->written = 0;
transfer->total_bytes_read = 0;
transfer->total_written = 0;
transfer->written_but_not_consumed = 0;
transfer->read_errors_in_a_row = 0;
transfer->last_read_skip_fd = 0;
#ifdef HAVE_SPLICE
transfer->splice_failed_fd = -1;
#endif /* HAVE_SPLICE */
transfer->line_positions_length = 0;
transfer->line_positions_head = 0;
transfer->last_output_position = 0;
}
/*
* Reset the calculated parts of the "flags" state structure.
*/
void pv_reset_flags(pvtransientflags_t flags)
{
if (NULL == flags)
return;
flags->reparse_display = 1;
}
/*
* Reset the calculated parts of a "display" state structure.
*/
void pv_reset_display(pvdisplay_t display)
{
if (NULL == display)
return;
display->initial_offset = 0;
display->output_produced = false;
}
@@ -55,60 +165,21 @@ void pv_state_reset(pvstate_t state)
if (NULL == state)
return;
state->flag.reparse_display = 1;
pv_reset_flags(&(state->flags));
state->status.current_input_file = -1;
state->display.initial_offset = 0;
state->display.display_visible = false;
pv_reset_display(&(state->display));
pv_reset_display(&(state->extra_display));
state->extra_display.initial_offset = 0;
state->extra_display.display_visible = false;
/*
* Explicitly set important floating point values to 0, as memset()
* is not recommended for this.
*/
state->calc.transfer_rate = 0.0;
state->calc.average_rate = 0.0;
state->calc.prev_elapsed_sec = 0.0;
state->calc.prev_rate = 0.0;
state->calc.prev_trans = 0.0;
state->calc.current_avg_rate = 0.0;
state->calc.rate_min = 0.0;
state->calc.rate_max = 0.0;
state->calc.rate_sum = 0.0;
state->calc.ratesquared_sum = 0.0;
state->calc.measurements_taken = 0;
state->calc.prev_transferred = 0;
state->calc.percentage = 0.0;
state->calc.history_first = state->calc.history_last = 0;
if (NULL != state->calc.history) {
state->calc.history[0].elapsed_sec = 0.0;
}
state->transfer.elapsed_seconds = 0.0;
state->transfer.read_position = 0;
state->transfer.write_position = 0;
state->transfer.to_write = 0;
state->transfer.written = 0;
state->transfer.total_written = 0;
state->transfer.written_but_not_consumed = 0;
state->transfer.read_errors_in_a_row = 0;
state->transfer.last_read_skip_fd = 0;
#ifdef HAVE_SPLICE
state->transfer.splice_failed_fd = -1;
#endif /* HAVE_SPLICE */
state->transfer.line_positions_length = 0;
state->transfer.line_positions_head = 0;
state->transfer.last_output_position = 0;
pv_reset_calc(&(state->calc));
pv_reset_transfer(&(state->transfer));
}
/*
* Create a new state structure, and return it, or 0 (NULL) on error.
*/
pvstate_t pv_state_alloc(const char *program_name)
pvstate_t pv_state_alloc(void)
{
pvstate_t state;
@@ -117,19 +188,7 @@ pvstate_t pv_state_alloc(const char *program_name)
return NULL;
memset(state, 0, sizeof(*state));
/* splint 3.1.2 thinks this is required for some reason. */
if (NULL != state->status.program_name) {
free(state->status.program_name);
}
state->status.program_name = pv_strdup(program_name);
if (NULL == state->status.program_name) {
free(state);
return NULL;
}
state->control.watch_pid = 0;
state->control.watch_fd = -1;
state->watchfd.count = 0;
state->control.output_fd = -1;
#ifdef HAVE_IPC
state->cursor.shmid = -1;
@@ -157,6 +216,46 @@ pvstate_t pv_state_alloc(const char *program_name)
}
/*
* Free dynamic contents of a display structure.
*/
void pv_freecontents_display(pvdisplay_t display)
{
if (NULL != display->display_buffer)
free(display->display_buffer);
display->display_buffer = NULL;
}
/*
* Free dynamic contents of a transfer state structure.
*/
void pv_freecontents_transfer(pvtransferstate_t transfer)
{
/*@-keeptrans@ */
if (NULL != transfer->transfer_buffer)
free(transfer->transfer_buffer);
transfer->transfer_buffer = NULL;
/*@+keeptrans@ */
/* splint - explicitly freeing this structure, so free() here is OK. */
if (NULL != transfer->line_positions)
free(transfer->line_positions);
transfer->line_positions = NULL;
}
/*
* Free dynamic contents of a calculated transfer state structure.
*/
void pv_freecontents_calc(pvtransfercalc_t calc)
{
if (NULL != calc->history)
free(calc->history);
calc->history = NULL;
}
/*
* Free a state structure, after which it can no longer be used.
*/
@@ -172,9 +271,9 @@ void pv_state_free(pvstate_t state)
if (state->control.output_fd >= 0) {
if (STDOUT_FILENO != state->control.output_fd) {
if (close(state->control.output_fd) < 0) {
fprintf(stderr, "%s: %s: %s\n", state->status.program_name,
NULL == state->control.output_name ? "(null)" : state->control.output_name,
strerror(errno));
pv_error("%s: %s",
NULL == state->control.output_name ? "(null)" : state->control.output_name,
strerror(errno));
}
}
state->control.output_fd = -1;
@@ -185,17 +284,8 @@ void pv_state_free(pvstate_t state)
state->control.output_name = NULL;
}
if (NULL != state->status.program_name)
free(state->status.program_name);
state->status.program_name = NULL;
if (NULL != state->display.display_buffer)
free(state->display.display_buffer);
state->display.display_buffer = NULL;
if (NULL != state->extra_display.display_buffer)
free(state->extra_display.display_buffer);
state->extra_display.display_buffer = NULL;
pv_freecontents_display(&(state->display));
pv_freecontents_display(&(state->extra_display));
if (NULL != state->control.name) {
free(state->control.name);
@@ -217,20 +307,9 @@ void pv_state_free(pvstate_t state)
state->control.extra_format_string = NULL;
}
/*@-keeptrans@ */
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. */
pv_freecontents_transfer(&(state->transfer));
if (NULL != state->transfer.line_positions)
free(state->transfer.line_positions);
state->transfer.line_positions = NULL;
if (NULL != state->calc.history)
free(state->calc.history);
state->calc.history = NULL;
pv_freecontents_calc(&(state->calc));
if (NULL != state->files.filename) {
unsigned int file_idx;
@@ -244,6 +323,15 @@ void pv_state_free(pvstate_t state)
state->files.filename = NULL;
}
if (NULL != state->watchfd.pid) {
free(state->watchfd.pid);
state->watchfd.pid = NULL;
}
if (NULL != state->watchfd.fd) {
free(state->watchfd.fd);
state->watchfd.fd = NULL;
}
free(state);
return;
@@ -316,7 +404,7 @@ void pv_state_set_format(pvstate_t state, bool progress, bool timer, bool eta, b
state->control.name = pv_strdup(name);
/* Tell pv_format() that the format has changed. */
state->flag.reparse_display = 1;
state->flags.reparse_display = 1;
}
@@ -531,16 +619,6 @@ void pv_state_extra_display_set(pvstate_t state, /*@null@ */ const char *val)
}
}
void pv_state_watch_pid_set(pvstate_t state, pid_t val)
{
state->control.watch_pid = val;
}
void pv_state_watch_fd_set(pvstate_t state, int val)
{
state->control.watch_fd = val;
}
void pv_state_output_set(pvstate_t state, int fd, const char *name)
{
/*
@@ -549,9 +627,9 @@ void pv_state_output_set(pvstate_t state, int fd, const char *name)
*/
if (state->control.output_fd >= 0 && state->control.output_fd != STDOUT_FILENO) {
if (close(state->control.output_fd) < 0) {
fprintf(stderr, "%s: %s: %s\n", state->status.program_name,
NULL == state->control.output_name ? "(null)" : state->control.output_name,
strerror(errno));
pv_error("%s: %s",
NULL == state->control.output_name ? "(null)" : state->control.output_name,
strerror(errno));
}
}
if (NULL != state->control.output_name)
@@ -574,19 +652,12 @@ void pv_state_average_rate_window_set(pvstate_t state, unsigned int val)
if (val < 1)
val = 1;
state->control.average_rate_window = val;
if (val >= 20) {
state->calc.history_len = (size_t) (val / 5 + 1);
state->control.history_interval = 5;
} else {
state->calc.history_len = (size_t) (val + 1);
state->control.history_interval = 1;
}
pv_alloc_history(state);
state->control.history_interval = pv_update_calc_average_rate_window(&(state->calc), val);
}
void pv_state_set_can_display_utf8(pvstate_t state, bool val)
void pv_state_set_terminal_supports_utf8(pvstate_t state, bool val)
{
state->control.can_display_utf8 = val;
state->status.terminal_supports_utf8 = val;
}
/*
@@ -595,43 +666,91 @@ void pv_state_set_can_display_utf8(pvstate_t state, bool val)
void pv_state_inputfiles(pvstate_t state, unsigned int input_file_count, const char **input_files)
{
unsigned int file_idx;
/*@only@ */ nullable_string_t *new_array;
/* Free the old array and its contents, if there was one. */
if (NULL != state->files.filename) {
for (file_idx = 0; file_idx < state->files.file_count; file_idx++) {
/*@-unqualifiedtrans@ */
free(state->files.filename[file_idx]);
/*@+unqualifiedtrans@ */
/*
* TODO: find a way to tell splint the array
* contents are "only" and "null" as well as the
* array itself.
*/
}
free(state->files.filename);
state->files.filename = NULL;
state->files.file_count = 0;
}
state->files.filename = calloc((size_t) (input_file_count + 1), sizeof(char *));
if (NULL == state->files.filename) {
/* Allocate an empty new array of the right size. */
new_array = calloc((size_t) (input_file_count + 1), sizeof(char *));
if (NULL == new_array) {
/*@-mustfreefresh@ *//* see similar _() issue above */
fprintf(stderr, "%s: %s: %s\n", state->status.program_name, _("file list allocation failed"),
strerror(errno));
pv_error("%s: %s", _("file list allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
state->files.filename = new_array;
/* Populate the new array with copies of the filenames. */
for (file_idx = 0; file_idx < input_file_count; file_idx++) {
/*@-nullstate@ */
state->files.filename[file_idx] = pv_strdup(input_files[file_idx]);
if (NULL == state->files.filename[file_idx]) {
/*@only@ */ char *new_string;
new_string = pv_strdup(input_files[file_idx]);
if (NULL == new_string) {
/*@-mustfreefresh@ *//* see similar _() issue above */
fprintf(stderr, "%s: %s: %s\n", state->status.program_name,
_("file list allocation failed"), strerror(errno));
pv_error("%s: %s", _("file list allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
state->files.filename[file_idx] = new_string;
}
state->files.file_count = input_file_count;
}
/*@+nullstate@*/
/* splint: see unqualifiedtrans note by free() above. */
/*
* Set the arrays of watchfd process IDs and file descriptors.
*/
void pv_state_watchfds(pvstate_t state, unsigned int watchfd_count, const pid_t * pids, const int *fds)
{
unsigned int item_idx;
/*@only@ */ pid_t *new_pid_array = NULL;
/*@only@ */ int *new_fd_array = NULL;
/* Free the old arrays, if there were any. */
if (NULL != state->watchfd.pid) {
free(state->watchfd.pid);
state->watchfd.pid = NULL;
}
if (NULL != state->watchfd.fd) {
free(state->watchfd.fd);
state->watchfd.fd = NULL;
}
state->watchfd.count = 0;
state->watchfd.multiple_pids = false;
/* Allocate empty new arrays of the right size. */
new_pid_array = calloc((size_t) (watchfd_count + 1), sizeof(pid_t));
if (NULL == new_pid_array) {
/*@-mustfreefresh@ *//* see similar _() issue above */
pv_error("%s: %s", _("process list allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
state->watchfd.pid = new_pid_array;
new_fd_array = calloc((size_t) (watchfd_count + 1), sizeof(int));
if (NULL == new_fd_array) {
/*@-mustfreefresh@ *//* see similar _() issue above */
pv_error("%s: %s", _("file descriptor list allocation failed"), strerror(errno));
/*@+mustfreefresh@ */
return;
}
state->watchfd.fd = new_fd_array;
/* Populate the new arrays with the values supplied. */
for (item_idx = 0; item_idx < watchfd_count; item_idx++) {
state->watchfd.pid[item_idx] = pids[item_idx];
state->watchfd.fd[item_idx] = fds[item_idx];
if ((item_idx > 0) && (pids[item_idx] != pids[item_idx - 1]))
state->watchfd.multiple_pids = true;
}
state->watchfd.count = watchfd_count;
debug("%s=%d, %s=%s", "watchfd.count", state->watchfd.count, "multiple_pids",
state->watchfd.multiple_pids ? "true" : "false");
}
+58 -33
View File
@@ -300,41 +300,63 @@ static ssize_t pv__transfer_write_repeated(int fd, char *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->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.
* in the input buffer, capped to the number of bytes left until
* state->control.size is reached if state->control.stop_at_size is true.
* If state->control.rate_limit is >0, and/or "max_to_write" is >0, and
* splice() is used, then the maximum number of bytes read will be further
* capped to the value of "max_to_write", since splice() writes as well as
* reads.
*
* 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.
* 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->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->transfer.written since they've been written
* to the output).
* 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->transfer.written since
* they've been written to the output).
*
* On read error, updates state->status.exit_status, and if allowed by
* Also increases state->transfer.total_bytes_read by the number of bytes
* read, regardless of whether splice() was used, since total_bytes_read is
* what it says it is, rather than being a buffer indicator.
*
* On read error, updates state->status.exit_status, and if max_to_write 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
* point, then also sets *eof_out to true.
*/
static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t allowed)
static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t max_to_write)
{
bool do_not_skip_errors;
size_t bytes_can_read;
off_t amount_to_skip, amount_skipped, orig_offset, skip_offset;
ssize_t nread;
#ifdef HAVE_SPLICE
size_t bytes_to_splice;
#endif /* HAVE_SPLICE */
do_not_skip_errors = false;
if (0 == state->control.skip_errors)
do_not_skip_errors = true;
bytes_can_read = state->transfer.buffer_size - state->transfer.read_position;
/*
* Don't read past control.size if stop_at_size is true (issue
* #166).
*
* This isn't workable in line mode.
*/
if (state->control.stop_at_size && !state->control.linemode) {
off_t bytes_remaining_to_read = state->control.size - state->transfer.total_bytes_read;
if ((long long) bytes_can_read > (long long) bytes_remaining_to_read) {
debug("%lld > (%lld-%lld=%lld): %s", (long long) bytes_can_read,
(long long) (state->control.size), (long long) state->transfer.total_bytes_read,
(long long) bytes_remaining_to_read, "truncating for stop-at-size");
bytes_can_read = (size_t) bytes_remaining_to_read;
}
}
nread = 0;
#ifdef HAVE_SPLICE
@@ -342,8 +364,10 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
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;
size_t bytes_to_splice;
if (state->control.rate_limit > 0 || max_to_write != 0) {
bytes_to_splice = (size_t) max_to_write;
} else {
bytes_to_splice = bytes_can_read;
}
@@ -365,6 +389,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
*/
} else if (nread > 0) {
state->transfer.written = nread;
state->transfer.total_bytes_read += nread;
#ifdef HAVE_FDATASYNC
if (state->control.sync_after_write) {
/*
@@ -430,6 +455,8 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
#else
state->transfer.read_position += nread;
#endif /* HAVE_SPLICE */
/* Update the counter of all bytes read so far. */
state->transfer.total_bytes_read += nread;
return 1;
}
@@ -460,7 +487,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
* reached the end of this file.
*/
if (do_not_skip_errors) {
pv_error(state, "%s: %s: %s", pv_current_file_name(state), _("read failed"), strerror(errno));
pv_error("%s: %s: %s", pv_current_file_name(state), _("read failed"), strerror(errno));
*eof_in = true;
if (state->transfer.write_position >= state->transfer.read_position) {
*eof_out = true;
@@ -476,7 +503,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
if (!state->transfer.read_error_warning_shown) {
/*@-compdef@ */
pv_error(state, "%s: %s: %s", pv_current_file_name(state), _("warning: read errors detected"),
pv_error("%s: %s: %s", pv_current_file_name(state), _("warning: read errors detected"),
strerror(errno));
/*@+compdef@ */
/* splint - see previous pv_current_file_name() call. */
@@ -492,7 +519,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
*/
if (0 > orig_offset) {
/*@-compdef@ */
pv_error(state, "%s: %s: %s", pv_current_file_name(state), _("file is not seekable"), strerror(errno));
pv_error("%s: %s: %s", pv_current_file_name(state), _("file is not seekable"), strerror(errno));
/*@+compdef@ */
/* splint - see previous pv_current_file_name() calls. */
*eof_in = true;
@@ -569,8 +596,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
*/
if (EINVAL != errno) {
/*@-compdef@ */
pv_error(state,
"%s: %s: %s", pv_current_file_name(state), _("failed to seek past error"),
pv_error("%s: %s: %s", pv_current_file_name(state), _("failed to seek past error"),
strerror(errno));
/*@+compdef@ */
/* splint - see previous pv_current_file_name() calls. */
@@ -588,7 +614,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou
state->transfer.read_position += amount_skipped;
if (state->control.skip_errors < 2) {
/*@-compdef@ */
pv_error(state, "%s: %s: %ld - %ld (%ld %s)",
pv_error("%s: %s: %ld - %ld (%ld %s)",
pv_current_file_name(state),
_("skipped past read error"), (long) orig_offset, (long) skip_offset,
(long) amount_skipped, _("B"));
@@ -631,7 +657,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
int write_errno;
if (NULL == state->transfer.transfer_buffer) {
pv_error(state, "%s", _("no transfer buffer allocated"));
pv_error("%s", _("no transfer buffer allocated"));
state->status.exit_status |= PV_ERROREXIT_MEMORY;
*eof_out = true;
state->transfer.written = -1;
@@ -673,7 +699,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
(long) (new_timer.it_value.tv_usec));
if (0 != setitimer(ITIMER_REAL, &new_timer, NULL)) {
pv_error(state, "%s: %s", _("failed to set interval timer"), strerror(errno));
pv_error("%s: %s", _("failed to set interval timer"), strerror(errno));
}
#else /* ! HAVE_SETITIMER */
@@ -699,7 +725,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
new_timer.it_value.tv_sec = 0;
new_timer.it_value.tv_usec = 0;
if (0 != setitimer(ITIMER_REAL, &new_timer, NULL)) {
pv_error(state, "%s: %s", _("failed to clear interval timer"), strerror(errno));
pv_error("%s: %s", _("failed to clear interval timer"), strerror(errno));
}
/*@+unrecog@ */
@@ -741,7 +767,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
state->transfer.line_positions =
calloc((size_t) (state->transfer.line_positions_capacity), sizeof(off_t));
if (NULL == state->transfer.line_positions) {
pv_error(state, "%s: %s", _("line position buffer allocation failed"),
pv_error("%s: %s", _("line position buffer allocation failed"),
strerror(errno));
}
/*@+mustfreeonly@ */
@@ -910,12 +936,12 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
if (EPIPE == write_errno) {
*eof_in = true;
*eof_out = true;
state->flag.pipe_closed = 1;
state->flags.pipe_closed = 1;
debug("%s", "SIGPIPE received - setting pipe_closed");
return 0;
}
pv_error(state, "%s: %s", _("write failed"), strerror(write_errno));
pv_error("%s: %s", _("write failed"), strerror(write_errno));
state->status.exit_status |= PV_ERROREXIT_TRANSFER;
*eof_out = true;
state->transfer.written = -1;
@@ -940,7 +966,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
/*@only@*/
static char *pv__allocate_aligned_buffer(int outfd, int infd, size_t target_size)
{
char *newptr;
void *newptr;
#if defined(HAVE_FPATHCONF) && defined(HAVE_POSIX_MEMALIGN) && defined(_PC_REC_XFER_ALIGN)
long input_alignment, output_alignment, min_alignment;
@@ -1054,7 +1080,7 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
state->transfer.transfer_buffer =
pv__allocate_aligned_buffer(state->control.output_fd, fd, state->control.target_buffer_size + 32);
if (NULL == state->transfer.transfer_buffer) {
pv_error(state, "%s: %s", _("buffer allocation failed"), strerror(errno));
pv_error("%s: %s", _("buffer allocation failed"), strerror(errno));
state->status.exit_status |= PV_ERROREXIT_MEMORY;
return -1;
}
@@ -1156,8 +1182,7 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
* Any other error is a problem and we must report back.
*/
/*@-compdef@ */
pv_error(state, "%s: %s: %d: %s", pv_current_file_name(state), _("select call failed"), n,
strerror(errno));
pv_error("%s: %s: %d: %s", pv_current_file_name(state), _("select call failed"), n, strerror(errno));
/*@+compdef@ */
/* splint - see previous pv_current_file_name() calls. */
+145 -133
View File
@@ -96,7 +96,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
if (kill(info->watch_pid, 0) != 0) {
if (!automatic)
pv_error(state, "%s %u: %s", _("pid"), info->watch_pid, strerror(errno));
pv_error("%s %u: %s", _("pid"), info->watch_pid, strerror(errno));
return 1;
}
@@ -105,8 +105,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
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));
pv_error("%s %u: %s %d: %s", _("pid"), info->watch_pid, _("fd"), info->watch_fd, strerror(errno));
return 3;
}
@@ -116,7 +115,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
if (!(0 == stat(info->file_fdpath, &(info->sb_fd)))) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
pv_error("%s %u: %s %d: %s: %s",
_("pid"),
info->watch_pid, _("fd"), info->watch_fd, info->file_fdpath, strerror(errno));
return 3;
@@ -124,7 +123,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
if (!filesize(info)) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
pv_error("%s %u: %s %d: %s: %s",
_("pid"),
info->watch_pid,
_("fd"), info->watch_fd, info->file_fdpath, _("not a regular file or block device"));
@@ -162,7 +161,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
if (kill(info->watch_pid, 0) != 0) {
if (!automatic)
pv_error(state, "%s %u: %s", _("pid"), info->watch_pid, strerror(errno));
pv_error("%s %u: %s", _("pid"), info->watch_pid, strerror(errno));
return 1;
}
(void) pv_snprintf(info->file_fdinfo, PV_SIZEOF_FILE_FDINFO,
@@ -180,7 +179,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
* and then only if it's a block device - see filesize().
*/
if (!automatic)
pv_error(state, "%s %u: %s %d: %s",
pv_error("%s %u: %s %d: %s",
_("pid"), info->watch_pid, _("fd"), info->watch_fd, strerror(errno));
return 2;
}
@@ -188,7 +187,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
if (!((0 == stat(info->file_fd, &(info->sb_fd)))
&& (0 == lstat(info->file_fd, &(info->sb_fd_link))))) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
pv_error("%s %u: %s %d: %s: %s",
_("pid"),
info->watch_pid, _("fd"), info->watch_fd, info->file_fdpath, strerror(errno));
return 3;
@@ -198,7 +197,7 @@ int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, bool automatic)
if (!filesize(info)) {
if (!automatic)
pv_error(state, "%s %u: %s %d: %s: %s",
pv_error("%s %u: %s %d: %s: %s",
_("pid"),
info->watch_pid,
_("fd"), info->watch_fd, info->file_fdpath, _("not a regular file or block device"));
@@ -297,7 +296,7 @@ static int pidfds(pvstate_t state, unsigned int pid, struct proc_fdinfo **fds, i
{
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));
pv_error("%s: unable to list pid fds: %s", _("pid"), strerror(errno));
return -1;
}
@@ -305,7 +304,7 @@ static int pidfds(pvstate_t state, unsigned int pid, struct proc_fdinfo **fds, i
*fds = (struct proc_fdinfo *) malloc(size_needed);
if (*fds == NULL) {
pv_error(state, "%s: alloc failed: %s", _("pid"), strerror(errno));
pv_error("%s: alloc failed: %s", _("pid"), strerror(errno));
return -1;
}
memset(*fds, 0, size_needed);
@@ -354,6 +353,10 @@ static bool extend_info_array(int *array_length_ptr, pvwatchfd_t * info_array_pt
return false;
}
new_info_array[array_length - 1].unused = true;
debug("%s", "extended info array");
*info_array_ptr = new_info_array;
*array_length_ptr = array_length;
return true;
@@ -364,25 +367,76 @@ static bool extend_info_array(int *array_length_ptr, pvwatchfd_t * info_array_pt
/*@+compdef @ */
/*
* Reset calculated values in the given watchfd info structure.
*/
void pv_reset_watchfd(pvwatchfd_t info)
{
if (NULL == info)
return;
pv_reset_calc(&(info->calc));
pv_reset_transfer(&(info->transfer));
pv_reset_flags(&(info->flags));
pv_reset_display(&(info->display));
}
/*
* Free dynamically allocated areas in the given watchfd info structure.
*/
void pv_freecontents_watchfd(pvwatchfd_t info)
{
if (NULL == info)
return;
pv_freecontents_calc(&(info->calc));
pv_freecontents_transfer(&(info->transfer));
pv_freecontents_display(&(info->display));
}
/*
* Comparison function for qsort, to compare two pvwatchfd_s structures.
*/
static int pv_compare_watchfd(const void *a, const void *b)
{
int fd_a, fd_b;
fd_a = 0;
fd_b = 0;
if (NULL != a)
fd_a = ((pvwatchfd_t) a)->watch_fd;
if (NULL != b)
fd_b = ((pvwatchfd_t) b)->watch_fd;
if (fd_a < fd_b)
return -1;
if (fd_a > fd_b)
return 1;
return 0;
}
/*
* Scan the given process and update the arrays with any new file
* descriptors.
* descriptors. If "watch_fd" is not -1, then all other file descriptors
* numbers will be ignored,
*
* Returns 0 on success, 1 if the process no longer exists or could not be
* read, or 2 for a memory allocation error.
*/
int pv_watchpid_scanfds(pvstate_t state,
pid_t watch_pid, int *array_length_ptr, pvwatchfd_t * info_array_ptr, int *fd_to_idx)
int pv_watchpid_scanfds(pvstate_t state, pid_t watch_pid, int watch_fd, int *array_length_ptr,
pvwatchfd_t * info_array_ptr)
{
int array_length = 0;
struct pvwatchfd_s *info_array = NULL;
bool changes_made;
#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"));
pv_error("%s: pidfds failed", _("pid"));
return -1;
}
#else
@@ -401,18 +455,19 @@ int pv_watchpid_scanfds(pvstate_t state,
array_length = *array_length_ptr;
info_array = *info_array_ptr;
changes_made = false;
#ifdef __APPLE__
if (fd_infos_count < 1) {
pv_error(state, "%s: no fds found", _("pid"));
pv_error("%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;
int fd, check_idx, found_idx, use_idx, rc;
off_t position_now;
const char *use_format_string;
fd = -1;
#ifdef __APPLE__
@@ -422,24 +477,35 @@ int pv_watchpid_scanfds(pvstate_t state,
continue;
#endif
/* Skip if the fd is outside the array. */
if ((fd < 0) || (fd >= FD_SETSIZE))
/* Skip if the fd is negative. */
if (fd < 0)
continue;
/* If a watch_fd was specified, skip if this isn't it. */
if (watch_fd >= 0 && watch_fd != fd)
continue;
/*
* Skip if this fd is already known to us.
*/
if (fd_to_idx[fd] != -1) {
continue;
found_idx = -1;
for (check_idx = 0; check_idx < array_length; check_idx++) {
if (info_array[check_idx].unused)
continue;
if (info_array[check_idx].watch_fd != fd)
continue;
found_idx = check_idx;
break;
}
if (found_idx >= 0)
continue;
/*
* See if there's an empty slot we can re-use. An empty slot
* has a watch_pid of 0.
* See if there's an empty slot we can re-use.
*/
use_idx = -1;
for (check_idx = 0; check_idx < array_length; check_idx++) {
if (info_array[check_idx].watch_pid == 0) {
if (info_array[check_idx].unused) {
use_idx = check_idx;
break;
}
@@ -458,69 +524,25 @@ int pv_watchpid_scanfds(pvstate_t state,
debug("%s: %d => index %d", "found new fd", fd, use_idx);
changes_made = true;
/*
* Initialise the details of this new entry.
*/
memset(&(info_array[use_idx]), 0, sizeof(info_array[use_idx]));
pv_reset_watchfd(&(info_array[use_idx]));
info_array[use_idx].watch_pid = watch_pid;
info_array[use_idx].watch_fd = fd;
/* Allocate new display state. */
/*@-mustfreeonly@ *//* splint - this is not a leak, this is a new entry. */
info_array[use_idx].state = pv_state_alloc(state->status.program_name);
/*@+mustfreeonly@ */
if (NULL == info_array[use_idx].state)
return 2;
/* Copy the main status.cwd value to the new state. */
memcpy(&(info_array[use_idx].state->status.cwd), &(state->status.cwd), sizeof(state->status.cwd)); /* flawfinder: ignore */
/* flawfinder: bounded to destination object size. */
info_array[use_idx].unused = false;
info_array[use_idx].displayable = true;
/*
* Copy over all the control values, blanking out the
* dynamically allocated strings, and setting the default
* format (fixed buffer) to the required format string
* instead of allocating a new dynamic format string for the
* copy (so there's less dynamic allocation going on).
* Set the average rate window so that a new history buffer
* is allocated for this state.
*/
memcpy(&(info_array[use_idx].state->control), &(state->control), sizeof(state->control)); /* flawfinder: ignore */
/* flawfinder: bounded to destination object size. */
/*@-mustfreeonly@ *//* splint - this is not a leak, this is a new entry. */
info_array[use_idx].state->control.name = NULL;
info_array[use_idx].state->control.format_string = NULL;
info_array[use_idx].state->control.output_name = NULL;
info_array[use_idx].state->control.default_bar_style = NULL;
/*@+mustfreeonly@ */
info_array[use_idx].state->control.default_format[0] = '\0';
use_format_string =
NULL != state->control.format_string ? state->control.format_string : state->control.default_format;
if (NULL != use_format_string)
(void) pv_snprintf(info_array[use_idx].state->control.default_format, PV_SIZEOF_DEFAULT_FORMAT,
"%.510s", use_format_string);
/*
* Duplicate the default bar style string, if there is one.
*/
if (NULL != state->control.default_bar_style) {
pv_state_default_bar_style_set(info_array[use_idx].state, state->control.default_bar_style);
}
/*
* Copy over all the display values, blanking out the
* dynamically allocated parts as above; then set the
* average rate window so that a new history buffer is
* allocated for this state.
*/
memcpy(&(info_array[use_idx].state->display), &(state->display), sizeof(state->display)); /* flawfinder: ignore */
/* flawfinder: bounded to destination object size. */
/*@-mustfreeonly@ *//* splint - this is not a leak, this is a new entry. */
info_array[use_idx].state->display.display_buffer = NULL;
info_array[use_idx].state->display.display_buffer_size = 0;
info_array[use_idx].state->calc.history = NULL;
info_array[use_idx].state->calc.history_len = 0;
/*@+mustfreeonly@ */
pv_state_average_rate_window_set(info_array[use_idx].state, state->control.average_rate_window);
(void) pv_update_calc_average_rate_window(&(info_array[use_idx].calc),
state->control.average_rate_window);
#ifdef __APPLE__
if (fd_infos[i].proc_fdtype != PROX_FDTYPE_VNODE) {
@@ -528,70 +550,33 @@ int pv_watchpid_scanfds(pvstate_t state,
}
#endif
/* Retrieve the details of this file descriptor. */
rc = pv_watchfd_info(state, &(info_array[use_idx]), true);
rc = pv_watchfd_info(state, &(info_array[use_idx]), -1 == watch_fd ? true : false);
/*
* Lookup failed - mark this slot as being free for re-use.
*/
if ((rc != 0) && (rc != 4)) {
debug("%s %d: %s: %d", "fd", fd, "lookup failed - marking slot for re-use", use_idx);
info_array[use_idx].watch_pid = 0;
if (NULL != info_array[use_idx].state)
pv_state_free(info_array[use_idx].state);
/*@-mustfreeonly@ *//* not a leak - we've just free()d it. */
info_array[use_idx].state = NULL;
/*@+mustfreeonly@ */
pv_freecontents_watchfd(&(info_array[use_idx]));
info_array[use_idx].unused = true;
info_array[use_idx].displayable = false;
continue;
}
fd_to_idx[fd] = use_idx;
/*
* Not displayable - set fd to -1 so the main loop doesn't
* show it.
* Not displayable - mark it as such so the main loop
* doesn't show it.
*/
if (rc != 0) {
debug("%s %d: %s", "fd", fd, "marking as not displayable");
info_array[use_idx].watch_fd = -1;
}
/* NULL check on the state - skip if not usable. */
if (NULL == info_array[use_idx].state) {
debug("%s %d: %s", "fd", fd, "state is NULL - marking as not displayable");
info_array[use_idx].watch_fd = -1;
continue;
}
/*
* Set the displayed size appropriately; if the size is 0,
* or not known, remove %e and %I from the state's default
* format string so that neither estimated time remaining
* nor estimated time of completion are displayed.
*/
info_array[use_idx].state->control.size = info_array[use_idx].size;
if (info_array[use_idx].state->control.size < 1) {
char *fmt;
while (NULL != (fmt = strstr(info_array[use_idx].state->control.default_format, "%e"))) {
debug("%s", "zero size - removing estimated time remaining");
/* strlen-1 here to include trailing \0 */
memmove(fmt, fmt + 2, strlen(fmt) - 1); /* flawfinder: ignore */
info_array[use_idx].state->flag.reparse_display = 1;
}
while (NULL != (fmt = strstr(info_array[use_idx].state->control.default_format, "%I"))) {
debug("%s", "zero size - removing estimated completion time");
/* strlen-1 here to include trailing \0 */
memmove(fmt, fmt + 2, strlen(fmt) - 1); /* flawfinder: ignore */
info_array[use_idx].state->flag.reparse_display = 1;
}
/* flawfinder: default_format is always \0-terminated. */
info_array[use_idx].displayable = false;
}
/* Set the info display_name appropriately. */
pv_watchpid_setname(state, &(info_array[use_idx]));
/* Carry the display_name through to the display state, and reparse. */
pv_state_name_set(info_array[use_idx].state, info_array[use_idx].display_name);
info_array[use_idx].state->flag.reparse_display = 1;
/* Force the display to be re-parsed. */
info_array[use_idx].flags.reparse_display = 1;
pv_elapsedtime_read(&(info_array[use_idx].start_time));
@@ -600,11 +585,11 @@ int pv_watchpid_scanfds(pvstate_t state,
* display), if known, so that ETA and so on are calculated
* correctly.
*/
info_array[use_idx].state->display.initial_offset = 0;
info_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) {
info_array[use_idx].state->display.initial_offset = position_now;
info_array[use_idx].display.initial_offset = position_now;
info_array[use_idx].position = position_now;
}
}
@@ -616,6 +601,14 @@ int pv_watchpid_scanfds(pvstate_t state,
(void) closedir(dptr);
#endif
/*
* If any changes were made (i.e. new file descriptors were found),
* sort the array so that file descriptors are always displayed in
* ascending numerical order.
*/
if (changes_made && NULL != info_array && array_length > 1)
qsort(info_array, (size_t) array_length, sizeof(info_array[0]), pv_compare_watchfd);
return 0;
}
@@ -624,6 +617,9 @@ int pv_watchpid_scanfds(pvstate_t state,
* Set the display name for the given watched file descriptor, truncating at
* the relevant places according to the current screen width.
*
* If more than one distinct PID is being watched, include the PID in the
* name as well as the file descriptor number.
*
* If the file descriptor is pointing to a file under the current working
* directory, show its relative path, not the full path.
*/
@@ -646,20 +642,36 @@ void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
}
max_display_length = (int) (state->control.width / 2) - 6;
if (state->watchfd.multiple_pids)
max_display_length -= 9;
if (max_display_length >= (int) path_length) {
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME, "%4d:%.498s", info->watch_fd, file_fdpath);
if (state->watchfd.multiple_pids) {
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME, "%8d:%4d:%.498s", (int) (info->watch_pid),
info->watch_fd, file_fdpath);
} else {
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME, "%4d:%.498s", info->watch_fd, file_fdpath);
}
} else {
int prefix_length, suffix_length;
prefix_length = max_display_length / 4;
suffix_length = max_display_length - prefix_length - 3;
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME,
"%4d:%.*s...%.*s",
info->watch_fd, prefix_length,
file_fdpath, suffix_length, file_fdpath + path_length - suffix_length);
if (state->watchfd.multiple_pids) {
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME,
"%8d:%4d:%.*s...%.*s",
(int) (info->watch_pid), info->watch_fd, prefix_length,
file_fdpath, suffix_length, file_fdpath + path_length - suffix_length);
} else {
(void) pv_snprintf(info->display_name,
PV_SIZEOF_DISPLAY_NAME,
"%4d:%.*s...%.*s",
info->watch_fd, prefix_length,
file_fdpath, suffix_length, file_fdpath + path_length - suffix_length);
}
}
debug("%s: %d: [%s]", "set name for fd", info->watch_fd, info->display_name);
+75
View File
@@ -0,0 +1,75 @@
#!/bin/sh
#
# Make sure -S stops reading at the given size.
#
# See https://codeberg.org/ivarch/pv/issues/166
# Allow all tests to be skipped, e.g. during a release build
test "${SKIP_ALL_TESTS}" = "1" && exit 77
true "${testSubject:?not set - call this from 'make check'}"
true "${workFile1:?not set - call this from 'make check'}"
true "${workFile2:?not set - call this from 'make check'}"
printf '%s\n' 'abcdefghi' | (
"${testSubject}" -qSs5 > "${workFile1}"
cat > "${workFile2}"
)
# pv should have read 5 bytes and put them into workFile1.
pvOutput="$(cat "${workFile1}")"
if ! test "${pvOutput}" = 'abcde'; then
echo "expected pv to write [abcde], got [${pvOutput}]"
exit 1
fi
# cat should have read the remaining bytes and put them into workFile2.
catOutput="$(cat "${workFile2}")"
if ! test "${catOutput}" = 'fghi'; then
echo "expected cat to write [fghi], got [${catOutput}]"
exit 1
fi
# Now repeat the test with -X to make sure there's no over-read there either.
printf '%s\n' 'abcdefghi' | (
"${testSubject}" -qXSs5 > "${workFile1}"
cat > "${workFile2}"
)
# pv should have read 5 bytes and put nothing into workFile1.
pvOutput="$(cat "${workFile1}")"
if test -s "${workFile1}"; then
echo "with -X, expected pv to write nothing, got [${pvOutput}]"
exit 1
fi
# cat should have read the remaining bytes and put them into workFile2.
catOutput="$(cat "${workFile2}")"
if ! test "${catOutput}" = 'fghi'; then
echo "with pv -X, expected cat to write [fghi], got [${catOutput}]"
exit 1
fi
# Test again with -C to ensure that it works with splice turned off.
printf '%s\n' 'abcdefghi' | (
"${testSubject}" -qCSs5 > "${workFile1}"
cat > "${workFile2}"
)
# pv should have read 5 bytes and put them into workFile1.
pvOutput="$(cat "${workFile1}")"
if ! test "${pvOutput}" = 'abcde'; then
echo "with -C, expected pv to write [abcde], got [${pvOutput}]"
exit 1
fi
# cat should have read the remaining bytes and put them into workFile2.
catOutput="$(cat "${workFile2}")"
if ! test "${catOutput}" = 'fghi'; then
echo "with pv -C, expected cat to write [fghi], got [${catOutput}]"
exit 1
fi
exit 0