Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
546074853e | ||
|
|
7deef78ea5 | ||
|
|
a38e05e749 | ||
|
|
493634e26c | ||
|
|
f96a43e366 | ||
|
|
b434c858a2 | ||
|
|
30e30f0196 | ||
|
|
1a70cc228a | ||
|
|
17ca4fc9c9 | ||
|
|
0aac6d6aac | ||
|
|
61021eab6b | ||
|
|
e59452d765 | ||
|
|
d2647ac55c | ||
|
|
c2c58762f0 | ||
|
|
0a55710cfc | ||
|
|
660d3da704 | ||
|
|
972f8b7df8 | ||
|
|
a40bdfb55f | ||
|
|
3c9ab822fe | ||
|
|
fb5ce33518 | ||
|
|
5c15337662 | ||
|
|
71f929e29c | ||
|
|
c21ad6fdf1 | ||
|
|
f0895177e7 | ||
|
|
72686655cf | ||
|
|
2efe598855 | ||
|
|
54913fddbe | ||
|
|
023cf22a59 | ||
|
|
164d7f7738 | ||
|
|
6b8acd9e01 | ||
|
|
3f6dc99aa5 | ||
|
|
d939d45c27 | ||
|
|
fc8326a2b4 | ||
|
|
8d939c9b99 | ||
|
|
72d9efc993 | ||
|
|
64c4e8efb9 | ||
|
|
25dadb2bfd | ||
|
|
80b68a73ee | ||
|
|
3437b75256 | ||
|
|
462415a88a | ||
|
|
d23a7e929e | ||
|
|
f18fa637c6 | ||
|
|
9bff7f0bb5 | ||
|
|
771b61db30 | ||
|
|
615c1d5321 | ||
|
|
3442d7651a | ||
|
|
7982badb65 | ||
|
|
a83a549de5 | ||
|
|
b1797c51e6 | ||
|
|
8504964f1a | ||
|
|
f83aa2272b | ||
|
|
fb7c05c262 | ||
|
|
e6f611f4de | ||
|
|
bd4ca7301c | ||
|
|
242297a3c6 | ||
|
|
0a658f99bb | ||
|
|
8df1c29c37 | ||
|
|
a8b7cd19bd | ||
|
|
b4f525fd79 | ||
|
|
8caa977a35 | ||
|
|
f6d398738e | ||
|
|
11dc25966d | ||
|
|
efc8b33e81 | ||
|
|
be066f6c8c | ||
|
|
6a1ad7d374 | ||
|
|
751263376b | ||
|
|
d903a7d188 | ||
|
|
a4e2243102 | ||
|
|
9fe604df1a | ||
|
|
64cd9cd85c | ||
|
|
10ef5a8596 | ||
|
|
77ed2e5989 | ||
|
|
8ae549c47f | ||
|
|
284ceba52b | ||
|
|
3ea19829d7 | ||
|
|
c49fc4aa57 | ||
|
|
7fdb6716e1 | ||
|
|
c61c589378 | ||
|
|
c688987087 | ||
|
|
0b2f9ec397 | ||
|
|
8a8e6d71a4 | ||
|
|
a0a9d682ca | ||
|
|
05a72bf75e | ||
|
|
22bf08f8e4 | ||
|
|
b5fbd1978e | ||
|
|
db80f838ff | ||
|
|
8c2e934768 | ||
|
|
dbce5b355e | ||
|
|
12cc996d32 | ||
|
|
4a0f9e713c | ||
|
|
8771b901d9 | ||
|
|
48ac509af7 | ||
|
|
f70627c031 | ||
|
|
1e6c9704b1 | ||
|
|
a629a488d7 | ||
|
|
ad1d0e1c9a | ||
|
|
4f9d746823 | ||
|
|
9fc9b6a8ed | ||
|
|
9ab82cde1e | ||
|
|
a7f392e3c3 | ||
|
|
574ea04502 | ||
|
|
5282a521b5 | ||
|
|
52634f01f9 | ||
|
|
a0f2d9c9c7 | ||
|
|
8386c05978 | ||
|
|
6a2b9a2788 | ||
|
|
e04f50f0dc | ||
|
|
021dc6e054 | ||
|
|
7d7efac7c6 | ||
|
|
f79bed3cb8 | ||
|
|
2171f40703 | ||
|
|
960ff1572f | ||
|
|
da2a2e6fd2 | ||
|
|
005bc2f841 | ||
|
|
ecc0c0e414 | ||
|
|
18548d217b | ||
|
|
653326ca9b | ||
|
|
0cf8902d9b | ||
|
|
762676f4e1 | ||
|
|
3bd49a0c3f | ||
|
|
870dfad9fd | ||
|
|
3b0891b128 | ||
|
|
b3c854b27a | ||
|
|
a923bdaca4 | ||
|
|
0070a74390 | ||
|
|
283bafa228 | ||
|
|
03bd428345 | ||
|
|
f77b853f3f | ||
|
|
43a89a5c61 | ||
|
|
44d7f94c31 | ||
|
|
7c84dc9890 | ||
|
|
025577a13f | ||
|
|
c180cc85cf | ||
|
|
092a30dd7d | ||
|
|
cd7c8f7849 | ||
|
|
89ee1332fe | ||
|
|
b926fffe80 | ||
|
|
7924a796ea | ||
|
|
8d45738126 | ||
|
|
e687c9b4d9 | ||
|
|
d2e9028726 | ||
|
|
e6638faffc | ||
|
|
f000530746 | ||
|
|
5bf04f841b | ||
|
|
5d95797aff | ||
|
|
9db2907a48 | ||
|
|
5423ae40d6 | ||
|
|
2de68acfea | ||
|
|
71e29b7388 | ||
|
|
6d6619cbb4 | ||
|
|
651053491e | ||
|
|
81f9919992 | ||
|
|
b57170d596 | ||
|
|
60462c033b | ||
|
|
3f597e59e0 | ||
|
|
a62051e5ff | ||
|
|
5483ddf024 | ||
|
|
62ef4b91fc | ||
|
|
8664521f08 | ||
|
|
6ef23916f0 | ||
|
|
73f8a2fb02 | ||
|
|
a552fc5329 | ||
|
|
505a91a6ed | ||
|
|
0d3b678800 | ||
|
|
efb115c2aa | ||
|
|
8721d285ce | ||
|
|
f421f9979d | ||
|
|
d5ad641102 | ||
|
|
ec6199c973 | ||
|
|
0eb09d097e | ||
|
|
13265b3d6b | ||
|
|
dbc7cd7bac | ||
|
|
4c1f36cda4 | ||
|
|
987af6ba16 | ||
|
|
58451ae18b | ||
|
|
cd2f5cbbfa | ||
|
|
896ff890d8 | ||
|
|
8ba24e39e0 | ||
|
|
0cf4e50e96 | ||
|
|
c8ad7eb0e2 | ||
|
|
42e47e8291 | ||
|
|
7d6c7d0735 | ||
|
|
16177a3b9d | ||
|
|
16a16460fc | ||
|
|
24d3351d5d | ||
|
|
daa06e5415 | ||
|
|
dc6cd1819d | ||
|
|
1ef1d858f8 | ||
|
|
74c75d36cc | ||
|
|
7a4264fe1e | ||
|
|
5decddeb42 | ||
|
|
0f08153214 | ||
|
|
5c3743e1f8 | ||
|
|
4a287f96fd | ||
|
|
0c35ae8d9e | ||
|
|
ddb2ff9b06 | ||
|
|
32398dd5fb | ||
|
|
cec252f98f | ||
|
|
c186198a7e | ||
|
|
ec46261757 | ||
|
|
ff0355ca9c | ||
|
|
2bd364fee8 | ||
|
|
823350a186 | ||
|
|
c58ddb4d66 | ||
|
|
447ec06234 | ||
|
|
21ca350946 | ||
|
|
46902e1c0c | ||
|
|
02bf302f96 | ||
|
|
76327fdf01 | ||
|
|
0044ed18ae | ||
|
|
a9bbb55220 | ||
|
|
69a2358d47 | ||
|
|
8664395e5b | ||
|
|
3c09b31f92 | ||
|
|
43e2eaa4db | ||
|
|
f3e98da13b | ||
|
|
25eaa2661a | ||
|
|
4f58a3d751 | ||
|
|
7d18083dda | ||
|
|
f0aca0a2ce | ||
|
|
18c76175b2 | ||
|
|
6dbde0c559 | ||
|
|
8fa9df6e7a | ||
|
|
e3382b1a62 | ||
|
|
29c7a21725 | ||
|
|
7a0ee9c7fa | ||
|
|
cb71277df4 | ||
|
|
9f5923864b | ||
|
|
60563f3e3c | ||
|
|
c49abf1608 | ||
|
|
250a794873 | ||
|
|
78f4a60bf7 | ||
|
|
2a93e33d38 | ||
|
|
5efd4d045f | ||
|
|
0516ba53bd | ||
|
|
1d76c0bc64 | ||
|
|
73bc1ab139 | ||
|
|
35fdb331e4 | ||
|
|
9ceda2059d | ||
|
|
0e24c9f453 | ||
|
|
ad54067b48 | ||
|
|
e99a58b430 | ||
|
|
51a5de71c1 | ||
|
|
06eca8cefa | ||
|
|
a4494159ea | ||
|
|
c95e25776e |
+18
-3
@@ -22,6 +22,19 @@ src/pv/cursor.c \
|
||||
src/pv/display.c \
|
||||
src/pv/elapsedtime.c \
|
||||
src/pv/file.c \
|
||||
src/pv/format/averagerate.c \
|
||||
src/pv/format/barstyle.c \
|
||||
src/pv/format/bufferpercent.c \
|
||||
src/pv/format/bytes.c \
|
||||
src/pv/format/eta.c \
|
||||
src/pv/format/fineta.c \
|
||||
src/pv/format/lastwritten.c \
|
||||
src/pv/format/name.c \
|
||||
src/pv/format/previousline.c \
|
||||
src/pv/format/progressbar.c \
|
||||
src/pv/format/rate.c \
|
||||
src/pv/format/sgr.c \
|
||||
src/pv/format/timer.c \
|
||||
src/pv/loop.c \
|
||||
src/pv/number.c \
|
||||
src/pv/proctitle.c \
|
||||
@@ -82,10 +95,12 @@ tests/Modifiers_-_--line-mode.test \
|
||||
tests/Modifiers_-_--size_from_file_size.test \
|
||||
tests/Modifiers_-_--size.test \
|
||||
tests/Modifiers_-_--sync.test \
|
||||
tests/Sparse_-_Basic.test \
|
||||
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
|
||||
|
||||
@@ -102,10 +117,10 @@ SUFFIXES = .c .o .e
|
||||
-flawfinder $< >> $@ 2>&1
|
||||
|
||||
indent:
|
||||
cd $(srcdir) && indent -npro -kr -i8 -cd42 -c45 -l120 src/*/*.c
|
||||
cd $(srcdir) && indent -npro -kr -i8 -cd42 -c45 -l120 src/*/*.c src/*/*/*.c
|
||||
|
||||
indentclean:
|
||||
rm -f $(srcdir)/src/*/*.c~
|
||||
rm -f $(srcdir)/src/*/*.c~ $(srcdir)/src/*/*/*.c~
|
||||
|
||||
analyse: $(pv_SOURCES:.c=.e) FORCE
|
||||
grep -E -e '^Finished checking --' -e 'Hits = ' $+ 2>/dev/null || true
|
||||
@@ -113,7 +128,7 @@ analyse: $(pv_SOURCES:.c=.e) FORCE
|
||||
FORCE:
|
||||
|
||||
clean-local:
|
||||
rm -f src/*/*.e
|
||||
rm -f src/*/*.e src/*/*/*.e
|
||||
|
||||
# Convenience alias for "make check": "make test"
|
||||
test: check
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
# Introduction
|
||||
|
||||
This is the README for **pv** ("Pipe Viewer"), a terminal-based tool for
|
||||
monitoring the progress of data through a pipeline. It can be inserted into
|
||||
any normal pipeline between two processes to give a visual indication of how
|
||||
quickly data is passing through, how long it has taken, how near to
|
||||
completion it is, and an estimate of how long it will be until completion.
|
||||
**pv** ("Pipe Viewer") is a terminal-based tool for monitoring the progress
|
||||
of data through a pipeline and modifying its flow.
|
||||
|
||||
It can be inserted into any normal pipeline between two processes to give a
|
||||
visual indication of how quickly data is passing through, how long it has
|
||||
taken, how near to completion it is, and an estimate of how long it will be
|
||||
until completion. Data flow rate, error handling strategy, buffer size, and
|
||||
cache interaction can all be adjusted.
|
||||
|
||||
In "**\--watchfd**" mode, **pv** will inspect another process and show its
|
||||
progress through the files it has open.
|
||||
|
||||
|
||||
# Documentation
|
||||
@@ -51,7 +57,7 @@ run it as described above.
|
||||
See "[docs/ACKNOWLEDGEMENTS.md](./docs/ACKNOWLEDGEMENTS.md)" for a list of
|
||||
contributors.
|
||||
|
||||
Copyright (C) 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood.
|
||||
Copyright (C) 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood.
|
||||
|
||||
License GPLv3+: GNU GPL version 3 or later <https://www.gnu.org/licenses/gpl-3.0.html>.
|
||||
|
||||
@@ -69,12 +75,12 @@ You should have received a copy of the GNU General Public License, version
|
||||
3, in "[docs/COPYING](./docs/COPYING)". If not, see
|
||||
<https://www.gnu.org/licenses/gpl-3.0.html>.
|
||||
|
||||
Please report any bugs to **pv@ivarch.com**, or use the issue tracker linked
|
||||
from the **pv** home page.
|
||||
Please report bugs or request features via the issue tracker linked from the
|
||||
home page.
|
||||
|
||||
The **pv** home page is at:
|
||||
|
||||
> [https://www.ivarch.com/programs/pv.shtml](https://www.ivarch.com/programs/pv.shtml)
|
||||
> [https://ivarch.com/p/pv](https://ivarch.com/p/pv)
|
||||
|
||||
The latest version can always be found here.
|
||||
|
||||
|
||||
+27
-7
@@ -1,10 +1,10 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
dnl
|
||||
dnl Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
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.15], [pv@ivarch.com], [pv], [https://www.ivarch.com/programs/pv.shtml])
|
||||
AC_INIT([pv], [1.9.44], [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])
|
||||
@@ -33,6 +33,7 @@ AC_CHECK_FUNCS([setitimer])
|
||||
AC_CHECK_FUNCS([setproctitle])
|
||||
AC_CHECK_HEADERS([getopt.h])
|
||||
AC_CHECK_HEADERS([limits.h])
|
||||
AC_CHECK_HEADERS([langinfo.h])
|
||||
AC_CHECK_HEADERS([wctype.h])
|
||||
AC_CHECK_HEADERS([termios.h])
|
||||
AC_CHECK_HEADERS([libgen.h])
|
||||
@@ -43,8 +44,10 @@ AC_CHECK_MEMBERS([struct stat.st_blksize])
|
||||
AC_CHECK_DECLS([SA_SIGINFO], [], [], [[#include <signal.h>]])
|
||||
|
||||
AC_SEARCH_LIBS([sqrtl],[m])
|
||||
AC_SEARCH_LIBS([fmod],[m])
|
||||
AC_CHECK_HEADERS([math.h])
|
||||
AC_CHECK_FUNCS([sqrtl])
|
||||
AC_CHECK_FUNCS([fmod])
|
||||
|
||||
dnl Libraries that may contain key functions.
|
||||
AC_SEARCH_LIBS([clock_gettime],[rt])
|
||||
@@ -93,7 +96,7 @@ static void receiveUSR2( __attribute__((unused))
|
||||
(void) sigaction(SIGUSR2, &sa, NULL);
|
||||
raise(SIGUSR2);
|
||||
#endif
|
||||
return signalSender == 0 ? 1 : 0;
|
||||
return signalSender < 1 ? 1 : 0;
|
||||
]])], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([SIGINFO_PROVIDES_PID], [1], [Signal handlers can determine the sending PID])
|
||||
@@ -108,7 +111,7 @@ AC_DEFINE([SIGINFO_PROVIDES_PID], [1], [Signal handlers can determine the sendin
|
||||
AH_BOTTOM([#include "config-aux.h"])
|
||||
|
||||
AC_ARG_ENABLE([debugging],
|
||||
[ --enable-debugging compile with debugging support],
|
||||
[AS_HELP_STRING([--enable-debugging], [compile with debugging support])],
|
||||
if test "$enable_debugging" = "yes"; then
|
||||
CFLAGS="$CFLAGS -g -Wall"
|
||||
AC_DEFINE([ENABLE_DEBUGGING], [1], [Debugging support enabled])
|
||||
@@ -116,14 +119,15 @@ AC_ARG_ENABLE([debugging],
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([profiling],
|
||||
[ --enable-profiling compile with profiling support],
|
||||
[AS_HELP_STRING([--enable-profiling], [compile with profiling support])],
|
||||
if test "$enable_profiling" = "yes"; then
|
||||
CFLAGS="-pg $CFLAGS"
|
||||
fi
|
||||
)
|
||||
|
||||
SPLICE_SUPPORT="no"
|
||||
AC_ARG_ENABLE([splice], [ --disable-splice do not use splice system call],
|
||||
AC_ARG_ENABLE([splice],
|
||||
[AS_HELP_STRING([--disable-splice], [do not use splice system call])],
|
||||
if test "$enable_splice" = "yes"; then
|
||||
SPLICE_SUPPORT="yes"
|
||||
fi,
|
||||
@@ -131,13 +135,28 @@ AC_ARG_ENABLE([splice], [ --disable-splice do not use splice system call
|
||||
)
|
||||
|
||||
IPC_SUPPORT="no"
|
||||
AC_ARG_ENABLE([ipc], [ --disable-ipc turn off IPC messaging],
|
||||
AC_ARG_ENABLE([ipc],
|
||||
[AS_HELP_STRING([--disable-ipc], [turn off IPC messaging])],
|
||||
if test "$enable_ipc" = "yes"; then
|
||||
IPC_SUPPORT="yes"
|
||||
fi,
|
||||
IPC_SUPPORT="yes"
|
||||
)
|
||||
|
||||
AC_ARG_WITH([ncurses],
|
||||
[AS_HELP_STRING([--without-ncurses], [disable the use of ncurses for terminal info])],
|
||||
[],
|
||||
[with_curses=yes])
|
||||
AS_IF([test "x$with_ncurses" != xno],
|
||||
[
|
||||
AC_SEARCH_LIBS([tigetnum],[tinfo ncurses], [
|
||||
AC_CHECK_HEADERS([term.h],[
|
||||
AC_DEFINE([ENABLE_NCURSES], [1], [Build with ncurses support])
|
||||
])
|
||||
], [])
|
||||
],
|
||||
[])
|
||||
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static], [enable static linking])],
|
||||
[
|
||||
@@ -154,6 +173,7 @@ yes
|
||||
|
||||
if test "$IPC_SUPPORT" = "yes"; then
|
||||
AC_CHECK_HEADERS([sys/ipc.h], [], [IPC_SUPPORT=no])
|
||||
AC_CHECK_HEADERS([sys/shm.h], [], [IPC_SUPPORT=no])
|
||||
AC_CHECK_HEADERS([sys/param.h])
|
||||
if test "$IPC_SUPPORT" = "yes"; then
|
||||
AC_CHECK_FUNCS([shmget], [], [IPC_SUPPORT=no])
|
||||
|
||||
+32
-23
@@ -84,27 +84,32 @@ is acknowledged and greatly appreciated:
|
||||
* [Nick Black](https://nick-black.com) - added **--bits** option
|
||||
* [Andrew Schulman](https://github.com/andrew-schulman) - provided reproducible example of terminal size detection issue in 1.7.17/1.7.18
|
||||
* [fuschia74](https://github.com/fuchsia74) - provided **--enable-static** patch for "`configure`"
|
||||
* [Wilhelm von Thiele](https://github.com/TurtleWilly) - assisted with OS X cleanups ([#73](https://codeberg.org/a-j-wood/pv/issues/73), [#74](https://codeberg.org/a-j-wood/pv/issues/74))
|
||||
* Matějů Miroslav, Ing. - suggested fix for ETA and elapsed time faults when suspending and resuming a machine ([#13](https://codeberg.org/a-j-wood/pv/issues/13))
|
||||
* Anthony DeRobertis - suggested the **--error-skip-block** option ([#37](https://codeberg.org/a-j-wood/pv/issues/37))
|
||||
* [Wilhelm von Thiele](https://github.com/TurtleWilly) - assisted with OS X cleanups ([#73](https://codeberg.org/ivarch/pv/issues/73), [#74](https://codeberg.org/ivarch/pv/issues/74))
|
||||
* Matějů Miroslav, Ing. - suggested fix for ETA and elapsed time faults when suspending and resuming a machine ([#13](https://codeberg.org/ivarch/pv/issues/13))
|
||||
* Anthony DeRobertis - suggested the **--error-skip-block** option ([#37](https://codeberg.org/ivarch/pv/issues/37))
|
||||
* Benoit Pierre - provided patches for compilation without IPC support, without HAVE_STRUCT_STAT_ST_BLKSIZE, and on MacOS
|
||||
* [gustav-b](https://codeberg.org/gustav-b) - suggested percentage formatting correction ([#80](https://codeberg.org/a-j-wood/pv/issues/80))
|
||||
* [Thomas Bertels](https://codeberg.org/tbertels) - updated French translations ([#83](https://codeberg.org/a-j-wood/pv/pulls/83))
|
||||
* [kevinruddy](https://codeberg.org/kevinruddy) - added decimal units option ([#85](https://codeberg.org/a-j-wood/pv/pulls/85))
|
||||
* [xmort](https://codeberg.org/xmort) - added **--output** option ([#90](https://codeberg.org/a-j-wood/pv/pulls/90))
|
||||
* [bogiord](https://codeberg.org/bogiord) - reported the loss of output block device size detection in 1.8.10, and suggested the fix ([#91](https://codeberg.org/a-j-wood/pv/issues/91))
|
||||
* [eborisch](https://codeberg.org/eborisch) - provided fix for misbehaviour when used with "`zfs send`" due to treating zero sized writes (generally due to timer interruption) as end of file ([#92](https://codeberg.org/a-j-wood/pv/pulls/92), [#93](https://codeberg.org/a-j-wood/pv/pulls/93))
|
||||
* [alexanderperlis](https://codeberg.org/alexanderperlis) - provided initial support for block devices with **--size `@`FILE** ([#94](https://codeberg.org/a-j-wood/pv/pulls/94))
|
||||
* [jettero](https://codeberg.org/jettero) - reported double-free coredump when using **--watchfd** after 1.8.10 ([#96](https://codeberg.org/a-j-wood/pv/issues/96))
|
||||
* Venky.N.Iyer - suggested **--stats** ([#49](https://codeberg.org/a-j-wood/pv/issues/49))
|
||||
* Roland Kletzing - suggested **--rate** with **--numeric** ([#17](https://codeberg.org/a-j-wood/pv/issues/17))
|
||||
* [Michael Mior](https://codeberg.org/michaelmior) - suggested **--store-and-forward** ([#100](https://codeberg.org/a-j-wood/pv/issues/100))
|
||||
* [dbungert](https://codeberg.org/dbungert) - reported issue with *valgrind* 3.23 misreporting leaking file descriptors ([#97](https://codeberg.org/a-j-wood/pv/issues/97))
|
||||
* Joachim Haga - suggested showing progress in the window title ([#3](https://codeberg.org/a-j-wood/pv/issues/3))
|
||||
* [Martin Sarsale](https://github.com/runa) - suggested showing progress in the process title ([#4](https://codeberg.org/a-j-wood/pv/issues/4))
|
||||
* [2bits](https://github.com/2bits) - reported position sensing fault with **--watchfd** in 1.9.0 ([#118](https://codeberg.org/a-j-wood/pv/issues/118))
|
||||
* [heitbaum](https://codeberg.org/heitbaum) - assisted with cross-compilation fault introduced in 1.9.7 ([#120](https://codeberg.org/a-j-wood/pv/issues/120))
|
||||
* [meego](https://codeberg.org/meego) - suggested "**%nL**", the last line preview ([#121](https://codeberg.org/a-j-wood/pv/issues/121))
|
||||
* [gustav-b](https://codeberg.org/gustav-b) - suggested percentage formatting correction ([#80](https://codeberg.org/ivarch/pv/issues/80))
|
||||
* [Thomas Bertels](https://codeberg.org/tbertels) - updated French translations ([#83](https://codeberg.org/ivarch/pv/pulls/83))
|
||||
* [kevinruddy](https://codeberg.org/kevinruddy) - added decimal units option ([#85](https://codeberg.org/ivarch/pv/pulls/85))
|
||||
* [xmort](https://codeberg.org/xmort) - added **--output** option ([#90](https://codeberg.org/ivarch/pv/pulls/90))
|
||||
* [bogiord](https://codeberg.org/bogiord) - reported the loss of output block device size detection in 1.8.10, and suggested the fix ([#91](https://codeberg.org/ivarch/pv/issues/91))
|
||||
* [eborisch](https://codeberg.org/eborisch) - provided fix for misbehaviour when used with "`zfs send`" due to treating zero sized writes (generally due to timer interruption) as end of file ([#92](https://codeberg.org/ivarch/pv/pulls/92), [#93](https://codeberg.org/ivarch/pv/pulls/93))
|
||||
* [alexanderperlis](https://codeberg.org/alexanderperlis) - provided initial support for block devices with **--size `@`FILE** ([#94](https://codeberg.org/ivarch/pv/pulls/94))
|
||||
* [jettero](https://codeberg.org/jettero) - reported double-free coredump when using **--watchfd** after 1.8.10 ([#96](https://codeberg.org/ivarch/pv/issues/96))
|
||||
* Venky.N.Iyer - suggested **--stats** ([#49](https://codeberg.org/ivarch/pv/issues/49))
|
||||
* Roland Kletzing - suggested **--rate** with **--numeric** ([#17](https://codeberg.org/ivarch/pv/issues/17))
|
||||
* [Michael Mior](https://codeberg.org/michaelmior) - suggested **--store-and-forward** ([#100](https://codeberg.org/ivarch/pv/issues/100))
|
||||
* [dbungert](https://codeberg.org/dbungert) - reported issue with *valgrind* 3.23 misreporting leaking file descriptors ([#97](https://codeberg.org/ivarch/pv/issues/97))
|
||||
* Joachim Haga - suggested showing progress in the window title ([#3](https://codeberg.org/ivarch/pv/issues/3))
|
||||
* [Martin Sarsale](https://github.com/runa) - suggested showing progress in the process title ([#4](https://codeberg.org/ivarch/pv/issues/4))
|
||||
* [2bits](https://github.com/2bits) - reported position sensing fault with **--watchfd** in 1.9.0 ([#118](https://codeberg.org/ivarch/pv/issues/118))
|
||||
* [heitbaum](https://codeberg.org/heitbaum) - assisted with cross-compilation fault introduced in 1.9.7 ([#120](https://codeberg.org/ivarch/pv/issues/120))
|
||||
* [meego](https://codeberg.org/meego) - suggested "**%nL**", the last line preview ([#121](https://codeberg.org/ivarch/pv/issues/121))
|
||||
* [Alexander Petrossian](https://github.com/neopaf) - suggested using Unicode output for a more granular progress bar, and provided the codepoints to use ([#15](https://codeberg.org/ivarch/pv/issues/15))
|
||||
* [jmealo](https://codeberg.org/jmealo) - suggested JSON progress output ([#127](https://codeberg.org/ivarch/pv/issues/127))
|
||||
* [ipaqmaster](https://codeberg.org/ipaqmaster) - investigated 100%-CPU utilisation bug when piping to a command that has exited ([#164](https://codeberg.org/ivarch/pv/issues/164))
|
||||
* Andriy Galetski, and also [thinrope](https://codeberg.org/thinrope) - suggested the "**--sparse**" option ([#45](https://codeberg.org/ivarch/pv/issues/45))
|
||||
* [KimHansen](https://codeberg.org/KimHansen) - suggested that "**--watchfd**" should keep its display when the process ends ([#81](https://codeberg.org/ivarch/pv/issues/81))
|
||||
|
||||
Translations provided through [Codeberg Weblate](https://translate.codeberg.org/projects/pv/):
|
||||
|
||||
@@ -112,16 +117,20 @@ Translations provided through [Codeberg Weblate](https://translate.codeberg.org/
|
||||
* [mmatous](https://translate.codeberg.org/user/mmatous/) (135)
|
||||
* **French**
|
||||
* anonymous suggestions (7)
|
||||
* [milimarg](https://codeberg.org/milimarg) (13)
|
||||
* [Maxi_Mega](https://translate.codeberg.org/user/Maxi_Mega/) (11)
|
||||
* **German**
|
||||
* [Hartmut Goebel](https://translate.codeberg.org/user/htgoebel/) (77)
|
||||
* [Benny](https://translate.codeberg.org/user/Benny/) (6)
|
||||
* [m0yellow](https://translate.codeberg.org/user/m0yellow/) (9)
|
||||
* [Benny](https://translate.codeberg.org/user/Benny/) (7)
|
||||
* [kre](https://translate.codeberg.org/user/kre/) (2)
|
||||
* [fnetX](https://translate.codeberg.org/user/fnetX/) (1)
|
||||
* **Polish**
|
||||
* [coralpink](https://translate.codeberg.org/user/coralpink/) (100)
|
||||
* [coralpink](https://translate.codeberg.org/user/coralpink/) (106)
|
||||
* **Russian**
|
||||
* [0ko](https://translate.codeberg.org/user/0ko/) (151)
|
||||
* [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)
|
||||
|
||||
---
|
||||
|
||||
+48
-48
@@ -1,30 +1,30 @@
|
||||
# Notes for developers and translators
|
||||
|
||||
The following "`configure`" options will be of interest to developers and
|
||||
The following _configure_ options will be of interest to developers and
|
||||
translators:
|
||||
|
||||
* `--enable-debugging` - build in debugging support
|
||||
* `--enable-profiling` - build in support for profiling
|
||||
* **--enable-debugging** - build in debugging support
|
||||
* **--enable-profiling** - build in support for profiling
|
||||
|
||||
These "`make`" targets are available:
|
||||
These targets are available when running _make_:
|
||||
|
||||
* `make analyse` - run _splint_ and _flawfinder_ on all C source files
|
||||
* "`make analyse`" - run _splint_ and _flawfinder_ on all C source files
|
||||
|
||||
|
||||
## Debugging and profiling support
|
||||
|
||||
When "`./configure --enable-debugging`" is used, the "`pv`" produced by
|
||||
"`make`" will support an extra option, "`--debug FILE`", which will cause
|
||||
debugging output to be written to *FILE*. This is not recommended for
|
||||
production builds due to the extra processing it introduces, and the
|
||||
potential size of the output.
|
||||
When "`./configure --enable-debugging`" is used, the _pv_ produced by _make_
|
||||
will support an extra option, "**--debug FILE**", which will cause debugging
|
||||
output to be written to *FILE*. This is not recommended for production
|
||||
builds due to the extra processing it introduces, and the potential size of
|
||||
the output.
|
||||
|
||||
Within the code, "`debug()`" is used in a similar way to "`printf()`". It
|
||||
will automatically include the calling function, source file, and line
|
||||
Within the code, "**debug()**" is used in a similar way to "**printf()**".
|
||||
It will automatically include the calling function, source file, and line
|
||||
number, so they don't need to be included in the parameters. When debugging
|
||||
support is not enabled, it evaluates to a null statement.
|
||||
|
||||
This does mean that if you call "`debug()`", make sure it has no side
|
||||
This does mean that if you call "**debug()**", make sure it has no side
|
||||
effects, as they won't be present in builds without debugging support.
|
||||
|
||||
Builds produced after "`./configure --enable-profiling`" will write profile
|
||||
@@ -35,11 +35,11 @@ Please note that the memory safety checks will fail with profiling enabled.
|
||||
## Source code analysis
|
||||
|
||||
Running "`make analyse`" runs _splint_ and _flawfinder_ on all C sources,
|
||||
writing the output of both programs to files named "`*.e`" for each "`*.c`".
|
||||
writing the output of both programs to files named _"*.e"_ for each _"*.c"_.
|
||||
|
||||
There are no dependency rules set up for these "`.e`" files, so if a header
|
||||
file is altered, manually remove the relevant "`.e`" files, or update the
|
||||
timestamp of the relevant "`.c`" files, before running "`make analyse`"
|
||||
There are no dependency rules set up for these _".e"_ files, so if a header
|
||||
file is altered, manually remove the relevant _".e"_ files, or update the
|
||||
timestamp of the relevant _".c"_ files, before running "`make analyse`"
|
||||
again.
|
||||
|
||||
The goal is for all C source files to generate zero warnings from either
|
||||
@@ -65,8 +65,8 @@ Alternatively, read on for details of how to maintain the translations
|
||||
directly within the source tree.
|
||||
|
||||
The message catalogues used to translate program messages into other
|
||||
languages are in the "`po/`" directory, named "`xx.po`", where "`xx`"
|
||||
is the ISO 639-1 2-letter language code, such as "`fr`" for French.
|
||||
languages are in the _"po/"_ directory, named _"xx.po"_, where _"xx"_
|
||||
is the ISO 639-1 2-letter language code, such as "**fr**" for French.
|
||||
|
||||
Each of these files contains lines like this:
|
||||
|
||||
@@ -74,16 +74,16 @@ Each of these files contains lines like this:
|
||||
msgid "failed to get terminal name"
|
||||
msgstr "erro ao ler o nome do terminal"
|
||||
|
||||
The comment line, starting "`#`", shows the source filename and line number
|
||||
at which this message can be found. The "`msgid`" is the original message
|
||||
in the program, in English. The "`msgstr`" is the translated text.
|
||||
The comment line, starting _"#"_, shows the source filename and line number
|
||||
at which this message can be found. The _"msgid"_ is the original message
|
||||
in the program, in English. The _"msgstr"_ is the translated text.
|
||||
|
||||
It is the "`msgstr`" lines which need to be updated by translators.
|
||||
It is the _"msgstr"_ lines which need to be updated by translators.
|
||||
|
||||
Message catalogue files should all be encoded as UTF-8.
|
||||
|
||||
After making a change to a "`.po`" file, test it by compiling it and installing
|
||||
to a temporary location, like this:
|
||||
After making a change to a _".po"_ file, test it by compiling it and
|
||||
installing to a temporary location, like this:
|
||||
|
||||
./configure --enable-debugging --prefix=/tmp/yourtest
|
||||
make clean
|
||||
@@ -96,40 +96,40 @@ to a temporary location, like this:
|
||||
/tmp/yourtest/bin/pv --help
|
||||
exit
|
||||
|
||||
Replace "`--help`" with whatever is appropriate for your test. In this
|
||||
example, the language being tested is "`de`" (German), on a system which is
|
||||
Replace "**--help**" with whatever is appropriate for your test. In this
|
||||
example, the language being tested is _"de"_ (German), on a system which is
|
||||
running with UTF-8 support.
|
||||
|
||||
In the example above, a new shell is started by typing "`bash`" so that
|
||||
after your tests, "`exit`" will return you to your previous shell with your
|
||||
language settings intact.
|
||||
|
||||
Note that at the start, you have to re-run "`configure`" with "`--prefix`"
|
||||
Note that at the start, you have to re-run _configure_ with "**--prefix**"
|
||||
rather than using "`make DESTDIR=...`", because the locale directory is set
|
||||
at compile time. Also, on Debian at least, both "`LC_ALL`" and "`LANGUAGE`"
|
||||
must be set.
|
||||
at compile time. Also, on Debian at least, both the environment variables
|
||||
_"LC_ALL"_ and _"LANGUAGE"_ must be set.
|
||||
|
||||
To find untranslated strings in a language that's already supported but
|
||||
which you can help with gaps in, use this command:
|
||||
|
||||
msgattrib --untranslated < po/fr.po
|
||||
|
||||
replacing "`po/fr.po`" as appropriate.
|
||||
replacing _"po/fr.po"_ as appropriate.
|
||||
|
||||
To add a new language, create the new message catalogue file under "`po/`"
|
||||
by copying "`po/pv.pot`" to "`po/xx.po`", where "`xx`" is the language code,
|
||||
and adjusting it. The "`.pot`" file is generated automatically by "`make`".
|
||||
To add a new language, create the new message catalogue file under _"po/"_
|
||||
by copying _"po/pv.pot"_ to _"po/xx.po"_, where _"xx"_ is the language code,
|
||||
and adjusting it. The _".pot"_ file is generated automatically by _make_.
|
||||
|
||||
Next, add the language code to "`po/LINGUAS`" - this is a list of the
|
||||
Next, add the language code to _"po/LINGUAS"_ - this is a list of the
|
||||
2-letter codes of the supported languages.
|
||||
|
||||
Finally, run "`./config.status`" and "`make -C po update-po`".
|
||||
|
||||
When the source code is updated, running "`make -C po update-po`" will
|
||||
update the "`pv.pot`" file so that it lists where all the messages are in
|
||||
the source. It will also use _msgmerge_ to update all of the "`.po`" files
|
||||
from the updated "`pv.pot`" file. After doing this, look for missing
|
||||
translations (empty "`msgstr`" lines) or translations marked as "fuzzy", as
|
||||
update the _"pv.pot"_ file so that it lists where all the messages are in
|
||||
the source. It will also use _msgmerge_ to update all of the _".po"_ files
|
||||
from the updated _"pv.pot"_ file. After doing this, look for missing
|
||||
translations (empty _"msgstr"_ lines) or translations marked as "fuzzy", as
|
||||
these will need to be corrected by translators.
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ these will need to be corrected by translators.
|
||||
The package maintainer should run through these steps for a new release:
|
||||
|
||||
* Check for patches and bug reports:
|
||||
* <https://codeberg.org/a-j-wood/pv/issues>
|
||||
* <https://codeberg.org/ivarch/pv/issues>
|
||||
* <https://tracker.debian.org/pkg/pv>
|
||||
* <https://launchpad.net/ubuntu/+source/pv>
|
||||
* <https://archlinux.org/packages/extra/x86_64/pv/>
|
||||
@@ -146,25 +146,25 @@ The package maintainer should run through these steps for a new release:
|
||||
* <https://cvsweb.openbsd.org/ports/sysutils/pv/>
|
||||
* <https://packages.fedoraproject.org/pkgs/pv/pv/>
|
||||
* Run "`make indent; make indent indentclean check`"
|
||||
* Check that `po/POTFILES.in` is up to date
|
||||
* Check that _po/POTFILES.in_ is up to date
|
||||
* Run "`make -C po update-po`"
|
||||
* Run "`make analyse`" and see whether remaining warnings can be addressed
|
||||
* Version bump and documentation checks:
|
||||
* Update the version in `configure.ac` and `docs/NEWS.md`
|
||||
* Check that `docs/NEWS.md` is up to date
|
||||
* Check that the manual `docs/pv.1` is up to date
|
||||
* Update the version in _configure.ac_ and _docs/NEWS.md_
|
||||
* Check that _docs/NEWS.md_ is up to date
|
||||
* Check that the manual _docs/pv.1_ is up to date
|
||||
* Run "`make docs/pv.1.md`" and, if using VPATH, copy the result to the source directory
|
||||
* Check that the year displayed by src/main/version.c is correct
|
||||
* Check that the year displayed by _src/main/version.c_ is correct
|
||||
* Ensure everything has been committed to the repository
|
||||
* Run "`autoreconf`" in the source directory
|
||||
* Run "`autoreconf -is`" in the source directory
|
||||
* Consistency and build checks:
|
||||
* Wipe the build directory, and run "`configure`" there
|
||||
* Wipe the build directory, and run _configure_ there
|
||||
* Run "`make distcheck`"
|
||||
* Run "`./configure && make check`" on all test systems including Cygwin, using the `tar.gz` that was just created
|
||||
* Run a cross-compilation check
|
||||
* Run "`make release MAINTAINER=<signing-user>`"
|
||||
* Update the project web site:
|
||||
* Copy the release `.tar.gz`, `.txt`, and `.asc` files to the web site
|
||||
* 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
|
||||
* Update the news and manual on the web site
|
||||
* Update the version numbers on the web site
|
||||
|
||||
+101
-51
@@ -1,40 +1,90 @@
|
||||
### 1.9.44 - 18 October 2025
|
||||
|
||||
* *feature:* new **--sparse** option to write sparse output ([#45](https://codeberg.org/ivarch/pv/issues/45))
|
||||
* *fix:* don't clear the **--watchfd** display when the watched process ends ([#81](https://codeberg.org/ivarch/pv/issues/81))
|
||||
|
||||
### 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))
|
||||
* *fix:* correct a memory handling fault when using **--bar-style** with **--watchfd** ([#163](https://codeberg.org/ivarch/pv/issues/163))
|
||||
* *i18n:* French translations updated
|
||||
|
||||
### 1.9.31 - 28 January 2025
|
||||
|
||||
* *feature:* the **--format** option can now be used with **--numeric** for customised numeric output, such as JSON ([#127](https://codeberg.org/ivarch/pv/issues/127))
|
||||
* *i18n:* German translations updated
|
||||
* *i18n:* Polish translations updated
|
||||
* *i18n:* Russian translations updated
|
||||
|
||||
### 1.9.27 - 12 January 2025
|
||||
|
||||
* *fix:* turn off IPC support if _sys/shm.h_ is not available, for compilation on Termux
|
||||
* *fix:* bypass valgrind checks on ARM by default due to false positives
|
||||
|
||||
### 1.9.25 - 22 December 2024
|
||||
|
||||
* *fix:* test failure of **--watchfd** on macOS corrected ([#124](https://codeberg.org/ivarch/pv/issues/124))
|
||||
|
||||
### 1.9.24 - 19 December 2024
|
||||
|
||||
* *feature:* new **--format** sequences for graphical progress bars - "**%{bar-block}**", "**%{bar-granular}**", and "**%{bar-shaded}**" ([#15](https://codeberg.org/ivarch/pv/issues/15))
|
||||
* *feature:* new **--format** sequence "**%{sgr:colour,...}**" to use ECMA-48 Select Graphic Rendition codes to add colours
|
||||
* *feature:* new **--bar-style** option to change the default bar style ([#15](https://codeberg.org/ivarch/pv/issues/15))
|
||||
* *feature:* allow decimal values such as "1.5G" with "**--size**", "**--rate-limit**", "**--buffer-size**", and "**error-skip-block**" ([#35](https://codeberg.org/ivarch/pv/issues/35))
|
||||
* *cleanup:* improve progress bar granularity on wide displays by internally tracking the transfer percentage as a decimal number
|
||||
* *cleanup:* correct detection of **--remote** usability on GNU Hurd
|
||||
* *cleanup:* reduce likelihood of race conditions in tests when running on slow systems
|
||||
* *cleanup:* reduce memory footprint
|
||||
* *docs:* simplified the synopsis section of the manual
|
||||
|
||||
### 1.9.15 - 8 December 2024
|
||||
|
||||
* *feature:* new **--format** sequence "**%nL**", showing the most recent line written ([#121](https://codeberg.org/a-j-wood/pv/issues/121))
|
||||
* *feature:* new **--format** sequence "**%nL**", showing the most recent line written ([#121](https://codeberg.org/ivarch/pv/issues/121))
|
||||
* *feature:* each **--format** sequence now has a more readable equivalent name, for example "**%r**" can be written as "**%{rate}**"
|
||||
* *feature:* new **--format** sequences "**%{progress-bar-only}**" and "**%{progress-amount-only}**"
|
||||
* *fix:* allow **--format** to include "%nA" more than once, with different "n" values ([#122](https://codeberg.org/a-j-wood/pv/issues/122))
|
||||
* *fix:* allow **--format** to include "%nA" more than once, with different "n" values ([#122](https://codeberg.org/ivarch/pv/issues/122))
|
||||
* *fix:* allow **--format** to include "%p" more than once, with optional width prefix
|
||||
* *fix:* calculate width correctly when wide characters are in **--format** strings
|
||||
* *fix:* add _configure_ script fallback for **--remote** check when cross-compiling ([#120](https://codeberg.org/a-j-wood/pv/issues/120))
|
||||
* *fix:* allow **extra-display** to be changed by **--remote** ([#123](https://codeberg.org/a-j-wood/pv/issues/123))
|
||||
* *fix:* add _configure_ script fallback for **--remote** check when cross-compiling ([#120](https://codeberg.org/ivarch/pv/issues/120))
|
||||
* *fix:* allow **extra-display** to be changed by **--remote** ([#123](https://codeberg.org/ivarch/pv/issues/123))
|
||||
* *cleanup:* refactored display formatters into separate functions
|
||||
* *cleanup:* improve format parser handling of dangling or invalid "%" sequences
|
||||
|
||||
### 1.9.7 - 2 December 2024
|
||||
|
||||
* *feature:* new **--extra-display** option to update window and process titles ([#3](https://codeberg.org/a-j-wood/pv/issues/3), [#4](https://codeberg.org/a-j-wood/pv/issues/4))
|
||||
* *fix:* correct failure to report file positions in **--watchfd** ([#118](https://codeberg.org/a-j-wood/pv/issues/118))
|
||||
* *feature:* new **--extra-display** option to update window and process titles ([#3](https://codeberg.org/ivarch/pv/issues/3), [#4](https://codeberg.org/ivarch/pv/issues/4))
|
||||
* *fix:* correct failure to report file positions in **--watchfd** ([#118](https://codeberg.org/ivarch/pv/issues/118))
|
||||
* *i18n:* Russian translations added
|
||||
* *cleanup:* tests added for **--watchfd** ([#10](https://codeberg.org/a-j-wood/pv/issues/10))
|
||||
* *cleanup:* worked around file descriptor leak false positives in valgrind 3.23 ([#97](https://codeberg.org/a-j-wood/pv/issues/97))
|
||||
* *cleanup:* tests added for **--watchfd** ([#10](https://codeberg.org/ivarch/pv/issues/10))
|
||||
* *cleanup:* worked around file descriptor leak false positives in valgrind 3.23 ([#97](https://codeberg.org/ivarch/pv/issues/97))
|
||||
* *cleanup:* cleared all *shellcheck* warnings in the test scripts
|
||||
* *cleanup:* check at compile-time whether **--remote** is going to be usable ([#119](https://codeberg.org/a-j-wood/pv/issues/119))
|
||||
* *cleanup:* check at compile-time whether **--remote** is going to be usable ([#119](https://codeberg.org/ivarch/pv/issues/119))
|
||||
|
||||
### 1.9.0 - 15 October 2024
|
||||
|
||||
* *feature:* new **--store-and-forward** option to read input to a file first, then write it to the output ([#100](https://codeberg.org/a-j-wood/pv/issues/100))
|
||||
* *feature:* new **--stats** option to show transfer stats at the end, like "`ping`" ([#49](https://codeberg.org/a-j-wood/pv/issues/49))
|
||||
* *feature:* **--rate** can now be used with **--numeric** ([#17](https://codeberg.org/a-j-wood/pv/issues/17))
|
||||
* *feature:* **--gauge** with **--progress** to show rate gauge when size is unknown ([#46](https://codeberg.org/a-j-wood/pv/issues/46))
|
||||
* *feature:* new **--store-and-forward** option to read input to a file first, then write it to the output ([#100](https://codeberg.org/ivarch/pv/issues/100))
|
||||
* *feature:* new **--stats** option to show transfer stats at the end, like "`ping`" ([#49](https://codeberg.org/ivarch/pv/issues/49))
|
||||
* *feature:* **--rate** can now be used with **--numeric** ([#17](https://codeberg.org/ivarch/pv/issues/17))
|
||||
* *feature:* **--gauge** with **--progress** to show rate gauge when size is unknown ([#46](https://codeberg.org/ivarch/pv/issues/46))
|
||||
* *i18n:* comprehensive German translations update
|
||||
* *i18n:* comprehensive Polish translations update
|
||||
* *i18n:* complete Turkish translations added
|
||||
* *i18n:* complete Czech translations added
|
||||
* *i18n:* updates to French translations
|
||||
* *fix:* resume stopped pipelines when running in the background (part of [#56](https://codeberg.org/a-j-wood/pv/issues/56))
|
||||
* *fix:* resume stopped pipelines when running in the background (part of [#56](https://codeberg.org/ivarch/pv/issues/56))
|
||||
* *fix:* inspect the output pipe buffer to give a more accurate progress indicator of how much the next command has consumed
|
||||
* *fix:* prefix completion time (**--fineta**) with *FIN* rather than *ETA* ([#43](https://codeberg.org/a-j-wood/pv/issues/43))
|
||||
* *fix:* prefix completion time (**--fineta**) with *FIN* rather than *ETA* ([#43](https://codeberg.org/ivarch/pv/issues/43))
|
||||
* *fix:* surround average rate (**--average-rate**) with brackets rather than square brackets
|
||||
* *fix:* correct a memory leak in **--watchfd PID**
|
||||
* *fix:* make **--direct-io** work correctly with **--output** instead of assuming stdout
|
||||
@@ -49,44 +99,44 @@
|
||||
|
||||
### 1.8.14 - 7 September 2024
|
||||
|
||||
* *fix:* correct double-free on exit when using **--watchfd** ([#96](https://codeberg.org/a-j-wood/pv/issues/96)) reported by [jettero](https://codeberg.org/jettero)
|
||||
* *fix:* correct double-free on exit when using **--watchfd** ([#96](https://codeberg.org/ivarch/pv/issues/96)) reported by [jettero](https://codeberg.org/jettero)
|
||||
|
||||
### 1.8.13 - 18 August 2024
|
||||
|
||||
* *feature:* when using **--size @FILE**, *FILE* can be a block device, and its size will be used (pull request [#94](https://codeberg.org/a-j-wood/pv/pulls/94)) supplied by [alexanderperlis](https://codeberg.org/alexanderperlis)
|
||||
* *feature:* when using **--size @FILE**, *FILE* can be a block device, and its size will be used (pull request [#94](https://codeberg.org/ivarch/pv/pulls/94)) supplied by [alexanderperlis](https://codeberg.org/alexanderperlis)
|
||||
|
||||
### 1.8.12 - 18 July 2024
|
||||
|
||||
* *fix:* correct the detection of output block device size that was broken in 1.8.10 ([#91](https://codeberg.org/a-j-wood/pv/issues/91))
|
||||
* *fix:* do not treat a zero/interrupted write as an end of file (pull requests [#92](https://codeberg.org/a-j-wood/pv/pulls/92) and [#93](https://codeberg.org/a-j-wood/pv/pulls/93))
|
||||
* *fix:* correct the detection of output block device size that was broken in 1.8.10 ([#91](https://codeberg.org/ivarch/pv/issues/91))
|
||||
* *fix:* do not treat a zero/interrupted write as an end of file (pull requests [#92](https://codeberg.org/ivarch/pv/pulls/92) and [#93](https://codeberg.org/ivarch/pv/pulls/93))
|
||||
|
||||
### 1.8.10 - 15 June 2024
|
||||
|
||||
* *feature:* new **--output** option to write to a file instead of standard output (pull request [#90](https://codeberg.org/a-j-wood/pv/pulls/90)) supplied by [xmort](https://codeberg.org/xmort)
|
||||
* *feature:* new **--output** option to write to a file instead of standard output (pull request [#90](https://codeberg.org/ivarch/pv/pulls/90)) supplied by [xmort](https://codeberg.org/xmort)
|
||||
|
||||
### 1.8.9 - 21 April 2024
|
||||
|
||||
* *feature:* new **--si** option to display and interpret size suffixes in multiples of 1000 rather than 1024 (pull request [#85](https://codeberg.org/a-j-wood/pv/pulls/85)) supplied by [kevinruddy](https://codeberg.org/kevinruddy)
|
||||
* *fix:* continue producing progress output when the output is blocking writes ([#34](https://codeberg.org/a-j-wood/pv/issues/34), [#86](https://codeberg.org/a-j-wood/pv/issues/86), [#87](https://codeberg.org/a-j-wood/pv/issues/87))
|
||||
* *fix:* honour the *TMPDIR* / *TMP* environment variables again, rather than hard-coding "`/tmp`", when using a terminal lock file (originally removed in 1.8.0) ([#88](https://codeberg.org/a-j-wood/pv/issues/88))
|
||||
* *i18n:* corrections and missing strings added to French translations (pull request [#83](https://codeberg.org/a-j-wood/pv/pulls/83)) supplied by [Thomas Bertels](https://codeberg.org/tbertels)
|
||||
* *feature:* new **--si** option to display and interpret size suffixes in multiples of 1000 rather than 1024 (pull request [#85](https://codeberg.org/ivarch/pv/pulls/85)) supplied by [kevinruddy](https://codeberg.org/kevinruddy)
|
||||
* *fix:* continue producing progress output when the output is blocking writes ([#34](https://codeberg.org/ivarch/pv/issues/34), [#86](https://codeberg.org/ivarch/pv/issues/86), [#87](https://codeberg.org/ivarch/pv/issues/87))
|
||||
* *fix:* honour the *TMPDIR* / *TMP* environment variables again, rather than hard-coding "`/tmp`", when using a terminal lock file (originally removed in 1.8.0) ([#88](https://codeberg.org/ivarch/pv/issues/88))
|
||||
* *i18n:* corrections and missing strings added to French translations (pull request [#83](https://codeberg.org/ivarch/pv/pulls/83)) supplied by [Thomas Bertels](https://codeberg.org/tbertels)
|
||||
|
||||
### 1.8.5 - 19 November 2023
|
||||
|
||||
* *fix:* corrected percentage formatting so it doesn't jump from 2 to 3 characters wide at 100% ([#80](https://codeberg.org/a-j-wood/pv/issues/80))
|
||||
* *fix:* corrected percentage formatting so it doesn't jump from 2 to 3 characters wide at 100% ([#80](https://codeberg.org/ivarch/pv/issues/80))
|
||||
* *fix:* replaced **--remote** mechanism, using a temporary file instead of SysV IPC, so it can work reliably even when there are multiple PV instances
|
||||
* *fix:* corrected compilation failure when without IPC support
|
||||
* *security:* addressed all issues highlighted by the software auditing tools "`splint`" and "`flawfinder`" (see "`make analyse`") ([#77](https://codeberg.org/a-j-wood/pv/issues/77))
|
||||
* *security:* addressed all issues highlighted by the software auditing tools "`splint`" and "`flawfinder`" (see "`make analyse`") ([#77](https://codeberg.org/ivarch/pv/issues/77))
|
||||
* *cleanup:* compilation warnings fixed on non-IPC and MacOS systems
|
||||
|
||||
### 1.8.0 - 24 September 2023
|
||||
|
||||
#### Features
|
||||
|
||||
* *feature:* new **--discard** option to discard input as if writing to */dev/null* ([#42](https://codeberg.org/a-j-wood/pv/issues/42))
|
||||
* *feature:* new **--error-skip-block** option to make **--skip-errors** skip whole blocks ([#37](https://codeberg.org/a-j-wood/pv/issues/37))
|
||||
* *feature:* use `posix_fadvise()` like `cat`(1) does, to improve efficiency ([#39](https://codeberg.org/a-j-wood/pv/issues/39))
|
||||
* *feature:* new **--enable-static** option to "`configure`" for static builds ([#75](https://codeberg.org/a-j-wood/pv/pull/75))
|
||||
* *feature:* new **--discard** option to discard input as if writing to */dev/null* ([#42](https://codeberg.org/ivarch/pv/issues/42))
|
||||
* *feature:* new **--error-skip-block** option to make **--skip-errors** skip whole blocks ([#37](https://codeberg.org/ivarch/pv/issues/37))
|
||||
* *feature:* use `posix_fadvise()` like `cat`(1) does, to improve efficiency ([#39](https://codeberg.org/ivarch/pv/issues/39))
|
||||
* *feature:* new **--enable-static** option to "`configure`" for static builds ([#75](https://codeberg.org/ivarch/pv/pull/75))
|
||||
|
||||
#### Security
|
||||
|
||||
@@ -98,10 +148,10 @@
|
||||
|
||||
* *fix:* only report errors about missing files when starting to transfer from them, not while calculating size, and behave more like `cat`(1) by skipping them and moving on
|
||||
* *fix:* auto-calculate total line count with **--line-mode** when all inputs are regular files
|
||||
* *fix:* use `clock_gettime()` in ETA calculation to cope with machine suspend/resume ([#13](https://codeberg.org/a-j-wood/pv/issues/13))
|
||||
* *fix:* if **--width** or **--height** were provided, do not change them when the window size changes ([#36](https://codeberg.org/a-j-wood/pv/issues/36))
|
||||
* *fix:* when a file descriptor position in **--watchfd** moves backwards, show the rate using the correct prefix ([#41](https://codeberg.org/a-j-wood/pv/issues/41))
|
||||
* *fix:* rewrite terminal state save/restore so state is not intermittently garbled on exit when using **--cursor** ([#20](https://codeberg.org/a-j-wood/pv/issues/20)), ([#24](https://codeberg.org/a-j-wood/pv/issues/24))
|
||||
* *fix:* use `clock_gettime()` in ETA calculation to cope with machine suspend/resume ([#13](https://codeberg.org/ivarch/pv/issues/13))
|
||||
* *fix:* if **--width** or **--height** were provided, do not change them when the window size changes ([#36](https://codeberg.org/ivarch/pv/issues/36))
|
||||
* *fix:* when a file descriptor position in **--watchfd** moves backwards, show the rate using the correct prefix ([#41](https://codeberg.org/ivarch/pv/issues/41))
|
||||
* *fix:* rewrite terminal state save/restore so state is not intermittently garbled on exit when using **--cursor** ([#20](https://codeberg.org/ivarch/pv/issues/20)), ([#24](https://codeberg.org/ivarch/pv/issues/24))
|
||||
|
||||
#### Cleanups
|
||||
|
||||
@@ -110,8 +160,8 @@
|
||||
* *cleanup:* replaced the test harness with the one native to GNU Automake
|
||||
* *cleanup:* added a test for terminal width detection to "`make check`"
|
||||
* *cleanup:* added a test to "`make check`" to ensure that "`make install`" installs everything expected
|
||||
* *cleanup:* replaced *AC_HEADER_TIOCGWINSZ* with *AC_CHECK_HEADERS(sys/ioctl.h)* for better MacOS compatibility ([#74](https://codeberg.org/a-j-wood/pv/issues/74))
|
||||
* *cleanup:* with **--sync**, call `fsync()` instead of `fdatasync()` on incapable systems ([#73](https://codeberg.org/a-j-wood/pv/issues/73))
|
||||
* *cleanup:* replaced *AC_HEADER_TIOCGWINSZ* with *AC_CHECK_HEADERS(sys/ioctl.h)* for better MacOS compatibility ([#74](https://codeberg.org/ivarch/pv/issues/74))
|
||||
* *cleanup:* with **--sync**, call `fsync()` instead of `fdatasync()` on incapable systems ([#73](https://codeberg.org/ivarch/pv/issues/73))
|
||||
* *cleanup:* the manual is now a static file instead of needing to be built with "`configure`"
|
||||
|
||||
#### Dropped items
|
||||
@@ -127,7 +177,7 @@
|
||||
|
||||
### 1.7.24 - 30 July 2023
|
||||
|
||||
* *fix:* correct terminal size detection, broken in 1.7.17 by the configuration script rewrite ([#72](https://codeberg.org/a-j-wood/pv/issues/72))
|
||||
* *fix:* correct terminal size detection, broken in 1.7.17 by the configuration script rewrite ([#72](https://codeberg.org/ivarch/pv/issues/72))
|
||||
* *security:* removed *DEBUG* environment variable in debug mode, added **--debug** instead
|
||||
* *cleanup:* added "`make analyse`" to run "`splint`" and "`flawfinder`" on all source files
|
||||
* *cleanup:* corrected detection of boolean capability
|
||||
@@ -140,8 +190,8 @@
|
||||
|
||||
### 1.7.17 - 27 July 2023
|
||||
|
||||
* *feature:* new **--sync** option to flush cache to disk after every write (related to [#6](https://codeberg.org/a-j-wood/pv/issues/6), to improve accuracy when writing to slow disks)
|
||||
* *feature:* new **--direct-io** option to bypass cache - implements [#29 "Option to enable O_DIRECT"](https://codeberg.org/a-j-wood/pv/issues/29) - requested by Romain Kang, Jacek Wielemborek
|
||||
* *feature:* new **--sync** option to flush cache to disk after every write (related to [#6](https://codeberg.org/ivarch/pv/issues/6), to improve accuracy when writing to slow disks)
|
||||
* *feature:* new **--direct-io** option to bypass cache - implements [#29 "Option to enable O_DIRECT"](https://codeberg.org/ivarch/pv/issues/29) - requested by Romain Kang, Jacek Wielemborek
|
||||
* *fix:* correct byte prefix size to 2 spaces in rate display, so progress display size remains constant at low transfer rates
|
||||
* *cleanup:* rewrote `configure.in` as per suggestions in newer "`autoconf`" manuals
|
||||
* *cleanup:* replaced `header.in` with one generated by "`autoheader`", moving custom logic to a separate header file "`config-aux.h`"
|
||||
@@ -161,18 +211,18 @@
|
||||
### 1.7.0 - 17 July 2023
|
||||
|
||||
* *dropped:* support for Red Hat Enterprise Linux and its derivatives has been dropped; removed the RPM spec file, and will no longer build binaries
|
||||
* *feature:* the **--size** option now accepts "`@filename`" to use the size of another file (pull request [#57](https://codeberg.org/a-j-wood/pv/pull/57) supplied by [Dave Beckett](https://github.com/dajobe))
|
||||
* *feature:* the **--watchfd** option is now available on OS X (pull request [#60](https://codeberg.org/a-j-wood/pv/pull/60) supplied by [christoph-zededa](https://github.com/christoph-zededa))
|
||||
* *feature:* new **--bits** option to show bit count instead of byte count (adapted from pull request [#63](https://codeberg.org/a-j-wood/pv/pull/63) supplied by [Nick Black](https://nick-black.com))
|
||||
* *feature:* new **--average-rate-window** option, to set the window over which the average rate is calculated, also used for ETA (modified from pull request [#65](https://codeberg.org/a-j-wood/pv/pull/65) supplied by [lemonsqueeze](https://github.com/lemonsqueeze))
|
||||
* *feature:* the **--watchfd** option will now show relative filenames, if they are under the current directory (pull request [#66](https://codeberg.org/a-j-wood/pv/pull/66) supplied by [ikasty](https://github.com/ikasty))
|
||||
* *fix:* correction to `pv_in_foreground()` to behave as its comment block says it should, when not on a terminal - corrects [#19 "No output in Arch Linux initcpio after 1.6.6"](https://codeberg.org/a-j-wood/pv/issues/19), [#31 "No output written from inside zsh <() construct"](https://codeberg.org/a-j-wood/pv/issues/31), [#55 "pv Stopped Working in the Background"](https://codeberg.org/a-j-wood/pv/issues/55) (pull request [#64](https://codeberg.org/a-j-wood/pv/pull/64) supplied by [Michael Weiß](https://github.com/quitschbo))
|
||||
* *fix:* workaround for OS X 11 behaviour in configure script regarding stat64 at compile time (pull request [#57](https://codeberg.org/a-j-wood/pv/pull/57) supplied by [Dave Beckett](https://github.com/dajobe))
|
||||
* *fix:* workaround for macOS equivalence of stat to stat64 - patches from [Filippo Valsorda](https://github.com/FiloSottile) and [Demitri Muna](https://github.com/demitri), correcting [#33 "Fix compilation problems due to `stat64()` on Apple Silicon"](https://codeberg.org/a-j-wood/pv/issues/33)
|
||||
* *fix:* add burst rate limit to transfer, so rate limits are not broken by bursty traffic (pull request [#62](https://codeberg.org/a-j-wood/pv/pull/62) supplied by [Volodymyr Bychkovyak](https://github.com/vbychkoviak))
|
||||
* *fix:* corrected **--force** option so it will still output progress when not in the same process group as the owner of the terminal - corrects [#23 "No output with "-f" when run in background after 1.6.6"](https://codeberg.org/a-j-wood/pv/issues/23) and helps to correct [#31 "No output written from inside zsh <() construct"](https://codeberg.org/a-j-wood/pv/issues/31)
|
||||
* *fix:* corrected elapsed time display to show as D:HH:MM:SS after 1 day, like the ETA does - corrects [#16 "Show days in same format in ETA as in elapsed time"](https://codeberg.org/a-j-wood/pv/issues/16)
|
||||
* *fix:* corrected bug where percentages went down after 100% when in **--numeric** mode with a **--size** that was too small - corrects [#26 "Correct "-n" behaviour when going past 100% of "-s" size"](https://codeberg.org/a-j-wood/pv/issues/26)
|
||||
* *feature:* the **--size** option now accepts "`@filename`" to use the size of another file (pull request [#57](https://codeberg.org/ivarch/pv/pull/57) supplied by [Dave Beckett](https://github.com/dajobe))
|
||||
* *feature:* the **--watchfd** option is now available on OS X (pull request [#60](https://codeberg.org/ivarch/pv/pull/60) supplied by [christoph-zededa](https://github.com/christoph-zededa))
|
||||
* *feature:* new **--bits** option to show bit count instead of byte count (adapted from pull request [#63](https://codeberg.org/ivarch/pv/pull/63) supplied by [Nick Black](https://nick-black.com))
|
||||
* *feature:* new **--average-rate-window** option, to set the window over which the average rate is calculated, also used for ETA (modified from pull request [#65](https://codeberg.org/ivarch/pv/pull/65) supplied by [lemonsqueeze](https://github.com/lemonsqueeze))
|
||||
* *feature:* the **--watchfd** option will now show relative filenames, if they are under the current directory (pull request [#66](https://codeberg.org/ivarch/pv/pull/66) supplied by [ikasty](https://github.com/ikasty))
|
||||
* *fix:* correction to `pv_in_foreground()` to behave as its comment block says it should, when not on a terminal - corrects [#19 "No output in Arch Linux initcpio after 1.6.6"](https://codeberg.org/ivarch/pv/issues/19), [#31 "No output written from inside zsh <() construct"](https://codeberg.org/ivarch/pv/issues/31), [#55 "pv Stopped Working in the Background"](https://codeberg.org/ivarch/pv/issues/55) (pull request [#64](https://codeberg.org/ivarch/pv/pull/64) supplied by [Michael Weiß](https://github.com/quitschbo))
|
||||
* *fix:* workaround for OS X 11 behaviour in configure script regarding stat64 at compile time (pull request [#57](https://codeberg.org/ivarch/pv/pull/57) supplied by [Dave Beckett](https://github.com/dajobe))
|
||||
* *fix:* workaround for macOS equivalence of stat to stat64 - patches from [Filippo Valsorda](https://github.com/FiloSottile) and [Demitri Muna](https://github.com/demitri), correcting [#33 "Fix compilation problems due to `stat64()` on Apple Silicon"](https://codeberg.org/ivarch/pv/issues/33)
|
||||
* *fix:* add burst rate limit to transfer, so rate limits are not broken by bursty traffic (pull request [#62](https://codeberg.org/ivarch/pv/pull/62) supplied by [Volodymyr Bychkovyak](https://github.com/vbychkoviak))
|
||||
* *fix:* corrected **--force** option so it will still output progress when not in the same process group as the owner of the terminal - corrects [#23 "No output with "-f" when run in background after 1.6.6"](https://codeberg.org/ivarch/pv/issues/23) and helps to correct [#31 "No output written from inside zsh <() construct"](https://codeberg.org/ivarch/pv/issues/31)
|
||||
* *fix:* corrected elapsed time display to show as D:HH:MM:SS after 1 day, like the ETA does - corrects [#16 "Show days in same format in ETA as in elapsed time"](https://codeberg.org/ivarch/pv/issues/16)
|
||||
* *fix:* corrected bug where percentages went down after 100% when in **--numeric** mode with a **--size** that was too small - corrects [#26 "Correct "-n" behaviour when going past 100% of "-s" size"](https://codeberg.org/ivarch/pv/issues/26)
|
||||
* *i18n:* recoded Polish translation file to UTF-8
|
||||
* *i18n:* removed inaccurate fuzzy translation matches
|
||||
* *docs:* moved all open issues into GitHub and updated the TODO list
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
# The packages built with this script are not "official", in that they are
|
||||
# not part of any Linux distribution and may not follow the distribution's
|
||||
# policies. Use at your own risk.
|
||||
#
|
||||
# Copyright 2024-2025 Andrew Wood
|
||||
# License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
|
||||
sourceArchive="$1"
|
||||
test -n "${sourceArchive}" && test -f "${sourceArchive}" \
|
||||
@@ -27,8 +30,8 @@ pv (Pipe Viewer) can be inserted into any normal pipeline between two
|
||||
processes to give a visual indication of how quickly data is passing
|
||||
through, how long it has taken, how near to completion it is, and an
|
||||
estimate of how long it will be until completion."
|
||||
packageUrl="https://www.ivarch.com/programs/pv.shtml"
|
||||
sourceUrl="https://www.ivarch.com/programs/sources/${packageName}-%{version}.tar.gz"
|
||||
packageUrl="https://ivarch.com/p/pv"
|
||||
sourceUrl="https://ivarch.com/programs/sources/${packageName}-%{version}.tar.gz"
|
||||
packageEmail="Andrew Wood <pv@ivarch.com>"
|
||||
|
||||
workDir="$(mktemp -d)" || exit 1
|
||||
@@ -65,7 +68,7 @@ rm -rf "\${RPM_BUILD_ROOT}/usr/share/doc"
|
||||
%find_lang %{name}
|
||||
|
||||
%check
|
||||
make check
|
||||
make check SKIP_VALGRIND_TESTS=1
|
||||
|
||||
%clean
|
||||
test -n "\${RPM_BUILD_ROOT}" && test "\${RPM_BUILD_ROOT}" != '/' && rm -rf "\${RPM_BUILD_ROOT}"
|
||||
|
||||
@@ -1,114 +1,30 @@
|
||||
.TH PV 1 2024-12-08 pv-1.9.15 "User Commands"
|
||||
.TH PV 1 2025-10-18 pv-1.9.44 "User Commands"
|
||||
.\"
|
||||
.SH NAME
|
||||
pv \- monitor the progress of data through a pipe
|
||||
pv \- monitor and manage the progress of data through a pipe
|
||||
.\"
|
||||
.SH SYNOPSIS
|
||||
.B pv
|
||||
[\fIOPTION\fR]... [\fIFILE\fR]...
|
||||
.PP
|
||||
.SY pv
|
||||
.OP \-pteIrab8kTv
|
||||
.OP \-A NUM
|
||||
.OP \-F FORMAT
|
||||
.OP \-x SPEC
|
||||
.OP \-Wgl0fc
|
||||
.OP \-D SEC
|
||||
.OP \-s SIZE
|
||||
.OP \-i SEC
|
||||
.OP \-m SEC
|
||||
.OP \-w WIDTH
|
||||
.OP \-H HEIGHT
|
||||
.OP \-N NAME
|
||||
.OP \-o FILE
|
||||
.OP \-L RATE
|
||||
.OP \-B BYTES
|
||||
.OP \-CESYKX
|
||||
.OP \-Z BYTES
|
||||
.OP \-U FILE
|
||||
.OP \-P FILE
|
||||
.RI [ FILE
|
||||
\&.\|.\|.\&]
|
||||
\fBpv\fR [\fIOPTION\fR]... \fB\-d\fR|\fB\-\-watchfd\fR
|
||||
\fIPID\fR[:\fIFD\fR]|=\fINAME\fR|@\fILISTFILE\fR...
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-n
|
||||
.OP \-trbv
|
||||
.OP \-Wl0
|
||||
.OP \-D SEC
|
||||
.OP \-s SIZE
|
||||
.OP \-i SEC
|
||||
.OP \-o FILE
|
||||
.OP \-L RATE
|
||||
.OP \-B BYTES
|
||||
.OP \-CESYKX
|
||||
.OP \-Z BYTES
|
||||
.OP \-U FILE
|
||||
.OP \-P FILE
|
||||
.RI [ FILE
|
||||
\&.\|.\|.\&]
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-q
|
||||
.OP \-v
|
||||
.OP \-s SIZE
|
||||
.OP \-o FILE
|
||||
.OP \-L RATE
|
||||
.OP \-B BYTES
|
||||
.OP \-CESYKX
|
||||
.OP \-Z BYTES
|
||||
.OP \-U FILE
|
||||
.OP \-P FILE
|
||||
.RI [ FILE
|
||||
\&.\|.\|.\&]
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-R
|
||||
.I PID
|
||||
.OP \-pteIrabT
|
||||
.OP \-A NUM
|
||||
.OP \-F FORMAT
|
||||
.OP \-s SIZE
|
||||
.OP \-i SEC
|
||||
.OP \-w WIDTH
|
||||
.OP \-H HEIGHT
|
||||
.OP \-N NAME
|
||||
.OP \-L RATE
|
||||
.OP \-B BYTES
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-d
|
||||
.I PID:FD
|
||||
.OP \-pteIrab8kTnq
|
||||
.OP \-F FORMAT
|
||||
.OP \-i SEC
|
||||
.OP \-w WIDTH
|
||||
.OP \-H HEIGHT
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-d
|
||||
.I PID
|
||||
.OP \-pteIrab8kTnq
|
||||
.OP \-F FORMAT
|
||||
.OP \-i SEC
|
||||
.OP \-w WIDTH
|
||||
.OP \-H HEIGHT
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-h
|
||||
.PP
|
||||
.SY pv
|
||||
.B \-V
|
||||
.YS
|
||||
\fBpv\fR \fB\-R\fR|\fB\-\-remote\fR \fIPID\fR [\fIOPTION\fR]...
|
||||
.\"
|
||||
.SH DESCRIPTION
|
||||
Show the progress of data through a pipeline by giving information such as
|
||||
time elapsed, percentage completed (with progress bar), current throughput
|
||||
rate, total data transferred, and ETA.
|
||||
The data flow rate, error handling strategy, buffer size, and cache
|
||||
interaction can all be adjusted.
|
||||
.PP
|
||||
Each \fIFILE\fR is copied to standard output.
|
||||
With no \fIFILE\fR, or when \fIFILE\fR is \*(lq-\*(rq, standard input is
|
||||
read.
|
||||
This is the same behaviour as \fBcat\fR(1).
|
||||
.PP
|
||||
In \*(lq\fB\-\-watchfd\fR\*(rq mode, inspect another process and show its
|
||||
progress through the files it has open.
|
||||
.\"
|
||||
.SH OPTIONS
|
||||
.\"
|
||||
@@ -186,8 +102,7 @@ percentage, one per line, on standard error, suitable for passing to a tool
|
||||
such as \fBdialog\fR(1).
|
||||
Note that \*(lq\fB\-\-force\fR\*(rq is not required if
|
||||
\*(lq\fB\-\-numeric\fR\*(rq is being used.
|
||||
.TP
|
||||
.B ""
|
||||
.IP
|
||||
Combining \*(lq\fB\-\-numeric\fR\*(rq with \*(lq\fB\-\-bytes\fR\*(rq will
|
||||
cause the number of bytes processed so far to be output instead of a
|
||||
percentage.
|
||||
@@ -198,6 +113,13 @@ Adding \*(lq\fB\-\-rate\fR\*(rq adds the transfer rate to each output line
|
||||
byte/line count).
|
||||
Adding \*(lq\fB\-\-timer\fR\*(rq prefixes each output line with the elapsed
|
||||
time so far, as a decimal number of seconds.
|
||||
.IP
|
||||
Combining \*(lq\fB\-\-numeric\fR\*(rq with \*(lq\fB\-\-format\fR\*(rq allows
|
||||
for custom output. The default format string components for
|
||||
\*(lq\fB\-\-numeric\fR\*(rq are
|
||||
\*(lq\fB%t\~%b\~%r\~%{progress\-amount\-only}\fR\*(rq in that order, each
|
||||
item being active or inactive according to the rules above (so the default
|
||||
with no other options is \*(lq\fB%{progress\-amount\-only}\fR\*(rq.
|
||||
.TP
|
||||
.B \-q, \-\-quiet
|
||||
No output.
|
||||
@@ -236,13 +158,10 @@ A suffix of \*(lqK\*(rq, \*(lqM\*(rq, \*(lqG\*(rq, or \*(lqT\*(rq can be
|
||||
added to denote kibibytes (*1024), mebibytes, gibibytes, tebibytes.
|
||||
If \*(lq\fB\-\-si\fR\*(rq appears before this option, suffixes will denote
|
||||
kilobytes (*1000), megabytes, and so on instead.
|
||||
.TP
|
||||
.B ""
|
||||
.IP
|
||||
If \fISIZE\fR starts with \*(lq\fB@\fR\*(rq, the size of file whose name
|
||||
follows the @ will be used.
|
||||
.TP
|
||||
.B ""
|
||||
.TP
|
||||
.B \-g, \-\-gauge
|
||||
If the progress bar is shown but the size is not known, then instead of
|
||||
moving the bar left and right to show progress, show the current transfer
|
||||
@@ -252,8 +171,7 @@ rate as a percentage of the maximum rate seen so far.
|
||||
Instead of counting bytes, count lines (newline characters).
|
||||
The progress bar will only move when a new line is found, and the value
|
||||
passed to \*(lq\fB\-\-size\fR\*(rq will be interpreted as a line count.
|
||||
.TP
|
||||
.B ""
|
||||
.IP
|
||||
If this option is used without \*(lq\fB\-\-size\fR\*(rq, the "total size"
|
||||
(in this case, total line count) is calculated by reading through all input
|
||||
files once before transfer starts.
|
||||
@@ -293,6 +211,14 @@ Useful in conjunction with \*(lq\fB\-\-cursor\fR\*(rq if you have a
|
||||
complicated pipeline and you want to be able to tell different parts of it
|
||||
apart.
|
||||
.TP
|
||||
.BI \-u\ STYLE \fR,\ \fB\-\-bar\-style\ STYLE
|
||||
Change the default progress bar style shown by \*(lq\fB\-\-progress\fR\*(rq,
|
||||
or by the \*(lq\fB\-\-format\fR\*(rq sequences \*(lq\fB%{progress}\fR\*(rq
|
||||
or \*(lq\fB%{progress\-bar\-only}\fR\*(rq, to \fISTYLE\fR.
|
||||
The \fISTYLE\fR can be one of \fBplain\fR (the default), \fBblock\fR,
|
||||
\fBgranular\fR, or \fBshaded\fR.
|
||||
These styles are described in the \fBFORMATTING\fR section below.
|
||||
.TP
|
||||
.BI \-x\ SPEC \fR,\ \fB\-\-extra\-display\ SPEC
|
||||
As well as displaying progress to the terminal, also write it to \fISPEC\fR.
|
||||
The \fISPEC\fR must start with a comma-separated list of destinations, and
|
||||
@@ -340,7 +266,7 @@ The same suffixes as \*(lq\fB\-\-size\fR\*(rq can be used.
|
||||
The default buffer size is the block size of the input file's filesystem
|
||||
multiplied by 32 (512KiB max), or 400KiB if the block size cannot be
|
||||
determined.
|
||||
This can be useful on platforms like MacOS with pipelines that perform
|
||||
This can be useful on platforms like macOS with pipelines that perform
|
||||
better with specific buffer sizes such as 1024.
|
||||
Implies \*(lq\fB\-\-no\-splice\fR\*(rq.
|
||||
.TP
|
||||
@@ -351,9 +277,9 @@ from or to a pipe than regular \fBread\fR(2) and \fBwrite\fR(2), but means
|
||||
that the transfer buffer may not be used.
|
||||
This prevents \*(lq\fB\-\-buffer\-percent\fR\*(rq and
|
||||
\*(lq\fB\-\-last\-written\fR\*(rq from working, cannot work with
|
||||
\*(lq\fB\-\-discard\fR\*(rq, and makes \*(lq\fB\-\-buffer\-size\fR\*(rq
|
||||
redundant, so using any of those options automatically switches on
|
||||
\*(lq\fB\-\-no\-splice\fR\*(rq.
|
||||
\*(lq\fB\-\-sparse\fR\*(rq or \*(lq\fB\-\-discard\fR\*(rq, and makes
|
||||
\*(lq\fB\-\-buffer\-size\fR\*(rq redundant, so using any of those options
|
||||
automatically switches on \*(lq\fB\-\-no\-splice\fR\*(rq.
|
||||
Switching on this option results in a small loss of transfer efficiency.
|
||||
It has no effect on systems where \fBsplice\fR(2) is unavailable.
|
||||
.TP
|
||||
@@ -363,8 +289,7 @@ The corresponding parts of the output will be null bytes.
|
||||
At first only a few bytes will be skipped, but if there are many errors in a
|
||||
row then the skips will move up to chunks of 512.
|
||||
This is intended to be similar to \*(lq\fIdd\~conv=sync,noerror\fR\*(rq.
|
||||
.TP
|
||||
.B ""
|
||||
.IP
|
||||
Specify \*(lq\fB\-\-skip\-errors\fR\*(rq twice to only report a read error
|
||||
once per file, instead of reporting each byte range skipped.
|
||||
.TP
|
||||
@@ -376,8 +301,7 @@ block of \fIBYTES\fR bytes as soon as an error occurs.
|
||||
There may still be some shorter skips where the block being skipped
|
||||
coincides with the end of the transfer buffer.
|
||||
The same suffixes as \*(lq\fB\-\-size\fR\*(rq can be used.
|
||||
.TP
|
||||
.B ""
|
||||
.IP
|
||||
This option can only be used with \*(lq\fB\-\-skip\-errors\fR\*(rq
|
||||
and is intended for use when reading from a block device, such as
|
||||
\*(lq\fB\-\-skip\-errors\~\-\-error\-skip\-block\~4K\fR\*(rq
|
||||
@@ -405,6 +329,13 @@ failures with an error of \*(lqInvalid argument\*(rq, especially if reading
|
||||
and writing files across a variety of filesystems in a single \fBpv\fR call.
|
||||
Use this option with caution.
|
||||
.TP
|
||||
.B \-O, \-\-sparse
|
||||
When writing null bytes, try to seek, producing a sparse output file.
|
||||
Implies \*(lq\fB\-\-no\-splice\fR\*(rq.
|
||||
On filesystems without sparse file support, or when the output is not
|
||||
seekable, this option will have no effect other than to turn on
|
||||
\*(lq\fB\-\-no\-splice\fR\*(rq.
|
||||
.TP
|
||||
.B \-X, \-\-discard
|
||||
Instead of transferring input data to standard output, discard it.
|
||||
This is equivalent to redirecting standard output to \fI/dev/null\fR,
|
||||
@@ -418,8 +349,7 @@ exhausted, read all of \fIFILE\fR and write it to the output.
|
||||
\fIFILE\fR remains in place afterwards, unless it is
|
||||
\*(lq\fB-\fR\*(rq, in which case \fBpv\fR creates a temporary file for this
|
||||
purpose, and automatically removes it afterwards.
|
||||
.TP
|
||||
.B ""
|
||||
.IP
|
||||
This can be useful if you have a pipeline which generates data (your
|
||||
input) quickly but you don't know the size, and you wish to pass it to some
|
||||
slower process, once all of the input has been generated and you know its
|
||||
@@ -427,18 +357,32 @@ size, so you can see its progress.
|
||||
Note that when doing this with relatively small amounts of data,
|
||||
\*(lq\fB\-\-no-splice\fR\*(rq may be preferable so that pipe buffering
|
||||
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.
|
||||
.TP
|
||||
.B ""
|
||||
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.
|
||||
Other data transfer modifiers - and remote control - may not be used with
|
||||
this option.
|
||||
.IP
|
||||
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,
|
||||
@@ -452,7 +396,7 @@ Note that some options cannot be changed while running, such as
|
||||
\*(lq\fB\-\-force\fR\*(rq, \*(lq\fB\-\-delay\-start\fR\*(rq,
|
||||
\*(lq\fB\-\-skip\-errors\fR\*(rq, and \*(lq\fB\-\-stop\-at\-size\fR\*(rq.
|
||||
.\"
|
||||
.SS "General options"
|
||||
.SS "Other options"
|
||||
.TP
|
||||
.BI \-P\ FILE \fR,\ \fB\-\-pidfile\ FILE
|
||||
Save the process ID of \fBpv\fR in \fIFILE\fR.
|
||||
@@ -477,15 +421,43 @@ Equivalent to \*(lq\fB\-\-progress\fR\*(rq.
|
||||
Expands to fill the remaining space unless prefixed by a number to set the
|
||||
width, such as \*(lq\fB%20p\fR\*(rq or \*(lq\fB%20{progress}\fR\*(rq.
|
||||
.TP
|
||||
.B %{progress-bar-only}
|
||||
.BR %{progress\-bar\-only}
|
||||
Progress bar, without any sides, and without any percentage displayed
|
||||
afterwards.
|
||||
Expands to fill the remaining space unless prefixed by a number.
|
||||
.TP
|
||||
.B %{progress-amount-only}
|
||||
.B %{progress\-amount\-only}
|
||||
The percentage completion (or maximum rate, with \*(lq\fB\-\-gauge\fR\*(rq
|
||||
when the size is unknown).
|
||||
.TP
|
||||
.B %{bar\-plain}
|
||||
Progress bar in the standard plain format, without any sides, and without
|
||||
any percentage displayed afterwards.
|
||||
Expands to fill the remaining space unless prefixed by a number.
|
||||
.TP
|
||||
.B %{bar\-block}
|
||||
Progress bar using Unicode full blocks, without any sides, and without any
|
||||
percentage displayed afterwards.
|
||||
Expands to fill the remaining space unless prefixed by a number.
|
||||
If UTF-8 output is not available, the plain format is used.
|
||||
.TP
|
||||
.B %{bar\-granular}
|
||||
Progress bar using Unicode full blocks, and 1/8th blocks for partial fills,
|
||||
providing a more granular display.
|
||||
Like the other \*(lq%{bar}\*(rq strings this shows the bar without any
|
||||
sides, and without any percentage displayed afterwards, and expands to fill
|
||||
the remaining space unless prefixed by a number.
|
||||
If UTF-8 output is not available, the plain format is used.
|
||||
.TP
|
||||
.B %{bar\-shaded}
|
||||
Progress bar using Unicode full blocks and shade characters - dark and
|
||||
medium shade are used for partial fills, and the light shade is used for the
|
||||
background.
|
||||
Like the other \*(lq%{bar}\*(rq strings this shows the bar without any
|
||||
sides, and without any percentage displayed afterwards, and expands to fill
|
||||
the remaining space unless prefixed by a number.
|
||||
If UTF-8 output is not available, the plain format is used.
|
||||
.TP
|
||||
.BR %t ", " %{timer}
|
||||
Elapsed time.
|
||||
Equivalent to \*(lq\fB\-\-timer\fR\*(rq.
|
||||
@@ -502,7 +474,7 @@ Equivalent to \*(lq\fB\-\-fineta\fR\*(rq.
|
||||
Current data transfer rate.
|
||||
Equivalent to \*(lq\fB\-\-rate\fR\*(rq.
|
||||
.TP
|
||||
.BR %a ", " %{average-rate}
|
||||
.BR %a ", " %{average\-rate}
|
||||
Average data transfer rate.
|
||||
Equivalent to \*(lq\fB\-\-average\-rate\fR\*(rq.
|
||||
.TP
|
||||
@@ -512,19 +484,19 @@ Equivalent to \*(lq\fB\-\-bytes\fR\*(rq.
|
||||
If \*(lq\fB\-\-bits\fR\*(rq was specified, \*(lq\fB%b\fR\*(rq shows the bits
|
||||
transferred so far, not bytes.
|
||||
.TP
|
||||
.BR %T ", " %{buffer-percent}
|
||||
.BR %T ", " %{buffer\-percent}
|
||||
Percentage of the transfer buffer in use.
|
||||
Equivalent to \*(lq\fB\-\-buffer\-percent\fR\*(rq.
|
||||
Displays \*(lq{\-\-\-\-}\*(rq if the transfer is being done with
|
||||
\fBsplice\fR(2), since splicing to or from pipes does not use the buffer.
|
||||
.TP
|
||||
.BR %nA ", " %n{last-written}
|
||||
.BR %nA ", " %n{last\-written}
|
||||
Show the last \fIn\fR bytes written (for example, \*(lq\fB%16A\fR\*(rq shows
|
||||
the last 16 bytes).
|
||||
Shows only dots if the transfer is being done with \fBsplice\fR(2), since
|
||||
splicing to or from pipes does not use the buffer.
|
||||
.TP
|
||||
.BR %nL ", " %n{previous-line}
|
||||
.BR %nL ", " %n{previous\-line}
|
||||
Show the first \fIn\fR bytes of the most recently written line (for example,
|
||||
\*(lq\fB%40L\fR\*(rq shows the first 40 bytes).
|
||||
If no \fIn\fR is given, then this expands to fill the available space.
|
||||
@@ -534,6 +506,58 @@ Shows only spaces if the transfer is being done with \fBsplice\fR(2).
|
||||
Show the name prefix given by \*(lq\fB\-\-name\fR\*(rq.
|
||||
Padded to 9 characters with spaces, and suffixed with \*(lq:\*(rq.
|
||||
.TP
|
||||
.B %{sgr:colour,...}
|
||||
Emit ECMA-48 SGR (Select Graphic Rendition) codes if the terminal supports
|
||||
colours, where \fIcolour,...\fR is a comma-separated list of any of the
|
||||
keywords below, or the numeric values from \fBconsole_codes\fR(4). If
|
||||
colour support is not available, nothing is emitted.
|
||||
.IP
|
||||
Supported keywords are:
|
||||
\fBreset\fR or \fBnone\fR,
|
||||
\fBblack\fR,
|
||||
\fBred\fR,
|
||||
\fBgreen\fR,
|
||||
\fBbrown\fR or \fByellow\fR,
|
||||
\fBblue\fR,
|
||||
\fBmagenta\fR,
|
||||
\fBcyan\fR,
|
||||
\fBwhite\fR,
|
||||
\fBfg\-black\fR,
|
||||
\fBfg\-red\fR,
|
||||
\fBfg\-green\fR,
|
||||
\fBfg\-brown\fR or \fBfg\-yellow\fR,
|
||||
\fBfg\-blue\fR,
|
||||
\fBfg\-magenta\fR,
|
||||
\fBfg\-cyan\fR,
|
||||
\fBfg\-white\fR,
|
||||
\fBfg\-default\fR,
|
||||
\fBbg\-black\fR,
|
||||
\fBbg\-red\fR,
|
||||
\fBbg\-green\fR,
|
||||
\fBbg\-brown\fR or \fBbg\-yellow\fR,
|
||||
\fBbg\-blue\fR,
|
||||
\fBbg\-magenta\fR,
|
||||
\fBbg\-cyan\fR,
|
||||
\fBbg\-white\fR,
|
||||
\fBbg\-default\fR,
|
||||
\fBbold\fR,
|
||||
\fBdim\fR,
|
||||
\fBitalic\fR,
|
||||
\fBunderscore\fR or \fBunderline\fR,
|
||||
\fBblink\fR,
|
||||
\fBreverse\fR,
|
||||
\fBno\-bold\fR or \fBno\-dim\fR,
|
||||
\fBno\-italic\fR,
|
||||
\fBno\-underscore\fR or \fBno\-underline\fR,
|
||||
\fBno\-blink\fR,
|
||||
\fBno\-reverse\fR.
|
||||
.IP
|
||||
With colours, the optional "fg-" prefix indicates foreground; a prefix of
|
||||
"bg-" indicates background.
|
||||
.IP
|
||||
For example, \*(lq\fB%{sgr:green,bold}TEXT%{sgr:reset}\fR\*(lq will make
|
||||
\fITEXT\fR bold green on supported terminals.
|
||||
.TP
|
||||
.B %%
|
||||
A single \*(lq%\*(rq.
|
||||
.PP
|
||||
@@ -568,7 +592,7 @@ Show only the elapsed time - useful as a simple timer, such as
|
||||
The default behaviour: progress bar, elapsed time, estimated completion
|
||||
time, current rate, and byte counter.
|
||||
.PP
|
||||
On MacOS, it may be useful to specify \*(lq\fB\-\-buffer\-size\~1024\fR\*(rq
|
||||
On macOS, it may be useful to specify \*(lq\fB\-\-buffer\-size\~1024\fR\*(rq
|
||||
in a pipeline, as this may improve performance.
|
||||
.PP
|
||||
To watch how quickly a file is transferred using \fBnc\fR(1):
|
||||
@@ -584,19 +608,18 @@ expected size to \fBpv\fR:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
cat file | pv \-s 12345 | nc \-w 1 somewhere.com 3000
|
||||
cat file | pv \-\-size 12345 | nc \-w 1 somewhere.com 3000
|
||||
.EE
|
||||
.in
|
||||
.PP
|
||||
A more complicated example using numeric output to feed into the
|
||||
\fBdialog\fR(1) program for a full-screen progress display:
|
||||
To watch the progress of creating a tar.gz archive:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
(tar cf \- . \e
|
||||
| pv \-n \-s $(du \-sb . | awk '{print $1}') \e
|
||||
| gzip \-9 > out.tgz) 2>&1 \e
|
||||
| dialog \-\-gauge 'Progress' 7 70
|
||||
tar cf \- directory/ \e
|
||||
| pv \-\-size $(du \-sb directory/ | awk '{print $1}') \e
|
||||
| gzip \-9 \e
|
||||
> out.tar.gz
|
||||
.EE
|
||||
.in
|
||||
.PP
|
||||
@@ -629,19 +652,28 @@ device, then the size of the block device will be used and \fBpv\fR will
|
||||
automatically stop at that size as if \*(lq\fB\-\-stop\-at\-size\fR\*(rq had
|
||||
been given.
|
||||
.PP
|
||||
(Linux only): Watching file descriptor 3 opened by another process 1234:
|
||||
(Linux and macOS only): Watching file descriptor 3 opened by another process 1234:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
pv \-d 1234:3
|
||||
pv \-\-watchfd 1234:3
|
||||
.EE
|
||||
.in
|
||||
.PP
|
||||
(Linux only): Watching all file descriptors used by process 1234:
|
||||
(Linux and macOS only): Watching all file descriptors used by process 1234:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
pv \-d 1234
|
||||
pv \-\-watchfd 1234
|
||||
.EE
|
||||
.in
|
||||
.PP
|
||||
Rate-limiting the transfer between two processes in a pipeline, with no
|
||||
display:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
producer | pv \-\-quiet \-\-rate\-limit 1M | consumer
|
||||
.EE
|
||||
.in
|
||||
.PP
|
||||
@@ -650,7 +682,15 @@ the progress display:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
pv \-F '%a %p : %L' big.log | processing-script
|
||||
pv \-\-format '%a %p : %L' big.log | processing-script
|
||||
.EE
|
||||
.in
|
||||
.PP
|
||||
Showing progress as lines of JSON data:
|
||||
.PP
|
||||
.in +4
|
||||
.EX
|
||||
pv \-\-numeric \-\-format '{"elapsed":%t,"bytes":%b,"rate":%r,"percentage":%{progress-amount-only}}' big.log | processing-script
|
||||
.EE
|
||||
.in
|
||||
.\"
|
||||
@@ -659,23 +699,23 @@ An exit status of 1 indicates a problem with the \*(lq\fB\-\-remote\fR\*(rq
|
||||
or \*(lq\fB\-\-pidfile\fR\*(rq options.
|
||||
.PP
|
||||
Any other exit status is a bitmask of the following:
|
||||
.TP
|
||||
.B 2
|
||||
.TP 5
|
||||
\~\fB2\fR
|
||||
One or more files could not be accessed, \fBstat\fR(2)ed, or opened.
|
||||
.TP
|
||||
.B 4
|
||||
\~\fB4\fR
|
||||
An input file was the same as the output file.
|
||||
.TP
|
||||
.B 8
|
||||
\~\fB8\fR
|
||||
Internal error with closing a file or moving to the next file.
|
||||
.TP
|
||||
.B 16
|
||||
\~\fB16\fR
|
||||
There was an error while transferring data from one or more input files.
|
||||
.TP
|
||||
.B 32
|
||||
\~\fB32\fR
|
||||
A signal was caught that caused an early exit.
|
||||
.TP
|
||||
.B 64
|
||||
\~\fB64\fR
|
||||
Memory allocation failed.
|
||||
.PP
|
||||
A zero exit status indicates no problems.
|
||||
@@ -727,7 +767,7 @@ pv InputFile | ( while read \-r line; do sleep 0.1; done; )
|
||||
.in
|
||||
.PP
|
||||
Refer to
|
||||
.UR https://codeberg.org/a-j-wood/pv/issues/105
|
||||
.UR https://codeberg.org/ivarch/pv/issues/105
|
||||
issue #105
|
||||
.UE
|
||||
for full details.
|
||||
@@ -749,25 +789,45 @@ passed to \*(lq\fB\-\-size\fR\*(rq, and activate
|
||||
The \*(lq\fB%nA\fR\*(rq and \*(lq\fB%nL\fR\*(rq format sequences may not be
|
||||
effective with small input files, and \*(lq\fB%nL\fR\*(rq may be a few lines
|
||||
out due to buffering within the pipeline itself.
|
||||
.PP
|
||||
Numbers passed to \*(lq\fB\-\-size\fR\*(rq, \*(lq\fB\-\-rate\-limit\fR\*(rq,
|
||||
\*(lq\fB\-\-buffer\-size\fR\*(rq, and \*(lq\fB\-\-error\-skip\-block\fR\*(rq
|
||||
may all be expressed as decimals if followed by a suffix, so for example
|
||||
\*(lq\fI\-\-size\~1.5G\fR\*(rq is equivalent to
|
||||
\*(lq\fI\-\-size\~1536M\fR\*(rq.
|
||||
.PP
|
||||
Numbers passed to \*(lq\fB\-\-interval\fR\*(rq and
|
||||
\*(lq\fB\-\-delay\-start\fR\*(rq may be integers or decimals, but may not
|
||||
have a suffix.
|
||||
.PP
|
||||
Numbers passed to \*(lq\fB\-\-last\-written\fR\*(rq,
|
||||
\*(lq\fB\-\-width\fR\*(rq, \*(lq\fB\-\-height\fR\*(rq,
|
||||
\*(lq\fB\-\-average\-rate\-window\fR\*(rq, and \*(lq\fB\-\-remote\fR\*(rq
|
||||
must be integers with no suffix.
|
||||
.PP
|
||||
When \*(lq\fB\-\-sparse\fR\*(rq is in effect and output is being written to
|
||||
a file, that file may look like it has stopped growing if inspected with
|
||||
\fBls\fR(1) while null bytes are being written, even though \fBpv\fR still
|
||||
reports progress.
|
||||
This is because of the way sparse output is achieved, and the file will be
|
||||
the correct size when the transfer ends.
|
||||
.\"
|
||||
.SH REPORTING BUGS
|
||||
Please report any bugs to \fBpv@ivarch.com\fR.
|
||||
.PP
|
||||
Alternatively, use the issue tracker linked from the
|
||||
.UR https://www.ivarch.com/programs/pv.shtml
|
||||
Please report bugs or feature requests via the issue tracker linked from the
|
||||
.UR https://ivarch.com/p/pv
|
||||
\fBpv\fR home page
|
||||
.UE .
|
||||
.\"
|
||||
.SH "SEE ALSO"
|
||||
.BR cat (1),
|
||||
.BR dialog (1),
|
||||
.BR splice (2),
|
||||
.BR fdatasync (2),
|
||||
.BR open (2)
|
||||
(for \fBO_DIRECT\fR)
|
||||
(for \fBO_DIRECT\fR),
|
||||
.BR console_codes (4)
|
||||
.\"
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood.
|
||||
Copyright \(co 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood.
|
||||
.PP
|
||||
License GPLv3+:
|
||||
.UR https://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
+177
-82
@@ -1,50 +1,29 @@
|
||||
# NAME
|
||||
|
||||
pv - monitor the progress of data through a pipe
|
||||
pv - monitor and manage the progress of data through a pipe
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**pv** \[*OPTION*\]\... \[*FILE*\]\...
|
||||
|
||||
**pv** \[ **-pteIrab8kTv** \] \[ **-A** NUM \] \[ **-F** FORMAT \] \[
|
||||
**-x** SPEC \] \[ **-Wgl0fc** \] \[ **-D** SEC \] \[ **-s** SIZE \] \[
|
||||
**-i** SEC \] \[ **-m** SEC \] \[ **-w** WIDTH \] \[ **-H** HEIGHT \] \[
|
||||
**-N** NAME \] \[ **-o** FILE \] \[ **-L** RATE \] \[ **-B** BYTES \] \[
|
||||
**-CESYKX** \] \[ **-Z** BYTES \] \[ **-U** FILE \] \[ **-P** FILE \]
|
||||
[*FILE* . . .\]
|
||||
**pv** \[*OPTION*\]\... **-d**\|**\--watchfd**
|
||||
*PID*\[:*FD*\]\|=*NAME*\|@*LISTFILE*\...
|
||||
|
||||
**pv** **-n** \[ **-trbv** \] \[ **-Wl0** \] \[ **-D** SEC \] \[ **-s**
|
||||
SIZE \] \[ **-i** SEC \] \[ **-o** FILE \] \[ **-L** RATE \] \[ **-B**
|
||||
BYTES \] \[ **-CESYKX** \] \[ **-Z** BYTES \] \[ **-U** FILE \] \[
|
||||
**-P** FILE \] \[*FILE* . . .\]
|
||||
|
||||
**pv** **-q** \[ **-v** \] \[ **-s** SIZE \] \[ **-o** FILE \] \[ **-L**
|
||||
RATE \] \[ **-B** BYTES \] \[ **-CESYKX** \] \[ **-Z** BYTES \] \[
|
||||
**-U** FILE \] \[ **-P** FILE \] \[*FILE* . . .\]
|
||||
|
||||
**pv** **-R** *PID* \[ **-pteIrabT** \] \[ **-A** NUM \] \[ **-F**
|
||||
FORMAT \] \[ **-s** SIZE \] \[ **-i** SEC \] \[ **-w** WIDTH \] \[
|
||||
**-H** HEIGHT \] \[ **-N** NAME \] \[ **-L** RATE \] \[ **-B** BYTES \]
|
||||
|
||||
**pv** **-d** *PID:FD* \[ **-pteIrab8kTnq** \] \[ **-F** FORMAT \] \[
|
||||
**-i** SEC \] \[ **-w** WIDTH \] \[ **-H** HEIGHT \]
|
||||
|
||||
**pv** **-d** *PID* \[ **-pteIrab8kTnq** \] \[ **-F** FORMAT \] \[
|
||||
**-i** SEC \] \[ **-w** WIDTH \] \[ **-H** HEIGHT \]
|
||||
|
||||
**pv** **-h**
|
||||
|
||||
**pv** **-V**
|
||||
**pv** **-R**\|**\--remote** *PID* \[*OPTION*\]\...
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Show the progress of data through a pipeline by giving information such
|
||||
as time elapsed, percentage completed (with progress bar), current
|
||||
throughput rate, total data transferred, and ETA.
|
||||
throughput rate, total data transferred, and ETA. The data flow rate,
|
||||
error handling strategy, buffer size, and cache interaction can all be
|
||||
adjusted.
|
||||
|
||||
Each *FILE* is copied to standard output. With no *FILE*, or when *FILE*
|
||||
is "-", standard input is read. This is the same behaviour as
|
||||
**cat**(1).
|
||||
is "-", standard input is read.
|
||||
|
||||
In "**\--watchfd**" mode, inspect another process and show its progress
|
||||
through the files it has open.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
@@ -126,7 +105,7 @@ are explicitly switched on will be shown.
|
||||
suitable for passing to a tool such as **dialog**(1). Note that
|
||||
"**\--force**" is not required if "**\--numeric**" is being used.
|
||||
|
||||
: Combining "**\--numeric**" with "**\--bytes**" will cause the number
|
||||
Combining "**\--numeric**" with "**\--bytes**" will cause the number
|
||||
of bytes processed so far to be output instead of a percentage.
|
||||
Adding "**\--line-mode**" as well as "**\--bytes**" writes the
|
||||
number of lines instead of bytes or a percentage. Adding
|
||||
@@ -135,6 +114,12 @@ are explicitly switched on will be shown.
|
||||
count). Adding "**\--timer**" prefixes each output line with the
|
||||
elapsed time so far, as a decimal number of seconds.
|
||||
|
||||
Combining "**\--numeric**" with "**\--format**" allows for custom
|
||||
output. The default format string components for "**\--numeric**"
|
||||
are "**%t %b %r %{progress-amount-only}**" in that order, each item
|
||||
being active or inactive according to the rules above (so the
|
||||
default with no other options is "**%{progress-amount-only}**".
|
||||
|
||||
**-q, \--quiet**
|
||||
|
||||
: No output. Useful if the "**\--rate-limit**" option is being used on
|
||||
@@ -176,11 +161,9 @@ are explicitly switched on will be shown.
|
||||
tebibytes. If "**\--si**" appears before this option, suffixes will
|
||||
denote kilobytes (\*1000), megabytes, and so on instead.
|
||||
|
||||
: If *SIZE* starts with "**@**", the size of file whose name follows
|
||||
If *SIZE* starts with "**@**", the size of file whose name follows
|
||||
the @ will be used.
|
||||
|
||||
:
|
||||
|
||||
**-g, \--gauge**
|
||||
|
||||
: If the progress bar is shown but the size is not known, then instead
|
||||
@@ -193,7 +176,7 @@ are explicitly switched on will be shown.
|
||||
progress bar will only move when a new line is found, and the value
|
||||
passed to "**\--size**" will be interpreted as a line count.
|
||||
|
||||
: If this option is used without "**\--size**", the \"total size\" (in
|
||||
If this option is used without "**\--size**", the \"total size\" (in
|
||||
this case, total line count) is calculated by reading through all
|
||||
input files once before transfer starts. If any inputs are pipes or
|
||||
non-regular files, or are unreadable, the total size will not be
|
||||
@@ -235,6 +218,14 @@ are explicitly switched on will be shown.
|
||||
with "**\--cursor**" if you have a complicated pipeline and you want
|
||||
to be able to tell different parts of it apart.
|
||||
|
||||
**-u STYLE, \--bar-style STYLE**
|
||||
|
||||
: Change the default progress bar style shown by "**\--progress**", or
|
||||
by the "**\--format**" sequences "**%{progress}**" or
|
||||
"**%{progress-bar-only}**", to *STYLE*. The *STYLE* can be one of
|
||||
**plain** (the default), **block**, **granular**, or **shaded**.
|
||||
These styles are described in the **FORMATTING** section below.
|
||||
|
||||
**-x SPEC, \--extra-display SPEC**
|
||||
|
||||
: As well as displaying progress to the terminal, also write it to
|
||||
@@ -284,7 +275,7 @@ are explicitly switched on will be shown.
|
||||
"**\--size**" can be used. The default buffer size is the block size
|
||||
of the input file\'s filesystem multiplied by 32 (512KiB max), or
|
||||
400KiB if the block size cannot be determined. This can be useful on
|
||||
platforms like MacOS with pipelines that perform better with
|
||||
platforms like macOS with pipelines that perform better with
|
||||
specific buffer sizes such as 1024. Implies "**\--no-splice**".
|
||||
|
||||
**-C, \--no-splice**
|
||||
@@ -294,11 +285,11 @@ are explicitly switched on will be shown.
|
||||
data from or to a pipe than regular **read**(2) and **write**(2),
|
||||
but means that the transfer buffer may not be used. This prevents
|
||||
"**\--buffer-percent**" and "**\--last-written**" from working,
|
||||
cannot work with "**\--discard**", and makes "**\--buffer-size**"
|
||||
redundant, so using any of those options automatically switches on
|
||||
"**\--no-splice**". Switching on this option results in a small loss
|
||||
of transfer efficiency. It has no effect on systems where
|
||||
**splice**(2) is unavailable.
|
||||
cannot work with "**\--sparse**" or "**\--discard**", and makes
|
||||
"**\--buffer-size**" redundant, so using any of those options
|
||||
automatically switches on "**\--no-splice**". Switching on this
|
||||
option results in a small loss of transfer efficiency. It has no
|
||||
effect on systems where **splice**(2) is unavailable.
|
||||
|
||||
**-E, \--skip-errors**
|
||||
|
||||
@@ -308,7 +299,7 @@ are explicitly switched on will be shown.
|
||||
errors in a row then the skips will move up to chunks of 512. This
|
||||
is intended to be similar to "*dd conv=sync,noerror*".
|
||||
|
||||
: Specify "**\--skip-errors**" twice to only report a read error once
|
||||
Specify "**\--skip-errors**" twice to only report a read error once
|
||||
per file, instead of reporting each byte range skipped.
|
||||
|
||||
**-Z BYTES, \--error-skip-block BYTES**
|
||||
@@ -321,7 +312,7 @@ are explicitly switched on will be shown.
|
||||
coincides with the end of the transfer buffer. The same suffixes as
|
||||
"**\--size**" can be used.
|
||||
|
||||
: This option can only be used with "**\--skip-errors**" and is
|
||||
This option can only be used with "**\--skip-errors**" and is
|
||||
intended for use when reading from a block device, such as
|
||||
"**\--skip-errors \--error-skip-block 4K**" to skip in 4 kibibyte
|
||||
blocks. This will speed up reads from faulty media, at the expense
|
||||
@@ -349,6 +340,13 @@ are explicitly switched on will be shown.
|
||||
especially if reading and writing files across a variety of
|
||||
filesystems in a single **pv** call. Use this option with caution.
|
||||
|
||||
**-O, \--sparse**
|
||||
|
||||
: When writing null bytes, try to seek, producing a sparse output
|
||||
file. Implies "**\--no-splice**". On filesystems without sparse file
|
||||
support, or when the output is not seekable, this option will have
|
||||
no effect other than to turn on "**\--no-splice**".
|
||||
|
||||
**-X, \--discard**
|
||||
|
||||
: Instead of transferring input data to standard output, discard it.
|
||||
@@ -365,7 +363,7 @@ are explicitly switched on will be shown.
|
||||
**pv** creates a temporary file for this purpose, and automatically
|
||||
removes it afterwards.
|
||||
|
||||
: This can be useful if you have a pipeline which generates data (your
|
||||
This can be useful if you have a pipeline which generates data (your
|
||||
input) quickly but you don\'t know the size, and you wish to pass it
|
||||
to some slower process, once all of the input has been generated and
|
||||
you know its size, so you can see its progress. Note that when doing
|
||||
@@ -373,17 +371,31 @@ are explicitly switched on will be shown.
|
||||
be preferable so that pipe buffering doesn\'t affect the progress
|
||||
display.
|
||||
|
||||
**-d PID\[:FD\], \--watchfd PID\[:FD\]**
|
||||
## Alternative operating modes
|
||||
|
||||
**-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**
|
||||
|
||||
@@ -398,7 +410,7 @@ are explicitly switched on will be shown.
|
||||
"**\--delay-start**", "**\--skip-errors**", and
|
||||
"**\--stop-at-size**".
|
||||
|
||||
## General options
|
||||
## Other options
|
||||
|
||||
**-P FILE, \--pidfile FILE**
|
||||
|
||||
@@ -438,6 +450,38 @@ contain the following sequences:
|
||||
: The percentage completion (or maximum rate, with "**\--gauge**" when
|
||||
the size is unknown).
|
||||
|
||||
**%{bar-plain}**
|
||||
|
||||
: Progress bar in the standard plain format, without any sides, and
|
||||
without any percentage displayed afterwards. Expands to fill the
|
||||
remaining space unless prefixed by a number.
|
||||
|
||||
**%{bar-block}**
|
||||
|
||||
: Progress bar using Unicode full blocks, without any sides, and
|
||||
without any percentage displayed afterwards. Expands to fill the
|
||||
remaining space unless prefixed by a number. If UTF-8 output is not
|
||||
available, the plain format is used.
|
||||
|
||||
**%{bar-granular}**
|
||||
|
||||
: Progress bar using Unicode full blocks, and 1/8th blocks for partial
|
||||
fills, providing a more granular display. Like the other "%{bar}"
|
||||
strings this shows the bar without any sides, and without any
|
||||
percentage displayed afterwards, and expands to fill the remaining
|
||||
space unless prefixed by a number. If UTF-8 output is not available,
|
||||
the plain format is used.
|
||||
|
||||
**%{bar-shaded}**
|
||||
|
||||
: Progress bar using Unicode full blocks and shade characters - dark
|
||||
and medium shade are used for partial fills, and the light shade is
|
||||
used for the background. Like the other "%{bar}" strings this shows
|
||||
the bar without any sides, and without any percentage displayed
|
||||
afterwards, and expands to fill the remaining space unless prefixed
|
||||
by a number. If UTF-8 output is not available, the plain format is
|
||||
used.
|
||||
|
||||
**%t**, **%{timer}**
|
||||
|
||||
: Elapsed time. Equivalent to "**\--timer**".
|
||||
@@ -491,6 +535,31 @@ contain the following sequences:
|
||||
: Show the name prefix given by "**\--name**". Padded to 9 characters
|
||||
with spaces, and suffixed with ":".
|
||||
|
||||
**%{sgr:colour,\...}**
|
||||
|
||||
: Emit ECMA-48 SGR (Select Graphic Rendition) codes if the terminal
|
||||
supports colours, where *colour,\...* is a comma-separated list of
|
||||
any of the keywords below, or the numeric values from
|
||||
**console_codes**(4). If colour support is not available, nothing is
|
||||
emitted.
|
||||
|
||||
Supported keywords are: **reset** or **none**, **black**, **red**,
|
||||
**green**, **brown** or **yellow**, **blue**, **magenta**, **cyan**,
|
||||
**white**, **fg-black**, **fg-red**, **fg-green**, **fg-brown** or
|
||||
**fg-yellow**, **fg-blue**, **fg-magenta**, **fg-cyan**,
|
||||
**fg-white**, **fg-default**, **bg-black**, **bg-red**,
|
||||
**bg-green**, **bg-brown** or **bg-yellow**, **bg-blue**,
|
||||
**bg-magenta**, **bg-cyan**, **bg-white**, **bg-default**, **bold**,
|
||||
**dim**, **italic**, **underscore** or **underline**, **blink**,
|
||||
**reverse**, **no-bold** or **no-dim**, **no-italic**,
|
||||
**no-underscore** or **no-underline**, **no-blink**, **no-reverse**.
|
||||
|
||||
With colours, the optional \"fg-\" prefix indicates foreground; a
|
||||
prefix of \"bg-\" indicates background.
|
||||
|
||||
For example, "**%{sgr:green,bold}TEXT%{sgr:reset}**" will make
|
||||
*TEXT* bold green on supported terminals.
|
||||
|
||||
**%%**
|
||||
|
||||
: A single "%".
|
||||
@@ -532,7 +601,7 @@ Some suggested common switch combinations:
|
||||
: The default behaviour: progress bar, elapsed time, estimated
|
||||
completion time, current rate, and byte counter.
|
||||
|
||||
On MacOS, it may be useful to specify "**\--buffer-size 1024**" in a
|
||||
On macOS, it may be useful to specify "**\--buffer-size 1024**" in a
|
||||
pipeline, as this may improve performance.
|
||||
|
||||
To watch how quickly a file is transferred using **nc**(1):
|
||||
@@ -542,15 +611,14 @@ To watch how quickly a file is transferred using **nc**(1):
|
||||
A similar example, transferring a file from another process and passing
|
||||
the expected size to **pv**:
|
||||
|
||||
cat file | pv -s 12345 | nc -w 1 somewhere.com 3000
|
||||
cat file | pv --size 12345 | nc -w 1 somewhere.com 3000
|
||||
|
||||
A more complicated example using numeric output to feed into the
|
||||
**dialog**(1) program for a full-screen progress display:
|
||||
To watch the progress of creating a tar.gz archive:
|
||||
|
||||
(tar cf - . \
|
||||
| pv -n -s $(du -sb . | awk '{print $1}') \
|
||||
| gzip -9 > out.tgz) 2>&1 \
|
||||
| dialog --gauge 'Progress' 7 70
|
||||
tar cf - directory/ \
|
||||
| pv --size $(du -sb directory/ | awk '{print $1}') \
|
||||
| gzip -9 \
|
||||
> out.tar.gz
|
||||
|
||||
Taking an image of a disk, skipping errors:
|
||||
|
||||
@@ -569,18 +637,29 @@ block device, then the size of the block device will be used and **pv**
|
||||
will automatically stop at that size as if "**\--stop-at-size**" had
|
||||
been given.
|
||||
|
||||
(Linux only): Watching file descriptor 3 opened by another process 1234:
|
||||
(Linux and macOS only): Watching file descriptor 3 opened by another
|
||||
process 1234:
|
||||
|
||||
pv -d 1234:3
|
||||
pv --watchfd 1234:3
|
||||
|
||||
(Linux only): Watching all file descriptors used by process 1234:
|
||||
(Linux and macOS only): Watching all file descriptors used by process
|
||||
1234:
|
||||
|
||||
pv -d 1234
|
||||
pv --watchfd 1234
|
||||
|
||||
Rate-limiting the transfer between two processes in a pipeline, with no
|
||||
display:
|
||||
|
||||
producer | pv --quiet --rate-limit 1M | consumer
|
||||
|
||||
Sending logs to a processing script, showing the most recent line as
|
||||
part of the progress display:
|
||||
|
||||
pv -F '%a %p : %L' big.log | processing-script
|
||||
pv --format '%a %p : %L' big.log | processing-script
|
||||
|
||||
Showing progress as lines of JSON data:
|
||||
|
||||
pv --numeric --format '{"elapsed":%t,"bytes":%b,"rate":%r,"percentage":%{progress-amount-only}}' big.log | processing-script
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
@@ -589,28 +668,28 @@ An exit status of 1 indicates a problem with the "**\--remote**" or
|
||||
|
||||
Any other exit status is a bitmask of the following:
|
||||
|
||||
**2**
|
||||
**2**
|
||||
|
||||
: One or more files could not be accessed, **stat**(2)ed, or opened.
|
||||
|
||||
**4**
|
||||
**4**
|
||||
|
||||
: An input file was the same as the output file.
|
||||
|
||||
**8**
|
||||
**8**
|
||||
|
||||
: Internal error with closing a file or moving to the next file.
|
||||
|
||||
**16**
|
||||
**16**
|
||||
|
||||
: There was an error while transferring data from one or more input
|
||||
files.
|
||||
|
||||
**32**
|
||||
**32**
|
||||
|
||||
: A signal was caught that caused an early exit.
|
||||
|
||||
**64**
|
||||
**64**
|
||||
|
||||
: Memory allocation failed.
|
||||
|
||||
@@ -654,7 +733,7 @@ brackets to force the use of a subshell:
|
||||
|
||||
pv InputFile | ( while read -r line; do sleep 0.1; done; )
|
||||
|
||||
Refer to [issue #105](https://codeberg.org/a-j-wood/pv/issues/105) for
|
||||
Refer to [issue #105](https://codeberg.org/ivarch/pv/issues/105) for
|
||||
full details.
|
||||
|
||||
The "**\--remote**" option requires that either */run/user/\<uid\>/* or
|
||||
@@ -673,21 +752,37 @@ The "**%nA**" and "**%nL**" format sequences may not be effective with
|
||||
small input files, and "**%nL**" may be a few lines out due to buffering
|
||||
within the pipeline itself.
|
||||
|
||||
Numbers passed to "**\--size**", "**\--rate-limit**",
|
||||
"**\--buffer-size**", and "**\--error-skip-block**" may all be expressed
|
||||
as decimals if followed by a suffix, so for example "*\--size 1.5G*" is
|
||||
equivalent to "*\--size 1536M*".
|
||||
|
||||
Numbers passed to "**\--interval**" and "**\--delay-start**" may be
|
||||
integers or decimals, but may not have a suffix.
|
||||
|
||||
Numbers passed to "**\--last-written**", "**\--width**",
|
||||
"**\--height**", "**\--average-rate-window**", and "**\--remote**" must
|
||||
be integers with no suffix.
|
||||
|
||||
When "**\--sparse**" is in effect and output is being written to a file,
|
||||
that file may look like it has stopped growing if inspected with
|
||||
**ls**(1) while null bytes are being written, even though **pv** still
|
||||
reports progress. This is because of the way sparse output is achieved,
|
||||
and the file will be the correct size when the transfer ends.
|
||||
|
||||
# REPORTING BUGS
|
||||
|
||||
Please report any bugs to **pv@ivarch.com**.
|
||||
|
||||
Alternatively, use the issue tracker linked from the [**pv** home
|
||||
page](https://www.ivarch.com/programs/pv.shtml).
|
||||
Please report bugs or feature requests via the issue tracker linked from
|
||||
the [**pv** home page](https://ivarch.com/p/pv).
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**cat**(1), **dialog**(1), **splice**(2), **fdatasync**(2), **open**(2)
|
||||
(for **O_DIRECT**)
|
||||
**cat**(1), **splice**(2), **fdatasync**(2), **open**(2) (for
|
||||
**O_DIRECT**), **console_codes**(4)
|
||||
|
||||
# COPYRIGHT
|
||||
|
||||
Copyright © 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew
|
||||
Copyright © 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew
|
||||
Wood.
|
||||
|
||||
License GPLv3+: [GNU GPL version 3 or
|
||||
|
||||
+130
-54
@@ -4,13 +4,30 @@
|
||||
# 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'.
|
||||
|
||||
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"
|
||||
|
||||
status () {
|
||||
test -n "$*" && printf "\n"
|
||||
printf '\e]0;%s\007\r' "$*" >&2
|
||||
if test -n "$*"; then
|
||||
tput rev >&2
|
||||
printf " -- %s -- " "$*" >&2
|
||||
tput sgr0 >&2
|
||||
printf "\n\n"
|
||||
fi
|
||||
}
|
||||
|
||||
possiblyDie () {
|
||||
printf "\n" >&2
|
||||
@@ -19,116 +36,175 @@ possiblyDie () {
|
||||
tput sgr0 >&2
|
||||
printf "\n%s\n" "Type 'y' and hit Enter to continue anyway."
|
||||
read -r line
|
||||
test "${line}" = "y" || exit 1
|
||||
test "${line}" = "y" || { status ""; exit 1; }
|
||||
}
|
||||
|
||||
test -e "${labTestScript}" || labTestScript=""
|
||||
|
||||
# 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.
|
||||
|
||||
status "Initial checks"
|
||||
|
||||
# Check MAINTAINER is provided.
|
||||
test -n "${MAINTAINER}" || possiblyDie "environment variable MAINTAINER is empty"
|
||||
|
||||
# * Check that `po/POTFILES.in` is up to date
|
||||
inFile="$(sort < "${srcdir}/po/POTFILES.in")"
|
||||
realList="$(find "${srcdir}" -name "*.c" -printf "%P\n" | sort)"
|
||||
test "${inFile}" = "${realList}" || possiblyDie "po/POTFILES.in is incorrect"
|
||||
# * Check that _po/POTFILES.in_ is up to date
|
||||
if test -d "${srcdir}/po"; then
|
||||
inFile="$(sort < "${srcdir}/po/POTFILES.in")"
|
||||
realList="$(find "${srcdir}" -name "*.c" -printf "%P\n" | sort)"
|
||||
test "${inFile}" = "${realList}" || possiblyDie "po/POTFILES.in is incorrect"
|
||||
fi
|
||||
|
||||
# * Run "`make analyse`" and see whether remaining warnings can be addressed
|
||||
status "Initial build"
|
||||
make || possiblyDie "failed 'make'"
|
||||
|
||||
# * Run "_make analyse_" and see whether remaining warnings can be addressed
|
||||
status "Source analysis"
|
||||
make analyse || possiblyDie "failed 'make analyse'"
|
||||
|
||||
# * Version bump and documentation checks:
|
||||
# * Check that `docs/NEWS.md` is up to date
|
||||
|
||||
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"
|
||||
|
||||
# * Check the version in `configure.ac` and `docs/NEWS.md` were updated
|
||||
# * Check the version in both _configure.ac_ and _docs/NEWS.md_ was updated
|
||||
versionInConfig="$(grep ^AC_INIT "${srcdir}/configure.ac" | cut -d '[' -f 3 | cut -d ']' -f 1)"
|
||||
test "${versionInConfig}" = "${versionInNews}" || possiblyDie "version in configure.ac (${versionInConfig}) mismatches NEWS.md (${versionInNews})"
|
||||
|
||||
# * Check that the manual `docs/pv.1` is up to date
|
||||
versionInManual="$(awk 'FNR==1 {print $5}' "${srcdir}/docs/pv.1" | cut -d - -f 2)"
|
||||
test "${versionInManual}" = "${versionInNews}" || possiblyDie "version in pv.1 (${versionInManual}) mismatches NEWS.md (${versionInNews})"
|
||||
# * Check that the manuals are up to date
|
||||
for manPage in ${manuals}; do
|
||||
versionInManual="$(awk 'FNR==1 {print $5}' "${srcdir}/docs/${manPage}" | cut -d - -f 2)"
|
||||
test "${versionInManual}" = "${versionInNews}" || possiblyDie "version in ${manPage} (${versionInManual}) mismatches NEWS.md (${versionInNews})"
|
||||
done
|
||||
|
||||
# * Check that the year displayed by src/main/version.c is correct
|
||||
yearInSource="$(grep -F 'printf("Copyright' "${srcdir}/src/main/version.c" | cut -d '"' -f 4)"
|
||||
# * Check that the program version is correct
|
||||
versionInVersionOutput="$(./"${mainProgram}" --version | awk 'FNR==1{print $NF}')"
|
||||
test "${versionInVersionOutput}" = "${versionInNews}" || possiblyDie "version in '${mainProgram} --version' (${versionInVersionOutput}) mismatches NEWS.md (${versionInNews})"
|
||||
|
||||
# * Check that the year displayed by --version is correct
|
||||
yearInVersion="$(./"${mainProgram}" --version | awk '/^Copyright/{print $2}')"
|
||||
yearNow="$(date '+%Y')"
|
||||
test "${yearInSource}" = "${yearNow}" || possiblyDie "the year in src/main/version.c (${yearInSource}) is not this year (${yearNow})"
|
||||
test "${yearInVersion}" = "${yearNow}" || possiblyDie "the year in '--version' (${yearInVersion}) is not this year (${yearNow})"
|
||||
|
||||
# * Run "`make docs/pv.1.md`" and, if using VPATH, copy the result to the source directory
|
||||
# * Make the Markdown version of the manuals and, if using VPATH, copy the result to the source directory
|
||||
# We also wipe everything in "docs" so we don't accidentally package
|
||||
# leftover working files.
|
||||
rm -f docs/*
|
||||
make docs/pv.1.md
|
||||
cp docs/pv.1.md "${srcdir}/docs/pv.1.md"
|
||||
|
||||
# * Run "`make indent; make indent indentclean check`"
|
||||
status "Markdown manual"
|
||||
|
||||
rm -f docs/*
|
||||
for manPage in ${manuals}; do
|
||||
make "docs/${manPage}.md"
|
||||
cp "docs/${manPage}.md" "${srcdir}/docs/${manPage}.md"
|
||||
done
|
||||
|
||||
# * Run "_make indent; make indent indentclean check_"
|
||||
status "Reformat source"
|
||||
make indent
|
||||
make indent indentclean
|
||||
# The check will run later as part of "make distcheck".
|
||||
|
||||
# * Run "`make -C po update-po`"
|
||||
make -C po update-po || possiblyDie "update-po failed"
|
||||
# * Run "_make -C po update-po_"
|
||||
status "Update po files"
|
||||
if test -d "${srcdir}/po"; then
|
||||
make -C po update-po || possiblyDie "update-po failed"
|
||||
fi
|
||||
|
||||
# * Run "`autoreconf`" in the source directory
|
||||
# * Run "_autoreconf_" in the source directory
|
||||
status "Run autoreconf"
|
||||
(cd "${srcdir}" && autoreconf -is) || possiblyDie "autoreconf failed"
|
||||
|
||||
# * Ensure everything has been committed to the repository
|
||||
status "Commit check"
|
||||
gitStatus="$(cd "${srcdir}" && git status --porcelain=v1)" || possiblyDie "failed to run 'git status'"
|
||||
test -z "${gitStatus}" || possiblyDie "not everything is committed - 'git status' is not empty"
|
||||
|
||||
# * Consistency and build checks:
|
||||
# * Wipe the build directory, and run "`configure`" there
|
||||
# * Run "`make distcheck`"
|
||||
# * Run "`make release MAINTAINER=<signing-user>`"
|
||||
# * Wipe the build directory, and run "_configure_" there
|
||||
# * Run "_make distcheck_"
|
||||
# * Run "_make release MAINTAINER=<signing-user>_"
|
||||
# NB "make release" implies "make distcheck".
|
||||
# We set SKIP_VALGRIND_TESTS=1 because the full tests will run in the lab
|
||||
# check.
|
||||
status "Release archive"
|
||||
workDir="$(mktemp -d)" || possiblyDie "mktemp failed"
|
||||
trap 'chmod -R u+w "${workDir}"; rm -rf "${workDir}"' EXIT
|
||||
(
|
||||
cd "${workDir}" || exit 1
|
||||
sh "${srcdir}/configure" || exit 1
|
||||
export SKIP_VALGRIND_TESTS=1
|
||||
make -j8 release || exit 1
|
||||
make -j8 release SKIP_VALGRIND_TESTS=1 || exit 1
|
||||
exit 0
|
||||
) || possiblyDie "failed on 'make release'"
|
||||
|
||||
sourceArchive="$(find "${workDir}" -mindepth 1 -maxdepth 1 -type f -name "*.tar.gz")"
|
||||
test -e "${sourceArchive}.asc" || possiblyDie "release was not signed"
|
||||
|
||||
# * Run "`./configure && make check`" on all test systems including Cygwin, using the `tar.gz` that was just created
|
||||
# * Run "_./configure && make check_" on all test systems, using the _tar.gz_ that was just created
|
||||
# * Run a cross-compilation check
|
||||
sh "${srcdir}/docs/test-on-vm-lab.sh" "${sourceArchive}" || possiblyDie "lab test failed"
|
||||
if test -n "${labTestScript}"; then
|
||||
status "Lab test"
|
||||
sh "${labTestScript}" "${sourceArchive}" || possiblyDie "lab test failed"
|
||||
fi
|
||||
|
||||
# * Update the project web site:
|
||||
# * 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
|
||||
rm -rf "RELEASE-${versionInNews}"
|
||||
mkdir "RELEASE-${versionInNews}"
|
||||
cp "${sourceArchive}" "${sourceArchive}.asc" "${sourceArchive}.txt" "RELEASE-${versionInNews}/" || possiblyDie "failed to copy release files"
|
||||
# * 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"
|
||||
releaseDir="PV-RELEASE-${versionInNews}"
|
||||
rm -rf "${releaseDir}"
|
||||
mkdir "${releaseDir}"
|
||||
cp "${sourceArchive}" "${sourceArchive}.asc" "${sourceArchive}.txt" "${releaseDir}/" || possiblyDie "failed to copy release files"
|
||||
|
||||
pandoc --from markdown --to html --shift-heading-level-by=1 < "${srcdir}/docs/pv.1.md" > "RELEASE-${versionInNews}/manual.html"
|
||||
pandoc --from markdown --to html < "${srcdir}/docs/NEWS.md" > "RELEASE-${versionInNews}/news.html"
|
||||
status "HTML docs"
|
||||
for manPage in ${manuals}; do
|
||||
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" > "${releaseDir}/news.html"
|
||||
|
||||
# Build OS packages.
|
||||
packagingHosts="$(cat ~/.config/packaging-hosts 2>/dev/null)"
|
||||
for buildHost in ${packagingHosts}; do
|
||||
remoteWorkDir="$(ssh "${buildHost}" "mktemp -d")" || continue
|
||||
test -n "${remoteWorkDir}" || continue
|
||||
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 "${srcdir}/docs/build-package.sh" "${buildHost}:${remoteWorkDir}/" || buildOK=false
|
||||
${buildOK} && scp "${sourceArchive}" "${buildHost}:${remoteWorkDir}/" || buildOK=false
|
||||
${buildOK} && ssh -t "${buildHost}" "cd \"${remoteWorkDir}\" && SKIP_VALGRIND_TESTS=\"${SKIP_VALGRIND_TESTS}\" MAINTAINER=\"${MAINTAINER}\" sh ./build-package.sh ./*gz" || buildOK=false
|
||||
${buildOK} && ssh "${buildHost}" "rm \"${remoteWorkDir}\"/${sourceArchive##*/} \"${remoteWorkDir}/build-package.sh\""
|
||||
${buildOK} && mkdir -p "RELEASE-${versionInNews}/${buildHost}"
|
||||
${buildOK} && scp "${buildHost}:${remoteWorkDir}/*" "RELEASE-${versionInNews}/${buildHost}/"
|
||||
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
|
||||
|
||||
@@ -21,7 +21,12 @@
|
||||
# (without timestamps), "framework-output.log" (messages from this script),
|
||||
# and the "config.log", "test-suite.log", and "tests/" from the build area.
|
||||
#
|
||||
# Requires "scw" (https://www.ivarch.com/programs/scw.shtml).
|
||||
# Requires "scw" (https://ivarch.com/p/scw).
|
||||
#
|
||||
# Copyright 2024-2025 Andrew Wood
|
||||
# License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
#
|
||||
# Version: 0.0.1 / 16 Dec 2024
|
||||
|
||||
# Number of tests to run in parallel on each host.
|
||||
concurrency="1"
|
||||
@@ -135,7 +140,7 @@ if test "$1" = "--testRunner"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
labHosts="$(cat ~/.config/lab-hosts 2>/dev/null)"
|
||||
labHosts="$(grep -v '^#' ~/.config/lab-hosts 2>/dev/null)"
|
||||
|
||||
workDir=$(mktemp -d) || exit 1
|
||||
trap 'rm -rf "${workDir}"' EXIT
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
cs
|
||||
de
|
||||
es
|
||||
fi
|
||||
fr
|
||||
pl
|
||||
pt
|
||||
|
||||
@@ -9,6 +9,19 @@ src/pv/cursor.c
|
||||
src/pv/display.c
|
||||
src/pv/elapsedtime.c
|
||||
src/pv/file.c
|
||||
src/pv/format/averagerate.c
|
||||
src/pv/format/barstyle.c
|
||||
src/pv/format/bufferpercent.c
|
||||
src/pv/format/bytes.c
|
||||
src/pv/format/eta.c
|
||||
src/pv/format/fineta.c
|
||||
src/pv/format/lastwritten.c
|
||||
src/pv/format/name.c
|
||||
src/pv/format/previousline.c
|
||||
src/pv/format/progressbar.c
|
||||
src/pv/format/rate.c
|
||||
src/pv/format/sgr.c
|
||||
src/pv/format/timer.c
|
||||
src/pv/loop.c
|
||||
src/pv/number.c
|
||||
src/pv/proctitle.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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"
|
||||
@@ -141,201 +141,229 @@ msgid "prefix visual information with NAME"
|
||||
msgstr "přidej JMÉNO před vizuální informace"
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgid "STYLE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
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 "po dokončení vypiš údaje o přenosu"
|
||||
|
||||
#: src/main/help.c:318
|
||||
#: src/main/help.c:321
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr "vypisuj výstup i pokud standardní chybový výstup není terminál"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "pozicuj kurzor pomocí řídících znaků"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr "SOUBOR"
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr "zapiš výstup do SOUBORu namísto standardního výstupu"
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr "RYCH"
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "omez přenosovou rychlost na RYCH bajtů za sekundu"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr "BAJT"
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "použij vyrovnávací pamět BAJT bajtů"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "nepoužívej splice(), vždy použij read/write"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "ignoruj chyby při čtení vstupu"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr "přeskakuj chyby v blocích BAJTů naráz"
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "zastav po přenosu --size bajtů"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr "po každém zápisu vyprázdni cache na disk"
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr "použij přímý V/V k obejítí cache"
|
||||
|
||||
#: src/main/help.c:352
|
||||
#: src/main/help.c:355
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr "zahoď vstup namísto zápisu na výstup"
|
||||
|
||||
#: src/main/help.c:355
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr "zapiš veškerý vstup do SOUBORu před výpisem na výstup"
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgstr "PID[:DS]"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "sleduj soubor DS otevřený procesem PID"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "aktualizuj nastavení procesu PID"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "ulož id procesu do SOUBORu"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "ukaž pomoc a skonči"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "ukaž informace o verzi a skonči"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr "zapiš ladící záznamy do SOUBORu"
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Použití: %s [VOLBY] [SOUBOR]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
"Spoj SOUBOR(y) nebo standardní vstup na standardního výstup, s monitoringem."
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "Prosím, hlašte veškeré chyby na: %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr "(vstup)"
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr "selhala alokace stavu"
|
||||
|
||||
#: src/main/options.c:144 src/pv/file.c:324
|
||||
msgid "failed to stat file"
|
||||
msgstr "nebylo možné zjistit informace o souboru"
|
||||
#: src/main/options.c:370
|
||||
msgid "list files may not contain @ lines"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:158
|
||||
msgid "is a directory"
|
||||
msgstr "je adresář"
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr "selhalo vytváření jména pro soubor v sysfs"
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr "selhalo čtení velikosti souboru v sysfs"
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr "selhalo otevření blokového zařízení"
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr "selhalo zjištění velikosti blokového zařízení"
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "selhala alokace struktury pro volby"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "selhala alokace struktury pro argv"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "očekáván celočíselný argument"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "očekáván číselný argument"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "očekáváno ID procesu nebo dvojice PID:DS"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "neplatné ID procesu"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "selhala alokace struktury pro volby"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "selhala alokace struktury pro argv"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "očekáván celočíselný argument"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "očekáván číselný argument"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Zkuste `%s --help' pro více informací."
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Zkuste `%s --h' pro více informací."
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
@@ -343,19 +371,19 @@ msgstr ""
|
||||
"při sledování deskriptorů souborů nelze použít řádkový mód nebo volby pro "
|
||||
"modifikaci přenosu"
|
||||
|
||||
#: src/main/options.c:721
|
||||
#: src/main/options.c:1090
|
||||
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:730
|
||||
#: src/main/options.c:1099
|
||||
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:739
|
||||
#: src/main/options.c:1108
|
||||
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:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "není dostupné na systémech bez /proc/self/fdinfo"
|
||||
|
||||
@@ -363,7 +391,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"
|
||||
|
||||
@@ -399,149 +427,162 @@ msgstr "selhal pokus o uzamčení"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "selhalo otevření terminálu"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr "yzafpnum kMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr "yzafpnum KMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr "b/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#: 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:96
|
||||
#: src/pv/format/rate.c:40
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: 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:35
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/format/fineta.c:80
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/loop.c:564
|
||||
msgid "rate min/avg/max/mdev"
|
||||
msgstr "rychlost min/avg/max/std"
|
||||
|
||||
#: src/pv/loop.c:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr "rychlost neměřena"
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:572 src/pv/state.c:583
|
||||
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:917
|
||||
msgid "write failed"
|
||||
msgstr "zápis selhal"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr "selhala alokace seznamu souborů"
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
msgid "file descriptor list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: 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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr "vyrovnávací paměť není alokována"
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr "selhalo nastavení intervalového časovače"
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr "selhalo vynulování intervalového časovače"
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr "selhala alokace vyrovnávací paměti pro pozici v řádcích"
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "zápis selhal"
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
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í"
|
||||
|
||||
#~ msgid "PID[:FD]"
|
||||
#~ msgstr "PID[:DS]"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"PO-Revision-Date: 2024-10-13 20:43+0000\n"
|
||||
"Last-Translator: fnetX <otto@codeberg.org>\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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"
|
||||
"Language: de\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.9.2\n"
|
||||
"Date: 1999-06-01 15:18:29+0100\n"
|
||||
"From: Andrew Wood <ivarch@ubik>\n"
|
||||
"Xgettext-Options: --default-domain=pkgbuild --directory=./.pkgdir --add-"
|
||||
@@ -157,203 +157,231 @@ msgid "prefix visual information with NAME"
|
||||
msgstr "setze den NAMEn für visuelle Darstellung"
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgstr ""
|
||||
msgid "STYLE"
|
||||
msgstr "Stil"
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr ""
|
||||
msgid "set default bar style to NAME"
|
||||
msgstr "setze die voreingestellte Darstellung auf NAME"
|
||||
|
||||
#: src/main/help.c:314
|
||||
msgid "SPEC"
|
||||
msgstr "STIL"
|
||||
|
||||
#: src/main/help.c:315
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr "Fortschritt auch an SPEC senden"
|
||||
|
||||
#: src/main/help.c:318
|
||||
msgid "output transfer statistics at the end"
|
||||
msgstr "Übertragungsstatistiken am Ende ausgeben"
|
||||
|
||||
#: src/main/help.c:318
|
||||
#: src/main/help.c:321
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr ""
|
||||
"Ausgabe auch dann erzwingen, wenn der Fehlerausgabe-Kanal kein Terminal ist"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "benutze Escape-Sequenzen zur Cursor-Positionierung"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr "DATEI"
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr "schreibe die Ausgabe in DATEI statt in die Standardausgabe"
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr "RATE"
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "beschränke die Transferrate auf RATE Byte pro Sekunde"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr "BYTES"
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "benutze einen Puffer in der Größe von BYTES"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "anstelle von splice() immer read/write benutzen"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "Lesefehler in der Eingabe nicht beachten"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr "bei Fehlern BYTES am Stück überspringen"
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "anhalten, nachdem --size Bytes übertragen wurden"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr "schreibe den Cache nach jedem Schreibvorgang auf die Festplatte"
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr "verwende direkte E/A, um den Cache zu umgehen"
|
||||
|
||||
#: src/main/help.c:352
|
||||
#: src/main/help.c:355
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr "verwirf die Eingabe anstatt in die Ausgabe zu schreiben"
|
||||
|
||||
#: src/main/help.c:355
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr "Ausgabe nach FILE schrieben bevor sie ausgegeben wird"
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgstr "PID[:FD]"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "die vom Prozess PID geöffnete Datei FD beobachten"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "Einstellungen der Prozess-PID updaten"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "Prozess-ID in DATEI speichern"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "zeige diese Hilfe und beende"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "zeige Versionsinformationen und beende"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr "schreibe Debug-Protokolle in DATEI"
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Aufruf: %s [OPTION] [DATEI]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
"Verbindet DATEI(en) oder den Standard-Eingabe-Kanal mit dem Standard-Ausgabe-"
|
||||
"Kanal und misst den Datenstrom."
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
msgstr "unterstützte Formate:"
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "Bitte senden Sie Fehlerberichte an %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr "(eingabe)"
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr "Speicherzuweisung für `state' fehlgeschlagen"
|
||||
|
||||
#: src/main/options.c:144 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:158
|
||||
msgid "is a directory"
|
||||
msgstr "ist ein Verzeichnis"
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr "konnte Sysfs-Dateinamen nicht erzeugen"
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr "konnte Größe der Sysfs-Datei nicht lesen"
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr "konnte Blockgerät nicht öffnen"
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr "konnte Größe des Blockgeräts nicht ermitteln"
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "Speicherzuweisung für `option' fehlgeschlagen"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "Speicherzuweisung für `argv' der Option fehlgeschlagen"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "Ganzzahliges Argument erwartet"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "numerisches Argument erwartet"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "Prozess-ID oder PID:FD-Paar erwartet"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "ungültige Prozess-ID"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "Speicherzuweisung für `option' fehlgeschlagen"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "Speicherzuweisung für `argv' der Option fehlgeschlagen"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr "numerischen Wert nicht verstanden"
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "Ganzzahliges Argument erwartet"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "numerisches Argument erwartet"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "`%s --help' zeigt weitere Informationen an."
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "`%s -h' zeigt weitere Informationen an."
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
@@ -361,24 +389,24 @@ msgstr ""
|
||||
"Beim Beobachten von Dateideskriptoren können keine Optionen für den "
|
||||
"Zeilenmodus oder den Übertragungsmodifikator verwendet werden"
|
||||
|
||||
#: src/main/options.c:721
|
||||
#: src/main/options.c:1090
|
||||
msgid "cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
"Beim Beobachten von Dateideskriptoren kann Cursor-Positionierung nicht "
|
||||
"verwendet werden"
|
||||
|
||||
#: src/main/options.c:730
|
||||
#: src/main/options.c:1099
|
||||
msgid "cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
"Beim Beobachten von Dateideskriptoren kann die Fernbedienung nicht verwenden "
|
||||
"werden"
|
||||
|
||||
#: src/main/options.c:739
|
||||
#: src/main/options.c:1108
|
||||
msgid "cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
"Beim Beobachten von Dateideskriptoren können Dateien nicht übertragen werden"
|
||||
|
||||
#: src/main/options.c:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "Nicht verfügbar auf Systemen ohne /proc/self/fdinfo"
|
||||
|
||||
@@ -386,7 +414,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"
|
||||
|
||||
@@ -422,150 +450,162 @@ msgstr "Sperrversuch fehlgeschlagen"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "konnte Terminal nicht öffnen"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr "yzafpnµm kMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr "yzafpnµm KMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr "b/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr "Endzeit"
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#, fuzzy
|
||||
msgid "rate min/avg/max/mdev"
|
||||
msgstr "Rate min/mittel/max/mdev"
|
||||
#: 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/loop.c:560
|
||||
#: 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:96
|
||||
#: src/pv/format/rate.c:40 src/pv/loop.c:565
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/format/bytes.c:35
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/format/fineta.c:80
|
||||
msgid "FIN"
|
||||
msgstr "Endzeit"
|
||||
|
||||
#: src/pv/loop.c:564
|
||||
msgid "rate min/avg/max/mdev"
|
||||
msgstr "Rate min/mittel/max/abweichung"
|
||||
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr "Übertragungsrate nicht gemessen"
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:572 src/pv/state.c:583
|
||||
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:917
|
||||
msgid "write failed"
|
||||
msgstr "write-Aufruf fehlgeschlagen"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr "Speicherzuweisung für die Dateiliste fehlgeschlagen"
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
msgid "file descriptor list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: 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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr "Speicherzuweisung für den Transferpuffer fehlgeschlagen"
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr "konnte Intervall-Timer nicht setzen"
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr "konnte Intervall-Timer nicht löschen"
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr "Zuweisung des Zeilenpuffers fehlgeschlagen"
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "write-Aufruf fehlgeschlagen"
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
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"
|
||||
|
||||
#~ msgid "PID[:FD]"
|
||||
#~ msgstr "PID[:FD]"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+0100\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -136,218 +136,246 @@ msgid "prefix visual information with NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgid "STYLE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
msgid "set default bar style to NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:314
|
||||
msgid "SPEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:315
|
||||
msgid "output transfer statistics at the end"
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:318
|
||||
msgid "output even if standard error is not a terminal"
|
||||
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:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:352
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:355
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:361
|
||||
msgid "PID"
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:362
|
||||
msgid "update settings of process PID"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:367
|
||||
msgid "save process ID in FILE"
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:370
|
||||
msgid "show this help and exit"
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:144 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:158
|
||||
msgid "is a directory"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:721
|
||||
#: src/main/options.c:1090
|
||||
msgid "cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:730
|
||||
#: src/main/options.c:1099
|
||||
msgid "cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:739
|
||||
#: src/main/options.c:1108
|
||||
msgid "cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr ""
|
||||
|
||||
@@ -355,7 +383,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 ""
|
||||
|
||||
@@ -391,149 +419,159 @@ msgstr ""
|
||||
msgid "failed to open terminal"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#: 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:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:572 src/pv/state.c:583
|
||||
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:917
|
||||
msgid "write failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
msgid "select call failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
#, 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-18 19:34+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:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
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 "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:572
|
||||
#, 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:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1090
|
||||
msgid "cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1099
|
||||
msgid "cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1108
|
||||
msgid "cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1133
|
||||
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:754 src/pv/transfer.c:1135
|
||||
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:775 src/pv/loop.c:791 src/pv/loop.c:809 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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
msgid "select call failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
@@ -1,15 +1,15 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"PO-Revision-Date: 2024-10-12 11:13+0000\n"
|
||||
"Last-Translator: a-j-wood <a-j-wood@users.noreply.translate.codeberg.org>\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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"
|
||||
"Language: fr\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.11.4\n"
|
||||
"Date: 1999-06-01 15:18:29+0100\n"
|
||||
"From: Andrew Wood <ivarch@ubik>\n"
|
||||
"Xgettext-Options: --default-domain=pkgbuild --directory=./.pkgdir --add-"
|
||||
@@ -158,203 +158,231 @@ msgid "prefix visual information with NAME"
|
||||
msgstr "préfixer les informations visuelles avec NOM"
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgstr ""
|
||||
msgid "STYLE"
|
||||
msgstr "STYLE"
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr ""
|
||||
msgid "set default bar style to NAME"
|
||||
msgstr "définir le style de barre par défaut à NOM"
|
||||
|
||||
#: src/main/help.c:314
|
||||
msgid "SPEC"
|
||||
msgstr "SPÉCIFICATION"
|
||||
|
||||
#: src/main/help.c:315
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr "aussi envoyer la progression à SPÉCIFICATION"
|
||||
|
||||
#: src/main/help.c:318
|
||||
msgid "output transfer statistics at the end"
|
||||
msgstr "afficher les statistiques de transfert à la fin"
|
||||
|
||||
#: src/main/help.c:318
|
||||
#: src/main/help.c:321
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr ""
|
||||
"imprimer vers la sortie d'erreur standard même si ce n'est pas un terminal"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "utiliser les séquences d'échappements de positionnement de curseur"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr "FICHIER"
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr "écrire la sortie dans FICHIER au lieu de la sortie standard"
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr "TAUX"
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "limite le taux de transfert à TAUX octets par seconde"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr "OCTETS"
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "Utiliser une mémoire tampon de OCTETS octets"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "ne jamais utiliser splice(), toujours utiliser read/write"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "ignorer les erreurs de lecture dans l'entrée"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr "ignorer les erreurs dans OCTETS blocs à la fois"
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "arrêter après le transfert de --size octets"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr "vider le cache sur le disque après chaque écriture"
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr "utiliser les E/S directes pour contourner le cache"
|
||||
|
||||
#: src/main/help.c:352
|
||||
#: src/main/help.c:355
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr "rejeter l'entrée au lieu de l'écrire vers la sortie"
|
||||
|
||||
#: src/main/help.c:355
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr "écrire toute l'entrée vers FICHIER avant de l'écrire vers la sortie"
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgstr "PID[:FD]"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "surveiller le fichier FD ouvert par le processus PID"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "mettre à jour la configuration du processus PID"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "enregistrer l'ID de processus dans FICHIER"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "afficher cette aide puis quitter"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "afficher la version puis quitter"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr "écrire les journaux de déboggage vers FICHIER"
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Utilisation : %s [OPTIONS] [FICHIER]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
"Concaténer FICHIER(s), ou l'entrée standard, sur la sortie standard avec "
|
||||
"monitorage."
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
msgstr "Séquences de formatage supportées :"
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "SVP rapporter tous bogues à %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr "(entrée)"
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr "échec de l'allocation de mémoire de condition"
|
||||
|
||||
#: src/main/options.c:144 src/pv/file.c:324
|
||||
msgid "failed to stat file"
|
||||
msgstr "échec à statuer sur le fichier"
|
||||
|
||||
#: src/main/options.c:158
|
||||
msgid "is a directory"
|
||||
msgstr "est un répertoire"
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
#: src/main/options.c:370
|
||||
msgid "list files may not contain @ lines"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "l'allocation pour la structure d'une option a échoué"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "l'allocation pour la structure de l'option argv a échoué"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "Valeur entière attendue"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "Valeur numérique attendue"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "ID de processus ou paire pid:fd attendue"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "ID de processus non valide"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "l'allocation pour la structure d'une option a échoué"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "l'allocation pour la structure de l'option argv a échoué"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr "valeur numérique non comprise"
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "Valeur entière attendue"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "Valeur numérique attendue"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Essayez `%s --help' pour plus d'informations."
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Essayez `%s -h' pour plus d'informations."
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
@@ -362,25 +390,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:721
|
||||
#: src/main/options.c:1090
|
||||
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:730
|
||||
#: src/main/options.c:1099
|
||||
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:739
|
||||
#: src/main/options.c:1108
|
||||
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:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "non disponible sur les systèmes sans /proc/self/fdinfo"
|
||||
|
||||
@@ -388,7 +416,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"
|
||||
|
||||
@@ -426,152 +454,165 @@ msgstr "échec de la tentative de verrouillage"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "échec de l'ouverture du terminal"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
msgstr "yzafpnum kMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
msgstr "yzafpnum KMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "O/s"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr "O"
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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 ""
|
||||
msgstr "(stdin)"
|
||||
|
||||
#: src/pv/loop.c:548
|
||||
#: 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:96
|
||||
#: src/pv/format/rate.c:40
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: 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:35
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
|
||||
msgid "B"
|
||||
msgstr "O"
|
||||
|
||||
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/format/fineta.c:80
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/loop.c:564
|
||||
msgid "rate min/avg/max/mdev"
|
||||
msgstr ""
|
||||
msgstr "taux min/moy/max/écart-type"
|
||||
|
||||
#: src/pv/loop.c:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr ""
|
||||
msgstr "taux non mesuré"
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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 ""
|
||||
msgstr "pid"
|
||||
|
||||
#: src/pv/state.c:40
|
||||
#: src/pv/loop.c:809 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 "l'allocation de la structure de l'historique a échoué"
|
||||
|
||||
#: src/pv/state.c:572 src/pv/state.c:583
|
||||
#: src/pv/state.c:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr "échec de l'allocation de la liste de fichiers"
|
||||
|
||||
#: src/pv/transfer.c:463
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
msgid "file descriptor list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:490
|
||||
msgid "read failed"
|
||||
msgstr "la lecture a échoué"
|
||||
|
||||
#: src/pv/transfer.c:479
|
||||
#: src/pv/transfer.c:506
|
||||
msgid "warning: read errors detected"
|
||||
msgstr "avertissement : erreurs de lecture détectées"
|
||||
|
||||
#: src/pv/transfer.c:495
|
||||
#: src/pv/transfer.c:522
|
||||
msgid "file is not seekable"
|
||||
msgstr "ne peut pas se déplacer dans le fichier"
|
||||
|
||||
#: src/pv/transfer.c:573
|
||||
#: 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:593
|
||||
#: src/pv/transfer.c:619
|
||||
msgid "skipped past read error"
|
||||
msgstr "erreur de lecture dépassée"
|
||||
|
||||
#: src/pv/transfer.c:634
|
||||
#: src/pv/transfer.c:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr "aucun tampon de transfert alloué"
|
||||
|
||||
#: src/pv/transfer.c:676
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr ""
|
||||
msgstr "La définition de l'intervalle du minuteur a échoué"
|
||||
|
||||
#: src/pv/transfer.c:702
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr ""
|
||||
msgstr "La réinitialisation des intervalles du minuteur a échoué"
|
||||
|
||||
#: src/pv/transfer.c:744
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr ""
|
||||
msgstr "L'allocation de la position de la ligne de la mémoire tampon a échoué"
|
||||
|
||||
#: src/pv/transfer.c:917
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "l'écriture a échoué"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
#: src/pv/transfer.c:1237
|
||||
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
|
||||
msgid "fd"
|
||||
msgstr ""
|
||||
|
||||
#: 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 "pas un fichier ordinaire ou un périphérique de bloc"
|
||||
|
||||
#~ msgid "PID[:FD]"
|
||||
#~ msgstr "PID[:FD]"
|
||||
|
||||
#~ msgid "failed to set alarm signal handler"
|
||||
#~ msgstr "échec de la définition du gestionnaire de signal d'alarme"
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"PO-Revision-Date: 2024-10-20 14:07+0000\n"
|
||||
"Last-Translator: coralpink <coralpink@users.noreply.translate.codeberg.org>\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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.7.2\n"
|
||||
"X-Generator: Weblate 5.13.2\n"
|
||||
|
||||
#: src/main/help.c:236
|
||||
msgid "show progress bar"
|
||||
@@ -151,204 +151,232 @@ msgid "prefix visual information with NAME"
|
||||
msgstr "poprzedź informacje prefiksem NAZWA"
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgstr ""
|
||||
msgid "STYLE"
|
||||
msgstr "STYL"
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr ""
|
||||
msgid "set default bar style to NAME"
|
||||
msgstr "ustaw domyślny styl paska postępu na STYL"
|
||||
|
||||
#: src/main/help.c:314
|
||||
msgid "SPEC"
|
||||
msgstr "SPEC"
|
||||
|
||||
#: src/main/help.c:315
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr "wysyłaj postęp również do SPEC"
|
||||
|
||||
#: src/main/help.c:318
|
||||
msgid "output transfer statistics at the end"
|
||||
msgstr "wyświetl na końcu statystyki transferu"
|
||||
|
||||
#: src/main/help.c:318
|
||||
#: src/main/help.c:321
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr "pokaż wyjście nawet standardowe wyjście błędu nie jest terminalem"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "używaj znaków ucieczki do pozycjonowania kursora"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr "PLIK"
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr "zapisz wyjście do PLIK zamiast do wyjścia standardowego"
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr "PRĘDKOŚĆ"
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "ogranicz przesyłane dane do PRĘDKOŚĆ bajtów na sekundę"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr "BAJTY"
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "użyj bufora o rozmiarze BAJTY"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "nigdy nie używaj splice(), zawsze używaj read/write"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "pomijaj błędy odczytu wejścia"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr "pomijaj błędy w blokach po BAJTY bajtów na raz"
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "zakończ po przesłaniu --size bajtów"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr "wymuś zapis pamięci podręcznej na dysk po każdym zapisie"
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr ""
|
||||
"użyj bezpośredniego wejścia/wyjścia celem pominięcia pamięci podręcznej"
|
||||
|
||||
#: src/main/help.c:352
|
||||
#: src/main/help.c:355
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr "zignoruj dane wejściowe zamiast wyświetlić je na wyjściu standardowym"
|
||||
|
||||
#: src/main/help.c:355
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr ""
|
||||
"zapisz wszystkie dane wejściowe do PLIK przed wyświetleniem ich na wyjściu"
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgstr "PID[:FD]"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "obserwuj plik FD otworzony przez proces PID"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "zaktualizuj ustawienia procesu PID"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "zapisz ID procesu do PLIK"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "wyświetl te informacje z pomocą i wyjdź"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "wyświetl informacje o wersji i wyjdź"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr "zapisz logi debugujące do PLIK"
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Sposób użycia: %s [OPCJA] [PLIK]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
"Łączenie PLIK(ów) lub wejścia standardowego, do wyjścia standardowego z "
|
||||
"monitoringiem."
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
msgstr "Wspierane sekwencje formatowania:"
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "Proszę przesyłać zgłoszenia błędów do %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr "(wejście)"
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr "alokacja stanu programu nie powiodła się"
|
||||
|
||||
#: src/main/options.c:144 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:158
|
||||
msgid "is a directory"
|
||||
msgstr "jest katalogiem"
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr "nie udało się wygenerować nazwy pliku dla sysfs"
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr "nie udało się odczytać rozmiaru pliku sysfs"
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr "nie udało się otworzyć urządzenia blokowego"
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr "nie udało się ustalić rozmiaru urządzenia blokowego"
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "nie udało się zaalokować struktur opcji"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "nie udało się zaalokować struktur opcji argv"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "oczekiwany argument typu liczby całkowitej"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "oczekiwany argument liczbowy"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "oczekiwany proces ID lub para PID:FD"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "niepoprawne ID procesu"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "nie udało się zaalokować struktur opcji"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "nie udało się zaalokować struktur opcji argv"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr "wartość liczbowa niezrozumiana"
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "oczekiwany argument typu liczby całkowitej"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "oczekiwany argument liczbowy"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Spróbuj `%s --help' by uzyskać więcej informacji."
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Spróbuj `%s -h' by uzyskać więcej informacji."
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
@@ -356,23 +384,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:721
|
||||
#: src/main/options.c:1090
|
||||
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:730
|
||||
#: src/main/options.c:1099
|
||||
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:739
|
||||
#: src/main/options.c:1108
|
||||
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:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "niedostępne na systemach bez /proc/self/fdinfo"
|
||||
|
||||
@@ -380,7 +408,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"
|
||||
|
||||
@@ -417,151 +445,164 @@ msgstr "blokada zasobów nie powiodła się"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "nie udało się otworzyć terminala"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr "yzafpnum kMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr "yzafpnum KMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr "b/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#: 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:96
|
||||
#: src/pv/format/rate.c:40
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: 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:35
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/format/fineta.c:80
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/loop.c:564
|
||||
msgid "rate min/avg/max/mdev"
|
||||
msgstr "prędkość min/śr/max/odch"
|
||||
|
||||
#: src/pv/loop.c:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr "prędkość niezmierzona"
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:809 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:572 src/pv/state.c:583
|
||||
#: src/pv/state.c:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr "nie udało się zaalokować listy plików"
|
||||
|
||||
#: src/pv/transfer.c:463
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr "nie udało się zaalokować listy procesów"
|
||||
|
||||
#: src/pv/state.c:795
|
||||
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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr "brak zaalokowanego bufora transferu"
|
||||
|
||||
#: src/pv/transfer.c:676
|
||||
#: src/pv/transfer.c:751
|
||||
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:777
|
||||
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:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr "alokacja buforu pozycji linii nie powiodła się"
|
||||
|
||||
#: src/pv/transfer.c:917
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "błąd zapisu"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
#: src/pv/transfer.c:1237
|
||||
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"
|
||||
|
||||
#~ msgid "PID[:FD]"
|
||||
#~ msgstr "PID[:FD]"
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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"
|
||||
@@ -144,202 +144,230 @@ msgid "prefix visual information with NAME"
|
||||
msgstr "exibe NAME antes das demais informações"
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgid "STYLE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
msgid "set default bar style to NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:314
|
||||
msgid "SPEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:315
|
||||
msgid "output transfer statistics at the end"
|
||||
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 "gera dados mesmo que a saída de erro seja redirecionada"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "utiliza caracteres de escape para posicionar o cursor"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "limita a transferência a RATE bytes por segundo"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "use um tamanho de buffer de BYTES"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "nunca use splice(), sempre use read/write"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "ignorar erros de leitura em entrada"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "parar após --size bytes terem sido transferidos"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:352
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:355
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "assistir arquivo FD aberto pelo processo PID"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "atualizar as configurações do processo PID"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "salvar ID do processo em FILE"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "exibe esta tela de ajuda e termina"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "exibe a versão e termina"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Uso: %s [OPÇÕES] [ARQUIVOS]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
"Concatena ARQUIVO(s) ou a entrada padrão e grava na saída padrão, com "
|
||||
"monitoramento."
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "Por favor, reporte quaisquer defeitos para %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr "alocação de memória de status falhou"
|
||||
|
||||
#: src/main/options.c:144 src/pv/file.c:324
|
||||
msgid "failed to stat file"
|
||||
msgstr "erro obtendo informações do arquivo"
|
||||
|
||||
#: src/main/options.c:158
|
||||
msgid "is a directory"
|
||||
#: src/main/options.c:370
|
||||
msgid "list files may not contain @ lines"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "erro na alocação da estrutura de opções"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "erro na alocação da estrutura de opções argv"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "argumento inteiro esperado"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "argumento numérico esperado"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "ID do processo ou par pid:fd esperado"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "ID de processo inválido"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "erro na alocação da estrutura de opções"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "erro na alocação da estrutura de opções argv"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "argumento inteiro esperado"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "argumento numérico esperado"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Tente `%s --help' para maiores informações."
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Tente `%s -h' para maiores informações."
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
@@ -347,21 +375,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:721
|
||||
#: src/main/options.c:1090
|
||||
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:730
|
||||
#: src/main/options.c:1099
|
||||
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:739
|
||||
#: src/main/options.c:1108
|
||||
msgid "cannot transfer files when watching file descriptors"
|
||||
msgstr "não pode transferir arquivos ao assistir descritores de arquivo"
|
||||
|
||||
#: src/main/options.c:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "não disponível em sistemas sem /proc/self/fdinfo"
|
||||
|
||||
@@ -369,7 +397,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"
|
||||
|
||||
@@ -405,149 +433,159 @@ msgstr "tentativa de bloqueio falhou"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "erro abrindo o terminal"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#: 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 "B/s"
|
||||
|
||||
#: 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 "ETA"
|
||||
|
||||
#: 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:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:572 src/pv/state.c:583
|
||||
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:917
|
||||
msgid "write failed"
|
||||
msgstr "erro de gravação"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
msgid "file descriptor list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: 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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "erro de gravação"
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
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"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\n"
|
||||
"PO-Revision-Date: 2024-10-22 18:07+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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"
|
||||
"Language: ru\n"
|
||||
@@ -11,7 +11,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.8.1\n"
|
||||
"X-Generator: Weblate 5.9.2\n"
|
||||
|
||||
#: src/main/help.c:236
|
||||
msgid "show progress bar"
|
||||
@@ -142,219 +142,247 @@ 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:312
|
||||
#: src/main/help.c:315
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:315
|
||||
#: src/main/help.c:318
|
||||
msgid "output transfer statistics at the end"
|
||||
msgstr "после завершения показать статистику"
|
||||
|
||||
#: src/main/help.c:318
|
||||
#: src/main/help.c:321
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr "вевести, даже если стд. ошибка не является терминалом"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr ""
|
||||
"использовать символьные последовательности для позиционирования курсора"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr "ФАЙЛ"
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr "направить вывод в ФАЙЛ вместо стд. вывода"
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr "СКОР"
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "ограничить скорость передачи до СКОР байт/сек"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr "БАЙТ"
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "использовать буфер размера БАЙТ"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "использовать чтение/запись вместо splice()"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "пропустить ошибки чтения во вводе"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr "пропускать ошибки в <БАЙТ> блоках за раз"
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "остановить после передачи --size байт"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr "сбрасывать кеш на диск каждый раз"
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr "использовать прямой ввод/вывод для обхода кеша"
|
||||
|
||||
#: src/main/help.c:352
|
||||
#: src/main/help.c:355
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr "отбрасывать ввод вместо записи в вывод"
|
||||
|
||||
#: src/main/help.c:355
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr "записывать весь ввод в ФАЙЛ прежде, чем отправлять на вывод"
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgstr "ИДпр[:FD]"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "следить за FD файла, открытого процессом ИДпр"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr "ИДпр"
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "обновить настройки ИДпр процесса"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "сохранить ИД процесса в ФАЙЛ"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "показать справку и завершить работу"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "показать версию программы и завершить работу"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr "вести запись отладочного журнала в ФАЙЛ"
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Использование: %s [ОПЦИИ] [ФАЙЛ]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
msgstr "Поддерживаемые последовательности:"
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "Сообщайте о проблемах на: %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr "(ввод)"
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:144 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:158
|
||||
msgid "is a directory"
|
||||
msgstr "является каталогом"
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr "не удалось создать имя файла sysfs"
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr "не удалось узнать размер файла sysfs"
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr "не удалось открыть блочное устройство"
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr "не удалось определить размер блочного устройства"
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "не удалось выделить память для структуры опций"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "не удалось выделить память для структуры опций argv"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "ожидалось целое число"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "ожидалось число"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "ожидался ИД процесса или пара ИДпр:ДФ"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "неправильный ИД процесса"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "не удалось выделить память для структуры опций"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "не удалось выделить память для структуры опций argv"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr "число не распознано"
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "ожидалось целое число"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "ожидалось число"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Выполните `%s --help' для получения подробностей."
|
||||
|
||||
#: src/main/options.c:681
|
||||
#: src/main/options.c:1050
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Выполните `%s -h' для получения подробностей."
|
||||
|
||||
#: src/main/options.c:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:721
|
||||
#: src/main/options.c:1090
|
||||
msgid "cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:730
|
||||
#: src/main/options.c:1099
|
||||
msgid "cannot use remote control when watching file descriptors"
|
||||
msgstr "удалённое управление невозможно при отслеживании дескрипторов файлов"
|
||||
|
||||
#: src/main/options.c:739
|
||||
#: src/main/options.c:1108
|
||||
msgid "cannot transfer files when watching file descriptors"
|
||||
msgstr "передача файлов невозможна при отслеживании дескрипторов файлов"
|
||||
|
||||
#: src/main/options.c:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "невозможно на системах без /proc/self/fdinfo"
|
||||
|
||||
@@ -362,7 +390,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"
|
||||
|
||||
@@ -400,149 +428,162 @@ msgstr "попытка блокировки не удалась"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "не удалось открыть терминал"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr "бит/с"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr "/с"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "байт/с"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ОЖИД"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr "ЗАВЕРШ"
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr "бит"
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr "байт"
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#: 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:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr "скорость не изменяется"
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:572 src/pv/state.c:583
|
||||
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:917
|
||||
msgid "write failed"
|
||||
msgstr "запись не удалась"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr "не удалось выделить память для списка файлов"
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:795
|
||||
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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr "не выделена память для буфера передачи"
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr "не удалось задать измеритель временного промежутка"
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr "не удалось очистить измеритель временного промежутка"
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "запись не удалась"
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
msgid "select call failed"
|
||||
msgstr "запрос выборки не удался"
|
||||
|
||||
#: src/pv/watchpid.c:129 src/pv/watchpid.c:203
|
||||
msgid "not a regular file or block device"
|
||||
msgstr "не является обычным файлом или блочным устройством"
|
||||
|
||||
#~ msgid "PID[:FD]"
|
||||
#~ msgstr "ИДпр[:FD]"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: pv 1.8.14\n"
|
||||
"Report-Msgid-Bugs-To: pv@ivarch.com\n"
|
||||
"POT-Creation-Date: 2024-12-08 22:22+0000\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"
|
||||
"Report-Msgid-Bugs-To: https://codeberg.org/ivarch/pv/issues\n"
|
||||
"POT-Creation-Date: 2025-10-18 19:34+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"
|
||||
@@ -142,201 +142,229 @@ msgid "prefix visual information with NAME"
|
||||
msgstr "görsel bilgiyi İSİM ile öne ekle"
|
||||
|
||||
#: src/main/help.c:311
|
||||
msgid "SPEC"
|
||||
msgstr ""
|
||||
msgid "STYLE"
|
||||
msgstr "BİÇİM"
|
||||
|
||||
#: src/main/help.c:312
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr ""
|
||||
msgid "set default bar style to NAME"
|
||||
msgstr "öntanımlı çubuk biçimini İSİM olarak ayarla"
|
||||
|
||||
#: src/main/help.c:314
|
||||
msgid "SPEC"
|
||||
msgstr "BELİRT"
|
||||
|
||||
#: src/main/help.c:315
|
||||
msgid "also send progress to SPEC"
|
||||
msgstr "ilerlemeyi BELİRT ögesine de gönder"
|
||||
|
||||
#: src/main/help.c:318
|
||||
msgid "output transfer statistics at the end"
|
||||
msgstr "transfer istatistiklerini sonda göster"
|
||||
|
||||
#: src/main/help.c:318
|
||||
#: src/main/help.c:321
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr "standart hata bir terminal olmasa bile çıktı yazdır"
|
||||
|
||||
#: src/main/help.c:321
|
||||
#: src/main/help.c:324
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "imleç konumlandırma kaçış dizilerini kullan"
|
||||
|
||||
#: src/main/help.c:324 src/main/help.c:354 src/main/help.c:366
|
||||
#: src/main/help.c:376
|
||||
#: src/main/help.c:327 src/main/help.c:360 src/main/help.c:372
|
||||
#: src/main/help.c:382
|
||||
msgid "FILE"
|
||||
msgstr "DOSYA"
|
||||
|
||||
#: src/main/help.c:325
|
||||
#: src/main/help.c:328
|
||||
msgid "write output to FILE instead of stdout"
|
||||
msgstr "çıktıyı stdout yerine DOSYA'ya yaz"
|
||||
|
||||
#: src/main/help.c:327
|
||||
#: src/main/help.c:330
|
||||
msgid "RATE"
|
||||
msgstr "ORAN"
|
||||
|
||||
#: src/main/help.c:328
|
||||
#: src/main/help.c:331
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "aktarımı saniye başına ORAN bayt ile sınırlandırın"
|
||||
|
||||
#: src/main/help.c:330 src/main/help.c:339
|
||||
#: src/main/help.c:333 src/main/help.c:342
|
||||
msgid "BYTES"
|
||||
msgstr "BAYTLAR"
|
||||
|
||||
#: src/main/help.c:331
|
||||
#: src/main/help.c:334
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "BAYTLAR tampon boyutu kullanın"
|
||||
|
||||
#: src/main/help.c:334
|
||||
#: src/main/help.c:337
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr "splice() kullanma, her zaman read/write kullan"
|
||||
|
||||
#: src/main/help.c:337
|
||||
#: src/main/help.c:340
|
||||
msgid "skip read errors in input"
|
||||
msgstr "girdideki okuma hatalarını atla"
|
||||
|
||||
#: src/main/help.c:340
|
||||
#: src/main/help.c:343
|
||||
msgid "skip errors in BYTES blocks at a time"
|
||||
msgstr "BAYTLAR blokları halinde hataları atla"
|
||||
|
||||
#: src/main/help.c:343
|
||||
#: src/main/help.c:346
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "--size bayt transfer edildikten sonra dur"
|
||||
|
||||
#: src/main/help.c:346
|
||||
#: src/main/help.c:349
|
||||
msgid "flush cache to disk after every write"
|
||||
msgstr "her yazmadan sonra önbelleği diske boşalt"
|
||||
|
||||
#: src/main/help.c:349
|
||||
#: src/main/help.c:352
|
||||
msgid "use direct I/O to bypass cache"
|
||||
msgstr "Önbelleği atlamak için doğrudan I/O kullan"
|
||||
|
||||
#: src/main/help.c:352
|
||||
#: src/main/help.c:355
|
||||
msgid "try to seek instead of writing null bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
msgid "discard input instead of writing to output"
|
||||
msgstr "Girdiyi çıktıya yazmak yerine yok say"
|
||||
|
||||
#: src/main/help.c:355
|
||||
#: src/main/help.c:361
|
||||
msgid "write all input to FILE before writing to output"
|
||||
msgstr "çıktıya yazmadan önce tüm girdiyi DOSYA'ya yaz"
|
||||
|
||||
#: src/main/help.c:357
|
||||
msgid "PID[:FD]"
|
||||
msgstr "PID[:FD]"
|
||||
#: src/main/help.c:363
|
||||
msgid "PID[:FD]|=NAME|@LISTFILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:358
|
||||
#: src/main/help.c:364
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr "FD izleme dosyası PID işlemi tarafından açıldı"
|
||||
|
||||
#: src/main/help.c:361
|
||||
#: src/main/help.c:367
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: src/main/help.c:362
|
||||
#: src/main/help.c:368
|
||||
msgid "update settings of process PID"
|
||||
msgstr "süreç PID ayarlarını güncelle"
|
||||
|
||||
#: src/main/help.c:367
|
||||
#: src/main/help.c:373
|
||||
msgid "save process ID in FILE"
|
||||
msgstr "FILE'da işlem kimliğini (ID) kaydet"
|
||||
|
||||
#: src/main/help.c:370
|
||||
#: src/main/help.c:376
|
||||
msgid "show this help and exit"
|
||||
msgstr "bu yardımı göster ve çık"
|
||||
|
||||
#: src/main/help.c:373
|
||||
#: src/main/help.c:379
|
||||
msgid "show version information and exit"
|
||||
msgstr "sürüm bilgilerini göster ve çık"
|
||||
|
||||
#: src/main/help.c:377
|
||||
#: src/main/help.c:383
|
||||
msgid "write debug logs to FILE"
|
||||
msgstr "Hata ayıklama kayıtlarını DOSYA'ya yaz"
|
||||
|
||||
#: src/main/help.c:403
|
||||
#: src/main/help.c:409
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Kullanım şekli: %s [AYAR] [DOSYA]..."
|
||||
|
||||
#: src/main/help.c:414
|
||||
#: src/main/help.c:420
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output, with monitoring."
|
||||
msgstr ""
|
||||
"İzleme ile DOSYA(lar)ı veya standart girdiyi standart çıktı ile birleştirin."
|
||||
|
||||
#: src/main/help.c:552
|
||||
#: src/main/help.c:558
|
||||
msgid "Supported format sequences:"
|
||||
msgstr ""
|
||||
msgstr "Desteklenen biçim dizileri:"
|
||||
|
||||
#: src/main/help.c:566
|
||||
#: src/main/help.c:572
|
||||
#, c-format
|
||||
msgid "Please report any bugs to: %s"
|
||||
msgstr "Lütfen hataları şu adrese bildirin: %s"
|
||||
|
||||
#: src/main/main.c:230
|
||||
#: src/main/main.c:232
|
||||
msgid "(input)"
|
||||
msgstr "(giriş)"
|
||||
|
||||
#: src/main/main.c:319
|
||||
#: src/main/main.c:334
|
||||
msgid "state allocation failed"
|
||||
msgstr "durum tahsisi başarısız oldu"
|
||||
|
||||
#: src/main/options.c:144 src/pv/file.c:324
|
||||
msgid "failed to stat file"
|
||||
msgstr "dosya statüsünde başarısız oldu"
|
||||
#: src/main/options.c:370
|
||||
msgid "list files may not contain @ lines"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:158
|
||||
msgid "is a directory"
|
||||
msgstr "bir dizindir"
|
||||
|
||||
#: src/main/options.c:187
|
||||
msgid "failed to generate sysfs filename"
|
||||
msgstr "sysfs dosya adı oluşturulamadı"
|
||||
|
||||
#: src/main/options.c:209
|
||||
msgid "failed to read sysfs size file"
|
||||
msgstr "sysfs boyut dosyası okunamadı"
|
||||
|
||||
#: src/main/options.c:229
|
||||
msgid "failed to open block device"
|
||||
msgstr "blok aygıtı açılamadı"
|
||||
|
||||
#: src/main/options.c:239
|
||||
msgid "failed to determine size of block device"
|
||||
msgstr "blok aygıtının boyutu belirlenemedi"
|
||||
|
||||
#: src/main/options.c:344
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "seçenek yapısı tahsisi başarısız oldu"
|
||||
|
||||
#: src/main/options.c:363
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "seçenek yapısı argv tahsisi başarısız oldu"
|
||||
|
||||
#: src/main/options.c:425
|
||||
msgid "integer argument expected"
|
||||
msgstr "tamsayı bağımsız değişkeni bekleniyor"
|
||||
|
||||
#: src/main/options.c:436
|
||||
msgid "numeric argument expected"
|
||||
msgstr "sayısal bağımsız değişken bekleniyor"
|
||||
|
||||
#: src/main/options.c:447
|
||||
#: src/main/options.c:391 src/main/options.c:393 src/main/options.c:804
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr "süreç kimliği (ID) veya pid:fd çifti bekleniyor"
|
||||
|
||||
#: src/main/options.c:454
|
||||
#: src/main/options.c:403 src/main/options.c:405 src/main/options.c:811
|
||||
msgid "invalid process ID"
|
||||
msgstr "geçersiz süreç kimliği (ID)"
|
||||
|
||||
#: src/main/options.c:679
|
||||
#: 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:651
|
||||
msgid "option structure allocation failed"
|
||||
msgstr "seçenek yapısı tahsisi başarısız oldu"
|
||||
|
||||
#: src/main/options.c:670
|
||||
msgid "option structure argv allocation failed"
|
||||
msgstr "seçenek yapısı argv tahsisi başarısız oldu"
|
||||
|
||||
#: src/main/options.c:722
|
||||
msgid "numeric value not understood"
|
||||
msgstr "sayısal değer anlaşılmadı"
|
||||
|
||||
#: src/main/options.c:740
|
||||
msgid "integer argument expected"
|
||||
msgstr "tamsayı bağımsız değişkeni bekleniyor"
|
||||
|
||||
#: src/main/options.c:752
|
||||
msgid "numeric argument expected"
|
||||
msgstr "sayısal bağımsız değişken bekleniyor"
|
||||
|
||||
#: src/main/options.c:764
|
||||
msgid "missing filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:792
|
||||
msgid "missing process name"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:1048
|
||||
#, 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:681
|
||||
#: src/main/options.c:1050
|
||||
#, 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:712
|
||||
#: src/main/options.c:1081
|
||||
msgid ""
|
||||
"cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
@@ -344,19 +372,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:721
|
||||
#: src/main/options.c:1090
|
||||
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:730
|
||||
#: src/main/options.c:1099
|
||||
msgid "cannot use remote control when watching file descriptors"
|
||||
msgstr "dosya tanımlayıcılarını izlerken uzaktan kumandayı kullanamaz"
|
||||
|
||||
#: src/main/options.c:739
|
||||
#: src/main/options.c:1108
|
||||
msgid "cannot transfer files when watching file descriptors"
|
||||
msgstr "dosya tanımlayıcıları izlenirken dosya aktarılamıyor"
|
||||
|
||||
#: src/main/options.c:754
|
||||
#: src/main/options.c:1133
|
||||
msgid "not available on systems without /proc/self/fdinfo"
|
||||
msgstr "/proc/self/fdinfo olmayan sistemlerde kullanılamaz"
|
||||
|
||||
@@ -364,7 +392,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"
|
||||
|
||||
@@ -401,149 +429,162 @@ msgstr "kilit denemesi başarısız oldu"
|
||||
msgid "failed to open terminal"
|
||||
msgstr "terminal açılamadı"
|
||||
|
||||
#: src/pv/display.c:233
|
||||
#: src/pv/display.c:285
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr "yzafpnum kMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:251
|
||||
#: src/pv/display.c:303
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr "yzafpnum KMGTPEZY"
|
||||
|
||||
#: src/pv/display.c:523 src/pv/display.c:998 src/pv/display.c:1027
|
||||
#: src/pv/loop.c:549
|
||||
msgid "b/s"
|
||||
msgstr "b/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:527 src/pv/display.c:1002 src/pv/display.c:1031
|
||||
#: src/pv/loop.c:549
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:875 src/pv/display.c:879
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/display.c:961
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/display.c:1057
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/display.c:1060 src/pv/transfer.c:594
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/display.c:1641 src/pv/transfer.c:1056
|
||||
#: src/pv/display.c:1053 src/pv/loop.c:754 src/pv/transfer.c:1135
|
||||
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/loop.c:548
|
||||
#: 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:96
|
||||
#: src/pv/format/rate.c:40
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: 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:35
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: src/pv/format/bytes.c:39 src/pv/transfer.c:620
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/format/eta.c:52 src/pv/format/eta.c:56
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/format/fineta.c:80
|
||||
msgid "FIN"
|
||||
msgstr "FIN"
|
||||
|
||||
#: src/pv/loop.c:564
|
||||
msgid "rate min/avg/max/mdev"
|
||||
msgstr "oran min/ortalama/maks/standart sapma"
|
||||
|
||||
#: src/pv/loop.c:560
|
||||
#: src/pv/loop.c:576
|
||||
msgid "rate not measured"
|
||||
msgstr "oran ölçülmedi"
|
||||
|
||||
#: src/pv/loop.c:767 src/pv/loop.c:818 src/pv/loop.c:859 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:384 src/pv/watchpid.c:405
|
||||
#: src/pv/loop.c:775 src/pv/loop.c:791 src/pv/loop.c:809 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:572 src/pv/state.c:583
|
||||
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:917
|
||||
msgid "write failed"
|
||||
msgstr "yazma başarısız"
|
||||
|
||||
#: src/pv/transfer.c:1154
|
||||
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:809 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:741 src/pv/state.c:753
|
||||
msgid "file list allocation failed"
|
||||
msgstr "dosya listesi tahsisi başarısız oldu"
|
||||
|
||||
#: src/pv/state.c:787
|
||||
msgid "process list allocation failed"
|
||||
msgstr "işlem listesi tahsisi başarısız oldu"
|
||||
|
||||
#: src/pv/state.c:795
|
||||
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:663
|
||||
msgid "no transfer buffer allocated"
|
||||
msgstr "aktarım arabelleği ayrılmamış"
|
||||
|
||||
#: src/pv/transfer.c:751
|
||||
msgid "failed to set interval timer"
|
||||
msgstr "aralık zamanlayıcısı ayarlanamadı"
|
||||
|
||||
#: src/pv/transfer.c:777
|
||||
msgid "failed to clear interval timer"
|
||||
msgstr "aralık zamanlayıcısı temizlenemedi"
|
||||
|
||||
#: src/pv/transfer.c:822
|
||||
msgid "line position buffer allocation failed"
|
||||
msgstr "satır konumu arabellek tahsisi başarısız oldu"
|
||||
|
||||
#: src/pv/transfer.c:996
|
||||
msgid "write failed"
|
||||
msgstr "yazma başarısız"
|
||||
|
||||
#: src/pv/transfer.c:1237
|
||||
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"
|
||||
|
||||
#~ msgid "PID[:FD]"
|
||||
#~ msgstr "PID[:FD]"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* `configure' script. Include this after config.h and before anything
|
||||
* else.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
/* Debugging support enabled */
|
||||
#undef ENABLE_DEBUGGING
|
||||
|
||||
/* Build with ncurses support */
|
||||
#undef ENABLE_NCURSES
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
@@ -41,6 +44,9 @@
|
||||
/* Define to 1 if you have the `fdatasync' function. */
|
||||
#undef HAVE_FDATASYNC
|
||||
|
||||
/* Define to 1 if you have the `fmod' function. */
|
||||
#undef HAVE_FMOD
|
||||
|
||||
/* Define to 1 if you have the `fpathconf' function. */
|
||||
#undef HAVE_FPATHCONF
|
||||
|
||||
@@ -65,6 +71,9 @@
|
||||
/* IPC support enabled */
|
||||
#undef HAVE_IPC
|
||||
|
||||
/* Define to 1 if you have the <langinfo.h> header file. */
|
||||
#undef HAVE_LANGINFO_H
|
||||
|
||||
/* Define to 1 if you have the <libgen.h> header file. */
|
||||
#undef HAVE_LIBGEN_H
|
||||
|
||||
@@ -185,6 +194,9 @@
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/shm.h> header file. */
|
||||
#undef HAVE_SYS_SHM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
@@ -200,6 +212,9 @@
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define to 1 if you have the <term.h> header file. */
|
||||
#undef HAVE_TERM_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
|
||||
+18
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Global program option structure and the parsing function prototype.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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.
|
||||
*
|
||||
@@ -34,10 +44,13 @@ struct opts_s {
|
||||
/*@keep@*/ const char *program_name; /* name the program is running as */
|
||||
/*@keep@*/ /*@null@*/ char *output; /* fd to write output to */
|
||||
/*@keep@*/ /*@null@*/ char *name; /* display name, if any */
|
||||
/*@keep@*/ /*@null@*/ char *default_bar_style; /* default bar style */
|
||||
/*@keep@*/ /*@null@*/ char *format; /* output format, if any */
|
||||
/*@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 */
|
||||
@@ -46,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 */
|
||||
@@ -76,6 +89,7 @@ struct opts_s {
|
||||
bool stop_at_size; /* set if we stop at "size" bytes */
|
||||
bool sync_after_write; /* set if we sync after every write */
|
||||
bool direct_io; /* set if O_DIRECT is to be used */
|
||||
bool sparse_output; /* set if we leave holes in the output */
|
||||
bool discard_input; /* set to write nothing to output */
|
||||
bool show_stats; /* set to write statistics at the end */
|
||||
bool width_set_manually; /* width was set manually, not detected */
|
||||
|
||||
+273
-51
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions internal to the PV library. Include "config.h" first.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -9,6 +9,9 @@
|
||||
#ifndef _PV_INTERNAL_H
|
||||
#define _PV_INTERNAL_H 1
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
@@ -38,6 +41,7 @@ extern "C" {
|
||||
#define PV_SIZEOF_LASTWRITTEN_BUFFER 256
|
||||
#define PV_SIZEOF_PREVLINE_BUFFER 1024
|
||||
#define PV_FORMAT_ARRAY_MAX 100
|
||||
#define PV_SIZEOF_FORMAT_SEGMENTS_BUF 4096
|
||||
#define PV_SIZEOF_CRS_LOCK_FILE 1024
|
||||
|
||||
#define PV_SIZEOF_FILE_FDINFO 4096
|
||||
@@ -45,6 +49,10 @@ extern "C" {
|
||||
#define PV_SIZEOF_FILE_FDPATH 4096
|
||||
#define PV_SIZEOF_DISPLAY_NAME 512
|
||||
|
||||
#define PV_BARSTYLE_MAX 4 /* number of different styles allowed in a format */
|
||||
#define PV_BARSTYLE_SIZEOF_STRING 10 /* max length of a bar constituent component in bytes */
|
||||
#define PV_BARSTYLE_MAX_FILLERS 10 /* max number of bar filler strings */
|
||||
|
||||
#define PV_DISPLAY_WINDOWTITLE 1
|
||||
#define PV_DISPLAY_PROCESSTITLE 2
|
||||
|
||||
@@ -52,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 */
|
||||
};
|
||||
@@ -67,6 +75,65 @@ typedef enum {
|
||||
} pvtransfercount_t;
|
||||
|
||||
|
||||
/*
|
||||
* Structure describing a short string used as part of a progress bar, whose
|
||||
* width in display characters may not be the same as its length in bytes.
|
||||
*/
|
||||
struct pvbarstring_spec_s {
|
||||
char string[PV_BARSTYLE_SIZEOF_STRING];
|
||||
uint8_t width;
|
||||
uint8_t bytes;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure describing a style of progress bar.
|
||||
*
|
||||
* The part that moves back and forth when the size isn't known, such as
|
||||
* "<=>", is "indicator".
|
||||
*
|
||||
* The string used to populate the rest of the bar is one of "filler", which
|
||||
* contains "filler_entries" array items. The first item "filler[0]" is
|
||||
* used for an empty part such as " ". The last item
|
||||
* "filler[filler_entries-1]" is used for a 100% full part, such as "=".
|
||||
*
|
||||
* If there are more than the minimum of 2 entries, then the intervening
|
||||
* entries are used for partial fills.
|
||||
*
|
||||
* When there are only 2 entries and the bar isn't completely empty or full,
|
||||
* the last filled portion of the bar is filled with "tip" instead of the
|
||||
* last filler item to indicate the tip of the bar, such as ">".
|
||||
*
|
||||
* Note that only the indicator is expected to ever be wider than 1 display
|
||||
* character. All other items are expected to have a width of 0 or 1.
|
||||
*
|
||||
* The "style_id" is an opaque identifier that should only be used to
|
||||
* determine whether two styles are the same. It is always nonzero.
|
||||
*/
|
||||
struct pvbarstyle_s {
|
||||
uint8_t style_id;
|
||||
uint8_t filler_entries;
|
||||
struct pvbarstring_spec_s indicator;
|
||||
struct pvbarstring_spec_s tip;
|
||||
struct pvbarstring_spec_s filler[PV_BARSTYLE_MAX_FILLERS];
|
||||
};
|
||||
typedef struct pvbarstyle_s *pvbarstyle_t;
|
||||
|
||||
|
||||
/* Display format component type, -1 for static string. */
|
||||
typedef int8_t pvdisplay_component_t;
|
||||
#define PVDISPLAY_COMPONENT_MAX (127) /* INT8_MAX */
|
||||
|
||||
/* Byte count of a part of the display. */
|
||||
typedef uint16_t pvdisplay_bytecount_t;
|
||||
#define PVDISPLAY_BYTECOUNT_MAX (65535) /* UINT16_MAX */
|
||||
|
||||
/* Width of a part of the display. */
|
||||
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.
|
||||
*
|
||||
@@ -76,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 */
|
||||
@@ -102,17 +181,16 @@ struct pvstate_s {
|
||||
/*@only@*/ /*@null@*/ char *format_string; /* output format string */
|
||||
/*@only@*/ /*@null@*/ char *extra_format_string; /* extra format string */
|
||||
/*@null@*/ char *output_name; /* name of the output, for diagnostics */
|
||||
/*@null@*/ char *default_bar_style; /* which bar style to use by default */
|
||||
off_t error_skip_block; /* skip block size, 0 for adaptive */
|
||||
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 */
|
||||
unsigned int width; /* screen width */
|
||||
pvdisplay_width_t width; /* screen width */
|
||||
unsigned int height; /* screen height */
|
||||
unsigned int extra_displays; /* bitmask of extra display destinations */
|
||||
bool force; /* display even if not on terminal */
|
||||
@@ -125,11 +203,12 @@ struct pvstate_s {
|
||||
bool decimal_units; /* use decimal prefixes */
|
||||
bool null_terminated_lines; /* lines are null-terminated */
|
||||
bool no_display; /* do nothing other than pipe data */
|
||||
bool no_splice; /* never use splice() */
|
||||
bool stop_at_size; /* set if we stop at "size" bytes */
|
||||
bool sync_after_write; /* set if we sync after every write */
|
||||
bool direct_io; /* set if O_DIRECT is to be used */
|
||||
bool direct_io_changed; /* set when direct_io is changed */
|
||||
bool no_splice; /* never use splice() */
|
||||
bool sparse_output; /* set if we leave holes in the output */
|
||||
bool discard_input; /* write nothing to stdout */
|
||||
bool show_stats; /* show statistics on exit */
|
||||
bool width_set_manually; /* width was set manually, not detected */
|
||||
@@ -139,7 +218,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;
|
||||
@@ -164,7 +243,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 */
|
||||
@@ -172,7 +251,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 *
|
||||
@@ -181,13 +260,18 @@ struct pvstate_s {
|
||||
|
||||
struct pvdisplay_segment_s { /* format string broken into segments */
|
||||
/* See pv__format_init() for more details. */
|
||||
int type; /* component type, -1 for static string */
|
||||
size_t chosen_size; /* "n" from %<n>A, or 0 */
|
||||
size_t offset; /* start offset of this segment */
|
||||
size_t bytes; /* length of segment in bytes */
|
||||
size_t width; /* displayed width of segment */
|
||||
/*@dependent@*/ /*@null@*/ const char *string_parameter; /* parameter after colon in %{x:} */
|
||||
pvdisplay_bytecount_t string_parameter_bytes; /* number of bytes in string_parameter */
|
||||
pvdisplay_component_t type; /* component type, -1 for static string */
|
||||
int8_t parameter; /* component parameter, such as bar style index */
|
||||
pvdisplay_width_t chosen_size; /* "n" from %<n>A, or 0 */
|
||||
pvdisplay_bytecount_t offset; /* start offset of this segment in the build buffer */
|
||||
pvdisplay_bytecount_t bytes; /* length of segment in bytes in the build buffer */
|
||||
pvdisplay_width_t width; /* displayed width of segment */
|
||||
} format[PV_FORMAT_ARRAY_MAX];
|
||||
|
||||
struct pvbarstyle_s barstyle[PV_BARSTYLE_MAX];
|
||||
|
||||
/* The last-written "n" bytes. */
|
||||
char lastwritten_buffer[PV_SIZEOF_LASTWRITTEN_BUFFER];
|
||||
|
||||
@@ -197,18 +281,19 @@ struct pvstate_s {
|
||||
char next_line[PV_SIZEOF_PREVLINE_BUFFER];
|
||||
|
||||
/*@only@*/ /*@null@*/ char *display_buffer; /* buffer for display string */
|
||||
size_t display_buffer_size; /* size allocated to display buffer */
|
||||
size_t display_string_bytes; /* byte length of string in display buffer */
|
||||
size_t display_string_width; /* displayed width of string in display buffer */
|
||||
off_t initial_offset; /* offset when first opened (when watching fds) */
|
||||
size_t lastwritten_bytes; /* largest number of last-written bytes to show */
|
||||
size_t next_line_len; /* length of currently receiving line so far */
|
||||
off_t initial_offset; /* offset when first opened (when watching fds) */
|
||||
size_t next_line_len; /* length of currently receiving line so far */
|
||||
|
||||
size_t format_segment_count; /* number of format string segments */
|
||||
|
||||
pvtransfercount_t count_type; /* type of count for transfer, rate, etc */
|
||||
|
||||
unsigned int prev_screen_width; /* screen width last time we were called */
|
||||
pvdisplay_width_t prev_screen_width; /* screen width last time we were called */
|
||||
|
||||
pvdisplay_bytecount_t display_buffer_size; /* size allocated to display buffer */
|
||||
pvdisplay_bytecount_t display_string_bytes; /* byte length of string in display buffer */
|
||||
pvdisplay_width_t display_string_width; /* displayed width of string in display buffer */
|
||||
pvdisplay_bytecount_t lastwritten_bytes; /* largest number of last-written bytes to show */
|
||||
|
||||
bool showing_timer; /* set if showing timer */
|
||||
bool showing_bytes; /* set if showing byte/line count */
|
||||
@@ -216,8 +301,11 @@ struct pvstate_s {
|
||||
bool showing_last_written; /* set if displaying the last few bytes written */
|
||||
bool showing_previous_line; /* set if displaying the previously output line */
|
||||
|
||||
bool format_uses_colour; /* set if the format string uses colours */
|
||||
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;
|
||||
|
||||
@@ -227,7 +315,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 */
|
||||
|
||||
@@ -253,16 +341,16 @@ struct pvstate_s {
|
||||
|
||||
off_t prev_transferred; /* total amount transferred when called last time */
|
||||
|
||||
int percentage; /* transfer percentage completion */
|
||||
double percentage; /* transfer percentage completion */
|
||||
} calc;
|
||||
|
||||
/********************
|
||||
* 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 */
|
||||
@@ -275,6 +363,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;
|
||||
|
||||
/*******************
|
||||
@@ -295,7 +384,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 */
|
||||
@@ -307,6 +396,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) */
|
||||
|
||||
@@ -348,50 +438,182 @@ struct pvstate_s {
|
||||
bool splice_used;
|
||||
#endif
|
||||
bool read_error_warning_shown;
|
||||
bool output_not_seekable; /* set if lseek() fails on output */
|
||||
} 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@*/ 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 */
|
||||
};
|
||||
typedef struct pvformatter_args_s *pvformatter_args_t;
|
||||
|
||||
|
||||
/* Pointer to a formatter function. */
|
||||
typedef pvdisplay_bytecount_t (*pvdisplay_formatter_t)(pvformatter_args_t);
|
||||
|
||||
|
||||
/*
|
||||
* Structure defining a format string sequence following a %.
|
||||
*/
|
||||
struct pvdisplay_component_s {
|
||||
/*@null@ */ const char *match; /* string to match */
|
||||
/*@null@ */ pvdisplay_formatter_t function; /* function to call */
|
||||
bool dynamic; /* whether it can scale with screen size */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
pid_t watch_pid; /* PID to watch */
|
||||
int watch_fd; /* fd to watch, -1 = not displayed */
|
||||
struct timespec end_time; /* time the fd was marked as closed */
|
||||
pid_t watch_pid; /* PID the fd belongs to */
|
||||
int watch_fd; /* fd to watch */
|
||||
bool closed; /* true once the fd is closed */
|
||||
bool displayable; /* false if not displayable */
|
||||
bool unused; /* true if free for re-use */
|
||||
};
|
||||
typedef struct pvwatchfd_s *pvwatchfd_t;
|
||||
|
||||
typedef struct pvdisplay_s *pvdisplay_t;
|
||||
typedef struct pvdisplay_segment_s *pvdisplay_segment_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);
|
||||
bool pv_format(pvstate_t, /*@null@*/ const char *, pvdisplay_t, bool, bool);
|
||||
void pv_display(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);
|
||||
void pv_si_prefix(long double *, char *, const long double, pvtransfercount_t);
|
||||
void pv_describe_amount(char *, size_t, char *, long double, char *, char *, pvtransfercount_t);
|
||||
|
||||
int8_t pv_display_barstyle_index(pvformatter_args_t, const char *);
|
||||
|
||||
pvdisplay_bytecount_t pv_formatter_segmentcontent(char *, pvformatter_args_t);
|
||||
|
||||
/*
|
||||
* Formatting functions.
|
||||
*
|
||||
* Each formatting function takes a state, the current display, and the
|
||||
* segment it's for; it also takes a buffer, with a particular size, and an
|
||||
* offset at which to start writing to the buffer.
|
||||
*
|
||||
* If the component is dynamically sized (such as a progress bar with no
|
||||
* chosen_size constraint), the segment's "width" is expected to have
|
||||
* already been populated by the caller, with the target width.
|
||||
*
|
||||
* The function writes the appropriate string to the buffer at the offset,
|
||||
* and updates the segment's "offset" and "bytes". The number of bytes
|
||||
* written ("bytes") is also returned; it will be 0 if the string would not
|
||||
* fit into the buffer.
|
||||
*
|
||||
* The caller is expected to update the segment's "width".
|
||||
*
|
||||
* If called with a buffer size of 0, only the side effects occur (such as
|
||||
* setting flags like display->showing_timer).
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_progress(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_progress_bar_only(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_progress_amount_only(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_bar_default(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_bar_plain(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_bar_block(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_bar_granular(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_bar_shaded(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_eta(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_fineta(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_rate(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_average_rate(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_bytes(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_buffer_percent(pvformatter_args_t);
|
||||
pvdisplay_bytecount_t pv_formatter_last_written(pvformatter_args_t);
|
||||
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 (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);
|
||||
@@ -399,14 +621,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
|
||||
|
||||
+27
-14
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions used across the program.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -45,8 +45,9 @@ typedef struct pvstate_s *pvstate_t;
|
||||
* Valid number types for pv_getnum_check().
|
||||
*/
|
||||
typedef enum {
|
||||
PV_NUMTYPE_INTEGER,
|
||||
PV_NUMTYPE_DOUBLE
|
||||
PV_NUMTYPE_ANY_WITH_SUFFIX,
|
||||
PV_NUMTYPE_BARE_INTEGER,
|
||||
PV_NUMTYPE_BARE_DOUBLE
|
||||
} pv_numtype;
|
||||
|
||||
|
||||
@@ -54,6 +55,11 @@ typedef enum {
|
||||
* Simple string functions for processing numbers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return true if the character is an ASCII digit.
|
||||
*/
|
||||
extern bool pv_isdigit(char);
|
||||
|
||||
/*
|
||||
* Return the given string converted to a double, for use as a time
|
||||
* interval.
|
||||
@@ -80,11 +86,11 @@ extern unsigned int pv_getnum_count(const char *, bool);
|
||||
extern bool pv_getnum_check(const char *, pv_numtype);
|
||||
|
||||
/*
|
||||
* Return an integer representing the first amount as a percentage of the
|
||||
* Return a value representing the first amount as a percentage of the
|
||||
* second total, i.e. 100*amount/total. If the second value, the total, is
|
||||
* zero or less, return 0.
|
||||
*/
|
||||
extern int pv_percentage(off_t, const off_t);
|
||||
extern double pv_percentage(off_t, const off_t);
|
||||
|
||||
/*
|
||||
* String handling wrappers.
|
||||
@@ -120,6 +126,11 @@ extern size_t pv_strlcat(char *, const char *, size_t);
|
||||
*/
|
||||
extern size_t pv_strwidth(const char *, size_t);
|
||||
|
||||
/*
|
||||
* Return true if the character is printable.
|
||||
*/
|
||||
extern bool pv_isprint(char);
|
||||
|
||||
/*
|
||||
* Functions relating to elapsed time.
|
||||
*/
|
||||
@@ -164,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.
|
||||
@@ -205,6 +221,7 @@ extern void pv_state_error_skip_block_set(pvstate_t, off_t);
|
||||
extern void pv_state_stop_at_size_set(pvstate_t, bool);
|
||||
extern void pv_state_sync_after_write_set(pvstate_t, bool);
|
||||
extern void pv_state_direct_io_set(pvstate_t, bool);
|
||||
extern void pv_state_sparse_output_set(pvstate_t, bool);
|
||||
extern void pv_state_rate_limit_set(pvstate_t, off_t);
|
||||
extern void pv_state_target_buffer_size_set(pvstate_t, size_t);
|
||||
extern void pv_state_no_splice_set(pvstate_t, bool);
|
||||
@@ -214,14 +231,15 @@ extern void pv_state_interval_set(pvstate_t, double);
|
||||
extern void pv_state_width_set(pvstate_t, unsigned int, bool);
|
||||
extern void pv_state_height_set(pvstate_t, unsigned int, bool);
|
||||
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_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.
|
||||
@@ -256,15 +274,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.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Output debugging information.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
+8
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Output command-line help to stdout.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -308,6 +308,9 @@ void display_help(void)
|
||||
{ "-N", "--name", N_("NAME"),
|
||||
N_("prefix visual information with NAME"),
|
||||
{ 0, 0, 0, 0} },
|
||||
{ "-u", "--bar-style", N_("STYLE"),
|
||||
N_("set default bar style to NAME"),
|
||||
{ 0, 0, 0, 0} },
|
||||
{ "-x", "--extra-display", N_("SPEC"),
|
||||
N_("also send progress to SPEC"),
|
||||
{ 0, 0, 0, 0} },
|
||||
@@ -348,13 +351,16 @@ void display_help(void)
|
||||
{ "-K", "--direct-io", NULL,
|
||||
N_("use direct I/O to bypass cache"),
|
||||
{ 0, 0, 0, 0} },
|
||||
{ "-O", "--sparse", NULL,
|
||||
N_("try to seek instead of writing null bytes"),
|
||||
{ 0, 0, 0, 0} },
|
||||
{ "-X", "--discard", NULL,
|
||||
N_("discard input instead of writing to output"),
|
||||
{ 0, 0, 0, 0} },
|
||||
{ "-U", "--store-and-forward", N_("FILE"),
|
||||
N_("write all input to FILE before writing to output"),
|
||||
{ 0, 0, 0, 0} },
|
||||
{ "-d", "--watchfd", N_("PID[:FD]"),
|
||||
{ "-d", "--watchfd", N_("PID[:FD]|=NAME|@LISTFILE"),
|
||||
N_("watch file FD opened by process PID"),
|
||||
{ 0, 0, 0, 0} },
|
||||
#ifdef PV_REMOTE_CONTROL
|
||||
|
||||
+46
-14
@@ -2,7 +2,7 @@
|
||||
* Main program entry point - read the command line options, then perform
|
||||
* the appropriate actions.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -19,7 +19,9 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
int pv_remote_set(opts_t, pvstate_t);
|
||||
void pv_remote_init(void);
|
||||
@@ -279,6 +281,7 @@ int main(int argc, char **argv)
|
||||
/*@only@ */ pvstate_t state = NULL;
|
||||
int retcode = 0;
|
||||
bool can_have_eta = true;
|
||||
bool terminal_supports_utf8 = false;
|
||||
|
||||
#if ! HAVE_SETPROCTITLE
|
||||
initproctitle(argc, argv);
|
||||
@@ -289,6 +292,12 @@ int main(int argc, char **argv)
|
||||
(void) setlocale(LC_ALL, "");
|
||||
(void) bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
(void) textdomain(PACKAGE);
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
/*@-mustfreefresh@ *//* splint thinks nl_langinfo() leaks memory */
|
||||
if (0 == strcmp(nl_langinfo(CODESET), "UTF-8"))
|
||||
terminal_supports_utf8 = true;
|
||||
/*@+mustfreefresh@ */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Parse the command line arguments. */
|
||||
@@ -299,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@ */
|
||||
/*
|
||||
@@ -372,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.
|
||||
@@ -426,7 +448,12 @@ int main(int argc, char **argv)
|
||||
* do this before looking at setting the size, as the size
|
||||
* calculation looks at the output file if the input size can't be
|
||||
* calculated (issue #91).
|
||||
*
|
||||
* We have to set the sparse output flag before doing this, so that
|
||||
* in sparse mode the lseek() on O_APPEND can be done (issue #45);
|
||||
* see the comments in pv_state_output_set() in src/pv/state.c.
|
||||
*/
|
||||
pv_state_sparse_output_set(state, opts->sparse_output);
|
||||
retcode = pv__set_output(state, opts, opts->output);
|
||||
if (0 != retcode) {
|
||||
pv_state_free(state);
|
||||
@@ -443,7 +470,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.
|
||||
*/
|
||||
@@ -493,36 +520,41 @@ int main(int argc, char **argv)
|
||||
pv_state_no_splice_set(state, opts->no_splice);
|
||||
pv_state_size_set(state, opts->size);
|
||||
pv_state_name_set(state, opts->name);
|
||||
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", "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. */
|
||||
|
||||
+412
-33
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Parse command-line options.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
@@ -57,10 +66,16 @@ void opts_free( /*@only@ */ opts_t opts)
|
||||
free(opts->pidfile);
|
||||
if (NULL != opts->output)
|
||||
free(opts->output);
|
||||
if (NULL != opts->default_bar_style)
|
||||
free(opts->default_bar_style);
|
||||
if (NULL != opts->store_and_forward_file)
|
||||
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@ */
|
||||
@@ -102,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,
|
||||
@@ -134,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;
|
||||
@@ -296,6 +600,7 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
{ "width", 1, NULL, (int) 'w' },
|
||||
{ "height", 1, NULL, (int) 'H' },
|
||||
{ "name", 1, NULL, (int) 'N' },
|
||||
{ "bar-style", 1, NULL, (int) 'u' },
|
||||
{ "format", 1, NULL, (int) 'F' },
|
||||
{ "extra-display", 1, NULL, (int) 'x' },
|
||||
{ "stats", 0, NULL, (int) 'v' },
|
||||
@@ -307,6 +612,8 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
{ "stop-at-size", 0, NULL, (int) 'S' },
|
||||
{ "sync", 0, NULL, (int) 'Y' },
|
||||
{ "direct-io", 0, NULL, (int) 'K' },
|
||||
{ "sparse", 0, NULL, (int) 'O' },
|
||||
{ "sparse-output", 0, NULL, (int) 'O' },
|
||||
{ "discard", 0, NULL, (int) 'X' },
|
||||
{ "store-and-forward", 1, NULL, (int) 'U' },
|
||||
{ "remote", 1, NULL, (int) 'R' },
|
||||
@@ -322,14 +629,14 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
/*@+nullassign@ */
|
||||
int option_index = 0;
|
||||
#endif /* HAVE_GETOPT_LONG */
|
||||
char *short_options = "hVpteIrab8kTA:fvnqcWD:s:gl0i:w:H:N:F:x:L:B:CEZ:SYKXU:R:P:d:m:o:"
|
||||
char *short_options = "hVpteIrab8kTA:fvnqcWD:s:gl0i:w:H:N:u:F:x:L:B:CEZ:SYKOXU:R:P:d:m:o:"
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
"!:"
|
||||
#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;
|
||||
|
||||
@@ -369,10 +676,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;
|
||||
@@ -405,24 +711,33 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
break;
|
||||
/* falls through */
|
||||
/*@fallthrough@ */
|
||||
case 'L':
|
||||
/*@fallthrough@ */
|
||||
case 'B':
|
||||
/*@fallthrough@ */
|
||||
case 'Z':
|
||||
if (!pv_getnum_check(optarg, PV_NUMTYPE_ANY_WITH_SUFFIX)) {
|
||||
/*@-mustfreefresh@ *//* see above */
|
||||
fprintf(stderr, "%s: -%c: %s: %s\n", opts->program_name, c, optarg,
|
||||
_("numeric value not understood"));
|
||||
opts_free(opts);
|
||||
return NULL;
|
||||
/*@+mustfreefresh@ */
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
/*@fallthrough@ */
|
||||
case 'w':
|
||||
/*@fallthrough@ */
|
||||
case 'H':
|
||||
/*@fallthrough@ */
|
||||
case 'L':
|
||||
/*@fallthrough@ */
|
||||
case 'B':
|
||||
/*@fallthrough@ */
|
||||
case 'R':
|
||||
/*@fallthrough@ */
|
||||
case 'm':
|
||||
/*@fallthrough@ */
|
||||
case 'Z':
|
||||
if (!pv_getnum_check(optarg, PV_NUMTYPE_INTEGER)) {
|
||||
if (!pv_getnum_check(optarg, PV_NUMTYPE_BARE_INTEGER)) {
|
||||
/*@-mustfreefresh@ *//* see above */
|
||||
fprintf(stderr, "%s: -%c: %s\n", opts->program_name, c, _("integer argument expected"));
|
||||
fprintf(stderr, "%s: -%c: %s: %s\n", opts->program_name, c, optarg,
|
||||
_("integer argument expected"));
|
||||
opts_free(opts);
|
||||
return NULL;
|
||||
/*@+mustfreefresh@ */
|
||||
@@ -431,17 +746,59 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
case 'i':
|
||||
/*@fallthrough@ */
|
||||
case 'D':
|
||||
if (!pv_getnum_check(optarg, PV_NUMTYPE_DOUBLE)) {
|
||||
if (!pv_getnum_check(optarg, PV_NUMTYPE_BARE_DOUBLE)) {
|
||||
/*@-mustfreefresh@ *//* see above */
|
||||
fprintf(stderr, "%s: -%c: %s\n", opts->program_name, c, _("numeric argument expected"));
|
||||
fprintf(stderr, "%s: -%c: %s: %s\n", opts->program_name, c, optarg,
|
||||
_("numeric argument expected"));
|
||||
opts_free(opts);
|
||||
return NULL;
|
||||
/*@+mustfreefresh@ */
|
||||
}
|
||||
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"));
|
||||
@@ -467,11 +824,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;
|
||||
@@ -584,6 +941,14 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
opts->default_bar_style = pv_strdup(optarg);
|
||||
if (NULL == opts->default_bar_style) {
|
||||
fprintf(stderr, "%s: -u: %s\n", opts->program_name, strerror(errno));
|
||||
opts_free(opts);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
opts->rate_limit = pv_getnum_size(optarg, opts->decimal_units);
|
||||
break;
|
||||
@@ -609,6 +974,10 @@ opts_t opts_parse(unsigned int argc, char **argv)
|
||||
case 'K':
|
||||
opts->direct_io = true;
|
||||
break;
|
||||
case 'O':
|
||||
opts->sparse_output = true;
|
||||
opts->no_splice = true;
|
||||
break;
|
||||
case 'X':
|
||||
opts->discard_input = true;
|
||||
opts->no_splice = true;
|
||||
@@ -620,6 +989,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);
|
||||
@@ -649,12 +1019,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);
|
||||
@@ -703,7 +1072,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)) {
|
||||
@@ -733,14 +1102,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 */
|
||||
/*
|
||||
|
||||
+21
-17
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Remote-control functions.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Output version information to stdout.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -23,7 +23,7 @@ void display_version(void)
|
||||
/* GNU standard first line format: program and version only */
|
||||
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
|
||||
/* GNU standard second line format - "Copyright" always in English */
|
||||
printf("Copyright %s %s\n", "2024", "Andrew Wood");
|
||||
printf("Copyright %s %s\n", "2025", "Andrew Wood");
|
||||
/* GNU standard license line and free software notice */
|
||||
printf("%s\n", _("License: GPLv3+ <https://www.gnu.org/licenses/gpl-3.0.html>"));
|
||||
printf("%s\n", _("This is free software: you are free to change and redistribute it."));
|
||||
|
||||
+73
-62
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for updating the calculated state of the transfer.
|
||||
*
|
||||
* Copyright 2024 Andrew Wood
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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)
|
||||
state->calc.percentage = 0;
|
||||
if (state->calc.percentage > 100000)
|
||||
state->calc.percentage = 100000;
|
||||
if (calc->percentage < 0.0)
|
||||
calc->percentage = 0.0;
|
||||
if (calc->percentage > 100000.0)
|
||||
calc->percentage = 100000.0;
|
||||
}
|
||||
|
||||
+147
-140
@@ -10,7 +10,7 @@
|
||||
* terminal, so we try to use a lockfile if terminal locking doesn't work,
|
||||
* and finally abort if even that is unavailable.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+437
-985
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions relating to elapsed time.
|
||||
*
|
||||
* Copyright 2023-2024 Andrew Wood
|
||||
* Copyright 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
+31
-14
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for opening and closing files, and calculating their size.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Formatter function for average rate.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Average transfer rate.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_average_rate(pvformatter_args_t args)
|
||||
{
|
||||
char content[128]; /* flawfinder: ignore - always bounded */
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
/*@-mustfreefresh@ */
|
||||
if (args->control->numeric) {
|
||||
/* numeric - raw value without suffix. */
|
||||
(void) pv_snprintf(content, sizeof(content),
|
||||
"%.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->calc->average_rate, "", _("b/s"), args->display->count_type);
|
||||
} else {
|
||||
/* bytes or lines per second */
|
||||
pv_describe_amount(content,
|
||||
sizeof(content), "(%s)", args->calc->average_rate, _("/s"), _("B/s"),
|
||||
args->display->count_type);
|
||||
}
|
||||
/*@+mustfreefresh@ *//* splint: see above. */
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Formatter functions for styled progress bars.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <string.h>
|
||||
#if defined(ENABLE_NLS) && defined(HAVE_WCHAR_H)
|
||||
#include <wchar.h>
|
||||
#if defined(HAVE_WCTYPE_H)
|
||||
#include <wctype.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Populate "style" with the named bar style, falling back to plain if the
|
||||
* name was not recognised. Returns true if the named style was found.
|
||||
*
|
||||
* Note that strings are copied into the structure, rather than just
|
||||
* updating pointers, to maintain separation of concern between different
|
||||
* parts of the code - and because on 64-bit architectures, the sizes of the
|
||||
* data types and their associated alignment padding tend to outweigh the
|
||||
* memory savings from using pointers and shared strings.
|
||||
*/
|
||||
static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char *name)
|
||||
{
|
||||
#define populate_string(item, str, w) { \
|
||||
item.width = w; \
|
||||
item.bytes = strlen(str); /* flawfinder: ignore */ \
|
||||
if (item.bytes > 0 && item.bytes <= PV_BARSTYLE_SIZEOF_STRING) \
|
||||
memcpy(item.string, str, item.bytes); /* flawfinder: ignore */ \
|
||||
}
|
||||
/*
|
||||
* flawfinder - strlen() on null-terminated static strings is OK,
|
||||
* and with the memcpy(), we check the buffer is big enough.
|
||||
*/
|
||||
|
||||
memset(style, 0, sizeof(*style));
|
||||
|
||||
if (args->status->terminal_supports_utf8 && 0 == strcmp(name, "block")) {
|
||||
|
||||
style->style_id = 2;
|
||||
|
||||
populate_string(style->indicator, "◀▶", 2);
|
||||
populate_string(style->tip, "", 0);
|
||||
|
||||
populate_string(style->filler[0], " ", 1);
|
||||
populate_string(style->filler[1], "█", 1);
|
||||
|
||||
style->filler_entries = 2;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (args->status->terminal_supports_utf8 && 0 == strcmp(name, "granular")) {
|
||||
|
||||
style->style_id = 3;
|
||||
|
||||
populate_string(style->indicator, "◀▶", 2);
|
||||
populate_string(style->tip, "", 0);
|
||||
|
||||
populate_string(style->filler[0], " ", 1);
|
||||
populate_string(style->filler[1], "▏", 1);
|
||||
populate_string(style->filler[2], "▎", 1);
|
||||
populate_string(style->filler[3], "▍", 1);
|
||||
populate_string(style->filler[4], "▌", 1);
|
||||
populate_string(style->filler[5], "▋", 1);
|
||||
populate_string(style->filler[6], "▊", 1);
|
||||
populate_string(style->filler[7], "▉", 1);
|
||||
populate_string(style->filler[8], "█", 1);
|
||||
|
||||
style->filler_entries = 9;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (args->status->terminal_supports_utf8 && 0 == strcmp(name, "shaded")) {
|
||||
|
||||
style->style_id = 4;
|
||||
|
||||
populate_string(style->indicator, "▒▓▒", 3);
|
||||
populate_string(style->tip, "", 0);
|
||||
|
||||
populate_string(style->filler[0], "░", 1);
|
||||
populate_string(style->filler[1], "▒", 1);
|
||||
populate_string(style->filler[2], "▓", 1);
|
||||
populate_string(style->filler[3], "█", 1);
|
||||
|
||||
style->filler_entries = 4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Default plain style. */
|
||||
|
||||
style->style_id = 1;
|
||||
|
||||
populate_string(style->indicator, "<=>", 3);
|
||||
populate_string(style->tip, ">", 1);
|
||||
|
||||
populate_string(style->filler[0], " ", 1);
|
||||
populate_string(style->filler[1], "=", 1);
|
||||
|
||||
style->filler_entries = 2;
|
||||
|
||||
if (0 == strcmp(name, "plain"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the index into args->display->barstyle for the style with the
|
||||
* given name, adding that style to the array if it's not there already and
|
||||
* there's room.
|
||||
*
|
||||
* If there is no room, returns zero, so the first style is re-used.
|
||||
*/
|
||||
int8_t pv_display_barstyle_index(pvformatter_args_t args, const char *name)
|
||||
{
|
||||
struct pvbarstyle_s style;
|
||||
int8_t barstyle_index;
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
bool found;
|
||||
#endif
|
||||
|
||||
memset(&style, 0, sizeof(style));
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
found = pv_barstyle(args, &style, name);
|
||||
if (!found)
|
||||
debug("%s: %s", name, "bar style not found, using plain");
|
||||
#else
|
||||
(void) pv_barstyle(args, &style, name);
|
||||
#endif
|
||||
|
||||
for (barstyle_index = 0;
|
||||
barstyle_index < PV_BARSTYLE_MAX && args->display->barstyle[barstyle_index].style_id > 0;
|
||||
barstyle_index++) {
|
||||
if (args->display->barstyle[barstyle_index].style_id == style.style_id) {
|
||||
debug("%s: %s: %d", name, "found in bar style array", barstyle_index);
|
||||
return barstyle_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (barstyle_index >= PV_BARSTYLE_MAX) {
|
||||
debug("%s: %s", name, "no room to add another bar style - returning 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&(args->display->barstyle[barstyle_index]), &style, sizeof(style)); /* flawfinder: ignore */
|
||||
/* flawfinder - the destination is an array element of the right size. */
|
||||
debug("%s: %s: %d", name, "added to bar style array", barstyle_index);
|
||||
return barstyle_index;
|
||||
}
|
||||
|
||||
|
||||
pvdisplay_bytecount_t pv_formatter_bar_default(pvformatter_args_t args)
|
||||
{
|
||||
if (0 == args->segment->parameter) {
|
||||
const char *default_name;
|
||||
default_name = args->control->default_bar_style;
|
||||
/*@-branchstate@ */
|
||||
if (NULL == default_name)
|
||||
default_name = "plain";
|
||||
/*@+branchstate@ */
|
||||
/* splint - it doesn't matter that default_name may be static */
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, default_name);
|
||||
}
|
||||
return pv_formatter_progress_bar_only(args);
|
||||
}
|
||||
|
||||
pvdisplay_bytecount_t pv_formatter_bar_plain(pvformatter_args_t args)
|
||||
{
|
||||
if (0 == args->segment->parameter)
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, "plain");
|
||||
return pv_formatter_progress_bar_only(args);
|
||||
}
|
||||
|
||||
pvdisplay_bytecount_t pv_formatter_bar_block(pvformatter_args_t args)
|
||||
{
|
||||
if (0 == args->segment->parameter)
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, "block");
|
||||
return pv_formatter_progress_bar_only(args);
|
||||
}
|
||||
|
||||
pvdisplay_bytecount_t pv_formatter_bar_granular(pvformatter_args_t args)
|
||||
{
|
||||
if (0 == args->segment->parameter)
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, "granular");
|
||||
return pv_formatter_progress_bar_only(args);
|
||||
}
|
||||
|
||||
pvdisplay_bytecount_t pv_formatter_bar_shaded(pvformatter_args_t args)
|
||||
{
|
||||
if (0 == args->segment->parameter)
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, "shaded");
|
||||
return pv_formatter_progress_bar_only(args);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Formatter function for transfer buffer percentage utilisation.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Percentage transfer buffer utilisation.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_buffer_percent(pvformatter_args_t args)
|
||||
{
|
||||
char content[16]; /* flawfinder: ignore - always bounded */
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
if (args->transfer->buffer_size > 0) {
|
||||
double pct_used = pv_percentage((off_t)
|
||||
(args->transfer->read_position - args->transfer->write_position),
|
||||
(off_t)
|
||||
(args->transfer->buffer_size));
|
||||
(void) pv_snprintf(content, sizeof(content), "{%3.0f%%}", pct_used);
|
||||
}
|
||||
#ifdef HAVE_SPLICE
|
||||
if (args->transfer->splice_used)
|
||||
(void) pv_snprintf(content, sizeof(content), "{%s}", "----");
|
||||
#endif
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Formatter function for bytes or lines transferred.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Number of bytes or lines transferred.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_bytes(pvformatter_args_t args)
|
||||
{
|
||||
char content[128]; /* flawfinder: ignore - always bounded */
|
||||
|
||||
args->display->showing_bytes = true;
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
/*@-mustfreefresh@ */
|
||||
if (args->control->numeric) {
|
||||
/* Numeric mode - raw values only, no suffix. */
|
||||
(void) pv_snprintf(content, sizeof(content),
|
||||
"%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->transfer->transferred * 8), "", _("b"),
|
||||
args->display->count_type);
|
||||
} else {
|
||||
pv_describe_amount(content, sizeof(content), "%s",
|
||||
(long double) (args->transfer->transferred), "", _("B"), args->display->count_type);
|
||||
}
|
||||
/*@+mustfreefresh@ *//* splint - false positive from gettext(). */
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Formatter function for ETA display.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Estimated time until completion.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_eta(pvformatter_args_t args)
|
||||
{
|
||||
char content[128]; /* flawfinder: ignore - always bounded */
|
||||
long eta;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
/*
|
||||
* Don't try to calculate this if the size is not known.
|
||||
*/
|
||||
if (args->control->size < 1)
|
||||
return 0;
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
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, so we don't overrun the suffix buffer. This means
|
||||
* the ETA will always be less than 100,000 hours.
|
||||
*/
|
||||
eta = pv_bound_long(eta, 0, (long) 360000000L);
|
||||
|
||||
/*
|
||||
* If the ETA is more than a day, include a day count as well as
|
||||
* hours, minutes, and seconds.
|
||||
*/
|
||||
/*@-mustfreefresh@ */
|
||||
if (eta > 86400L) {
|
||||
(void) pv_snprintf(content,
|
||||
sizeof(content),
|
||||
"%.16s %ld:%02ld:%02ld:%02ld",
|
||||
_("ETA"), eta / 86400, (eta / 3600) % 24, (eta / 60) % 60, eta % 60);
|
||||
} else {
|
||||
(void) pv_snprintf(content,
|
||||
sizeof(content),
|
||||
"%.16s %ld:%02ld:%02ld", _("ETA"), eta / 3600, (eta / 60) % 60, eta % 60);
|
||||
}
|
||||
/*@+mustfreefresh@ *//* splint: see above. */
|
||||
|
||||
/*
|
||||
* If this is the final update, show a blank space where the ETA
|
||||
* used to be.
|
||||
*/
|
||||
if (args->display->final_update) {
|
||||
size_t erase_idx;
|
||||
for (erase_idx = 0; erase_idx < sizeof(content) && content[erase_idx] != '\0'; erase_idx++) {
|
||||
content[erase_idx] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Formatter function for the local time at which the transfer is expected
|
||||
* to complete.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/*
|
||||
* Estimated local time of completion.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_fineta(pvformatter_args_t args)
|
||||
{
|
||||
char content[128]; /* flawfinder: ignore - always bounded */
|
||||
time_t now, then;
|
||||
struct tm *time_ptr;
|
||||
long eta;
|
||||
const char *time_format;
|
||||
bool show_fineta;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
/*
|
||||
* Don't try to calculate this if the size is not known.
|
||||
*/
|
||||
if (args->control->size < 1)
|
||||
return 0;
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
now = time(NULL);
|
||||
show_fineta = true;
|
||||
time_format = NULL;
|
||||
|
||||
/*
|
||||
* The completion clock time may be hidden by a failed localtime
|
||||
* lookup.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Only include the date if the ETA is more than 6 hours
|
||||
* away.
|
||||
*/
|
||||
if (eta > (long) (6 * 3600)) {
|
||||
time_format = "%Y-%m-%d %H:%M:%S";
|
||||
} else {
|
||||
time_format = "%H:%M:%S";
|
||||
}
|
||||
|
||||
then = now + eta;
|
||||
time_ptr = localtime(&then);
|
||||
|
||||
if (NULL == time_ptr) {
|
||||
show_fineta = false;
|
||||
} else {
|
||||
/*
|
||||
* The localtime() function keeps data stored in a static
|
||||
* buffer that gets overwritten by time functions.
|
||||
*/
|
||||
struct tm time = *time_ptr;
|
||||
size_t content_bytes;
|
||||
|
||||
/*@-mustfreefresh@ */
|
||||
(void) pv_snprintf(content, sizeof(content), "%.16s ", _("FIN"));
|
||||
/*@+mustfreefresh@ *//* splint: see above. */
|
||||
content_bytes = strlen(content); /* flawfinder: ignore */
|
||||
/* flawfinder: always bounded with \0 by pv_snprintf(). */
|
||||
(void) strftime(content + content_bytes, sizeof(content) - 1 - content_bytes, time_format, &time);
|
||||
}
|
||||
|
||||
if (!show_fineta) {
|
||||
size_t erase_idx;
|
||||
for (erase_idx = 0; erase_idx < sizeof(content) && content[erase_idx] != '\0'; erase_idx++) {
|
||||
content[erase_idx] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Formatter function for showing the last bytes written.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Display the last few bytes written.
|
||||
*
|
||||
* As a side effect, this sets args->display->lastwritten_bytes to
|
||||
* the segment's chosen_size, if it was previously smaller than that.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_last_written(pvformatter_args_t args)
|
||||
{
|
||||
pvdisplay_bytecount_t bytes_to_show, read_offset, write_offset, remaining;
|
||||
|
||||
args->display->showing_last_written = true;
|
||||
|
||||
bytes_to_show = args->segment->chosen_size;
|
||||
if (0 == bytes_to_show)
|
||||
bytes_to_show = args->segment->width;
|
||||
if (0 == bytes_to_show)
|
||||
return 0;
|
||||
|
||||
if (bytes_to_show > PV_SIZEOF_LASTWRITTEN_BUFFER)
|
||||
bytes_to_show = PV_SIZEOF_LASTWRITTEN_BUFFER;
|
||||
if (bytes_to_show > args->display->lastwritten_bytes)
|
||||
args->display->lastwritten_bytes = bytes_to_show;
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
if (args->offset + bytes_to_show >= args->buffer_size)
|
||||
return 0;
|
||||
|
||||
args->segment->offset = args->offset;
|
||||
args->segment->bytes = bytes_to_show;
|
||||
|
||||
read_offset = args->display->lastwritten_bytes - bytes_to_show;
|
||||
write_offset = args->offset;
|
||||
for (remaining = bytes_to_show; remaining > 0; remaining--) {
|
||||
char display_char = args->display->lastwritten_buffer[read_offset++];
|
||||
args->buffer[write_offset++] = pv_isprint(display_char) ? display_char : '.';
|
||||
}
|
||||
|
||||
return bytes_to_show;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Formatter function for showing the name of the transfer.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* Display the transfer's name.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_name(pvformatter_args_t args)
|
||||
{
|
||||
char string_format[32]; /* flawfinder: ignore - always bounded */
|
||||
char content[512]; /* flawfinder: ignore - always bounded */
|
||||
pvdisplay_bytecount_t field_width;
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
field_width = args->segment->chosen_size;
|
||||
if (field_width < 1)
|
||||
field_width = 9;
|
||||
if (field_width > 500)
|
||||
field_width = 500;
|
||||
|
||||
memset(string_format, 0, sizeof(string_format));
|
||||
(void) pv_snprintf(string_format, sizeof(string_format), "%%%d.500s:", field_width);
|
||||
|
||||
content[0] = '\0';
|
||||
if (NULL != args->control->name) {
|
||||
(void) pv_snprintf(content, sizeof(content), string_format, args->control->name);
|
||||
}
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Formatter function for the most recently written line.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Display the previously written line.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_previous_line(pvformatter_args_t args)
|
||||
{
|
||||
pvdisplay_bytecount_t bytes_to_show, read_offset, write_offset, remaining;
|
||||
|
||||
args->display->showing_previous_line = true;
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
bytes_to_show = args->segment->chosen_size;
|
||||
if (0 == bytes_to_show)
|
||||
bytes_to_show = args->segment->width;
|
||||
if (0 == bytes_to_show)
|
||||
return 0;
|
||||
|
||||
if (bytes_to_show > PV_SIZEOF_PREVLINE_BUFFER)
|
||||
bytes_to_show = PV_SIZEOF_PREVLINE_BUFFER;
|
||||
|
||||
if (args->offset + bytes_to_show >= args->buffer_size)
|
||||
return 0;
|
||||
|
||||
args->segment->offset = args->offset;
|
||||
args->segment->bytes = bytes_to_show;
|
||||
|
||||
read_offset = 0;
|
||||
write_offset = args->offset;
|
||||
for (remaining = bytes_to_show; remaining > 0; remaining--) {
|
||||
char display_char = args->display->previous_line[read_offset++];
|
||||
args->buffer[write_offset++] = pv_isprint(display_char) ? display_char : ' ';
|
||||
}
|
||||
|
||||
return bytes_to_show;
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Formatter functions for progress bars.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_MATH_H
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/* Convenience macro for appending a string to the buffer. */
|
||||
#define append_to_buffer(x) { \
|
||||
if (buffer_offset < (buffer_size - x.bytes)) { \
|
||||
memcpy(&(buffer[buffer_offset]), x.string, x.bytes); /* flawfinder: ignore */ \
|
||||
buffer_offset += x.bytes; \
|
||||
} \
|
||||
}
|
||||
/*
|
||||
* flawfinder - we are checking that there is room in the destination
|
||||
* buffer, given its size and our current offset.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Write a progress bar to a buffer, in known-size or rate-gauge mode - a
|
||||
* bar, and a percentage (size) or max rate (gauge). The total width of the
|
||||
* content is bounded to the given width. Returns the number of bytes
|
||||
* written to the buffer.
|
||||
*
|
||||
* If "bar_sides" is false, only the bar itself is rendered, not the opening
|
||||
* and closing characters.
|
||||
*
|
||||
* If "include_bar" is false, the bar is omitted entirely.
|
||||
*
|
||||
* If "include_amount" is false, the percentage or rate after the bar is
|
||||
* omitted.
|
||||
*
|
||||
* This is only called by pv_formatter_progress().
|
||||
*/
|
||||
static pvdisplay_bytecount_t pv_formatter_progress_knownsize(pvformatter_args_t args, char *buffer,
|
||||
pvdisplay_bytecount_t buffer_size, bool bar_sides,
|
||||
bool include_bar, bool include_amount)
|
||||
{
|
||||
char after_bar[32]; /* flawfinder: ignore - only populated by pv_snprintf(). */
|
||||
pvdisplay_bytecount_t after_bar_bytes, buffer_offset;
|
||||
pvdisplay_width_t after_bar_width;
|
||||
pvdisplay_width_t bar_area_width, filled_bar_width, pad_count;
|
||||
double bar_percentage;
|
||||
pvbarstyle_t style;
|
||||
pvdisplay_bytecount_t full_cell_index;
|
||||
bool has_tip = false;
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (args->segment->parameter > 0 && args->segment->parameter <= PV_BARSTYLE_MAX) {
|
||||
style = &(args->display->barstyle[args->segment->parameter - 1]);
|
||||
} else {
|
||||
style = &(args->display->barstyle[0]);
|
||||
}
|
||||
|
||||
full_cell_index = style->filler_entries;
|
||||
if (full_cell_index > 0)
|
||||
full_cell_index--;
|
||||
if (1 == full_cell_index && style->tip.width > 0)
|
||||
has_tip = true;
|
||||
|
||||
memset(after_bar, 0, sizeof(after_bar));
|
||||
|
||||
if (args->control->size > 0) {
|
||||
/* Percentage of data transferred. */
|
||||
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->calc->rate_max > 0) {
|
||||
bar_percentage = (double) (100.0 * args->calc->transfer_rate / args->calc->rate_max);
|
||||
}
|
||||
|
||||
/*@-mustfreefresh@ */
|
||||
if (args->control->bits && !args->control->linemode) {
|
||||
/* bits per second */
|
||||
pv_describe_amount(after_bar, sizeof(after_bar), "/%s",
|
||||
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->calc->rate_max, _("/s"), _("B/s"), args->display->count_type);
|
||||
}
|
||||
/*@+mustfreefresh@ *//* splint: see above about gettext(). */
|
||||
}
|
||||
|
||||
if (!include_amount)
|
||||
after_bar[0] = '\0';
|
||||
|
||||
after_bar_bytes = strlen(after_bar); /* flawfinder: ignore */
|
||||
/* flawfinder: always \0-terminated by pv_snprintf() and the earlier memset(). */
|
||||
after_bar_width = pv_strwidth(after_bar, after_bar_bytes);
|
||||
|
||||
if (!include_bar) {
|
||||
/*
|
||||
* Only returning the "after bar" portion - the amount
|
||||
* (progress or max rate).
|
||||
*/
|
||||
if (buffer_size < after_bar_bytes)
|
||||
return 0;
|
||||
if (after_bar_bytes > 1) {
|
||||
/* NB we skip the leading space. */
|
||||
memmove(buffer, after_bar + 1, after_bar_bytes - 1);
|
||||
buffer[after_bar_bytes - 1] = '\0';
|
||||
return after_bar_bytes - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bar_sides) {
|
||||
if (args->segment->width < (after_bar_width + 2))
|
||||
return 0;
|
||||
bar_area_width = args->segment->width - after_bar_width - 2;
|
||||
} else {
|
||||
if (args->segment->width < after_bar_width)
|
||||
return 0;
|
||||
bar_area_width = args->segment->width - after_bar_width;
|
||||
}
|
||||
|
||||
filled_bar_width = (pvdisplay_width_t) ((bar_area_width * bar_percentage) / 100);
|
||||
/* Leave room for the tip of the bar. */
|
||||
if (has_tip && filled_bar_width > 0)
|
||||
filled_bar_width -= style->tip.width;
|
||||
|
||||
debug("percentage=%.2f width=%d bar_area_width=%d filled_bar_width=%d after_bar_width=%d", bar_percentage,
|
||||
args->segment->width, bar_area_width, filled_bar_width, after_bar_width);
|
||||
|
||||
buffer_offset = 0;
|
||||
|
||||
if (bar_sides) {
|
||||
/* The opening of the bar area. */
|
||||
buffer[buffer_offset++] = '[';
|
||||
}
|
||||
|
||||
/* The bar portion. */
|
||||
pad_count = 0;
|
||||
while (pad_count < filled_bar_width && pad_count < bar_area_width) {
|
||||
append_to_buffer(style->filler[full_cell_index]);
|
||||
pad_count += style->filler[full_cell_index].width;
|
||||
if (0 == style->filler[full_cell_index].width)
|
||||
pad_count++;
|
||||
}
|
||||
|
||||
/* The tip of the bar, if not at 100%. */
|
||||
if (has_tip && pad_count < bar_area_width) {
|
||||
append_to_buffer(style->tip);
|
||||
pad_count += style->tip.width;
|
||||
}
|
||||
|
||||
/* A partial cell, if there are intermediates and we're not at 100%. */
|
||||
if (pad_count < bar_area_width && full_cell_index > 1 && !has_tip) {
|
||||
double exact_width = (((double) bar_area_width) * bar_percentage) / 100.0;
|
||||
double cell_portion = exact_width - (double) filled_bar_width;
|
||||
double cell_index_double = ((double) full_cell_index) * cell_portion;
|
||||
size_t cell_index = (size_t) cell_index_double;
|
||||
|
||||
if (cell_index > full_cell_index)
|
||||
cell_index = full_cell_index;
|
||||
|
||||
append_to_buffer(style->filler[cell_index]);
|
||||
pad_count += style->filler[cell_index].width;
|
||||
if (0 == style->filler[cell_index].width)
|
||||
pad_count++;
|
||||
}
|
||||
|
||||
/* The spaces after the bar. */
|
||||
while (pad_count < bar_area_width) {
|
||||
append_to_buffer(style->filler[0]);
|
||||
pad_count += style->filler[0].width;
|
||||
if (0 == style->filler[0].width)
|
||||
pad_count++;
|
||||
}
|
||||
|
||||
if (bar_sides) {
|
||||
/* The closure of the bar area. */
|
||||
if (buffer_offset < buffer_size - 1)
|
||||
buffer[buffer_offset++] = ']';
|
||||
}
|
||||
|
||||
/* The percentage. */
|
||||
if (after_bar_bytes > 0 && after_bar_bytes < (buffer_size - 1 - buffer_offset)) {
|
||||
memmove(buffer + buffer_offset, after_bar, after_bar_bytes);
|
||||
buffer_offset += after_bar_bytes;
|
||||
}
|
||||
|
||||
buffer[buffer_offset] = '\0';
|
||||
|
||||
return buffer_offset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write a progress bar to a buffer, in unknown-size mode - just a moving
|
||||
* indicator. The total width of the content is bounded to the given width.
|
||||
* Returns the number of bytes written to the buffer.
|
||||
*
|
||||
* If "bar_sides" is false, only the bar itself is rendered, not the opening
|
||||
* and closing characters.
|
||||
*
|
||||
* This is only called by pv_formatter_progress().
|
||||
*/
|
||||
static pvdisplay_bytecount_t pv_formatter_progress_unknownsize(pvformatter_args_t args, char *buffer,
|
||||
pvdisplay_bytecount_t buffer_size, bool bar_sides)
|
||||
{
|
||||
pvdisplay_bytecount_t buffer_offset;
|
||||
pvdisplay_width_t bar_area_width, pad_count;
|
||||
double indicator_position, padding_width;
|
||||
pvbarstyle_t style;
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (args->segment->parameter > 0 && args->segment->parameter <= PV_BARSTYLE_MAX) {
|
||||
style = &(args->display->barstyle[args->segment->parameter - 1]);
|
||||
} else {
|
||||
style = &(args->display->barstyle[0]);
|
||||
}
|
||||
|
||||
if (bar_sides) {
|
||||
if (args->segment->width < (style->indicator.width + 3))
|
||||
return 0;
|
||||
bar_area_width = args->segment->width - (style->indicator.width + 2);
|
||||
} else {
|
||||
if (args->segment->width < (style->indicator.width + 2))
|
||||
return 0;
|
||||
bar_area_width = args->segment->width - style->indicator.width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that pv_calculate_transfer_rate() sets the percentage when
|
||||
* the size is unknown to a value that goes 0 - 200 and resets, so
|
||||
* here we make values above 100 send the indicator back down again,
|
||||
* so it moves back and forth.
|
||||
*/
|
||||
indicator_position = args->calc->percentage;
|
||||
if (indicator_position > 200.0)
|
||||
#if HAVE_FMOD
|
||||
indicator_position = fmod(indicator_position, 200.0);
|
||||
#else
|
||||
{
|
||||
while (indicator_position > 200.0)
|
||||
indicator_position -= 200.0;
|
||||
}
|
||||
#endif
|
||||
if (indicator_position > 100.0)
|
||||
indicator_position = 200.0 - indicator_position;
|
||||
if (indicator_position < 0.0)
|
||||
indicator_position = 0.0;
|
||||
|
||||
buffer_offset = 0;
|
||||
|
||||
if (bar_sides) {
|
||||
/* The opening of the bar area. */
|
||||
buffer[buffer_offset++] = '[';
|
||||
}
|
||||
|
||||
/* The spaces before the indicator. */
|
||||
pad_count = 0;
|
||||
padding_width = (((double) bar_area_width) * indicator_position) / 100.0;
|
||||
while (pad_count < bar_area_width && pad_count < (pvdisplay_width_t) padding_width) {
|
||||
append_to_buffer(style->filler[0]);
|
||||
pad_count += style->filler[0].width;
|
||||
if (0 == style->filler[0].width)
|
||||
pad_count++;
|
||||
}
|
||||
|
||||
/* The indicator. */
|
||||
if (buffer_offset < buffer_size - style->indicator.bytes) {
|
||||
append_to_buffer(style->indicator);
|
||||
}
|
||||
|
||||
/* The spaces after the indicator. */
|
||||
while (pad_count < bar_area_width) {
|
||||
append_to_buffer(style->filler[0]);
|
||||
pad_count += style->filler[0].width;
|
||||
if (0 == style->filler[0].width)
|
||||
pad_count++;
|
||||
}
|
||||
|
||||
if (bar_sides) {
|
||||
/* The closure of the bar area. */
|
||||
if (buffer_offset < buffer_size - 1)
|
||||
buffer[buffer_offset++] = ']';
|
||||
}
|
||||
|
||||
buffer[buffer_offset] = '\0';
|
||||
|
||||
return buffer_offset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Progress bar.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_progress(pvformatter_args_t args)
|
||||
{
|
||||
char content[4096]; /* flawfinder: ignore - always bounded */
|
||||
pvdisplay_bytecount_t bytes;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
if (0 == args->segment->parameter) {
|
||||
const char *default_name;
|
||||
default_name = args->control->default_bar_style;
|
||||
/*@-branchstate@ */
|
||||
if (NULL == default_name)
|
||||
default_name = "plain";
|
||||
/*@+branchstate@ */
|
||||
/* splint - it doesn't matter that default_name may be static */
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, default_name);
|
||||
}
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
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 {
|
||||
/* Unknown size - back-and-forth moving indicator. */
|
||||
bytes = pv_formatter_progress_unknownsize(args, content, sizeof(content), true);
|
||||
}
|
||||
|
||||
content[bytes] = '\0';
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Progress bar, without sides and without a number afterwards.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_progress_bar_only(pvformatter_args_t args)
|
||||
{
|
||||
char content[4096]; /* flawfinder: ignore - always bounded */
|
||||
pvdisplay_bytecount_t bytes;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
if (0 == args->segment->parameter) {
|
||||
const char *default_name;
|
||||
default_name = args->control->default_bar_style;
|
||||
/*@-branchstate@ */
|
||||
if (NULL == default_name)
|
||||
default_name = "plain";
|
||||
/*@+branchstate@ */
|
||||
/* splint - it doesn't matter that default_name may be static */
|
||||
args->segment->parameter = 1 + pv_display_barstyle_index(args, default_name);
|
||||
}
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
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 {
|
||||
/* Unknown size - back-and-forth moving indicator. */
|
||||
bytes = pv_formatter_progress_unknownsize(args, content, sizeof(content), false);
|
||||
}
|
||||
|
||||
content[bytes] = '\0';
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The number after the progress bar.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_progress_amount_only(pvformatter_args_t args)
|
||||
{
|
||||
char content[256]; /* flawfinder: ignore - always bounded */
|
||||
pvdisplay_bytecount_t bytes;
|
||||
|
||||
memset(content, 0, sizeof(content));
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
if (args->control->numeric) {
|
||||
/* Numeric mode - percentage as a rounded integer with no suffix. */
|
||||
(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->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 {
|
||||
/* Unknown size - no number. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
content[bytes] = '\0';
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Formatter function for the current rate of transfer.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Transfer rate.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_rate(pvformatter_args_t args)
|
||||
{
|
||||
char content[128]; /* flawfinder: ignore - always bounded */
|
||||
|
||||
args->display->showing_rate = true;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
if (0 == args->buffer_size)
|
||||
return 0;
|
||||
|
||||
/*@-mustfreefresh@ */
|
||||
if (args->control->numeric) {
|
||||
/* numeric - raw value without suffix. */
|
||||
(void) pv_snprintf(content, sizeof(content),
|
||||
"%.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->calc->transfer_rate, "", _("b/s"), args->display->count_type);
|
||||
} else {
|
||||
/* bytes or lines per second */
|
||||
pv_describe_amount(content, sizeof(content),
|
||||
"[%s]", args->calc->transfer_rate, _("/s"), _("B/s"), args->display->count_type);
|
||||
}
|
||||
/*@+mustfreefresh@ *//* splint: see above. */
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Formatter function for ECMA-48 SGR codes.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct sgr_keyword_map_s {
|
||||
/*@null@ */ const char *keyword;
|
||||
uint8_t bytes;
|
||||
uint8_t code;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Return an array mapping keywords to ECMA-48 SGR code numbers.
|
||||
*/
|
||||
/*@keep@ */ static struct sgr_keyword_map_s *sgr_keywords(void)
|
||||
{
|
||||
/*@keep@ */ static struct sgr_keyword_map_s keywords[] = {
|
||||
{ "reset", 0, 0 },
|
||||
{ "none", 0, 0 },
|
||||
{ "bold", 0, 1 },
|
||||
{ "dim", 0, 2 },
|
||||
{ "italic", 0, 3 },
|
||||
{ "underscore", 0, 4 },
|
||||
{ "underline", 0, 4 },
|
||||
{ "blink", 0, 5 },
|
||||
{ "reverse", 0, 7 },
|
||||
{ "no-bold", 0, 22 }, /* same as no-dim */
|
||||
{ "no-dim", 0, 22 },
|
||||
{ "no-italic", 0, 23 },
|
||||
{ "no-underscore", 0, 24 },
|
||||
{ "no-underline", 0, 24 },
|
||||
{ "no-blink", 0, 25 },
|
||||
{ "no-reverse", 0, 27 },
|
||||
{ "black", 0, 30 },
|
||||
{ "red", 0, 31 },
|
||||
{ "green", 0, 32 },
|
||||
{ "brown", 0, 33 },
|
||||
{ "yellow", 0, 33 },
|
||||
{ "blue", 0, 34 },
|
||||
{ "magenta", 0, 35 },
|
||||
{ "cyan", 0, 36 },
|
||||
{ "white", 0, 37 },
|
||||
{ "fg-black", 0, 30 },
|
||||
{ "fg-red", 0, 31 },
|
||||
{ "fg-green", 0, 32 },
|
||||
{ "fg-brown", 0, 33 },
|
||||
{ "fg-yellow", 0, 33 },
|
||||
{ "fg-blue", 0, 34 },
|
||||
{ "fg-magenta", 0, 35 },
|
||||
{ "fg-cyan", 0, 36 },
|
||||
{ "fg-white", 0, 37 },
|
||||
{ "fg-default", 0, 39 },
|
||||
{ "bg-black", 0, 40 },
|
||||
{ "bg-red", 0, 41 },
|
||||
{ "bg-green", 0, 42 },
|
||||
{ "bg-brown", 0, 43 },
|
||||
{ "bg-yellow", 0, 43 },
|
||||
{ "bg-blue", 0, 44 },
|
||||
{ "bg-magenta", 0, 45 },
|
||||
{ "bg-cyan", 0, 46 },
|
||||
{ "bg-white", 0, 47 },
|
||||
{ "bg-default", 0, 49 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
int keyword_index;
|
||||
|
||||
/* Calculate the lengths of each keyword on the first call. */
|
||||
if (0 == keywords[0].bytes) {
|
||||
for (keyword_index = 0; NULL != keywords[keyword_index].keyword; keyword_index++) {
|
||||
keywords[keyword_index].bytes = strlen(keywords[keyword_index].keyword); /* flawfinder: ignore */
|
||||
/* flawfinder - strlen() on a static null-terminated string is OK. */
|
||||
}
|
||||
}
|
||||
|
||||
/*@-compmempass@ */
|
||||
return keywords;
|
||||
/*@+compmempass@ */
|
||||
/*
|
||||
* splint - found no other way to pass static back without a false
|
||||
* positive warning about a memory leak.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Display SGR codes if colour output is supported.
|
||||
*/
|
||||
pvdisplay_bytecount_t pv_formatter_sgr(pvformatter_args_t args)
|
||||
{
|
||||
/*@keep@ */ static struct sgr_keyword_map_s *keywords;
|
||||
char content[1024]; /* flawfinder: ignore */
|
||||
pvdisplay_bytecount_t write_position, read_position, keyword_start, keyword_length;
|
||||
int numeric_value, code_count, most_recent_code;
|
||||
|
||||
/* flawfinder - null-terminated and bounded with pv_snprintf(). */
|
||||
|
||||
if (!args->display->colour_permitted)
|
||||
return 0;
|
||||
|
||||
args->display->format_uses_colour = true;
|
||||
|
||||
if (!args->status->terminal_supports_colour)
|
||||
return 0;
|
||||
if (NULL == args->segment->string_parameter)
|
||||
return 0;
|
||||
if (0 == args->segment->string_parameter_bytes)
|
||||
return 0;
|
||||
|
||||
keywords = sgr_keywords();
|
||||
|
||||
write_position = 0;
|
||||
content[0] = '\0';
|
||||
|
||||
debug("%p+%d [%.*s]", args->segment->string_parameter, args->segment->string_parameter_bytes,
|
||||
args->segment->string_parameter_bytes, args->segment->string_parameter);
|
||||
|
||||
read_position = 0;
|
||||
keyword_start = 0;
|
||||
keyword_length = 0;
|
||||
numeric_value = -1;
|
||||
code_count = 0;
|
||||
most_recent_code = -1;
|
||||
|
||||
while (read_position < args->segment->string_parameter_bytes) {
|
||||
char read_char = args->segment->string_parameter[read_position++];
|
||||
if ((',' == read_char) || (';' == read_char)) {
|
||||
keyword_length = read_position - keyword_start;
|
||||
if (keyword_length > 0)
|
||||
keyword_length--;
|
||||
} else {
|
||||
if ((read_char >= '0' && read_char <= '9')
|
||||
&& (numeric_value >= 0 || keyword_start == read_position - 1)) {
|
||||
if (keyword_start == read_position - 1)
|
||||
numeric_value = 0;
|
||||
numeric_value = numeric_value * 10 + (int) (read_char - '0');
|
||||
} else {
|
||||
numeric_value = -1;
|
||||
}
|
||||
if (read_position >= args->segment->string_parameter_bytes) {
|
||||
keyword_length = read_position - keyword_start;
|
||||
}
|
||||
}
|
||||
if (keyword_length > 0) {
|
||||
int code = -1;
|
||||
|
||||
debug("keyword@%d+%d: [%.*s]; numeric=%d", keyword_start, keyword_length, keyword_length,
|
||||
&(args->segment->string_parameter[keyword_start]), numeric_value);
|
||||
|
||||
if (numeric_value >= 0 && numeric_value < 255) {
|
||||
code = numeric_value;
|
||||
} else {
|
||||
int keyword_index;
|
||||
for (keyword_index = 0; -1 == code && NULL != keywords[keyword_index].keyword;
|
||||
keyword_index++) {
|
||||
if (keyword_length != keywords[keyword_index].bytes)
|
||||
continue;
|
||||
if (0 !=
|
||||
strncmp(keywords[keyword_index].keyword,
|
||||
&(args->segment->string_parameter[keyword_start]), keyword_length))
|
||||
continue;
|
||||
code = (int) (keywords[keyword_index].code);
|
||||
}
|
||||
}
|
||||
|
||||
debug("code=%d", code);
|
||||
|
||||
if (code >= 0) {
|
||||
if (code_count > 15) {
|
||||
write_position +=
|
||||
pv_snprintf(content + write_position, sizeof(content) - write_position,
|
||||
"%s", "m");
|
||||
code_count = 0;
|
||||
}
|
||||
if (0 == code_count) {
|
||||
write_position +=
|
||||
pv_snprintf(content + write_position, sizeof(content) - write_position,
|
||||
"%s", "\033[");
|
||||
} else {
|
||||
write_position +=
|
||||
pv_snprintf(content + write_position, sizeof(content) - write_position,
|
||||
"%s", ";");
|
||||
}
|
||||
write_position +=
|
||||
pv_snprintf(content + write_position, sizeof(content) - write_position, "%d", code);
|
||||
code_count++;
|
||||
most_recent_code = code;
|
||||
}
|
||||
|
||||
keyword_length = 0;
|
||||
keyword_start = read_position;
|
||||
}
|
||||
}
|
||||
|
||||
if (code_count > 0)
|
||||
write_position += pv_snprintf(content + write_position, sizeof(content) - write_position, "%s", "m");
|
||||
|
||||
if (most_recent_code > 0) {
|
||||
args->display->sgr_code_active = true;
|
||||
} else if (0 == most_recent_code) {
|
||||
args->display->sgr_code_active = false;
|
||||
}
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Formatter function for the elapsed transfer time.
|
||||
*
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "pv.h"
|
||||
#include "pv-internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Elapsed time.
|
||||
*/
|
||||
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;
|
||||
|
||||
content[0] = '\0';
|
||||
|
||||
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 (elapsed_seconds > (long double) 360000000.0L)
|
||||
elapsed_seconds = (long double) 360000000.0L;
|
||||
|
||||
/* Also check it's not negative. */
|
||||
if (elapsed_seconds < 0.0)
|
||||
elapsed_seconds = 0.0;
|
||||
|
||||
if (args->control->numeric) {
|
||||
/* Numeric mode - show the number of seconds, unformatted. */
|
||||
(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.
|
||||
*/
|
||||
(void) pv_snprintf(content,
|
||||
sizeof(content),
|
||||
"%ld:%02ld:%02ld:%02ld",
|
||||
((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) (elapsed_seconds)) / 3600,
|
||||
(((long) (elapsed_seconds)) / 60) % 60, ((long) (elapsed_seconds)) % 60);
|
||||
}
|
||||
|
||||
return pv_formatter_segmentcontent(content, args);
|
||||
}
|
||||
+540
-365
File diff suppressed because it is too large
Load Diff
+37
-30
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for converting strings to numbers.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -17,7 +17,7 @@
|
||||
* including <ctype.h> causes weird versioned glibc dependencies on certain
|
||||
* Red Hat systems, complicating package management.
|
||||
*/
|
||||
static bool pv__isdigit(char c)
|
||||
bool pv_isdigit(char c)
|
||||
{
|
||||
return ((c >= '0') && (c <= '9')) ? true : false;
|
||||
}
|
||||
@@ -37,21 +37,22 @@ off_t pv_getnum_size(const char *str, bool decimal_units)
|
||||
unsigned int fractional_divisor = 1;
|
||||
unsigned int binary_shift = 0;
|
||||
off_t decimal_multiplier = 0;
|
||||
size_t readpos = 0;
|
||||
|
||||
if (NULL == str)
|
||||
return (off_t) 0;
|
||||
|
||||
/* Skip any non-numeric leading characters. */
|
||||
while (str[0] != '\0' && (!pv__isdigit(str[0])))
|
||||
str++;
|
||||
while (str[readpos] != '\0' && (!pv_isdigit(str[readpos])))
|
||||
readpos++;
|
||||
|
||||
/*
|
||||
* Parse the integral part of the number - the digits before the
|
||||
* decimal mark or units.
|
||||
*/
|
||||
for (; pv__isdigit(str[0]); str++) {
|
||||
for (; pv_isdigit(str[readpos]); readpos++) {
|
||||
integral_part = integral_part * 10;
|
||||
integral_part += (off_t) (str[0] - '0');
|
||||
integral_part += (off_t) (str[readpos] - '0');
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -62,13 +63,13 @@ off_t pv_getnum_size(const char *str, bool decimal_units)
|
||||
* will fail if there are any locales whose decimal mark is not one
|
||||
* of those two characters.
|
||||
*/
|
||||
if (('.' == str[0]) || (',' == str[0])) {
|
||||
str++;
|
||||
for (; pv__isdigit(str[0]); str++) {
|
||||
if (('.' == str[readpos]) || (',' == str[readpos])) {
|
||||
readpos++;
|
||||
for (; pv_isdigit(str[readpos]); readpos++) {
|
||||
/* Stop counting below 0.0001. */
|
||||
if (fractional_divisor < 10000) {
|
||||
fractional_part = fractional_part * 10;
|
||||
fractional_part += (off_t) (str[0] - '0');
|
||||
fractional_part += (off_t) (str[readpos] - '0');
|
||||
fractional_divisor = fractional_divisor * 10;
|
||||
}
|
||||
}
|
||||
@@ -78,11 +79,11 @@ off_t pv_getnum_size(const char *str, bool decimal_units)
|
||||
* Parse any units given (K=KiB=*1024, M=MiB=1024KiB, G=GiB=1024MiB,
|
||||
* T=TiB=1024GiB; replace 1024 with 1000 if decimal_units is true).
|
||||
*/
|
||||
if (str[0] != '\0') {
|
||||
if (str[readpos] != '\0') {
|
||||
/* Skip any spaces or tabs after the digits. */
|
||||
while ((' ' == str[0]) || ('\t' == str[0]))
|
||||
str++;
|
||||
switch (str[0]) {
|
||||
while ((' ' == str[readpos]) || ('\t' == str[readpos]))
|
||||
readpos++;
|
||||
switch (str[readpos]) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
binary_shift = 10;
|
||||
@@ -159,6 +160,8 @@ off_t pv_getnum_size(const char *str, bool decimal_units)
|
||||
fractional_part = fractional_part / fractional_divisor;
|
||||
integral_part += fractional_part;
|
||||
|
||||
debug("%s [%s] = %lld", str, decimal_units ? "decimal" : "binary", (long long) integral_part);
|
||||
|
||||
return integral_part;
|
||||
}
|
||||
|
||||
@@ -176,11 +179,11 @@ double pv_getnum_interval(const char *str)
|
||||
return 0.0;
|
||||
|
||||
/* Skip any non-digit characters at the start. */
|
||||
while (str[0] != '\0' && (!pv__isdigit(str[0])))
|
||||
while (str[0] != '\0' && (!pv_isdigit(str[0])))
|
||||
str++;
|
||||
|
||||
/* Parse the digits before the decimal mark. */
|
||||
for (; pv__isdigit(str[0]); str++) {
|
||||
for (; pv_isdigit(str[0]); str++) {
|
||||
result = result * 10;
|
||||
result += (double) (str[0] - '0');
|
||||
}
|
||||
@@ -193,7 +196,7 @@ double pv_getnum_interval(const char *str)
|
||||
str++;
|
||||
|
||||
/* Parse the digits after the decimal mark, up to 0.0000001. */
|
||||
for (; pv__isdigit(str[0]) && step < 1000000; str++) {
|
||||
for (; pv_isdigit(str[0]) && step < 1000000; str++) {
|
||||
step = step * 10;
|
||||
result += ((double) (str[0] - '0')) / step;
|
||||
}
|
||||
@@ -226,31 +229,31 @@ bool pv_getnum_check(const char *str, pv_numtype type)
|
||||
str++;
|
||||
|
||||
/* If the next character isn't a digit, this isn't a number. */
|
||||
if (!pv__isdigit(str[0]))
|
||||
if (!pv_isdigit(str[0]))
|
||||
return false;
|
||||
|
||||
/* Skip over the digits. */
|
||||
for (; pv__isdigit(str[0]); str++);
|
||||
for (; pv_isdigit(str[0]); str++);
|
||||
|
||||
/*
|
||||
* If there's a decimal mark (see note in pv_getnum_size() above),
|
||||
* check that too.
|
||||
*/
|
||||
if (('.' == str[0]) || (',' == str[0])) {
|
||||
/* Integers should have no decimal mark. */
|
||||
if (type == PV_NUMTYPE_INTEGER)
|
||||
/* Bare integers should have no decimal mark. */
|
||||
if (type == PV_NUMTYPE_BARE_INTEGER)
|
||||
return false;
|
||||
/* Skip the decimal mark, then all digits. */
|
||||
str++;
|
||||
for (; pv__isdigit(str[0]); str++);
|
||||
for (; pv_isdigit(str[0]); str++);
|
||||
}
|
||||
|
||||
/* If the string ends here, this is a valid number. */
|
||||
if ('\0' == str[0])
|
||||
return true;
|
||||
|
||||
/* A units suffix is not allowed for doubles, only for integers. */
|
||||
if (type == PV_NUMTYPE_DOUBLE)
|
||||
/* A units suffix is only allowed for ANY_WITH_SUFFIX. */
|
||||
if (type != PV_NUMTYPE_ANY_WITH_SUFFIX)
|
||||
return false;
|
||||
|
||||
/* Skip trailing spaces or tabs. */
|
||||
@@ -282,16 +285,20 @@ bool pv_getnum_check(const char *str, pv_numtype type)
|
||||
|
||||
|
||||
/*
|
||||
* Return an integer representing "amount" as a percentage of "total", i.e.
|
||||
* Return a value representing "amount" as a percentage of "total", i.e.
|
||||
* 100*amount/total. If "total" is zero or less, return 0.
|
||||
*/
|
||||
int pv_percentage(off_t amount, const off_t total)
|
||||
double pv_percentage(off_t amount, const off_t total)
|
||||
{
|
||||
double amount_as_double;
|
||||
|
||||
if (total < 1)
|
||||
return 0;
|
||||
return 0.0;
|
||||
|
||||
amount *= 100;
|
||||
amount /= total;
|
||||
amount_as_double = (double) amount;
|
||||
|
||||
return (int) amount;
|
||||
amount_as_double *= 100.0;
|
||||
amount_as_double /= (double) total;
|
||||
|
||||
return amount_as_double;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for setting the process title.
|
||||
*
|
||||
* Copyright 2024 Andrew Wood
|
||||
* Copyright 2024-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
|
||||
+28
-28
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Signal handling functions.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+375
-155
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* State management functions.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -21,29 +21,140 @@
|
||||
#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;
|
||||
transfer->output_not_seekable = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 +166,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;
|
||||
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 +189,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 +217,78 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Truncate the output file descriptor to its current position, if it's a
|
||||
* valid fd, we're in sparse output mode, and no lseek() failed.
|
||||
*/
|
||||
static void pv_truncate_output(pvstate_t state)
|
||||
{
|
||||
off_t current_offset;
|
||||
|
||||
if (!state->control.sparse_output)
|
||||
return;
|
||||
if (state->transfer.output_not_seekable)
|
||||
return;
|
||||
if (state->control.output_fd < 0)
|
||||
return;
|
||||
|
||||
current_offset = (off_t) lseek(state->control.output_fd, (off_t) 0, SEEK_CUR);
|
||||
if (current_offset == (off_t) - 1)
|
||||
return;
|
||||
|
||||
debug("%s: %ld", "truncating to current offset", (long) current_offset);
|
||||
|
||||
/*@+longintegral@ */
|
||||
/*
|
||||
* splint has trouble with off_t / __off_t.
|
||||
*/
|
||||
if (0 != ftruncate(state->control.output_fd, current_offset)) {
|
||||
debug("%s: %s", "output ftruncate() failed", strerror(errno));
|
||||
}
|
||||
/*@-longintegral@ */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free a state structure, after which it can no longer be used.
|
||||
*/
|
||||
@@ -170,11 +302,12 @@ void pv_state_free(pvstate_t state)
|
||||
* still know the program name and output filename.
|
||||
*/
|
||||
if (state->control.output_fd >= 0) {
|
||||
pv_truncate_output(state);
|
||||
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,23 +318,19 @@ 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);
|
||||
state->control.name = NULL;
|
||||
}
|
||||
|
||||
if (NULL != state->control.default_bar_style) {
|
||||
free(state->control.default_bar_style);
|
||||
state->control.default_bar_style = NULL;
|
||||
}
|
||||
|
||||
if (NULL != state->control.format_string) {
|
||||
free(state->control.format_string);
|
||||
state->control.format_string = NULL;
|
||||
@@ -212,20 +341,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;
|
||||
@@ -239,6 +357,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;
|
||||
@@ -258,36 +385,60 @@ void pv_state_set_format(pvstate_t state, bool progress, bool timer, bool eta, b
|
||||
}
|
||||
|
||||
state->control.default_format[0] = '\0';
|
||||
PV_ADDFORMAT(name, "%N");
|
||||
PV_ADDFORMAT(bytes, "%b");
|
||||
PV_ADDFORMAT(bufpercent, "%T");
|
||||
PV_ADDFORMAT(timer, "%t");
|
||||
PV_ADDFORMAT(rate, "%r");
|
||||
PV_ADDFORMAT(average_rate, "%a");
|
||||
PV_ADDFORMAT(progress, "%p");
|
||||
PV_ADDFORMAT(eta, "%e");
|
||||
PV_ADDFORMAT(fineta, "%I");
|
||||
if (lastwritten > 0) {
|
||||
char buf[16]; /* flawfinder: ignore */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
(void) pv_snprintf(buf, sizeof(buf), "%%%uA", (unsigned int) lastwritten);
|
||||
PV_ADDFORMAT(lastwritten > 0, buf);
|
||||
|
||||
if (false == state->control.numeric) {
|
||||
/* Standard progress display mode (without "--numeric"). */
|
||||
|
||||
/*
|
||||
* flawfinder rationale: large enough for string, zeroed
|
||||
* before use, only written to by pv_snprintf() with the
|
||||
* right buffer length.
|
||||
* Add the format strings for the enabled options in a
|
||||
* standard order.
|
||||
*/
|
||||
PV_ADDFORMAT(name, "%N");
|
||||
PV_ADDFORMAT(bytes, "%b");
|
||||
PV_ADDFORMAT(bufpercent, "%T");
|
||||
PV_ADDFORMAT(timer, "%t");
|
||||
PV_ADDFORMAT(rate, "%r");
|
||||
PV_ADDFORMAT(average_rate, "%a");
|
||||
PV_ADDFORMAT(progress, "%p");
|
||||
PV_ADDFORMAT(eta, "%e");
|
||||
PV_ADDFORMAT(fineta, "%I");
|
||||
|
||||
if (lastwritten > 0) {
|
||||
char buf[16]; /* flawfinder: ignore */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
(void) pv_snprintf(buf, sizeof(buf), "%%%uA", (unsigned int) lastwritten);
|
||||
PV_ADDFORMAT(lastwritten > 0, buf);
|
||||
/*
|
||||
* flawfinder rationale: large enough for string,
|
||||
* zeroed before use, only written to by
|
||||
* pv_snprintf() with the right buffer length.
|
||||
*/
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Numeric mode has different behaviour. */
|
||||
|
||||
PV_ADDFORMAT(timer, "%t");
|
||||
PV_ADDFORMAT(bytes, "%b");
|
||||
PV_ADDFORMAT(rate, "%r");
|
||||
PV_ADDFORMAT(!(bytes || rate), "%{progress-amount-only}");
|
||||
|
||||
}
|
||||
|
||||
debug("%s: [%s]", "default format set", state->control.default_format);
|
||||
|
||||
/* Free any previously set name. */
|
||||
if (NULL != state->control.name) {
|
||||
free(state->control.name);
|
||||
state->control.name = NULL;
|
||||
}
|
||||
|
||||
/* Set a new name if one was given. */
|
||||
if (NULL != name)
|
||||
state->control.name = pv_strdup(name);
|
||||
|
||||
state->flag.reparse_display = 1;
|
||||
/* Tell pv_format() that the format has changed. */
|
||||
state->flags.reparse_display = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -377,6 +528,11 @@ void pv_state_direct_io_set(pvstate_t state, bool val)
|
||||
state->control.direct_io_changed = true;
|
||||
}
|
||||
|
||||
void pv_state_sparse_output_set(pvstate_t state, bool val)
|
||||
{
|
||||
state->control.sparse_output = val;
|
||||
}
|
||||
|
||||
void pv_state_discard_input_set(pvstate_t state, bool val)
|
||||
{
|
||||
state->control.discard_input = val;
|
||||
@@ -409,7 +565,9 @@ void pv_state_interval_set(pvstate_t state, double val)
|
||||
|
||||
void pv_state_width_set(pvstate_t state, unsigned int val, bool was_set_manually)
|
||||
{
|
||||
state->control.width = val;
|
||||
if (val > PVDISPLAY_WIDTH_MAX)
|
||||
val = PVDISPLAY_WIDTH_MAX;
|
||||
state->control.width = (pvdisplay_width_t) val;
|
||||
state->control.width_set_manually = was_set_manually;
|
||||
}
|
||||
|
||||
@@ -429,6 +587,16 @@ void pv_state_name_set(pvstate_t state, /*@null@ */ const char *val)
|
||||
state->control.name = pv_strdup(val);
|
||||
}
|
||||
|
||||
void pv_state_default_bar_style_set(pvstate_t state, /*@null@ */ const char *val)
|
||||
{
|
||||
if (NULL != state->control.default_bar_style) {
|
||||
free(state->control.default_bar_style);
|
||||
state->control.default_bar_style = NULL;
|
||||
}
|
||||
if (NULL != val)
|
||||
state->control.default_bar_style = pv_strdup(val);
|
||||
}
|
||||
|
||||
void pv_state_format_string_set(pvstate_t state, /*@null@ */ const char *val)
|
||||
{
|
||||
if (NULL != state->control.format_string) {
|
||||
@@ -490,27 +658,18 @@ 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)
|
||||
{
|
||||
/*
|
||||
* Close any previous output file first, so we can report any errors
|
||||
* before we store the new output filename.
|
||||
*/
|
||||
pv_truncate_output(state);
|
||||
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)
|
||||
@@ -526,6 +685,22 @@ void pv_state_output_set(pvstate_t state, int fd, const char *name)
|
||||
*/
|
||||
fcntl(state->control.output_fd, F_SETFL, O_NONBLOCK | fcntl(state->control.output_fd, F_GETFL));
|
||||
#endif /* MAKE_OUTPUT_NONBLOCKING */
|
||||
|
||||
/*
|
||||
* In sparse output mode, if the output is in append mode (>>),
|
||||
* explicitly lseek() to the end of the file. Otherwise, the file
|
||||
* offset is not set until the first write(), which means that if
|
||||
* the input starts with null bytes, when we lseek() past them
|
||||
* relative to the current position, the "current position" is 0
|
||||
* rather than the end of the file, and the file gets truncated on
|
||||
* exit to the wrong size.
|
||||
*/
|
||||
if (state->control.sparse_output && 0 != (fcntl(fd, F_GETFL) & O_APPEND)) {
|
||||
debug("%s", "sparse output mode, and appending - seeking output to the end");
|
||||
if ((off_t) lseek(fd, 0, SEEK_END) == (off_t) - 1) {
|
||||
debug("%s: %s", "lseek failed", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pv_state_average_rate_window_set(pvstate_t state, unsigned int val)
|
||||
@@ -533,16 +708,13 @@ 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_terminal_supports_utf8(pvstate_t state, bool val)
|
||||
{
|
||||
state->status.terminal_supports_utf8 = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the array of input files.
|
||||
@@ -550,43 +722,91 @@ void pv_state_average_rate_window_set(pvstate_t state, unsigned int 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");
|
||||
}
|
||||
|
||||
+12
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for portably managing strings.
|
||||
*
|
||||
* Copyright 2023-2024 Andrew Wood
|
||||
* Copyright 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -304,3 +304,14 @@ size_t pv_strwidth(const char *string, size_t bytes)
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return true if the character is printable. This function is used instead
|
||||
* of the macro from <ctype.h> to avoid causing versioned glibc dependencies
|
||||
* on some systems.
|
||||
*/
|
||||
bool pv_isprint(char c)
|
||||
{
|
||||
return ((c >= (char) 32) && (c <= (char) 126)) ? true : false;
|
||||
}
|
||||
|
||||
+133
-39
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for transferring data between file descriptors.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -185,7 +185,7 @@ static ssize_t pv__transfer_read_repeated(int fd, char *buf, size_t count)
|
||||
* not guaranteed to succeed for _all_ sizes; we may end up returning 0 if this
|
||||
* occurs. (The first write() may return -1 / EINTR if the consumer doesn't
|
||||
* read any data before our timeout and the buffer of whatever stdout is is
|
||||
* near-full.) (see https://codeberg.org/a-j-wood/pv/pulls/93)
|
||||
* near-full.) (see https://codeberg.org/ivarch/pv/pulls/93)
|
||||
*
|
||||
* If "sync_after_write" is true, we call fdatasync() after each write() (or
|
||||
* fsync() if _POSIX_SYNCHRONIZED_IO is not > 0).
|
||||
@@ -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"));
|
||||
@@ -629,9 +655,12 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
|
||||
{
|
||||
ssize_t nwritten;
|
||||
int write_errno;
|
||||
bool all_nulls;
|
||||
off_t output_offset;
|
||||
size_t write_check_position, write_end_position;
|
||||
|
||||
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;
|
||||
@@ -645,6 +674,52 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
|
||||
nwritten = state->transfer.to_write;
|
||||
} else if (state->transfer.to_write > 0) {
|
||||
|
||||
/*
|
||||
* In sparse output mode, check whether all of the bytes to
|
||||
* be written are null, and if so, try to seek the output
|
||||
* instead of writing the null bytes.
|
||||
*/
|
||||
if (state->control.sparse_output && !state->transfer.output_not_seekable) {
|
||||
write_check_position = state->transfer.write_position;
|
||||
write_end_position = write_check_position + (size_t) (state->transfer.to_write);
|
||||
all_nulls = true;
|
||||
while (all_nulls && write_check_position < write_end_position) {
|
||||
if ('\0' == state->transfer.transfer_buffer[write_check_position]) {
|
||||
write_check_position++;
|
||||
} else {
|
||||
all_nulls = false;
|
||||
}
|
||||
}
|
||||
if (all_nulls) {
|
||||
|
||||
/*
|
||||
* Use lseek() to move forward in the file,
|
||||
* and then ftruncate() it to its new size.
|
||||
*
|
||||
* If any step fails, mark the output not
|
||||
* seekable so we stop trying.
|
||||
*/
|
||||
|
||||
/*@+longintegral@ */
|
||||
/*
|
||||
* splint has trouble with off_t / __off_t, in the lseek() call.
|
||||
*/
|
||||
output_offset =
|
||||
lseek(state->control.output_fd, (off_t) (state->transfer.to_write), SEEK_CUR);
|
||||
if (output_offset == (off_t) - 1) {
|
||||
debug("%s: %s", "output lseek() failed", strerror(errno));
|
||||
state->transfer.output_not_seekable = true;
|
||||
} else {
|
||||
/* Seek successful - skip write. */
|
||||
debug("%s (%ld) -> %s: %ld", "skipped null writes",
|
||||
(long) (state->transfer.to_write), "new position", (long) output_offset);
|
||||
nwritten = state->transfer.to_write;
|
||||
goto pv__transfer_write_completed;
|
||||
}
|
||||
/*@-longintegral@ */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an interval timer or an alarm to interrupt the write
|
||||
* with a signal if the write takes too long, so we can
|
||||
@@ -673,7 +748,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 +774,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@ */
|
||||
@@ -709,6 +784,9 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long
|
||||
#endif /* HAVE_SETITIMER */
|
||||
}
|
||||
|
||||
pv__transfer_write_completed:
|
||||
/* If lseek() worked for sparse output, it jumps down here. */
|
||||
|
||||
if (nwritten > 0) {
|
||||
bool tracking_lines = false;
|
||||
|
||||
@@ -741,7 +819,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,11 +988,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;
|
||||
@@ -939,7 +1018,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;
|
||||
@@ -1053,7 +1132,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;
|
||||
}
|
||||
@@ -1101,8 +1180,10 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
|
||||
if ((state->control.linemode) && (lineswritten != NULL))
|
||||
*lineswritten = 0;
|
||||
|
||||
if ((*eof_in) && (*eof_out))
|
||||
if ((*eof_in) && (*eof_out)) {
|
||||
debug("%s %d: %s", "fd", fd, "early return 0 - EOF in and out");
|
||||
return 0;
|
||||
}
|
||||
|
||||
check_read_fd = -1;
|
||||
check_write_fd = -1;
|
||||
@@ -1144,15 +1225,16 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
|
||||
/*
|
||||
* Ignore transient errors by returning 0 immediately.
|
||||
*/
|
||||
if (EINTR == errno)
|
||||
if (EINTR == errno) {
|
||||
debug("%s %d: %s", "fd", fd, "early return 0 - is_data_ready < 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
|
||||
@@ -1170,8 +1252,12 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
|
||||
* NB this can update state->transfer.written because of splice().
|
||||
*/
|
||||
if (ready_to_read) {
|
||||
if (pv__transfer_read(state, fd, eof_in, eof_out, allowed) == 0)
|
||||
if (pv__transfer_read(state, fd, eof_in, eof_out, allowed) == 0) {
|
||||
debug("%s %d: %s (%s=%s, %s=%s, %s=%lu)", "fd", fd,
|
||||
"early return 0 - pv__transfer_read returned 0", "eof_in", eof_in ? "true" : "false",
|
||||
"eof_out", eof_out ? "true" : "false", "allowed", (unsigned long) allowed);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1202,8 +1288,12 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
|
||||
&& (state->transfer.read_position > state->transfer.write_position)
|
||||
&& (state->transfer.to_write > 0)
|
||||
&& (NULL != lineswritten)) {
|
||||
if (pv__transfer_write(state, eof_in, eof_out, lineswritten) == 0)
|
||||
if (pv__transfer_write(state, eof_in, eof_out, lineswritten) == 0) {
|
||||
debug("%s %d: %s (%s=%s, %s=%s, %s=%lu)", "fd", fd,
|
||||
"early return 0 - pv__transfer_write returned 0", "eof_in", eof_in ? "true" : "false",
|
||||
"eof_out", eof_out ? "true" : "false", "lineswritten", (unsigned long) lineswritten);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#ifdef MAXIMISE_BUFFER_FILL
|
||||
/*
|
||||
@@ -1225,5 +1315,9 @@ ssize_t pv_transfer(pvstate_t state, int fd, bool *eof_in, bool *eof_out, off_t
|
||||
}
|
||||
#endif /* MAXIMISE_BUFFER_FILL */
|
||||
|
||||
if (0 == state->transfer.written) {
|
||||
debug("%s %d: %s", "fd", fd, "end-of-function return 0 - transfer.written is zero");
|
||||
}
|
||||
|
||||
return state->transfer.written;
|
||||
}
|
||||
|
||||
+161
-126
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Functions for watching file descriptors in other processes.
|
||||
*
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood
|
||||
* Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2025 Andrew Wood
|
||||
*
|
||||
* License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'.
|
||||
*/
|
||||
@@ -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,9 +304,10 @@ 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);
|
||||
|
||||
proc_pidinfo(pid, PROC_PIDLISTFDS, 0, *fds, size_needed);
|
||||
|
||||
@@ -353,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;
|
||||
@@ -363,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 descriptor
|
||||
* 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
|
||||
@@ -400,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__
|
||||
@@ -419,23 +475,47 @@ int pv_watchpid_scanfds(pvstate_t state,
|
||||
#else
|
||||
if (sscanf(d->d_name, "%d", &fd) != 1)
|
||||
continue;
|
||||
if ((fd < 0) || (fd >= FD_SETSIZE))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
if (info_array[check_idx].closed) {
|
||||
/*
|
||||
* If the fd is known but closed,
|
||||
* immediately free it for re-use.
|
||||
*/
|
||||
info_array[check_idx].unused = true;
|
||||
info_array[check_idx].displayable = false;
|
||||
pv_freecontents_watchfd(&(info_array[check_idx]));
|
||||
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;
|
||||
}
|
||||
@@ -454,61 +534,26 @@ 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].closed = false;
|
||||
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;
|
||||
/*@+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);
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
@@ -516,70 +561,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));
|
||||
|
||||
@@ -588,11 +596,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;
|
||||
}
|
||||
}
|
||||
@@ -604,6 +612,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;
|
||||
}
|
||||
|
||||
@@ -612,6 +628,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.
|
||||
*/
|
||||
@@ -634,20 +653,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);
|
||||
|
||||
@@ -29,8 +29,20 @@ if ! test -n "${testInstallDir}"; then
|
||||
fi
|
||||
|
||||
export DESTDIR="${testInstallDir}"
|
||||
if ! ${makeCommand} -C "${makeDir}" install DESTDIR="${testInstallDir}" >"${workFile1}" 2>&1; then
|
||||
echo "\`make install' exited $?"
|
||||
${makeCommand} -C "${makeDir}" install DESTDIR="${testInstallDir}" >"${workFile1}" 2>&1
|
||||
rc=$?
|
||||
if ! test "${rc}" -eq 0; then
|
||||
if ! test "${makeCommand}" = "make"; then
|
||||
# Retry with plain "make".
|
||||
makeCommand="make"
|
||||
${makeCommand} -C "${makeDir}" install DESTDIR="${testInstallDir}" >>"${workFile1}" 2>&1
|
||||
rc=$?
|
||||
fi
|
||||
fi
|
||||
if ! test ${rc} -eq 0; then
|
||||
echo "\`make install' exited ${rc}"
|
||||
echo "command: ${makeCommand} -C '${makeDir}' install DESTDIR='${testInstallDir}'"
|
||||
cat "${workFile1}"
|
||||
rm -rf "${testInstallDir}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -18,8 +18,11 @@ seq -w 3 1 100 \
|
||||
differentLines=$(tr '\r' '\n' < "${workFile1}" | sed '/^ *$/d' | sort | uniq | wc -l | tr -dc '0-9')
|
||||
lastLine=$(tr '\r' '\n' < "${workFile1}" | sed '/^ *$/d' | sed -n '$p')
|
||||
|
||||
if ! test "${differentLines}" -gt 5; then
|
||||
echo "fewer than 6 different outputs seen"
|
||||
# Even on very slow hosts, we should see at least 3 different output lines -
|
||||
# nothing at the start, something in the middle, and the last few numbers at
|
||||
# the end.
|
||||
if ! test "${differentLines}" -gt 2; then
|
||||
echo "fewer than 3 different outputs seen"
|
||||
tr '\r' '\n' < "${workFile1}" | sed '/^ *$/d' | sort | uniq
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -18,18 +18,21 @@ dd if=/dev/zero bs=500 count=1 2>/dev/null \
|
||||
lineCount=$(wc -l < "${workFile1}" | tr -dc '0-9')
|
||||
finalLine=$(sed -n '$p' < "${workFile1}")
|
||||
|
||||
# The number of output lines should be >8 and <13, and the final byte count
|
||||
# The number of output lines should be >6 and <13, and the final byte count
|
||||
# should be 500.
|
||||
#
|
||||
if ! test "${lineCount}" -gt 8; then
|
||||
echo "fewer than 9 output lines (${lineCount})"
|
||||
if ! test "${lineCount}" -gt 6; then
|
||||
echo "fewer than 7 output lines (${lineCount}):"
|
||||
cat "${workFile1}"
|
||||
exit 1
|
||||
fi
|
||||
if ! test "${lineCount}" -lt 13; then
|
||||
echo "more than 12 output lines (${lineCount})"
|
||||
echo "more than 12 output lines (${lineCount}):"
|
||||
cat "${workFile1}"
|
||||
exit 1
|
||||
fi
|
||||
if ! test "${finalLine}" = "500"; then
|
||||
echo "final byte count was not 500 (${finalLine})"
|
||||
echo "final byte count was not 500 (${finalLine}):"
|
||||
cat "${workFile1}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -18,14 +18,17 @@ if ! "${testSubject}" -h 2>/dev/null | grep -Eq "^ -R,"; then
|
||||
exit 77
|
||||
fi
|
||||
|
||||
# Generate some data.
|
||||
# Generate 10MiB of data.
|
||||
dd if=/dev/urandom of="${workFile1}" bs=1024 count=10240 2>/dev/null
|
||||
|
||||
# Run a few remote control commands in the background.
|
||||
#
|
||||
echo FAIL > "${workFile3}"
|
||||
true > "${workFile4}"
|
||||
(
|
||||
set +e
|
||||
# Don't start doing anything until the main transfer process, started below, has begun.
|
||||
while test -e "${workFile4}" && ! test -s "${workFile4}"; do sleep 0.1; done
|
||||
sleep 2
|
||||
for loopCount in 1 2 3; do
|
||||
"${testSubject}" -R "$(cat "${workFile4}")" -apterb || exit 1
|
||||
|
||||
@@ -27,7 +27,7 @@ dd if=/dev/urandom of="${workFile1}" bs=1024 count=10240 2>/dev/null
|
||||
true > "${workFile3}"
|
||||
(
|
||||
set +e
|
||||
while ! test -s "${workFile3}"; do usleep 200000 2>/dev/null || sleep 1; done
|
||||
while test -e "${workFile3}" && ! test -s "${workFile3}"; do usleep 200000 2>/dev/null || sleep 1; done
|
||||
for loopCount in 1 2 3; do
|
||||
"${testSubject}" -R "$(cat "${workFile3}")" -apterb || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
@@ -37,7 +37,7 @@ for loopCount in 1 2 3; do
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
"${testSubject}" -R "$(cat "${workFile3}")" -F "%e" || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
"${testSubject}" -R "$(cat "${workFile4}")" -x "window:%b" || exit 1
|
||||
"${testSubject}" -R "$(cat "${workFile3}")" -x "window:%b" || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
"${testSubject}" -R "$(cat "${workFile3}")" -N "." || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
|
||||
@@ -27,7 +27,7 @@ dd if=/dev/urandom of="${workFile1}" bs=1024 count=10240 2>/dev/null
|
||||
# Check from the POV of the process sending a control command.
|
||||
true > "${workFile3}"
|
||||
"${testSubject}" -L 100k -i 0.1 -f -P "${workFile3}" "${workFile1}" > "${workFile2}" 2>/dev/null &
|
||||
while ! test -s "${workFile3}"; do usleep 200000 2>/dev/null || sleep 1; done
|
||||
while test -e "${workFile3}" && ! test -s "${workFile3}"; do usleep 200000 2>/dev/null || sleep 1; done
|
||||
runWithValgrind -R "$(cat "${workFile3}")" -apterb 4>&1 || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
runWithValgrind -R "$(cat "${workFile3}")" -p 4>&1 || exit 1
|
||||
|
||||
@@ -24,6 +24,7 @@ fi
|
||||
|
||||
# Skip the test if "-d" does not work.
|
||||
sleep 2 &
|
||||
pid=$!
|
||||
sleep 0.1
|
||||
"${testSubject}" -d "${pid}" -f -i 0.5 >/dev/null 2>"${workFile1}"
|
||||
if grep -Fq ' -d: not available' "${workFile1}"; then
|
||||
@@ -34,17 +35,20 @@ fi
|
||||
# Check "--watchfd PID:FD".
|
||||
# See the "Watchfd" tests for more detail.
|
||||
seq 1 100 > "${workFile1}"
|
||||
true > "${workFile3}"
|
||||
# shellcheck disable=SC2030
|
||||
(sleep 1; read -r line; sleep 1; read -r line; sleep 1) <"${workFile1}" &
|
||||
(while test -e "${workFile3}" && ! test -s "${workFile3}"; do sleep 0.1; done; sleep 1; read -r line; sleep 1; read -r line; sleep 1) <"${workFile1}" &
|
||||
pid=$!
|
||||
sleep 0.1
|
||||
{ runWithValgrind -d "${pid}:0" -f -i 0.5 >/dev/null 2>&1; } 4>&1 || exit 1
|
||||
{ runWithValgrind -P "${workFile3}" -d "${pid}:0" -f -i 0.5 >/dev/null 2>&1; } 4>&1 || exit 1
|
||||
|
||||
# Check "--watchfd PID".
|
||||
seq 1 100 > "${workFile1}"
|
||||
seq 1 300 > "${workFile2}"
|
||||
true > "${workFile3}"
|
||||
# shellcheck disable=SC2030
|
||||
(
|
||||
while test -e "${workFile3}" && ! test -s "${workFile3}"; do sleep 0.1; done
|
||||
sleep 1
|
||||
read -r line
|
||||
exec 9<"${workFile2}"
|
||||
@@ -59,6 +63,6 @@ sleep 1
|
||||
) <"${workFile1}" &
|
||||
pid=$!
|
||||
sleep 0.1
|
||||
{ runWithValgrind -d "${pid}" -f -i 0.5 >/dev/null 2>&1; } 4>&1 || exit 1
|
||||
{ runWithValgrind -P "${workFile3}" -d "${pid}" -f -i 0.5 >/dev/null 2>&1; } 4>&1 || exit 1
|
||||
|
||||
exit 0
|
||||
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Transfer a large chunk of data through pv using pipes, sending it in a
|
||||
# bursty fashion, and make sure some of it consists of blocks of null bytes.
|
||||
# Check data correctness afterwards, and if dd can produce a sparse file,
|
||||
# check that pv's output is also sparse.
|
||||
|
||||
# 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'}"
|
||||
true "${workFile3:?not set - call this from 'make check'}"
|
||||
|
||||
# generate some data, with a hole in the middle.
|
||||
dd if=/dev/urandom of="${workFile1}" bs=4096 count=640 2>/dev/null
|
||||
dd if=/dev/null of="${workFile1}" bs=4096 count=0 seek=1280 2>/dev/null
|
||||
dd if=/dev/urandom of="${workFile1}" bs=4096 count=1280 seek=1280 2>/dev/null
|
||||
|
||||
# check that sparse files are supported.
|
||||
cat < "${workFile1}" > "${workFile3}"
|
||||
inputBlocks="$(ls -1s "${workFile1}" | awk '{print $1}')"
|
||||
nonSparseBlocks="$(ls -1s "${workFile3}" | awk '{print $1}')"
|
||||
if test "${inputBlocks}" -eq "${nonSparseBlocks}"; then
|
||||
echo 'sparse files not supported'
|
||||
exit 77
|
||||
fi
|
||||
|
||||
inputChecksum=$(cksum "${workFile1}" | awk '{print $1}')
|
||||
|
||||
# read through pv and test afterwards
|
||||
(
|
||||
dd if="${workFile1}" bs=1 count=9000
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1 skip=9000 count=1240
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1024 skip=10 count=1014
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1024 skip=1024 count=1024
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1024 skip=2048
|
||||
) 2>/dev/null | "${testSubject}" -q -O -L 2M | cat > "${workFile2}"
|
||||
|
||||
outputChecksum=$(cksum "${workFile2}" | awk '{print $1}')
|
||||
|
||||
if ! test "${inputChecksum}" = "${outputChecksum}"; then
|
||||
echo "checksum mismatch with dd | pv | cat"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# same again but with one less pipe
|
||||
(
|
||||
dd if="${workFile1}" bs=1 count=9000
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1 skip=9000 count=1240
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1024 skip=10 count=1014
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1024 skip=1024 count=1024
|
||||
sleep 1
|
||||
dd if="${workFile1}" bs=1024 skip=2048
|
||||
) 2>/dev/null | "${testSubject}" -q -O -L 2M > "${workFile2}"
|
||||
|
||||
outputChecksum=$(cksum "${workFile2}" | awk '{print $1}')
|
||||
|
||||
if ! test "${inputChecksum}" = "${outputChecksum}"; then
|
||||
echo "checksum mismatch with dd | pv > file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
outputBlocks="$(ls -1s "${workFile2}" | awk '{print $1}')"
|
||||
|
||||
# Note that we only check that the output has any holes at all (and that the
|
||||
# input had holes). We don't compare pv's output with dd's output directly,
|
||||
# because the exact number of holes might differ intermittently.
|
||||
|
||||
if test "${nonSparseBlocks}" -gt "${inputBlocks}" && ! test "${outputBlocks}" -lt "${nonSparseBlocks}"; then
|
||||
echo "output is not sparse"
|
||||
echo "input file:"
|
||||
ls -ls "${workFile1}"
|
||||
echo "output file:"
|
||||
ls -ls "${workFile2}"
|
||||
echo "input file without holes:"
|
||||
ls -ls "${workFile3}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -37,6 +37,7 @@ runInTerminal () {
|
||||
# tmux 1.8 doesn't have "resize-window"
|
||||
echo "resize-pane -x ${terminalWidth} -y 5"
|
||||
echo "pipe-pane 'cat > ${workFile1}'"
|
||||
sleep 0.5
|
||||
echo "respawn-pane -k \"${commandToRun}\""
|
||||
sleep "${secondsToWait}"
|
||||
echo "kill-server"
|
||||
@@ -51,7 +52,7 @@ runInTerminal () {
|
||||
# longest number of characters seen between "[" and "]".
|
||||
#
|
||||
runWidthTest () {
|
||||
runInTerminal "$1" 1 "${testSubject} -pSs 1K </dev/zero >/dev/null" \
|
||||
runInTerminal "$1" "$2" "${testSubject} -pSs 1K </dev/zero >/dev/null" \
|
||||
| tr '\r' '\n' \
|
||||
| sed -n 's/^.*\[//;s/\].*$//p' \
|
||||
| awk 'BEGIN {m=0} {n=length($0); m=(n>m?n:m)} END {print m}'
|
||||
@@ -64,7 +65,11 @@ runWidthTest () {
|
||||
#
|
||||
widthTest () {
|
||||
terminalWidth="$1"
|
||||
longestBar=$(runWidthTest "${terminalWidth}")
|
||||
longestBar=$(runWidthTest "${terminalWidth}" 1)
|
||||
# Retry test with longer delay, if null result.
|
||||
if test -z "${longestBar}" || test "${longestBar}" -eq 0; then
|
||||
longestBar=$(runWidthTest "${terminalWidth}" 5)
|
||||
fi
|
||||
if test -z "${longestBar}"; then
|
||||
echo "no output from test at width=${terminalWidth}"
|
||||
exit 1
|
||||
|
||||
@@ -17,10 +17,13 @@ if ! "${testSubject}" -h 2>/dev/null | grep -Eq "^ -R,"; then
|
||||
exit 77
|
||||
fi
|
||||
|
||||
# Generate an empty test file.
|
||||
# Generate a 10MiB test file of null bytes.
|
||||
dd if=/dev/zero of="${workFile1}" bs=1024 count=10240 2>/dev/null
|
||||
|
||||
true > "${workFile4}"
|
||||
(
|
||||
# Don't start doing anything until the main transfer process, started below, has begun.
|
||||
while test -e "${workFile4}" && ! test -s "${workFile4}"; do sleep 0.1; done
|
||||
sleep 1
|
||||
"${testSubject}" -R "$(cat "${workFile4}")" -a
|
||||
sleep 2
|
||||
|
||||
Executable
+75
@@ -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
|
||||
@@ -9,6 +9,7 @@ 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'}"
|
||||
true "${workFile3:?not set - call this from 'make check'}"
|
||||
true "${workFile4:?not set - call this from 'make check'}"
|
||||
|
||||
# Skip the test if "-d" is not available.
|
||||
if ! "${testSubject}" -h | grep -Fq ' -d'; then
|
||||
@@ -21,8 +22,12 @@ seq 1 300 > "${workFile2}"
|
||||
|
||||
# Run a background process to perform a few reads from a file, opening a
|
||||
# second file after a moment.
|
||||
# We only start doing anything once the PV process below has started (the
|
||||
# workFile3 check).
|
||||
# NB we just export line to make shellcheck think it's used.
|
||||
true > "${workFile3}"
|
||||
(
|
||||
while test -e "${workFile3}" && ! test -s "${workFile3}"; do sleep 0.1; done
|
||||
export line
|
||||
sleep 1
|
||||
read -r line
|
||||
@@ -34,17 +39,17 @@ sleep 1
|
||||
pid=$!
|
||||
|
||||
sleep 0.1
|
||||
"${testSubject}" -d "${pid}" -f -i 0.5 >/dev/null 2>"${workFile3}"
|
||||
"${testSubject}" -P "${workFile3}" -d "${pid}" -f -i 0.5 >/dev/null 2>"${workFile4}"
|
||||
|
||||
# Skip the test if "-d" does not work.
|
||||
if grep -Fq ' -d: not available' "${workFile3}"; then
|
||||
if grep -Fq ' -d: not available' "${workFile4}"; then
|
||||
echo "no \`--watchfd' / \`-d' option on this platform"
|
||||
exit 77
|
||||
fi
|
||||
|
||||
# Process the output to make it easier to handle.
|
||||
# NB "ESC [ A" is "cursor up", we turn that into "-" and a newline.
|
||||
tr '\r' '\n' < "${workFile3}" | sed 's/.\[A/-!/g' | tr '!' '\n' > "${workFile1}"
|
||||
tr '\r' '\n' < "${workFile4}" | sed 's/.\[A/-!/g' | tr '!' '\n' > "${workFile1}"
|
||||
|
||||
# We should see at least 2 file positions for fd 0.
|
||||
positionsReported="$(awk '/^ *0:/ {print $2}' < "${workFile1}" | sort -n | uniq)"
|
||||
|
||||
@@ -8,6 +8,7 @@ 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'}"
|
||||
true "${workFile3:?not set - call this from 'make check'}"
|
||||
|
||||
# Skip the test if "-d" is not available.
|
||||
if ! "${testSubject}" -h | grep -Fq ' -d'; then
|
||||
@@ -18,12 +19,18 @@ fi
|
||||
seq 1 100 > "${workFile1}"
|
||||
|
||||
# Run a background process to perform a few reads from a file.
|
||||
# We only start doing anything once the PV process below has started (the
|
||||
# workFile3 check).
|
||||
# NB we just export line to make shellcheck think it's used.
|
||||
(export line; sleep 1; read -r line; sleep 1; read -r line; sleep 1) <"${workFile1}" &
|
||||
true > "${workFile3}"
|
||||
(
|
||||
while test -e "${workFile3}" && ! test -s "${workFile3}"; do sleep 0.1; done
|
||||
export line; sleep 1; read -r line; sleep 1; read -r line; sleep 1
|
||||
) <"${workFile1}" &
|
||||
pid=$!
|
||||
|
||||
sleep 0.1
|
||||
"${testSubject}" -d "${pid}:0" -f -i 0.5 >/dev/null 2>"${workFile2}"
|
||||
"${testSubject}" -P "${workFile3}" -d "${pid}:0" -f -i 0.5 >/dev/null 2>"${workFile2}"
|
||||
|
||||
# Skip the test if "-d" does not work.
|
||||
if grep -Fq ' -d: not available' "${workFile2}"; then
|
||||
|
||||
@@ -35,6 +35,13 @@ if test "${SKIP_VALGRIND_TESTS}" = "1"; then
|
||||
exit 77
|
||||
fi
|
||||
|
||||
if command -v arch >/dev/null 2>&1 && arch | grep -Fq -e arm -e aarch; then
|
||||
if ! test "${ENABLE_VALGRIND_ARM}" = "1"; then
|
||||
echo "skipping valgrind on ARM without ENABLE_VALGRIND_ARM"
|
||||
exit 77
|
||||
fi
|
||||
fi
|
||||
|
||||
valgrindHelp="$(valgrind --help 2>&1)"
|
||||
for valgrindOption in "verbose" "show-error-list" "error-exitcode" "track-fds" "leak-check"; do
|
||||
echo "${valgrindHelp}" | grep -Fq "${valgrindOption}" || { echo "test requires \`valgrind --${valgrindOption}'"; exit 77; }
|
||||
|
||||
Reference in New Issue
Block a user