Initial commit based on v1.6.6
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
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.
|
||||
|
||||
|
||||
Documentation
|
||||
*************
|
||||
|
||||
A manual page is included in this distribution. See `man ./doc/quickref.1',
|
||||
or `man pv' after installation.
|
||||
|
||||
|
||||
Compilation
|
||||
***********
|
||||
|
||||
If you have downloaded `pv' from Subversion, first run "./generate.sh".
|
||||
|
||||
To compile the package, type "sh ./configure", which should generate a
|
||||
Makefile for your system. You may then type "make" to build everything.
|
||||
Note that GNU `make' is required; this may be installed as `gmake' on some
|
||||
systems, so if typing "make" gives an error, try "gmake" instead.
|
||||
|
||||
See the file `doc/INSTALL' for more about the `configure' script.
|
||||
|
||||
Developers note that you can do "./configure --enable-debugging" to cause
|
||||
debugging support to be built in, and "--enable-profiling" builds in
|
||||
profiling support (see "man gprof"). Also note that doing "make index" will
|
||||
generate an HTML code index (using "ctags" and "cproto"); this index lists
|
||||
all files used, all functions defined, and all TODOs marked in the code.
|
||||
|
||||
|
||||
Author and acknowledgements
|
||||
***************************
|
||||
|
||||
This package is copyright 2015 Andrew Wood, and is being distributed under
|
||||
the terms of the Artistic License 2.0. For more details of this license,
|
||||
see the file `doc/COPYING'.
|
||||
|
||||
Report bugs in `pv' using the contact form linked from the home page.
|
||||
|
||||
The `pv' home page is at:
|
||||
|
||||
http://www.ivarch.com/programs/pv.shtml
|
||||
|
||||
The latest version can always be found here.
|
||||
|
||||
Credit is also due to:
|
||||
|
||||
Jakub Hrozek <jhrozek@redhat.com>
|
||||
- Fedora package maintainer
|
||||
|
||||
Antoine Beaupré <anarcat@debian.org>
|
||||
- Debian package maintainer
|
||||
|
||||
Kevin Coyner <kcoyner@debian.org>
|
||||
Cédric Delfosse <cedric@debian.org>
|
||||
- previous Debian package maintainers
|
||||
|
||||
Eduardo Aguiar <eduardo.oliveira@sondabrasil.com.br>
|
||||
- provided Portuguese (Brazilian) translation
|
||||
|
||||
Stéphane Lacasse <stephane@gorfou.ca>
|
||||
- provided French translation
|
||||
|
||||
Marcos Kreinacke <public@kreinacke.com>
|
||||
- provided German translation
|
||||
|
||||
Bartosz Feñski <fenio@o2.pl> <http://skawina.eu.org/>
|
||||
- provided Polish translation along with Krystian Zubel
|
||||
|
||||
Joshua Jensen
|
||||
- reported RPM installation bug
|
||||
|
||||
Boris Folgmann <http://www.folgmann.com/en/>
|
||||
- reported cursor handling bug
|
||||
|
||||
Mathias Gumz
|
||||
- reported NLS bug
|
||||
|
||||
Daniel Roethlisberger
|
||||
- submitted patch to use lockfiles for -c if terminal locking fails
|
||||
|
||||
Adam Buchbinder
|
||||
- lots of help with a Cygwin port of -c
|
||||
|
||||
Mark Tomich <http://metuchen.dyndns.org>
|
||||
- suggested -B option
|
||||
|
||||
Gert Menke
|
||||
- reported bug when piping to dd with a large input buffer size
|
||||
|
||||
Ville Herva <Ville.Herva@iki.fi>
|
||||
- informative bug report about rate limiting performance
|
||||
|
||||
Elias Pipping
|
||||
- patch to compile properly on Darwin 9; potential NULL deref report
|
||||
|
||||
Patrick Collison
|
||||
- similar patch for OS X
|
||||
|
||||
Boris Lohner
|
||||
- reported problem that "-L" does not complain if given non-numeric value
|
||||
|
||||
Sebastian Kayser
|
||||
- supplied testing for SIGPIPE, demonstrated internationalisation problem
|
||||
|
||||
Laszlo Ersek <http://phptest11.atw.hu/>
|
||||
- reported shared memory leak on SIGINT with -c
|
||||
|
||||
Phil Rutschman <http://bandgap.rsnsoft.com/>
|
||||
- provided a patch for fully restoring terminal state on exit
|
||||
|
||||
Henry Precheur <http://henry.precheur.org/>
|
||||
- reporting and suggestions for --rate-limit bug when rate is under 10
|
||||
|
||||
E. Rosten <http://mi.eng.cam.ac.uk/~er258/>
|
||||
- supplied patch for block buffering in line mode
|
||||
|
||||
Kjetil Torgrim Homme
|
||||
- reported compilation error with default CFLAGS on non-GCC compilers
|
||||
|
||||
Alexandre de Verteuil
|
||||
- reported bug in OS X build and supplied test environment to fix in
|
||||
|
||||
Martin Baum
|
||||
- supplied patch to return nonzero exit status if terminated by signal
|
||||
|
||||
Sam Nelson <http://www.siliconfuture.net/>
|
||||
- supplied patch to fix trailing slash on DESTDIR
|
||||
|
||||
Daniel Pape
|
||||
- reported Cygwin installation problem due to DESTDIR
|
||||
|
||||
Philipp Beckers
|
||||
- ported to the Syabas PopcornHour A-100 series
|
||||
|
||||
Henry Gebhard <hsggebhardt@googlemail.com>
|
||||
- supplied patches to improve SI prefixes and add --average-rate
|
||||
|
||||
Vladimir Kokarev, Alexander Leo
|
||||
- reported that exit status did not reflect file errors
|
||||
|
||||
Thomas Rachel
|
||||
- submitted patches for IEEE1541 (MiB suffixes), 1+e03 bug
|
||||
|
||||
Guillaume Marcais
|
||||
- submitted speedup patch for line mode
|
||||
|
||||
Moritz Barsnick
|
||||
- submitted patch for compile warning in size calculation
|
||||
|
||||
Pawel Piatek
|
||||
- submitted RPM and patches for AIX
|
||||
|
||||
Sami Liedes
|
||||
- submitted patch for --timer and --bytes with --numeric
|
||||
|
||||
Steven Willis
|
||||
- reported problem with "-R" killing non-PV remote processes
|
||||
|
||||
Vladimir Pal, Vladimir Ermakov
|
||||
- submitted patch which led to development of --format option
|
||||
|
||||
Peter Samuelson <peter@p12n.org>
|
||||
- submitted patch to calculate size if stdout is a block device
|
||||
|
||||
Miguel Diaz
|
||||
- much Cygwin help (and packaging), found narrow-terminal bug
|
||||
|
||||
Jim Salter <http://ubuntuwiki.net>
|
||||
- commissioned work on the --skip-errors option
|
||||
|
||||
Wouter Pronk
|
||||
- reported build problem on SCO
|
||||
|
||||
Bryan Dongray <http://www.dongrays.com>
|
||||
- provided patches for test scripts failing on older Red Hats
|
||||
|
||||
Zev Weiss <www.bewilderbeest.net>
|
||||
- provided patch to fix splice() not using stdin
|
||||
|
||||
Zing Shishak
|
||||
- provided patch for --null / -0 (count null terminated lines)
|
||||
|
||||
Jacek Wielemborek <http://deetah.jogger.pl/kategorie/english>
|
||||
- implemented fdwatch in Python, suggested PV port
|
||||
- reported bug with "-l" and ETA / size
|
||||
- suggested common switches
|
||||
|
||||
Kim Krecht
|
||||
- suggested buffer fill status and last bytes output display options
|
||||
|
||||
Cristian Ciupitu <http://ciupicri.github.io>, Josh Stone
|
||||
- pointed out file descriptor leak with helpful suggestions
|
||||
(Josh Stone initially noticed the missing close)
|
||||
|
||||
Jan Seda
|
||||
- found issue with splice() and SPLICE_F_NONBLOCK causing slowdown
|
||||
|
||||
André Stapf
|
||||
- pointed out formatting problem e.g. 13GB -> 13.1GB which should be
|
||||
shown 13.0GB -> 13.1GB; highlighted on-startup row swapping in -c
|
||||
|
||||
Damon Harper <http://www.usrbin.ca/>
|
||||
- suggested "-D" / "--delay-start" option
|
||||
|
||||
Ganaël Laplanche <http://www.martymac.org>
|
||||
- provided patch for lstat64 on systems that do not support it
|
||||
|
||||
Peter Korsgaard <http://www.buildroot.net/>
|
||||
- provided similar patch for lstat64, specifically for uClibc support
|
||||
|
||||
Ralf Ramsauer <https://blog.ramses-pyramidenbau.de/>
|
||||
- reported bug which dropped transfer rate on terminal resize
|
||||
|
||||
Michiel Van Herwegen
|
||||
- reported and discussed bug with "-l" and ETA / size
|
||||
|
||||
Erkki Seppälä <http://www.inside.org/~flux/>
|
||||
- provided patch implementing "-I"
|
||||
|
||||
Eric A. Borisch
|
||||
- provided details of compatibility fix for "%Lu" in watchpid code
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Files from which this is generated (inside directory `autoconf/make'):
|
||||
#
|
||||
# package.mk # package name and distribution details
|
||||
# vars.mk # compilation, shell and linking variables
|
||||
# filelist.mk~ # lists of files
|
||||
# unreal.mk # phony targets
|
||||
# modules.mk~ # module linking rules
|
||||
# rules.mk # compilation rules
|
||||
# link.mk # real top-level targets
|
||||
# depend.mk~ # dependencies
|
||||
#
|
||||
#
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(src/main/version.c)
|
||||
|
||||
dnl We're using C.
|
||||
dnl
|
||||
AC_LANG_C
|
||||
|
||||
dnl Output a header file.
|
||||
dnl
|
||||
AC_CONFIG_HEADER(src/include/config.h:autoconf/header.in)
|
||||
|
||||
dnl Set directory to check for Configure scripts in.
|
||||
dnl
|
||||
AC_CONFIG_AUX_DIR(autoconf/scripts)
|
||||
|
||||
dnl Read in package details.
|
||||
dnl
|
||||
PACKAGE=`cat $srcdir/doc/PACKAGE`
|
||||
VERSION=`cat $srcdir/doc/VERSION`
|
||||
UCPACKAGE=`tr a-z A-Z < $srcdir/doc/PACKAGE`
|
||||
AC_SUBST(PACKAGE)
|
||||
AC_SUBST(VERSION)
|
||||
AC_SUBST(UCPACKAGE)
|
||||
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
|
||||
AC_DEFINE_UNQUOTED(PROGRAM_NAME, "$PACKAGE")
|
||||
AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
|
||||
|
||||
dnl Check for compile-time options.
|
||||
dnl
|
||||
AC_ARG_ENABLE(debugging,
|
||||
[ --enable-debugging compile with debugging support],
|
||||
if test "$enable_debugging" = "yes"; then
|
||||
CFLAGS="-g -Wall"
|
||||
AC_DEFINE(ENABLE_DEBUGGING)
|
||||
fi
|
||||
)
|
||||
AC_ARG_ENABLE(profiling,
|
||||
[ --enable-profiling compile with profiling support],
|
||||
if test "$enable_profiling" = "yes"; then
|
||||
CFLAGS="-pg $CFLAGS"
|
||||
fi
|
||||
)
|
||||
LFS_SUPPORT="no"
|
||||
AC_ARG_ENABLE(lfs, [ --disable-lfs disable LFS support],
|
||||
if test "$enable_lfs" = "yes"; then
|
||||
LFS_SUPPORT="yes"
|
||||
fi,
|
||||
LFS_SUPPORT="yes"
|
||||
)
|
||||
STATIC_NLS="no"
|
||||
AC_ARG_ENABLE(static-nls, [ --enable-static-nls hardcode NLS with no support files],
|
||||
if test "$enable_static_nls" = "yes"; then
|
||||
STATIC_NLS="yes"
|
||||
fi,
|
||||
STATIC_NLS="no"
|
||||
)
|
||||
NLS_SUPPORT="no"
|
||||
AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support],
|
||||
if test "$enable_nls" = "yes"; then
|
||||
NLS_SUPPORT="yes"
|
||||
fi,
|
||||
NLS_SUPPORT="yes"
|
||||
)
|
||||
SPLICE_SUPPORT="no"
|
||||
AC_ARG_ENABLE(splice, [ --disable-splice do not use splice system call],
|
||||
if test "$enable_splice" = "yes"; then
|
||||
SPLICE_SUPPORT="yes"
|
||||
fi,
|
||||
SPLICE_SUPPORT="yes"
|
||||
)
|
||||
IPC_SUPPORT="no"
|
||||
AC_ARG_ENABLE(ipc, [ --disable-ipc turn off IPC messaging],
|
||||
if test "$enable_ipc" = "yes"; then
|
||||
IPC_SUPPORT="yes"
|
||||
fi,
|
||||
IPC_SUPPORT="yes"
|
||||
)
|
||||
|
||||
dnl Check for various programs.
|
||||
dnl
|
||||
CFLAGS=${CFLAGS:-"-O"}
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
dnl AIX needs -lc128
|
||||
dnl
|
||||
AC_EGREP_CPP([yes], [#ifdef _AIX
|
||||
yes
|
||||
#endif
|
||||
], [LIBS="$LIBS -lc128"])
|
||||
|
||||
dnl NLS stuff.
|
||||
dnl
|
||||
ALL_LINGUAS="de fr pl pt"
|
||||
if test "$NLS_SUPPORT" = "yes"; then
|
||||
AC_DEFINE(ENABLE_NLS)
|
||||
AC_PATH_PROG(MSGFMT, msgfmt, NOMSGFMT)
|
||||
AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
|
||||
AC_PATH_PROG(XGETTEXT, xgettext, xgettext)
|
||||
if test "x$MSGFMT" = "xNOMSGFMT"; then
|
||||
MSGFMT=""
|
||||
STATIC_NLS="yes"
|
||||
fi
|
||||
if test "$STATIC_NLS" = "yes"; then
|
||||
CATALOGS=""
|
||||
NLSOBJ="src/nls/table.o"
|
||||
else
|
||||
AC_CHECK_LIB(intl, main)
|
||||
AC_CHECK_LIB(i, main)
|
||||
fi
|
||||
CATOBJEXT=.mo
|
||||
INSTOBJEXT=.mo
|
||||
for lang in $ALL_LINGUAS; do
|
||||
GMOFILES="$GMOFILES $lang.gmo"
|
||||
POFILES="$POFILES \$(srcdir)/src/nls/$lang.po"
|
||||
CATALOGS="$CATALOGS src/nls/$lang$CATOBJEXT";
|
||||
done
|
||||
if test "$STATIC_NLS" = "yes"; then
|
||||
CATALOGS=""
|
||||
else
|
||||
AC_CHECK_FUNC(gettext,
|
||||
[AC_DEFINE(HAVE_GETTEXT)
|
||||
NLSOBJ=""
|
||||
], [CATALOGS=""; NLSOBJ="src/nls/table.o"
|
||||
]
|
||||
)
|
||||
fi
|
||||
fi
|
||||
AC_CHECK_HEADERS(libintl.h)
|
||||
AC_CHECK_HEADERS(locale.h)
|
||||
AC_SUBST(MSGFMT)
|
||||
AC_SUBST(GMSGFMT)
|
||||
AC_SUBST(XGETTEXT)
|
||||
AC_SUBST(CATOBJEXT)
|
||||
AC_SUBST(INSTOBJEXT)
|
||||
AC_SUBST(GMOFILES)
|
||||
AC_SUBST(POFILES)
|
||||
AC_SUBST(CATALOGS)
|
||||
AC_SUBST(NLSOBJ)
|
||||
|
||||
dnl Getopt checks.
|
||||
dnl
|
||||
AC_CHECK_FUNCS(getopt_long getopt)
|
||||
AC_CHECK_HEADERS(getopt.h)
|
||||
|
||||
dnl LFS checks.
|
||||
dnl
|
||||
if test "$LFS_SUPPORT" = "yes"; then
|
||||
AC_CHECK_FUNCS(open64, AC_DEFINE(ENABLE_LARGEFILE))
|
||||
fi
|
||||
|
||||
dnl Check for various header files and set various other macros.
|
||||
dnl
|
||||
AC_DEFINE(HAVE_CONFIG_H)
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_FUNCS(memcpy basename snprintf stat64)
|
||||
AC_CHECK_HEADERS(limits.h)
|
||||
|
||||
if test "$IPC_SUPPORT" = "yes"; then
|
||||
AC_CHECK_HEADERS(sys/ipc.h sys/param.h libgen.h)
|
||||
fi
|
||||
|
||||
if test "$SPLICE_SUPPORT" = "yes"; then
|
||||
AC_CHECK_FUNCS(splice)
|
||||
fi
|
||||
|
||||
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||
AC_SUBST(INSTALL_DATA)
|
||||
|
||||
dnl Fudging for separate build directories.
|
||||
dnl
|
||||
subdirs=""
|
||||
for i in `find $srcdir/src -type d -print | sed s,$srcdir/,,`; do
|
||||
subdirs="$subdirs $i"
|
||||
done
|
||||
|
||||
dnl Stitch together the Makefile fragments.
|
||||
dnl
|
||||
mk_segments="autoconf/Makefile.in"
|
||||
for i in vars.mk package.mk filelist.mk~ unreal.mk modules.mk~ \
|
||||
rules.mk link.mk depend.mk~; do
|
||||
mk_segments="$mk_segments:autoconf/make/$i"
|
||||
done
|
||||
|
||||
dnl Output files (and create build directory structure too).
|
||||
dnl
|
||||
AC_OUTPUT(Makefile:$mk_segments doc/lsm:doc/lsm.in
|
||||
doc/quickref.1:doc/quickref.1.in
|
||||
doc/$PACKAGE.spec:doc/spec.in
|
||||
src/.dummy:doc/NEWS,
|
||||
rm -f src/.dummy
|
||||
for i in $subdirs; do
|
||||
test -d $i || mkdir $i
|
||||
done
|
||||
, subdirs="$subdirs")
|
||||
|
||||
dnl EOF
|
||||
@@ -0,0 +1,96 @@
|
||||
/*!NOINDEX*/
|
||||
/* Define if you have standard C headers. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define if you have "config.h" (yes, you have). */
|
||||
#undef HAVE_CONFIG_H
|
||||
|
||||
/* Various other header files. */
|
||||
#undef HAVE_GETOPT_H
|
||||
#undef HAVE_LIMITS_H
|
||||
#undef HAVE_SYS_IPC_H
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
#undef HAVE_LIBGEN_H
|
||||
|
||||
/* Functions. */
|
||||
#undef HAVE_GETOPT
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#undef HAVE_MEMCPY
|
||||
#undef HAVE_BASENAME
|
||||
#undef HAVE_SNPRINTF
|
||||
#undef HAVE_STAT64
|
||||
|
||||
#undef HAVE_SPLICE
|
||||
#ifdef HAVE_SPLICE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
/* NB the above must come before NLS, as NLS includes other system headers. */
|
||||
|
||||
/* NLS stuff. */
|
||||
#undef ENABLE_NLS
|
||||
#undef HAVE_LIBINTL_H
|
||||
#undef HAVE_LOCALE_H
|
||||
#undef HAVE_GETTEXT
|
||||
#ifdef ENABLE_NLS
|
||||
# include "library/gettext.h"
|
||||
#else
|
||||
# define _(String) (String)
|
||||
# define N_(String) (String)
|
||||
#endif
|
||||
|
||||
/* The name of the program. */
|
||||
#define PROGRAM_NAME "progname"
|
||||
|
||||
/* The name of the package. */
|
||||
#define PACKAGE ""
|
||||
|
||||
/* The current package version. */
|
||||
#define VERSION "0.0.0"
|
||||
|
||||
/* Various identification and legal stuff. */
|
||||
#define COPYRIGHT_YEAR _("2015")
|
||||
#define COPYRIGHT_HOLDER _("Andrew Wood <andrew.wood@ivarch.com>")
|
||||
#define PROJECT_HOMEPAGE "http://www.ivarch.com/programs/" PROGRAM_NAME ".shtml"
|
||||
#define BUG_REPORTS_TO _("<pv@ivarch.com>")
|
||||
|
||||
/* LFS support. */
|
||||
#undef ENABLE_LARGEFILE
|
||||
#ifdef ENABLE_LARGEFILE
|
||||
# define __USE_LARGEFILE64 1
|
||||
# define _LARGEFILE64_SOURCE 1
|
||||
#else
|
||||
/*
|
||||
* Some Macs have stat64 despite not having open64 while others don't have
|
||||
* either, so here even if we don't have open64 or LFS is disabled, we have
|
||||
* to check whether stat64 exists and only redefine it if it doesn't
|
||||
* otherwise some Macs fail to compile.
|
||||
*/
|
||||
# ifdef __APPLE__
|
||||
# ifndef HAVE_STAT64
|
||||
# define stat64 stat
|
||||
# define fstat64 fstat
|
||||
# define lstat64 lstat
|
||||
# endif
|
||||
# else
|
||||
# define stat64 stat
|
||||
# define fstat64 fstat
|
||||
# define lstat64 lstat
|
||||
# endif
|
||||
# define open64 open
|
||||
# define lseek64 lseek
|
||||
#endif
|
||||
|
||||
#undef HAVE_IPC
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#define HAVE_IPC 1
|
||||
#endif
|
||||
|
||||
#undef CURSOR_ANSWERBACK_BYTE_BY_BYTE
|
||||
#ifndef _AIX
|
||||
#define CURSOR_ANSWERBACK_BYTE_BY_BYTE 1
|
||||
#endif
|
||||
|
||||
/* Support for debugging output. */
|
||||
#undef ENABLE_DEBUGGING
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# Dependencies.
|
||||
#
|
||||
|
||||
src/library/getopt.d src/library/getopt.o: src/library/getopt.c src/include/config.h src/include/library/gettext.h
|
||||
src/library/gettext.d src/library/gettext.o: src/library/gettext.c src/include/config.h src/include/library/gettext.h
|
||||
src/pv/signal.d src/pv/signal.o: src/pv/signal.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/watchpid.d src/pv/watchpid.o: src/pv/watchpid.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/cursor.d src/pv/cursor.o: src/pv/cursor.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/file.d src/pv/file.o: src/pv/file.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/display.d src/pv/display.o: src/pv/display.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/loop.d src/pv/loop.o: src/pv/loop.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/number.d src/pv/number.o: src/pv/number.c src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/transfer.d src/pv/transfer.o: src/pv/transfer.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/pv/state.d src/pv/state.o: src/pv/state.c src/include/pv-internal.h src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/main/version.d src/main/version.o: src/main/version.c src/include/config.h src/include/library/gettext.h
|
||||
src/main/debug.d src/main/debug.o: src/main/debug.c src/include/config.h src/include/library/gettext.h src/include/pv.h
|
||||
src/main/main.d src/main/main.o: src/main/main.c src/include/config.h src/include/library/gettext.h src/include/options.h src/include/pv.h
|
||||
src/main/options.d src/main/options.o: src/main/options.c src/include/config.h src/include/library/gettext.h src/include/options.h src/include/library/getopt.h src/include/pv.h
|
||||
src/main/remote.d src/main/remote.o: src/main/remote.c src/include/config.h src/include/library/gettext.h src/include/options.h src/include/pv.h
|
||||
src/main/help.d src/main/help.o: src/main/help.c src/include/config.h src/include/library/gettext.h
|
||||
@@ -0,0 +1,62 @@
|
||||
# Automatically generated file listings
|
||||
#
|
||||
# Creation time: Fri Jun 30 22:23:37 BST 2017
|
||||
|
||||
allsrc = src/library/getopt.c \
|
||||
src/library/gettext.c \
|
||||
src/pv/signal.c \
|
||||
src/pv/watchpid.c \
|
||||
src/pv/cursor.c \
|
||||
src/pv/file.c \
|
||||
src/pv/display.c \
|
||||
src/pv/loop.c \
|
||||
src/pv/number.c \
|
||||
src/pv/transfer.c \
|
||||
src/pv/state.c \
|
||||
src/main/version.c \
|
||||
src/main/debug.c \
|
||||
src/main/main.c \
|
||||
src/main/options.c \
|
||||
src/main/remote.c \
|
||||
src/main/help.c
|
||||
|
||||
allobj = src/library/getopt.o \
|
||||
src/library/gettext.o \
|
||||
src/pv/signal.o \
|
||||
src/pv/watchpid.o \
|
||||
src/pv/cursor.o \
|
||||
src/pv/file.o \
|
||||
src/pv/display.o \
|
||||
src/pv/loop.o \
|
||||
src/pv/number.o \
|
||||
src/pv/transfer.o \
|
||||
src/pv/state.o \
|
||||
src/main/version.o \
|
||||
src/main/debug.o \
|
||||
src/main/main.o \
|
||||
src/main/options.o \
|
||||
src/main/remote.o \
|
||||
src/main/help.o \
|
||||
src/library.o \
|
||||
src/pv.o \
|
||||
src/nls.o \
|
||||
src/main.o
|
||||
|
||||
alldep = src/library/getopt.d \
|
||||
src/library/gettext.d \
|
||||
src/pv/signal.d \
|
||||
src/pv/watchpid.d \
|
||||
src/pv/cursor.d \
|
||||
src/pv/file.d \
|
||||
src/pv/display.d \
|
||||
src/pv/loop.d \
|
||||
src/pv/number.d \
|
||||
src/pv/transfer.d \
|
||||
src/pv/state.d \
|
||||
src/main/version.d \
|
||||
src/main/debug.d \
|
||||
src/main/main.d \
|
||||
src/main/options.d \
|
||||
src/main/remote.d \
|
||||
src/main/help.d
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Targets.
|
||||
#
|
||||
|
||||
$(package): src/main.o src/library.o src/pv.o @NLSOBJ@
|
||||
$(CC) $(LINKFLAGS) $(CFLAGS) -o $@ src/main.o src/library.o src/pv.o @NLSOBJ@ $(LIBS)
|
||||
|
||||
$(package)-static: src/main.o src/library.o src/pv.o @NLSOBJ@
|
||||
$(CC) $(LINKFLAGS) $(CFLAGS) -static -o $@ src/main.o src/library.o src/pv.o @NLSOBJ@ $(LIBS)
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,14 @@
|
||||
# Automatically generated module linking rules
|
||||
#
|
||||
# Creation time: Fri Jun 30 22:23:37 BST 2017
|
||||
|
||||
src/library.o: src/library/getopt.o src/library/gettext.o
|
||||
$(LD) $(LDFLAGS) -o $@ src/library/getopt.o src/library/gettext.o
|
||||
|
||||
src/pv.o: src/pv/cursor.o src/pv/display.o src/pv/file.o src/pv/loop.o src/pv/number.o src/pv/signal.o src/pv/state.o src/pv/transfer.o src/pv/watchpid.o
|
||||
$(LD) $(LDFLAGS) -o $@ src/pv/cursor.o src/pv/display.o src/pv/file.o src/pv/loop.o src/pv/number.o src/pv/signal.o src/pv/state.o src/pv/transfer.o src/pv/watchpid.o
|
||||
|
||||
src/main.o: src/main/debug.o src/main/help.o src/main/main.o src/main/options.o src/main/remote.o src/main/version.o
|
||||
$(LD) $(LDFLAGS) -o $@ src/main/debug.o src/main/help.o src/main/main.o src/main/options.o src/main/remote.o src/main/version.o
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Package name, version, and distribution files.
|
||||
#
|
||||
|
||||
package = @PACKAGE@
|
||||
version = @VERSION@
|
||||
PACKAGE = @PACKAGE@
|
||||
|
||||
distfiles = \
|
||||
$(srcdir)/README \
|
||||
$(srcdir)/autoconf \
|
||||
$(srcdir)/configure \
|
||||
$(srcdir)/doc \
|
||||
$(srcdir)/src \
|
||||
$(srcdir)/tests
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# Compilation rules.
|
||||
#
|
||||
|
||||
.SUFFIXES: .c .d .o
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
.c.d:
|
||||
sh $(srcdir)/autoconf/scripts/depend.sh \
|
||||
$(CC) $< $(<:%.c=%) $(srcdir) $(CFLAGS) $(CPPFLAGS) > $@
|
||||
|
||||
#
|
||||
# NLS stuff
|
||||
#
|
||||
|
||||
%.mo: %.po
|
||||
$(MSGFMT) -o $@ $<
|
||||
@touch $@
|
||||
@chmod 644 $@
|
||||
|
||||
%.gmo: %.po
|
||||
rm -f $@
|
||||
$(GMSGFMT) -o $@ $<
|
||||
@touch $@
|
||||
@chmod 644 $@
|
||||
|
||||
$(srcdir)/src/nls/$(PACKAGE).pot: $(allsrc)
|
||||
$(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(srcdir) \
|
||||
--add-comments --keyword=_ --keyword=N_ \
|
||||
$(allsrc)
|
||||
if cmp -s $(PACKAGE).po $@; then \
|
||||
rm -f $(PACKAGE).po; \
|
||||
else \
|
||||
rm -f $@; \
|
||||
mv $(PACKAGE).po $@; \
|
||||
chmod 644 $@; \
|
||||
fi
|
||||
|
||||
src/nls/table.c: $(POFILES)
|
||||
sh $(srcdir)/autoconf/scripts/po2table.sh $(POFILES) > src/nls/table.c
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#
|
||||
# Rules for all phony targets.
|
||||
#
|
||||
|
||||
.PHONY: all help make dep depend test check \
|
||||
clean depclean indentclean distclean cvsclean svnclean \
|
||||
index manhtml indent update-po \
|
||||
doc dist release \
|
||||
install uninstall \
|
||||
rpm srpm
|
||||
|
||||
all: $(alltarg) $(CATALOGS)
|
||||
|
||||
help:
|
||||
@echo 'This Makefile has the following utility targets:'
|
||||
@echo
|
||||
@echo ' all build all binary targets'
|
||||
@echo ' install install compiled package and manual'
|
||||
@echo ' uninstall uninstall the package'
|
||||
@echo ' check / test run standardised tests on the compiled binary'
|
||||
@echo
|
||||
@echo 'Developer targets:'
|
||||
@echo
|
||||
@echo ' make rebuild the Makefile (after adding new files)'
|
||||
@echo ' dep / depend rebuild .d (dependency) files'
|
||||
@echo ' clean remove .o (object) and .c~ (backup) files'
|
||||
@echo ' depclean remove .d (dependency) files'
|
||||
@echo ' indentclean remove files left over from "make indent"'
|
||||
@echo ' distclean remove everything not distributed'
|
||||
@echo ' cvsclean remove everything not in CVS/SVN'
|
||||
@echo
|
||||
@echo ' index generate an HTML index of source code'
|
||||
@echo ' manhtml output HTML man page to stdout'
|
||||
@echo ' indent reformat all source files with "indent"'
|
||||
@echo ' update-po update the .po files'
|
||||
@echo
|
||||
@echo ' dist create a source tarball for distribution'
|
||||
@echo ' rpm build a binary RPM (passes $$RPMFLAGS to RPM)'
|
||||
@echo ' srpm build a source RPM (passes $$RPMFLAGS to RPM)'
|
||||
@echo ' release dist+rpm+srpm'
|
||||
@echo
|
||||
|
||||
make:
|
||||
echo > $(srcdir)/autoconf/make/filelist.mk~
|
||||
echo > $(srcdir)/autoconf/make/modules.mk~
|
||||
cd $(srcdir); \
|
||||
bash autoconf/scripts/makemake.sh \
|
||||
autoconf/make/filelist.mk~ \
|
||||
autoconf/make/modules.mk~
|
||||
sh ./config.status
|
||||
|
||||
dep depend: $(alldep)
|
||||
echo '#' > $(srcdir)/autoconf/make/depend.mk~
|
||||
echo '# Dependencies.' >> $(srcdir)/autoconf/make/depend.mk~
|
||||
echo '#' >> $(srcdir)/autoconf/make/depend.mk~
|
||||
echo >> $(srcdir)/autoconf/make/depend.mk~
|
||||
cat $(alldep) >> $(srcdir)/autoconf/make/depend.mk~
|
||||
sh ./config.status
|
||||
|
||||
clean:
|
||||
rm -f $(allobj)
|
||||
|
||||
depclean:
|
||||
rm -f $(alldep)
|
||||
|
||||
indentclean:
|
||||
cd $(srcdir) && for FILE in $(allsrc); do rm -f ./$${FILE}~; done
|
||||
|
||||
update-po: $(srcdir)/src/nls/$(PACKAGE).pot
|
||||
catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
lang=$(srcdir)/`echo $$cat | sed 's/$(CATOBJEXT)$$//'`; \
|
||||
mv $$lang.po $$lang.old.po; \
|
||||
if $(MSGMERGE) $$lang.old.po $(srcdir)/src/nls/$(PACKAGE).pot > $$lang.po; then \
|
||||
rm -f $$lang.old.po; \
|
||||
else \
|
||||
echo "msgmerge for $$cat failed!"; \
|
||||
rm -f $$lang.po; \
|
||||
mv $$lang.old.po $$lang.po; \
|
||||
chmod 644 $$lang.po; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
distclean: clean depclean
|
||||
rm -f $(alltarg) src/include/config.h
|
||||
rm -rf $(package)-$(version).tar* $(package)-$(version) $(package)-$(version)-*.rpm
|
||||
rm -f *.html config.*
|
||||
rm Makefile
|
||||
|
||||
cvsclean svnclean: distclean
|
||||
rm -f doc/lsm
|
||||
rm -f doc/$(package).spec
|
||||
rm -f doc/quickref.1
|
||||
rm -f configure
|
||||
rm -f src/nls/*.gmo src/nls/*.mo
|
||||
echo > $(srcdir)/autoconf/make/depend.mk~
|
||||
echo > $(srcdir)/autoconf/make/filelist.mk~
|
||||
echo > $(srcdir)/autoconf/make/modules.mk~
|
||||
|
||||
doc:
|
||||
:
|
||||
|
||||
index:
|
||||
(cd $(srcdir); sh autoconf/scripts/index.sh $(srcdir)) > index.html
|
||||
|
||||
manhtml:
|
||||
@man2html ./doc/quickref.1 \
|
||||
| sed -e '1,/<BODY/d' -e '/<\/BODY/,$$d' \
|
||||
-e 's|<A [^>]*> </A>||ig' \
|
||||
-e 's|<A [^>]*>\([^<]*\)</A>|\1|ig' \
|
||||
-e '/<H1/d' -e 's|\(</H[0-9]>\)|\1<P>|ig' \
|
||||
-e 's/<DL COMPACT>/<DL>/ig' \
|
||||
-e 's/<[0-9A-Za-z_.-]\+@[0-9A-Za-z_.-]\+>//g' \
|
||||
-e 's|<I>\(http://.*\)</I>|<A HREF="\1">\1</A>|ig' \
|
||||
| sed -e '1,/<HR/d' -e '/<H2>Index/,/<HR/d' \
|
||||
|
||||
indent:
|
||||
cd $(srcdir) && indent -npro -kr -i8 -cd42 -c45 $(allsrc)
|
||||
|
||||
dist: doc update-po
|
||||
rm -rf $(package)-$(version)
|
||||
mkdir $(package)-$(version)
|
||||
cp -dprf Makefile $(distfiles) $(package)-$(version)
|
||||
cd $(package)-$(version); $(MAKE) distclean
|
||||
cp -dpf doc/lsm $(package)-$(version)/doc/
|
||||
cp -dpf doc/$(package).spec $(package)-$(version)/doc/
|
||||
chmod 644 `find $(package)-$(version) -type f -print`
|
||||
chmod 755 `find $(package)-$(version) -type d -print`
|
||||
chmod 755 `find $(package)-$(version)/autoconf/scripts`
|
||||
chmod 755 $(package)-$(version)/configure
|
||||
rm -rf DUMMY `find $(package)-$(version) -type d -name CVS`
|
||||
rm -rf DUMMY `find $(package)-$(version) -type d -name .svn`
|
||||
tar cf $(package)-$(version).tar $(package)-$(version)
|
||||
rm -rf $(package)-$(version)
|
||||
-gzip -f9 $(package)-$(version).tar
|
||||
|
||||
check test: $(alltarg)
|
||||
sh $(srcdir)/autoconf/scripts/run-test.sh ./$(package) $(srcdir)
|
||||
|
||||
install: all doc
|
||||
$(srcdir)/autoconf/scripts/mkinstalldirs \
|
||||
"$(DESTDIR)$(bindir)"
|
||||
$(srcdir)/autoconf/scripts/mkinstalldirs \
|
||||
"$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL) -m 755 $(package) \
|
||||
"$(DESTDIR)$(bindir)/$(package)"
|
||||
$(INSTALL) -m 644 doc/quickref.1 \
|
||||
"$(DESTDIR)$(mandir)/man1/$(package).1"
|
||||
if test -n "$(CATALOGS)"; then \
|
||||
catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
name=`echo $$cat | sed 's,^.*/,,g'`; \
|
||||
if test "`echo $$name | sed 's/.*\(\..*\)/\1/'`" = ".gmo"; then \
|
||||
destdir=$(gnulocaledir); \
|
||||
else \
|
||||
destdir=$(localedir); \
|
||||
fi; \
|
||||
lang=`echo $$name | sed 's/$(CATOBJEXT)$$//'`; \
|
||||
dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
|
||||
$(srcdir)/autoconf/scripts/mkinstalldirs $$dir; \
|
||||
$(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
|
||||
done; \
|
||||
fi
|
||||
|
||||
uninstall:
|
||||
-$(UNINSTALL) "$(DESTDIR)$(bindir)/$(package)"
|
||||
-$(UNINSTALL) "$(DESTDIR)$(mandir)/man1/$(package).1"
|
||||
-$(UNINSTALL) "$(DESTDIR)$(mandir)/man1/$(package).1.gz"
|
||||
-if test -n "$(CATALOGS)"; then \
|
||||
catalogs='$(CATALOGS)'; \
|
||||
for cat in $$catalogs; do \
|
||||
name=`echo $$cat | sed 's,^.*/,,g'`; \
|
||||
if test "`echo $$name | sed 's/.*\(\..*\)/\1/'`" = ".gmo"; then \
|
||||
destdir=$(gnulocaledir); \
|
||||
else \
|
||||
destdir=$(localedir); \
|
||||
fi; \
|
||||
lang=`echo $$name | sed 's/$(CATOBJEXT)$$//'`; \
|
||||
dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
|
||||
$(UNINSTALL) $$dir/$(PACKAGE)$(INSTOBJEXT); \
|
||||
done; \
|
||||
fi
|
||||
|
||||
rpm:
|
||||
test -e $(package)-$(version).tar.gz || $(MAKE) dist
|
||||
rpmbuild $(RPMFLAGS) --define="%_topdir `pwd`/rpm" -tb $(package)-$(version).tar.gz
|
||||
mv rpm/RPMS/*/$(package)-*.rpm .
|
||||
rm -rf rpm
|
||||
|
||||
srpm:
|
||||
test -e $(package)-$(version).tar.gz || $(MAKE) dist
|
||||
rpmbuild $(RPMFLAGS) --define="%_topdir `pwd`/rpm" -ts $(package)-$(version).tar.gz
|
||||
mv rpm/SRPMS/*$(package)-*.rpm .
|
||||
rm -rf rpm
|
||||
|
||||
release: dist rpm srpm
|
||||
zcat $(package)-$(version).tar.gz | bzip2 > $(package)-$(version).tar.bz2
|
||||
-grep -Fq '%_gpg_name' ~/.rpmmacros 2>/dev/null && rpm --addsign *.rpm
|
||||
-gpg --list-secret-keys 2>&1 | grep -Fq 'uid' && gpg -ab *.tar.gz && rename .asc .txt *.tar.gz.asc
|
||||
-gpg --list-secret-keys 2>&1 | grep -Fq 'uid' && gpg -ab *.tar.bz2 && rename .asc .txt *.tar.bz2.asc
|
||||
chmod 644 $(package)-$(version)*
|
||||
@@ -0,0 +1,46 @@
|
||||
#
|
||||
# Variables for Make.
|
||||
#
|
||||
|
||||
srcdir = @srcdir@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
infodir = @infodir@
|
||||
mandir = @mandir@
|
||||
etcdir = @prefix@/etc
|
||||
datadir = @datadir@
|
||||
sbindir = @sbindir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
gnulocaledir = $(prefix)/share/locale
|
||||
|
||||
CATALOGS = @CATALOGS@
|
||||
POFILES = @POFILES@
|
||||
GMSGFMT = @GMSGFMT@
|
||||
MSGFMT = @MSGFMT@
|
||||
XGETTEXT = @XGETTEXT@
|
||||
MSGMERGE = msgmerge
|
||||
CATOBJEXT = @CATOBJEXT@
|
||||
INSTOBJEXT = @INSTOBJEXT@
|
||||
|
||||
@SET_MAKE@
|
||||
SHELL = /bin/sh
|
||||
CC = @CC@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
UNINSTALL = rm -f
|
||||
|
||||
LDFLAGS = -r
|
||||
LINKFLAGS = @LDFLAGS@
|
||||
DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\"
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/src/include -Isrc/include $(DEFS)
|
||||
LIBS = @LIBS@
|
||||
|
||||
alltarg = @PACKAGE@
|
||||
|
||||
# EOF
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Benchmark the read/write performance of pv by looking at the number of
|
||||
# read() and write() calls and the average amount of data transferred each
|
||||
# time, as suggested by Ville Herva <Ville.Herva@iki.fi>.
|
||||
#
|
||||
|
||||
test_input=`mktemp /tmp/pvbench1XXXXXX`
|
||||
strace_output=`mktemp /tmp/pvbench2XXXXXX`
|
||||
|
||||
trap "rm -f ${test_input} ${strace_output}" 0
|
||||
|
||||
pv=${pv:-./pv}
|
||||
test -x ${pv} || pv=pv
|
||||
|
||||
dd if=/dev/zero of=${test_input} bs=1k count=1k >/dev/null 2>&1
|
||||
|
||||
echo -e "Buf(k)\tRate(k)\tReads\tRsize\tWrites\tWsize"
|
||||
|
||||
for ((buffer=100; buffer<=1000; buffer+=100)); do
|
||||
for ((rate=0; rate<=1000; rate+=100)); do
|
||||
rateparm="-L ${rate}k"
|
||||
test ${rate} -eq 0 && rateparm=""
|
||||
strace -tt -o ${strace_output} \
|
||||
${pv} ${rateparm} -B ${buffer}k \
|
||||
-f < ${test_input} > /dev/null 2>&1
|
||||
rdata=$(
|
||||
awk '$2~/^read\(0,/{c++;t+=$NF}END{print c "\t" t/c}' \
|
||||
${strace_output}
|
||||
)
|
||||
wdata=$(
|
||||
awk '$2~/^write\(1,/{c++;t+=$NF}END{print c "\t" t/c}' \
|
||||
${strace_output}
|
||||
)
|
||||
echo -e "${buffer}\t${rate}\t${rdata}\t${wdata}"
|
||||
done
|
||||
done
|
||||
|
||||
# EOF
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Generate dependencies for a C source file.
|
||||
#
|
||||
|
||||
CC=$1
|
||||
shift
|
||||
file=$1
|
||||
shift
|
||||
stem=$1
|
||||
shift
|
||||
srcdir=$1
|
||||
abssrc=`echo $srcdir | sed ':1
|
||||
s,^\./,,g
|
||||
t1'`
|
||||
shift
|
||||
|
||||
abssrc=`echo "$abssrc" | sed 's,\\.,\\\\.,g'`
|
||||
srcdir=`echo "$srcdir" | sed 's,\\.,\\\\.,g'`
|
||||
|
||||
$CC -M -MG $* $file \
|
||||
| sed -e 's, /[^ ]*,,g' -e "s,^.*\.o:,${stem}.d ${stem}.o:," \
|
||||
-e '/^ \\$/d' -e 's/ \\$//' \
|
||||
-e 's,'"$srcdir"'/,,g' -e 's,'"$abssrc"'/,,g' \
|
||||
| tr '\n' ' ' \
|
||||
| tr -s ' '
|
||||
|
||||
echo
|
||||
|
||||
# EOF
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
#!/bin/ash
|
||||
#
|
||||
# Script to generate an HTML index of all C code from the current directory
|
||||
# downwards (skipping directories ending in ~). The header comment in each
|
||||
# file is listed, and each function's prototype and comment are given. A
|
||||
# list of "TODO:" comments is also generated.
|
||||
#
|
||||
# Outputs the HTML on standard output.
|
||||
#
|
||||
# If a parameter is given, it is the prefix to put before any "view file"
|
||||
# links, eg ".." to link to "../dir/file.c" instead of "dir/file.c".
|
||||
#
|
||||
# Skips any files containing the string !NOINDEX.
|
||||
#
|
||||
# Requires ctags and cproto.
|
||||
#
|
||||
|
||||
OFFS=$1
|
||||
|
||||
|
||||
# Convert the given string to HTML-escaped values (<, >, & escaped) on
|
||||
# stdout.
|
||||
#
|
||||
html_safe () {
|
||||
echo "$*" \
|
||||
| sed -e 's|&|\&|g;s|<|\<|g;s|>|\>|g'
|
||||
}
|
||||
|
||||
|
||||
# Convert the given string to HTML-escaped values (<, >, & escaped) on
|
||||
# stdout, also adding a <BR> to the end of each line.
|
||||
#
|
||||
html_safebr () {
|
||||
echo "$*" \
|
||||
| sed -e 's|&|\&|g;s|<|\<|g;s|>|\>|g;s/$/<BR>/'
|
||||
}
|
||||
|
||||
ALLFILES=`find . -name '*~' -prune -o -type f -name '*.c' \
|
||||
-exec grep -FL '!NOINDEX' /dev/null '{}' ';'`
|
||||
|
||||
CTAGDATA=`echo "$ALLFILES" \
|
||||
| ctags -nRf- -L- --c-types=f \
|
||||
| sed 's/ .\// /;s/;" .*$//'`
|
||||
|
||||
FILELIST=`echo "$CTAGDATA" | cut -d ' ' -f 2 | sort | uniq`
|
||||
|
||||
echo '<HTML><HEAD>'
|
||||
echo '<TITLE>Source Code Index</TITLE>'
|
||||
echo '</HEAD><BODY>'
|
||||
echo '<H1><A NAME="top">Source Code Index</A></H1>'
|
||||
echo '<P><UL>'
|
||||
echo '<LI><A HREF="#files">File Listing</A></LI>'
|
||||
echo '<LI><A HREF="#funcs">Function Listing</A></LI>'
|
||||
echo '<LI><A HREF="#todo">To-Do Listing</A></LI>'
|
||||
echo '</UL></P>'
|
||||
|
||||
echo '<H2><A NAME="files">File Listing</A></H2>'
|
||||
echo '<P><UL>'
|
||||
echo "$FILELIST" \
|
||||
| sed -e \
|
||||
's|^.*$|<LI><CODE CLASS="filename"><A HREF="#file-\0">\0</A></CODE></LI>|'
|
||||
echo '</UL></P>'
|
||||
|
||||
for FILE in $FILELIST; do
|
||||
|
||||
DIR=`dirname $FILE`
|
||||
FUNCDEFS=`cproto -f1 -I. -Isrc/include -I$DIR $FILE 2>/dev/null \
|
||||
| sed -n 's/^.*[ *]\([^ *(]*\)(.*$/\1/p'`
|
||||
FILEHEAD="`sed -n -e \
|
||||
'1,/\*\//{/\/\*/,/\*\//{s/^[\/ *]//;s/^\*[\/]*//;p;};}' \
|
||||
< $FILE`"
|
||||
FILESHORTDESC=`echo "$FILEHEAD" | sed -n '1,/^ *$/{/^ *[^ ]*/p;}'`
|
||||
FILELONGDESC=`echo "$FILEHEAD" | sed '1,/^ *$/d'`
|
||||
|
||||
echo '<P><HR WIDTH="100%"></P>'
|
||||
echo '<P><TABLE BORDER="0"><TR>'
|
||||
echo '<TD VALIGN="TOP"><CODE CLASS="filename">'
|
||||
echo '<A NAME="file-'"$FILE"'">'"$FILE"'</A></CODE></TD>'
|
||||
echo '<TD VALIGN="TOP"> - </TD>'
|
||||
echo '<TD VALIGN="TOP">'`html_safe "$FILESHORTDESC"`'</TD>'
|
||||
echo '</TR></TABLE></P>'
|
||||
echo '<P><SMALL>[<A HREF="'"$OFFS/$FILE"'">View File</A>]</SMALL></P>'
|
||||
echo '<P><BLOCKQUOTE>'
|
||||
echo "`html_safebr "$FILELONGDESC"`"
|
||||
echo '</BLOCKQUOTE></P>'
|
||||
|
||||
if [ -n "$FUNCDEFS" ]; then
|
||||
echo '<P>Functions defined:</P>'
|
||||
echo '<P><UL>'
|
||||
echo "$FUNCDEFS" \
|
||||
| sed 's|^.*$|<A HREF="#func-\0---'"$FILE"'">\0</A>|' \
|
||||
| sed 's/^/<LI><CODE CLASS="funcname">/;s|$|</CODE></LI>|'
|
||||
echo '</UL></P>'
|
||||
fi
|
||||
|
||||
echo '<P ALIGN="RIGHT"><SMALL CLASS="navbar">['
|
||||
echo '<A HREF="#top">Top</A> |'
|
||||
echo '<A HREF="#todo">To Do</A> |'
|
||||
echo '<A HREF="#funcs">Functions</A> ]</SMALL></P>'
|
||||
done
|
||||
|
||||
echo '<H2><A NAME="funcs">Function Listing</A></H2>'
|
||||
echo '<P><UL>'
|
||||
echo "$CTAGDATA" | while read FUNC FILE LINENUM REST; do
|
||||
echo -n '<LI><CODE CLASS="funcname">'
|
||||
echo -n '<A HREF="#func-'"$FUNC"'---'"$FILE"'">'"$FUNC"'</A></CODE> '
|
||||
echo '[<CODE CLASS="filename">'"$FILE"'</CODE>]</LI>'
|
||||
done
|
||||
echo '</UL></P>'
|
||||
|
||||
echo "$CTAGDATA" | while read FUNC FILE LINENUM REST; do
|
||||
|
||||
FUNCDEF=`sed -n "$LINENUM,/{/p" < $FILE \
|
||||
| tr '\n' ' ' \
|
||||
| tr -d '{'`
|
||||
|
||||
LASTCOMLINE=`sed -n '1,'"$LINENUM"'{/\/\*/=;}' < $FILE | sed -n '$p'`
|
||||
[ -z "$LASTCOMLINE" ] && LASTCOMLINE=1
|
||||
LASTENDFUNCLINE=`sed -n '1,'"$LINENUM"'{/}/=;}' < $FILE | sed -n '$p'`
|
||||
[ -z "$LASTENDFUNCLINE" ] && LASTENDFUNCLINE=1
|
||||
FUNCHEAD="`sed -n -e \
|
||||
"$LASTCOMLINE,"'/\*\//{h;s/^[\/ *]//;s/^\*[\/]*//;p;x;/\*\//q;}' \
|
||||
< $FILE`"
|
||||
[ "$LASTCOMLINE" -le "$LASTENDFUNCLINE" ] && FUNCHEAD=""
|
||||
|
||||
echo '<P><HR WIDTH="100%"></P>'
|
||||
echo '<P ALIGN="LEFT">'
|
||||
echo -n '<CODE CLASS="funcname"><A NAME="func-'"$FUNC"'---'"$FILE"'">'
|
||||
echo -n "$FUNC"'</A></CODE> '
|
||||
echo -n '[<CODE CLASS="filename"><A HREF="#file-'"$FILE"'">'
|
||||
echo "$FILE"'</A></CODE>]'
|
||||
echo '</P>'
|
||||
|
||||
echo '<P><CODE CLASS="funcdef">'"`html_safe "$FUNCDEF"`"'</CODE></P>'
|
||||
|
||||
echo '<P><BLOCKQUOTE>'
|
||||
echo "`html_safebr "$FUNCHEAD"`"
|
||||
echo '</BLOCKQUOTE></P>'
|
||||
|
||||
echo '<P ALIGN="RIGHT"><SMALL CLASS="navbar">['
|
||||
echo '<A HREF="#top">Top</A> |'
|
||||
echo '<A HREF="#todo">To Do</A> |'
|
||||
echo '<A HREF="#files">Files</A> ]</SMALL></P>'
|
||||
done
|
||||
|
||||
echo '<H2><A NAME="todo">To Do Listing</A></H2>'
|
||||
echo '<P><UL>'
|
||||
for FILE in $FILELIST; do
|
||||
|
||||
TODOLINES=`sed -n \
|
||||
-e '/\/\*.*\*\//!{/\/\*/,/\*\//{/TODO:/{=;};};}' \
|
||||
-e '/\/\*.*\*\//{/TODO:/{=;};}' \
|
||||
< $FILE`
|
||||
|
||||
[ -z "$TODOLINES" ] && continue
|
||||
|
||||
echo -n '<LI><CODE CLASS="filename">'
|
||||
echo '<A HREF="#file-'"$FILE"'">'"$FILE"'</A></CODE>'
|
||||
echo '<UL>'
|
||||
|
||||
for NUM in $TODOLINES; do
|
||||
TODO=`sed -n "$NUM"'{s/^.*TODO://;s/\*\/.*$//;p;}' < $FILE`
|
||||
echo "<LI>[<B>$NUM</B>] `html_safe "$TODO"`</LI>"
|
||||
done
|
||||
|
||||
echo '</UL></LI>'
|
||||
done
|
||||
|
||||
echo '</BODY></HTML>'
|
||||
|
||||
# EOF
|
||||
Executable
+250
@@ -0,0 +1,250 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
||||
Executable
+113
@@ -0,0 +1,113 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Generate Makefile dependencies inclusion and module target file "depend.mk~"
|
||||
# by scanning the directory "src" for files ending in ".c" and ".d", and for
|
||||
# subdirectories not starting with "_".
|
||||
#
|
||||
# Modules live inside subdirectories called [^_]* - i.e. a directory "foo" will
|
||||
# have a rule created which links all code inside it to "foo.o".
|
||||
#
|
||||
# The directory "src/include" is never scanned; neither are CVS or SVN
|
||||
# directories.
|
||||
#
|
||||
|
||||
outlist=$1
|
||||
outlink=$2
|
||||
|
||||
FIND=find
|
||||
GREP=grep
|
||||
which gfind 2>/dev/null | grep /gfind >/dev/null && FIND=gfind
|
||||
which ggrep 2>/dev/null | grep /ggrep >/dev/null && GREP=ggrep
|
||||
|
||||
echo '# Automatically generated file listings' > $outlist
|
||||
echo '#' >> $outlist
|
||||
echo "# Creation time: `date`" >> $outlist
|
||||
echo >> $outlist
|
||||
|
||||
echo '# Automatically generated module linking rules' > $outlink
|
||||
echo '#' >> $outlink
|
||||
echo "# Creation time: `date`" >> $outlink
|
||||
echo >> $outlink
|
||||
|
||||
echo -n "Scanning for source files: "
|
||||
|
||||
allsrc=`$FIND src -type f -name "*.c" -print`
|
||||
allobj=`echo $allsrc | tr ' ' '\n' | sed 's/\.c$/.o/'`
|
||||
alldep=`echo $allsrc | tr ' ' '\n' | sed 's/\.c$/.d/'`
|
||||
|
||||
echo `echo $allsrc | wc -w | tr -d ' '` found
|
||||
|
||||
echo -n "Scanning for modules: "
|
||||
|
||||
modules=`$FIND src -type d -print \
|
||||
| $GREP -v '^src$' \
|
||||
| $GREP -v '/_' \
|
||||
| $GREP -v '^src/include' \
|
||||
| $GREP -v 'CVS' \
|
||||
| $GREP -v '.svn' \
|
||||
| while read DIR; do \
|
||||
CONTENT=\$(/bin/ls -d \$DIR/* \
|
||||
| $GREP -v '.po$' \
|
||||
| $GREP -v '.gmo$' \
|
||||
| $GREP -v '.mo$' \
|
||||
| $GREP -v '.h$' \
|
||||
| sed -n '$p'); \
|
||||
[ -n "\$CONTENT" ] || continue; \
|
||||
echo \$DIR; \
|
||||
done
|
||||
`
|
||||
|
||||
echo up to `echo $modules | wc -w | tr -d ' '` found
|
||||
|
||||
echo "Writing module linking rules"
|
||||
|
||||
echo -n [
|
||||
for i in $modules; do echo -n ' '; done
|
||||
echo -n -e ']\r['
|
||||
|
||||
for i in $modules; do
|
||||
echo -n '.'
|
||||
allobj="$allobj $i.o"
|
||||
deps=""
|
||||
for j in $i/*.c; do
|
||||
[ -f $j ] || continue
|
||||
newobj=`echo $j | sed -e 's@\.c$@.o@'`
|
||||
deps="$deps $newobj"
|
||||
done
|
||||
for j in $i/*; do
|
||||
[ -d "$j" ] || continue
|
||||
[ `basename $j` = "CVS" ] && continue
|
||||
[ `basename $j` = ".svn" ] && continue
|
||||
CONTENT=`/bin/ls -d $j/* \
|
||||
| $GREP -v '.po$' \
|
||||
| $GREP -v '.gmo$' \
|
||||
| $GREP -v '.mo$' \
|
||||
| $GREP -v '.h$' \
|
||||
| sed -n '$p'`
|
||||
[ -n "$CONTENT" ] || continue
|
||||
deps="$deps $j.o"
|
||||
done
|
||||
[ -n "$deps" ] || continue
|
||||
echo "$i.o: $deps" >> $outlink
|
||||
echo ' $(LD) $(LDFLAGS) -o $@' "$deps" >> $outlink
|
||||
echo >> $outlink
|
||||
done
|
||||
|
||||
echo ']'
|
||||
|
||||
echo "Listing source, object and dependency files"
|
||||
|
||||
echo -n "allsrc = " >> $outlist
|
||||
echo $allsrc | sed 's,src/nls/cat-id-tbl.c,,' | sed -e 's/ / \\!/g'\
|
||||
| tr '!' '\n' >> $outlist
|
||||
echo >> $outlist
|
||||
echo -n "allobj = " >> $outlist
|
||||
echo $allobj | sed -e 's/ / \\!/g' | tr '!' '\n' >> $outlist
|
||||
echo >> $outlist
|
||||
echo -n "alldep = " >> $outlist
|
||||
echo $alldep | sed -e 's/ / \\!/g' | tr '!' '\n' >> $outlist
|
||||
|
||||
echo >> $outlist
|
||||
echo >> $outlink
|
||||
|
||||
# EOF
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# mkinstalldirs --- make directory hierarchy
|
||||
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||
# Created: 1993-05-16
|
||||
# Last modified: 1994-03-25
|
||||
# Public domain
|
||||
|
||||
errstatus=0
|
||||
|
||||
for file in ${1+"$@"} ; do
|
||||
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
|
||||
shift
|
||||
|
||||
pathcomp=
|
||||
for d in ${1+"$@"} ; do
|
||||
pathcomp="$pathcomp$d"
|
||||
case "$pathcomp" in
|
||||
-* ) pathcomp=./$pathcomp ;;
|
||||
esac
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
echo "mkdir $pathcomp" 1>&2
|
||||
mkdir "$pathcomp" || errstatus=$?
|
||||
chmod 755 $pathcomp 2>/dev/null
|
||||
fi
|
||||
|
||||
pathcomp="$pathcomp/"
|
||||
done
|
||||
done
|
||||
|
||||
exit $errstatus
|
||||
|
||||
# mkinstalldirs ends here
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Messy script to convert all of the given .po files to a single C file on
|
||||
# stdout.
|
||||
|
||||
cat <<EOF
|
||||
/*
|
||||
* Translation table - automatically generated by po2table.sh.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
struct msgtable_s {
|
||||
char *msgid;
|
||||
char *msgstr;
|
||||
};
|
||||
|
||||
|
||||
struct msgtable_s *minigettext__gettable(char *lang)
|
||||
{
|
||||
if (0 == lang)
|
||||
return 0;
|
||||
|
||||
EOF
|
||||
|
||||
for POFILE in $*; do
|
||||
LANG=`basename "$POFILE" | sed 's/.po$//'`
|
||||
echo " if (strncmp(lang, \"$LANG\", 2) == 0) {"
|
||||
echo " static struct msgtable_s data[] = {";
|
||||
|
||||
awk 'BEGIN{i=0;s=0;}
|
||||
/^msgid[ ]+/ {
|
||||
if (s) print " }, ";
|
||||
print " {";
|
||||
print " " substr($0,7);
|
||||
i=1;
|
||||
s=0;
|
||||
}
|
||||
/^msgstr[ ]+/ {
|
||||
print " ,";
|
||||
i=0;s=1;
|
||||
print " " substr($0,8);
|
||||
}
|
||||
/^[ ]*"/ {
|
||||
if (i||s) print " " $0;
|
||||
}
|
||||
END {if (i||s) print " }\n";}
|
||||
' < "$POFILE"
|
||||
echo ' , { 0, 0 } };'
|
||||
echo " return data;"
|
||||
echo " }"
|
||||
done
|
||||
|
||||
cat <<EOF
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
EOF
|
||||
|
||||
# EOF
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run a test. Parameters are program name and source directory; if
|
||||
# additional parameters are given, they are the tests to run, otherwise all
|
||||
# tests are run.
|
||||
#
|
||||
|
||||
PROG="$1"
|
||||
SRCDIR="$2"
|
||||
shift
|
||||
shift
|
||||
TESTS="$*"
|
||||
|
||||
# Temporary working files
|
||||
#
|
||||
TMP1=`mktemp 2>/dev/null` || TMP1=.tmp1
|
||||
TMP2=`mktemp 2>/dev/null` || TMP2=.tmp2
|
||||
TMP3=`mktemp 2>/dev/null` || TMP3=.tmp3
|
||||
TMP4=`mktemp 2>/dev/null` || TMP4=.tmp4
|
||||
|
||||
export PROG TMP1 TMP2 TMP3 TMP4 # variables used by test scripts
|
||||
|
||||
FAIL=0
|
||||
|
||||
test -n "$TESTS" || TESTS=`ls "$SRCDIR/tests" | sort -n`
|
||||
|
||||
for SCRIPT in $TESTS; do
|
||||
test -f "$SCRIPT" || SCRIPT="$SRCDIR/tests/$SCRIPT"
|
||||
test -f "$SCRIPT" || SCRIPT=`ls "$SRCDIR/tests/$SCRIPT"*`
|
||||
test -f "$SCRIPT" || continue
|
||||
|
||||
echo `basename "$SCRIPT"`: " " | cut -b1-20 | sed 's/-/ - /' | tr "\n" ' '
|
||||
|
||||
STATUS=0
|
||||
sh -e "$SCRIPT" || STATUS=1
|
||||
test $STATUS -eq 1 && FAIL=1
|
||||
|
||||
test $STATUS -eq 1 && echo "FAILED" || echo "OK"
|
||||
done
|
||||
|
||||
rm -f $TMP1 $TMP2 $TMP3 $TMP4
|
||||
|
||||
exit $FAIL
|
||||
|
||||
# EOF
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
This package is free software, and is being distributed under the terms
|
||||
of the Artistic License 2.0.
|
||||
|
||||
----------------------------------------------------------
|
||||
|
||||
Artistic License 2.0
|
||||
|
||||
Copyright (c) 2000-2006, The Perl Foundation.
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed. Preamble
|
||||
|
||||
This license establishes the terms under which a given free software
|
||||
Package may be copied, modified, distributed, and/or redistributed. The
|
||||
intent is that the Copyright Holder maintains some artistic control
|
||||
over the development of that Package while still keeping the Package
|
||||
available as open source and free software.
|
||||
|
||||
You are always permitted to make arrangements wholly outside of this
|
||||
license directly with the Copyright Holder of a given Package. If the
|
||||
terms of this license do not permit the full use that you propose to
|
||||
make of the Package, you should contact the Copyright Holder and seek
|
||||
a different licensing arrangement. Definitions
|
||||
|
||||
"Copyright Holder" means the individual(s) or organization(s) named in
|
||||
the copyright notice for the entire Package.
|
||||
|
||||
"Contributor" means any party that has contributed code or other material
|
||||
to the Package, in accordance with the Copyright Holder's procedures.
|
||||
|
||||
"You" and "your" means any person who would like to copy, distribute,
|
||||
or modify the Package.
|
||||
|
||||
"Package" means the collection of files distributed by the Copyright
|
||||
Holder, and derivatives of that collection and/or of those files. A given
|
||||
Package may consist of either the Standard Version, or a Modified Version.
|
||||
|
||||
"Distribute" means providing a copy of the Package or making it accessible
|
||||
to anyone else, or in the case of a company or organization, to others
|
||||
outside of your company or organization.
|
||||
|
||||
"Distributor Fee" means any fee that you charge for Distributing this
|
||||
Package or providing support for this Package to another party. It does
|
||||
not mean licensing fees.
|
||||
|
||||
"Standard Version" refers to the Package if it has not been modified,
|
||||
or has been modified only in ways explicitly requested by the Copyright
|
||||
Holder.
|
||||
|
||||
"Modified Version" means the Package, if it has been changed, and such
|
||||
changes were not explicitly requested by the Copyright Holder.
|
||||
|
||||
"Original License" means this Artistic License as Distributed with the
|
||||
Standard Version of the Package, in its current version or as it may be
|
||||
modified by The Perl Foundation in the future.
|
||||
|
||||
"Source" form means the source code, documentation source, and
|
||||
configuration files for the Package.
|
||||
|
||||
"Compiled" form means the compiled bytecode, object code, binary, or any
|
||||
other form resulting from mechanical transformation or translation of
|
||||
the Source form. Permission for Use and Modification Without Distribution
|
||||
|
||||
(1) You are permitted to use the Standard Version and create and use
|
||||
Modified Versions for any purpose without restriction, provided that you
|
||||
do not Distribute the Modified Version. Permissions for Redistribution
|
||||
of the Standard Version
|
||||
|
||||
(2) You may Distribute verbatim copies of the Source form of the Standard
|
||||
Version of this Package in any medium without restriction, either gratis
|
||||
or for a Distributor Fee, provided that you duplicate all of the original
|
||||
copyright notices and associated disclaimers. At your discretion, such
|
||||
verbatim copies may or may not include a Compiled form of the Package.
|
||||
|
||||
(3) You may apply any bug fixes, portability changes, and other
|
||||
modifications made available from the Copyright Holder. The resulting
|
||||
Package will still be considered the Standard Version, and as such will
|
||||
be subject to the Original License. Distribution of Modified Versions
|
||||
of the Package as Source
|
||||
|
||||
(4) You may Distribute your Modified Version as Source (either gratis
|
||||
or for a Distributor Fee, and with or without a Compiled form of the
|
||||
Modified Version) provided that you clearly document how it differs
|
||||
from the Standard Version, including, but not limited to, documenting
|
||||
any non-standard features, executables, or modules, and provided that
|
||||
you do at least ONE of the following:
|
||||
|
||||
(a) make the Modified Version available to the Copyright Holder of the
|
||||
Standard Version, under the Original License, so that the Copyright Holder
|
||||
may include your modifications in the Standard Version.
|
||||
(b) ensure that installation of your Modified Version does not prevent the
|
||||
user installing or running the Standard Version. In addition, the Modified
|
||||
Version must bear a name that is different from the name of the Standard
|
||||
Version.
|
||||
(c) allow anyone who receives a copy of the Modified Version to make
|
||||
the Source form of the Modified Version available to others under
|
||||
(i) the Original License or
|
||||
(ii) a license that permits the licensee to freely copy, modify and
|
||||
redistribute the Modified Version using the same licensing terms that apply
|
||||
to the copy that the licensee received, and requires that the Source form of
|
||||
the Modified Version, and of any works derived from it, be made freely
|
||||
available in that license fees are prohibited but Distributor Fees are
|
||||
allowed. Distribution of Compiled Forms of the Standard Version or Modified
|
||||
Versions without the Source
|
||||
|
||||
(5) You may Distribute Compiled forms of the Standard Version without
|
||||
the Source, provided that you include complete instructions on how to
|
||||
get the Source of the Standard Version. Such instructions must be valid
|
||||
at the time of your distribution. If these instructions, at any time
|
||||
while you are carrying out such distribution, become invalid, you must
|
||||
provide new instructions on demand or cease further distribution. If
|
||||
you provide valid instructions or cease distribution within thirty days
|
||||
after you become aware that the instructions are invalid, then you do
|
||||
not forfeit any of your rights under this license.
|
||||
|
||||
(6) You may Distribute a Modified Version in Compiled form without the
|
||||
Source, provided that you comply with Section 4 with respect to the
|
||||
Source of the Modified Version. Aggregating or Linking the Package
|
||||
|
||||
(7) You may aggregate the Package (either the Standard Version or
|
||||
Modified Version) with other packages and Distribute the resulting
|
||||
aggregation provided that you do not charge a licensing fee for the
|
||||
Package. Distributor Fees are permitted, and licensing fees for other
|
||||
components in the aggregation are permitted. The terms of this license
|
||||
apply to the use and Distribution of the Standard or Modified Versions
|
||||
as included in the aggregation.
|
||||
|
||||
(8) You are permitted to link Modified and Standard Versions with other
|
||||
works, to embed the Package in a larger work of your own, or to build
|
||||
stand-alone binary or bytecode versions of applications that include the
|
||||
Package, and Distribute the result without restriction, provided the
|
||||
result does not expose a direct interface to the Package. Items That
|
||||
are Not Considered Part of a Modified Version
|
||||
|
||||
(9) Works (including, but not limited to, modules and scripts) that
|
||||
merely extend or make use of the Package, do not, by themselves, cause
|
||||
the Package to be a Modified Version. In addition, such works are not
|
||||
considered parts of the Package itself, and are not subject to the terms
|
||||
of this license. General Provisions
|
||||
|
||||
(10) Any use, modification, and distribution of the Standard or Modified
|
||||
Versions is governed by this Artistic License. By using, modifying or
|
||||
distributing the Package, you accept this license. Do not use, modify,
|
||||
or distribute the Package, if you do not accept this license.
|
||||
|
||||
(11) If your Modified Version has been derived from a Modified Version
|
||||
made by someone other than you, you are nevertheless required to ensure
|
||||
that your Modified Version complies with the requirements of this license.
|
||||
|
||||
(12) This license does not grant you the right to use any trademark,
|
||||
service mark, tradename, or logo of the Copyright Holder.
|
||||
|
||||
(13) This license includes the non-exclusive, worldwide, free-of-charge
|
||||
patent license to make, have made, use, offer to sell, sell, import
|
||||
and otherwise transfer the Package with respect to any patent claims
|
||||
licensable by the Copyright Holder that are necessarily infringed by the
|
||||
Package. If you institute patent litigation (including a cross-claim or
|
||||
counterclaim) against any party alleging that the Package constitutes
|
||||
direct or contributory patent infringement, then this Artistic License
|
||||
to you shall terminate on the date that such litigation is filed.
|
||||
|
||||
(14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT
|
||||
HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT
|
||||
PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER
|
||||
OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
|
||||
CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, a file
|
||||
`config.cache' that saves the results of its tests to speed up
|
||||
reconfiguring, and a file `config.log' containing compiler output
|
||||
(useful mainly for debugging `configure').
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If at some point `config.cache'
|
||||
contains results you don't want to keep, you may remove or edit it.
|
||||
|
||||
The file `configure.in' is used to create `configure' by a program
|
||||
called `autoconf'. You only need `configure.in' if you want to change
|
||||
it or regenerate `configure' using a newer version of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system. If you're
|
||||
using `csh' on an old version of System V, you might need to type
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. You can give `configure'
|
||||
initial values for variables by setting them in the environment. Using
|
||||
a Bourne-compatible shell, you can do that on the command line like
|
||||
this:
|
||||
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
|
||||
|
||||
Or on systems that have the `env' program, you can do it like this:
|
||||
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
If you have to use a `make' that does not supports the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a time
|
||||
in the source code directory. After you have installed the package for
|
||||
one architecture, use `make distclean' before reconfiguring for another
|
||||
architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||
PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=PATH' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' can not figure out
|
||||
automatically, but needs to determine by the type of host the package
|
||||
will run on. Usually `configure' can figure that out, but if it prints
|
||||
a message saying it can not guess the host type, give it the
|
||||
`--host=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name with three fields:
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the host type.
|
||||
|
||||
If you are building compiler tools for cross-compiling, you can also
|
||||
use the `--target=TYPE' option to select the type of system they will
|
||||
produce code for and the `--build=TYPE' option to select the type of
|
||||
system on which you are compiling the package.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Operation Controls
|
||||
==================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Use and save the results of the tests in FILE instead of
|
||||
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
|
||||
debugging `configure'.
|
||||
|
||||
`--help'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--version'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options.
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
1.6.6 - 30 June 2017
|
||||
- (r161) use %llu instead of %Lu for better compatibility (Eric A. Borisch)
|
||||
- (r162) (#1532) fix target buffer size (-B) being ignored (AndCycle, Ilya
|
||||
Basin, Antoine Beaupré)
|
||||
- (r164) cap read/write sizes, and check elapsed time during read/write
|
||||
cycles, to avoid display hangs with large buffers or slow media; also
|
||||
remove select() call from repeated_write function as it slows the
|
||||
transfer down and the wrapping alarm() means it is unnecessary
|
||||
- (r169) (#1477) use alternate form for transfer counter, such that 13GB
|
||||
is shown as 13.0GB so it's the same width as 13.1GB (André Stapf)
|
||||
- (r171) cleanup: units corrections in man page, of the form kb -> KiB
|
||||
- (r175) report error in "-d" if process fd directory is unreadable, or if
|
||||
process disappears before we start the main loop (Jacek Wielemborek)
|
||||
|
||||
1.6.0 - 15 March 2015
|
||||
- fix lstat64 support when unavailable - separate patches supplied by
|
||||
Ganael Laplanche and Peter Korsgaard
|
||||
- (#1506) new option "-D" / "--delay-start" to only show bar after N
|
||||
seconds (Damon Harper)
|
||||
- new option "--fineta" / "-I" to show ETA as time of day rather than time
|
||||
remaining - patch supplied by Erkki Seppälä (r147)
|
||||
- (#1509) change ETA (--eta / -e) so that days are given if the hours
|
||||
remaining are 24 or more (Jacek Wielemborek)
|
||||
- (#1499) repeat read and write attempts on partial buffer fill/empty to
|
||||
work around post-signal transfer rate drop reported by Ralf Ramsauer
|
||||
- (#1507) do not try to calculate total size in line mode, due to bug
|
||||
reported by Jacek Wielemborek and Michiel Van Herwegen
|
||||
- cleanup: removed defunct RATS comments and unnecessary copyright notices
|
||||
- clean up displayed lines when using --watchfd PID, when PID exits
|
||||
- output errors on a new line to avoid overwriting transfer bar
|
||||
|
||||
1.5.7 - 26 August 2014
|
||||
- show KiB instead of incorrect kiB (Debian bug #706175)
|
||||
- (#1284) do not gzip man page, for non-Linux OSes (Bob Friesenhahn)
|
||||
- work around "awk" bug in tests/016-numeric-timer in decimal "," locales
|
||||
- fix "make rpm" and "make srpm", extend "make release" to sign releases
|
||||
|
||||
1.5.3 - 4 May 2014
|
||||
- remove SPLICE_F_NONBLOCK to fix problem with slow splice() (Jan Seda)
|
||||
|
||||
1.5.2 - 10 February 2014
|
||||
- allow "--watchfd" to look at block devices
|
||||
- let "--watchfd PID:FD" work with "--size N"
|
||||
- moved contributors out of the manual as the list was too long
|
||||
(NB everyone is still listed in the README and always will be)
|
||||
|
||||
1.5.1 - 23 January 2014
|
||||
- new option "--watchfd" - suggested by Jacek Wielemborek and "fdwatch"
|
||||
- use non-block flag with splice()
|
||||
- new display option "--buffer-percent", suggested by Kim Krecht
|
||||
- new display option "--last-written", suggested by Kim Krecht
|
||||
- new transfer option "--no-splice"
|
||||
- fix for minor bug which dropped display elements after one empty one
|
||||
- fix for single fd leak on exit (Cristian Ciupitu)
|
||||
|
||||
1.4.12 - 5 August 2013
|
||||
- new option "--null" - patch supplied by Zing Shishak
|
||||
- AIX build fix (add "-lc128") - with help from Pawel Piatek
|
||||
- AIX "-c" fixes - with help from Pawel Piatek
|
||||
- SCO build fix (po2table.sh) - reported by Wouter Pronk
|
||||
- test scripts fix for older distributions - patch from Bryan Dongray
|
||||
- fix for splice() not using stdin - patch from Zev Weiss
|
||||
|
||||
1.4.6 - 22 January 2013
|
||||
- added patch from Pawel Piatek to omit O_NOFOLLOW in AIX
|
||||
|
||||
1.4.5 - 10 January 2013
|
||||
- updated manual page to show known problem with "-R" on Cygwin
|
||||
|
||||
1.4.4 - 11 December 2012
|
||||
- added debugging, see `pv -h' when configure run with "--enable-debugging"
|
||||
- rewrote cursor positioning code used when IPC is unavailable (Cygwin)
|
||||
- fixed cursor positioning cursor read answerback problem (Cygwin/Solaris)
|
||||
- fixed bug causing crash when progress displayed with too-small terminal
|
||||
|
||||
1.4.0 - 6 December 2012
|
||||
- new option "--skip-errors" commissioned by Jim Salter
|
||||
- if stdout is a block device, and we don't know the total size, use the
|
||||
size of that block device as the total (Peter Samuelson)
|
||||
- new option "--stop-at-size" to stop after "--size" bytes
|
||||
- report correct filename on read errors
|
||||
- fix use-after-free bug in remote PID cleanup code
|
||||
- refactored large chunks of code to make it more readable and to replace
|
||||
most static variables with a state structure
|
||||
|
||||
1.3.9 - 5 November 2012
|
||||
- allow "--format" parameters to be sent with "--remote"
|
||||
- configure option "--disable-ipc"
|
||||
- added tests for --numeric with --timer and --bytes
|
||||
- added tests for --remote
|
||||
|
||||
1.3.8 - 29 October 2012
|
||||
- new "--pidfile" option to save process ID to a file
|
||||
- integrated patch for --numeric with --timer and --bytes (Sami Liedes)
|
||||
- removed signalling from --remote to prevent accidental process kills
|
||||
- new "--format" option (originally Vladimir Pal / Vladimir Ermakov)
|
||||
|
||||
1.3.4 - 27 June 2012
|
||||
- new "--disable-splice" configure script option
|
||||
- fixed line mode size count with multiple files (Moritz Barsnick)
|
||||
- fixes for AIX core dumps (Pawel Piatek)
|
||||
|
||||
1.3.1 - 9 June 2012
|
||||
- do not use splice() if the write buffer is not empty (Thomas Rachel)
|
||||
- added test 15 (pipe transfers), and new test script
|
||||
|
||||
1.3.0 - 5 June 2012
|
||||
- added Tiger build patch from Olle Jonsson
|
||||
- fix 1024-boundary display garble (Debian bug #586763)
|
||||
- use splice(2) where available (Debian bug #601683)
|
||||
- added known bugs section of the manual page
|
||||
- fixed average rate test, 12 (Andrew Macheret)
|
||||
- use IEEE1541 units (Thomas Rachel)
|
||||
- bug with rate limit under 10 fixed (Henry Precheur)
|
||||
- speed up PV line mode (patch: Guillaume Marcais)
|
||||
- remove LD=ld from vars.mk to fix cross-compilation (paintitgray/PV#1291)
|
||||
|
||||
1.2.0 - 14 December 2010
|
||||
- integrated improved SI prefixes and --average-rate (Henry Gebhardt)
|
||||
- return nonzero if exiting due to SIGTERM (Martin Baum)
|
||||
- patch from Phil Rutschman to restore terminal properly on exit
|
||||
- fix i18n especially for --help (Sebastian Kayser)
|
||||
- refactored pv_display
|
||||
- we now have a coherent, documented, exit status
|
||||
- modified pipe test and new cksum test from Sebastian Kayser
|
||||
- default CFLAGS to just "-O" for non-GCC (Kjetil Torgrim Homme)
|
||||
- LFS compile fix for OS X 10.4 (Alexandre de Verteuil)
|
||||
- remove DESTDIR / suffix (Sam Nelson, Daniel Pape)
|
||||
- fixed potential NULL deref in transfer (Elias Pipping / LLVM/Clang)
|
||||
|
||||
1.1.4 - 6 March 2008
|
||||
- patch from Elias Pipping correcting compilation failure on Darwin 9
|
||||
- patch from Patrick Collison correcting similar problems on OS X
|
||||
- trap SIGINT/SIGHUP/SIGTERM so we clean up IPCs on exit (Laszlo Ersek)
|
||||
- abort if numeric option, eg -L, has non-numeric value (Boris Lohner)
|
||||
|
||||
1.1.0 - 30 August 2007
|
||||
- new option --remote (-R) to control an already-running process
|
||||
- new option --line-mode (-l) to count lines instead of bytes
|
||||
- fix for "-L" to be less resource intensive
|
||||
- fix for input/output equivalence check on Mac OS X
|
||||
- fix for size calculation in pipelines on Mac OS X
|
||||
- fixed "make uninstall"
|
||||
- removed /debian directory at request of new Debian maintainer
|
||||
|
||||
1.0.1 - 4 August 2007
|
||||
- licensing change from Artistic to Artistic 2.0
|
||||
- removed the "-l" / "--license" option
|
||||
|
||||
1.0.0 - 2 August 2007
|
||||
- act more like "cat" - just skip unreadable files, don't abort
|
||||
- removed text version of manual page, and obsolete Info file generation
|
||||
- code cleanup and separation of PV internals from CLI front-end
|
||||
|
||||
0.9.9 - 5 February 2007
|
||||
- new option --buffer-size (-B) suggested by Mark Tomich
|
||||
- build fix: HP/UX largefile compile fix from Timo Savinen
|
||||
- maintain better buffer filling during transfers
|
||||
- workaround: pv /dev/zero | dd bs=1M count=1k bug (reported by Gert Menke)
|
||||
- dropped support for the Texinfo manual
|
||||
|
||||
0.9.6 - 27 February 2006
|
||||
- bugfix: key_t incompatibility with Cygwin
|
||||
- bugfix: interval (-i) parameter parses numbers after decimal point
|
||||
- build fix: use static NLS if msgfmt is unavailable
|
||||
- on the final update, blank out the now-zero ETA
|
||||
|
||||
0.9.2 - 1 September 2005
|
||||
- Daniel Roethlisberger patch: use lockfiles if terminal locking fails
|
||||
|
||||
0.9.1 - 16 June 2005
|
||||
- minor RPM spec file fix for Fedora Core 4
|
||||
|
||||
0.9.0 - 15 November 2004
|
||||
- minor NLS bugfix
|
||||
|
||||
0.8.9 - 6 November 2004
|
||||
- decimal values now accepted for rate and size, eg "-L 1.23M"
|
||||
- code cleanup
|
||||
- developers: "make help" now lists Makefile targets
|
||||
|
||||
0.8.6 - 29 June 2004
|
||||
- use uu_lock() for terminal locking on FreeBSD
|
||||
|
||||
0.8.5 - 2 May 2004
|
||||
- cursor positioning (-c) reliability improved on systems with IPC
|
||||
- minor fix: made test 005 more reliable
|
||||
- new option --height (-H)
|
||||
|
||||
0.8.2 - 24 April 2004
|
||||
- allow k,m,g,t suffixes on numbers
|
||||
- added "srpm" and "release" Makefile targets
|
||||
|
||||
0.8.1 - 19 April 2004
|
||||
- bugfix in cursor positioning (-c)
|
||||
|
||||
0.8.0 - 12 February 2004
|
||||
- replaced GNU getopt with my library code
|
||||
- replaced GNU gettext with my very minimal replacement
|
||||
- use DESTDIR instead of RPM_BUILD_ROOT for optional installation prefix
|
||||
- looked for flaws using RATS, cleaned up code
|
||||
|
||||
0.7.0 - 8 February 2004
|
||||
- display buffer management fixes (thanks Cédric Delfosse)
|
||||
- replaced --enable-debug with --enable-debugging and --enable-profiling
|
||||
|
||||
0.6.4 - 14 January 2004
|
||||
- fixed minor bug in RPM installation
|
||||
- bugfix in "make index" (only of interest to developers)
|
||||
|
||||
0.6.3 - 22 December 2003
|
||||
- fixed transient bug that reported "resource unavailable" occasionally
|
||||
|
||||
0.6.2 - 6 August 2003
|
||||
- block devices now have their size read correctly, so pv /dev/hda1 works
|
||||
- minor code cleanups (mainly removal of CVS "Id" tags)
|
||||
|
||||
0.6.0 - 3 August 2003
|
||||
- doing ^Z then "bg" then "fg" now continues displaying
|
||||
|
||||
0.5.9 - 23 July 2003
|
||||
- fix for test 007 when not in C locale
|
||||
- fix for build process to use CPPFLAGS
|
||||
- fix for build process to use correct i18n libraries
|
||||
- fix for build process - more portable sed in dependency generator
|
||||
- fix for install process - remember to mkinstalldirs before installing
|
||||
- fixes for building on Mac OS X
|
||||
|
||||
0.5.3 - 4 May 2003
|
||||
- added Polish translation thanks to Bartosz Feñski
|
||||
<fenio@o2.pl> <http://skawina.eu.org/> and Krystian Zubel
|
||||
- moved doc/debian to ./debian at insistence of common sense
|
||||
- minor Solaris 8 compatibility fixes
|
||||
- seems to compile and test OK on Mac OS X
|
||||
|
||||
0.5.0 - 15 April 2003
|
||||
- added French translation thanks to Stéphane Lacasse
|
||||
<stephane@gorfou.ca>
|
||||
- added German translation thanks to Marcos Kreinacke
|
||||
<public@kreinacke.com>
|
||||
- switched LGPL reference from "Library" to "Lesser"
|
||||
|
||||
0.4.9 - 18 February 2003
|
||||
- support for >2GB files added where available (Debian bug #180986)
|
||||
- added doc/debian dir (from Cédric Delfosse)
|
||||
- added "make rpm" and "make deb" targets to build RPM and Debian packages
|
||||
- added a "make pv-static" rule to build a statically linked version
|
||||
|
||||
0.4.5 - 13 December 2002
|
||||
- added Portuguese (Brazilian) translation thanks to Eduardo Aguiar
|
||||
|
||||
0.4.4 - 7 December 2002
|
||||
- pause/resume support - don't count time while stopped
|
||||
- stop output when resumed in the background
|
||||
- terminal size change support
|
||||
- bugfix: <=> indicator no longer sticks at right hand edge
|
||||
|
||||
0.4.0 - 27 November 2002
|
||||
- allow decimal interval values, eg 0.1, 0.5, etc
|
||||
- some simple tests added (`make check')
|
||||
- smoother throughput limiting (--rate-limit), now done in 0.1sec chunks
|
||||
- bounds-check interval values (-i) - max update interval now 10 minutes
|
||||
- more reliable non-blocking output to keep display updated
|
||||
- no longer rely on atoll()
|
||||
- don't output final blank line if --numeric
|
||||
- use fcntl() instead of flock() for Solaris compatibility
|
||||
|
||||
0.3.0 - 25 November 2002
|
||||
- handle broken output pipe gracefully
|
||||
- continue updating display even when output pipe is blocking
|
||||
|
||||
0.2.6 - 21 October 2002
|
||||
- we now ignore EINTR on select()
|
||||
- variable-size buffer (still need to add code to change size)
|
||||
- added (tentative) support for internationalisation
|
||||
- removed superfluous --no-progress, etc options
|
||||
- optimised transfer by using bigger buffers, based on st_blksize
|
||||
- added --wait option to wait until transfer begins before showing progress
|
||||
- added --rate-limit option to limit rate to a maximum throughput
|
||||
- added --quiet option (no output at all) to be used with --rate-limit
|
||||
|
||||
0.2.5 - 23 July 2002
|
||||
- added [FILE]... arguments, like `cat'
|
||||
- function separation in code
|
||||
- some bug fixes related to numeric overflow
|
||||
|
||||
0.2.3 - 19 July 2002
|
||||
- Texinfo manual written, man page updated
|
||||
- byte counter added
|
||||
|
||||
0.2.0 - 18 July 2002
|
||||
- ETA counter added
|
||||
- screen width estimation added
|
||||
- progress bar added
|
||||
|
||||
0.1.0 - 17 July 2002
|
||||
- main loop created
|
||||
- rate counter added
|
||||
- elapsed time counter added
|
||||
- percentage calculation added
|
||||
|
||||
0.0.1 - 16 July 2002
|
||||
- package created
|
||||
- first draft of man page written
|
||||
@@ -0,0 +1 @@
|
||||
pv
|
||||
@@ -0,0 +1,35 @@
|
||||
Things still to do:
|
||||
|
||||
- allow -E to take a block size argument so errors cause a skip to the
|
||||
next block (Anthony DeRobertis)
|
||||
- (#1559) momentary ETA option (Luc Gommans)
|
||||
- (#1556) correct German translations (Richard Fonfara)
|
||||
- (#1557) use clock_gettime() in ETA calculation (Mateju Miroslav)
|
||||
- (#1561) show days in same format in ETA as in elapsed time
|
||||
- (#1562) allow -r with -l and -n to output lines/sec (Roland Kletzing)
|
||||
- (#1563) make -B imply -C (Johannes Gerer)
|
||||
- document zsh <() incompatibility (frederik@ofb.net - Frederik Eaton)
|
||||
- do not check terminal in -q/-n mode (zsh <(pv -n) fails)
|
||||
- if -w/-H was specified, ignore SIGWINCH
|
||||
- option to enable O_DIRECT (Romain Kang, Jacek Wielemborek)
|
||||
- use posix_fadvise() like cat(1) does (Jacek Wielemborek)
|
||||
- (#1508) add watchfd tests
|
||||
- (#1534) allow multiple -d options
|
||||
- (#1533) one-shot option (Jacek Wielemborek)
|
||||
- (#1505) option to switch rate to per minute if really slow
|
||||
- (#1510) option "--progress-from FILE", read last number and use it as bytes read:
|
||||
pv --progress-from <( while sleep 1; do du -sb somedir; done ) -s 123g
|
||||
(Jacek Wielemborek)
|
||||
- (#1476) (Debian #507682) adjustable averaging window for rate display
|
||||
- (#1286) option for process title (Martin Sarsale) as "pv - name:FooProcess -xyz - transferred: 1.3GB - 500KB/s - running: 10:15:30s"
|
||||
- (#1290) look at effect of O_SYNC or fsync on performance
|
||||
- (#1281) option (-x?) to use xterm title line for status (Joachim Haga)
|
||||
- (#1287) if the first pv exits, should the second become IPC leader?
|
||||
- (#1560) use Unicode for more granular progress bar (Alexander Petrossian)
|
||||
|
||||
- add development support for http://clang-analyzer.llvm.org/
|
||||
- stats for avg/min/max/stddev throughput (Venky.N.Iyer)
|
||||
- pv-ify a command line (Will Entriken) - "pv FOO | BAR | BAZ"
|
||||
- get more translations
|
||||
|
||||
Any assistance would be appreciated.
|
||||
@@ -0,0 +1 @@
|
||||
1.6.6
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
Begin3
|
||||
Title: @PACKAGE@
|
||||
Version: @VERSION@
|
||||
Entered-date: 30JUN17
|
||||
Description: A 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.
|
||||
Keywords: progress bar, console, pipe, transfer rate
|
||||
Author: Andrew Wood <andrew.wood@ivarch.com>
|
||||
Maintained-by: Andrew Wood <andrew.wood@ivarch.com>
|
||||
Primary-site: http://www.ivarch.com/programs/@PACKAGE@.shtml
|
||||
Alternate-site:
|
||||
Original-site:
|
||||
Platforms:
|
||||
Copying-policy: Artistic 2.0
|
||||
End
|
||||
@@ -0,0 +1,600 @@
|
||||
.TH @UCPACKAGE@ 1 "June 2017" Linux "User Manuals"
|
||||
.SH NAME
|
||||
@PACKAGE@ \- monitor the progress of data through a pipe
|
||||
.SH SYNOPSIS
|
||||
.B @PACKAGE@
|
||||
[\fIOPTION\fR]
|
||||
[\fIFILE\fR]...
|
||||
.br
|
||||
.B @PACKAGE@
|
||||
[\fI\-h\fR|\fI\-V\fR]
|
||||
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B @PACKAGE@
|
||||
shows 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.
|
||||
|
||||
To use it, insert it in a pipeline between two processes, with the
|
||||
appropriate options. Its standard input will be passed through to its
|
||||
standard output and progress will be shown on standard error.
|
||||
|
||||
.B @PACKAGE@
|
||||
will copy each supplied
|
||||
.B FILE
|
||||
in turn to standard output
|
||||
.BR "" "(" -
|
||||
means standard input), or if no
|
||||
.BR FILE s
|
||||
are specified just standard input is copied. This is the same behaviour
|
||||
as
|
||||
.BR cat (1).
|
||||
|
||||
A simple example to watch how quickly a file is transferred using
|
||||
.BR nc (1):
|
||||
|
||||
.RS
|
||||
.B @PACKAGE@ file | nc -w 1 somewhere.com 3000
|
||||
.RE
|
||||
|
||||
A similar example, transferring a file from another process and passing the
|
||||
expected size to
|
||||
.BR @PACKAGE@ :
|
||||
|
||||
.RS
|
||||
.B cat file | @PACKAGE@ -s 12345 | nc -w 1 somewhere.com 3000
|
||||
.RE
|
||||
|
||||
A more complicated example using numeric output to feed into the
|
||||
.BR dialog (1)
|
||||
program for a full-screen progress display:
|
||||
|
||||
.RS
|
||||
.B (tar cf - . \e
|
||||
.br
|
||||
.B " | @PACKAGE@ -n -s $(du -sb . | awk '{print $1}') \e"
|
||||
.br
|
||||
.B " | gzip -9 > out.tgz) 2>&1 \e"
|
||||
.br
|
||||
.B | dialog --gauge 'Progress' 7 70
|
||||
.RE
|
||||
|
||||
Taking an image of a disk, skipping errors:
|
||||
|
||||
.RS
|
||||
.B @PACKAGE@ -EE /dev/sda > disk-image.img
|
||||
.RE
|
||||
|
||||
Writing an image back to a disk:
|
||||
|
||||
.RS
|
||||
.B @PACKAGE@ disk-image.img > /dev/sda
|
||||
.RE
|
||||
|
||||
Zeroing a disk:
|
||||
|
||||
.RS
|
||||
.B @PACKAGE@ < /dev/zero > /dev/sda
|
||||
.RE
|
||||
|
||||
Note that if the input size cannot be calculated, and the output is a block
|
||||
device, then the size of the block device will be used and
|
||||
.B @PACKAGE@
|
||||
will automatically stop at that size as if
|
||||
.B \-S
|
||||
had been given.
|
||||
|
||||
(Linux only): Watching file descriptor 3 opened by another process 1234:
|
||||
|
||||
.RS
|
||||
.B @PACKAGE@ -d 1234:3
|
||||
.RE
|
||||
|
||||
(Linux only): Watching all file descriptors used by process 1234:
|
||||
|
||||
.RS
|
||||
.B @PACKAGE@ -d 1234
|
||||
.RE
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
.B @PACKAGE@
|
||||
takes many options, which are divided into display switches, output
|
||||
modifiers, and general options.
|
||||
|
||||
|
||||
.SH DISPLAY SWITCHES
|
||||
If no display switches are specified,
|
||||
.B @PACKAGE@
|
||||
behaves as if
|
||||
.BR \-p ", " \-t ", " \-e ", " \-r ", and " \-b
|
||||
had been given (i.e. everything except average rate is switched on).
|
||||
Otherwise, only those display types that are explicitly switched on will be
|
||||
shown.
|
||||
.TP
|
||||
.B \-p, \-\-progress
|
||||
Turn the progress bar on. If standard input is not a file and no
|
||||
size was given (with the
|
||||
.B \-s
|
||||
modifier), the progress bar cannot indicate how close to completion the
|
||||
transfer is, so it will just move left and right to indicate that data is
|
||||
moving.
|
||||
.TP
|
||||
.B \-t, \-\-timer
|
||||
Turn the timer on. This will display the total elapsed time that
|
||||
.B @PACKAGE@
|
||||
has been running for.
|
||||
.TP
|
||||
.B \-e, \-\-eta
|
||||
Turn the ETA timer on. This will attempt to guess, based on previous
|
||||
transfer rates and the total data size, how long it will be before
|
||||
completion. This option will have no effect if the total data size cannot
|
||||
be determined.
|
||||
.TP
|
||||
.B \-I, \-\-fineta
|
||||
Turn the ETA timer on, but display the estimated local time of arrival
|
||||
instead of time left. When the estimated time is more than 6 hours in the
|
||||
future, the date is shown as well.
|
||||
.TP
|
||||
.B \-r, \-\-rate
|
||||
Turn the rate counter on. This will display the current rate of data
|
||||
transfer.
|
||||
.TP
|
||||
.B \-a, \-\-average\-rate
|
||||
Turn the average rate counter on. This will display the average rate of
|
||||
data transfer so far.
|
||||
.TP
|
||||
.B \-b, \-\-bytes
|
||||
Turn the total byte counter on. This will display the total amount of
|
||||
data transferred so far.
|
||||
.TP
|
||||
.B \-T, \-\-buffer\-percent
|
||||
Turn on the transfer buffer percentage display. This will show the
|
||||
percentage of the transfer buffer in use - but see the caveat under
|
||||
.B %T
|
||||
in the
|
||||
.B FORMATTING
|
||||
section below.
|
||||
.TP
|
||||
.B \-A, \-\-last\-written NUM
|
||||
Show the last
|
||||
.B NUM
|
||||
bytes written - but see the caveat under
|
||||
.B %nA
|
||||
in the
|
||||
.B FORMATTING
|
||||
section below.
|
||||
.TP
|
||||
.B \-F, \-\-format FORMAT
|
||||
Ignore the options
|
||||
.BR \-p ,
|
||||
.BR \-t ,
|
||||
.BR \-e ,
|
||||
.BR \-r ,
|
||||
.BR \-a ,
|
||||
.BR \-b ,
|
||||
.BR \-T ,
|
||||
and
|
||||
.BR \-A ,
|
||||
and instead use the format string
|
||||
.B FORMAT
|
||||
to determine the output format. See the
|
||||
.B FORMATTING
|
||||
section below.
|
||||
.TP
|
||||
.B \-n, \-\-numeric
|
||||
Numeric output. Instead of giving a visual indication of progress,
|
||||
.B @PACKAGE@
|
||||
will give an integer percentage, one per line, on standard error, suitable
|
||||
for piping (via convoluted redirection) into
|
||||
.BR dialog (1).
|
||||
Note that
|
||||
.B \-f
|
||||
is not required if
|
||||
.B \-n
|
||||
is being used.
|
||||
.TP
|
||||
.B ""
|
||||
Note that if
|
||||
.B \-\-numeric
|
||||
is in use, then adding
|
||||
.B \-\-bytes
|
||||
will cause the number of bytes processed so far to be output instead of a
|
||||
percentage; if
|
||||
.B \-\-line\-mode
|
||||
is also in use, then instead of bytes or a percentage, the number of lines
|
||||
so far is output. And finally, if
|
||||
.B \-\-timer
|
||||
is also in use, then each output line is prefixed with the elapsed time
|
||||
so far, as a decimal number of seconds.
|
||||
.TP
|
||||
.B \-q, \-\-quiet
|
||||
No output. Useful if the
|
||||
.B \-L
|
||||
option is being used on its own to just limit the transfer rate of a pipe.
|
||||
|
||||
|
||||
.SH OUTPUT MODIFIERS
|
||||
.TP
|
||||
.B \-W, \-\-wait
|
||||
Wait until the first byte has been transferred before showing any progress
|
||||
information or calculating any ETAs. Useful if the program you are piping to
|
||||
or from requires extra information before it starts, eg piping data into
|
||||
.BR gpg (1)
|
||||
or
|
||||
.BR mcrypt (1)
|
||||
which require a passphrase before data can be processed.
|
||||
.TP
|
||||
.B \-D, \-\-delay-start SEC
|
||||
Wait until
|
||||
.B SEC
|
||||
seconds have passed before showing any progress information, for example in
|
||||
a script where you only want to show a progress bar if it starts taking a
|
||||
long time. Note that this can be a decimal such as 0.5.
|
||||
.TP
|
||||
.B \-s SIZE, \-\-size SIZE
|
||||
Assume the total amount of data to be transferred is
|
||||
.B SIZE
|
||||
bytes when calculating percentages and ETAs. The same suffixes of "k", "m"
|
||||
etc can be used as with
|
||||
.BR -L .
|
||||
.TP
|
||||
.B ""
|
||||
Has no effect if used with
|
||||
.B -d PID
|
||||
to watch all file descriptors of a process, but will work with
|
||||
.BR "-d PID:FD" .
|
||||
.TP
|
||||
.B \-l, \-\-line\-mode
|
||||
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 the
|
||||
.B \-s
|
||||
option will be interpreted as a line count. Note that file sizes are not
|
||||
automatically calculated when this option is used, to avoid having to read
|
||||
all files twice.
|
||||
.TP
|
||||
.B \-0, \-\-null
|
||||
Count lines as null terminated. This option implies \-\-line\-mode.
|
||||
.TP
|
||||
.B \-i SEC, \-\-interval SEC
|
||||
Wait
|
||||
.B SEC
|
||||
seconds between updates. The default is to update every second.
|
||||
Note that this can be a decimal such as 0.1.
|
||||
.TP
|
||||
.B \-w WIDTH, \-\-width WIDTH
|
||||
Assume the terminal is
|
||||
.B WIDTH
|
||||
characters wide, instead of trying to work it out (or assuming 80 if it
|
||||
cannot be guessed).
|
||||
.TP
|
||||
.B \-H HEIGHT, \-\-height HEIGHT
|
||||
Assume the terminal is
|
||||
.B HEIGHT
|
||||
rows high, instead of trying to work it out (or assuming 25 if it
|
||||
cannot be guessed).
|
||||
.TP
|
||||
.B \-N NAME, \-\-name NAME
|
||||
Prefix the output information with
|
||||
.BR NAME .
|
||||
Useful in conjunction with
|
||||
.B \-c
|
||||
if you have a complicated pipeline and you want to be able to tell different
|
||||
parts of it apart.
|
||||
.TP
|
||||
.B \-f, \-\-force
|
||||
Force output. Normally,
|
||||
.B @PACKAGE@
|
||||
will not output any visual display if standard error is not a terminal.
|
||||
This option forces it to do so.
|
||||
.TP
|
||||
.B \-c, \-\-cursor
|
||||
Use cursor positioning escape sequences instead of just using carriage
|
||||
returns. This is useful in conjunction with
|
||||
.B \-N
|
||||
(name) if you are using multiple
|
||||
.B @PACKAGE@
|
||||
invocations in a single, long, pipeline.
|
||||
|
||||
|
||||
.SH DATA TRANSFER MODIFIERS
|
||||
.TP
|
||||
.B \-L RATE, \-\-rate-limit RATE
|
||||
Limit the transfer to a maximum of
|
||||
.B RATE
|
||||
bytes per second. A suffix of "K", "M", "G", or "T" can be added to denote
|
||||
kibibytes (*1024), mebibytes, and so on.
|
||||
.TP
|
||||
.B \-B BYTES, \-\-buffer-size BYTES
|
||||
Use a transfer buffer size of
|
||||
.B BYTES
|
||||
bytes. A suffix of "K", "M", "G", or "T" can be added to denote
|
||||
kibibytes (*1024), mebibytes, and so on. 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.
|
||||
.TP
|
||||
.B \-C, \-\-no-splice
|
||||
Never use
|
||||
.BR splice (2),
|
||||
even if it would normally be possible. The
|
||||
.BR splice (2)
|
||||
system call is a more efficient way of transferring data from or to a pipe
|
||||
than regular
|
||||
.BR read (2)
|
||||
and
|
||||
.BR write (2),
|
||||
but means that the transfer buffer may not be used. This prevents
|
||||
.B \-A
|
||||
and
|
||||
.B \-T
|
||||
from working, so if you want to use
|
||||
.B \-A
|
||||
or
|
||||
.B \-T
|
||||
then you will need to use
|
||||
.BR \-C ,
|
||||
at the cost of a small loss in transfer efficiency.
|
||||
(This option has no effect on systems where
|
||||
.BR splice (2)
|
||||
is unavailable).
|
||||
.TP
|
||||
.B \-E, \-\-skip-errors
|
||||
Ignore read errors by attempting to skip past the offending sections. 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
|
||||
.B dd conv=sync,noerror
|
||||
but has not been as thoroughly tested.
|
||||
.TP
|
||||
.B ""
|
||||
Specify
|
||||
.B \-E
|
||||
twice to only report a read error once per file, instead of reporting each
|
||||
byte range skipped.
|
||||
.TP
|
||||
.B \-S, \-\-stop-at-size
|
||||
If a size was specified with
|
||||
.BR \-s ,
|
||||
stop transferring data once that many bytes have been written, instead of
|
||||
continuing to the end of input.
|
||||
.TP
|
||||
.B \-d PID[:FD], \-\-watchfd PID[:FD]
|
||||
Instead of transferring data, watch file descriptor
|
||||
.B FD
|
||||
of process
|
||||
.BR PID ,
|
||||
and show its progress. The
|
||||
.B @PACKAGE@
|
||||
process will exit when
|
||||
.B 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.
|
||||
.TP
|
||||
.B ""
|
||||
If only a
|
||||
.B 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
|
||||
.B @PACKAGE@
|
||||
process will exit when process
|
||||
.B PID
|
||||
exits.
|
||||
.TP
|
||||
.B \-R PID, \-\-remote PID
|
||||
If
|
||||
.B PID
|
||||
is an instance of
|
||||
.B @PACKAGE@
|
||||
that is already running,
|
||||
.B \-R PID
|
||||
will cause that instance to act as though it had been given
|
||||
this instance's command line instead. For example, if
|
||||
.B @PACKAGE@ -L 123K
|
||||
is running with process ID 9876, then running
|
||||
.B @PACKAGE@ -R 9876 -L 321K
|
||||
will cause it to start using a rate limit of 321KiB instead of 123KiB.
|
||||
Note that some options cannot be changed while running, such as
|
||||
.BR \-c ,
|
||||
.BR \-l ,
|
||||
.BR \-f ,
|
||||
.BR \-D ,
|
||||
.BR \-E ,
|
||||
and
|
||||
.BR \-S .
|
||||
|
||||
.SH GENERAL OPTIONS
|
||||
.TP
|
||||
.B \-P FILE, \-\-pidfile FILE
|
||||
Save the process ID of
|
||||
.B @PACKAGE@
|
||||
in
|
||||
.BR FILE .
|
||||
The file will be truncated if it already exists, and will be removed when
|
||||
.B @PACKAGE@
|
||||
exits. While
|
||||
.B @PACKAGE@
|
||||
is running, it will contain a single number - the process ID of
|
||||
.B @PACKAGE@
|
||||
- followed by a newline.
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
Print a usage message on standard output and exit successfully.
|
||||
.TP
|
||||
.B \-V, \-\-version
|
||||
Print version information on standard output and exit successfully.
|
||||
|
||||
|
||||
.SH FORMATTING
|
||||
If the
|
||||
.B \-F
|
||||
option is given, then the output format is determined by the given format
|
||||
string. Within that string, the following sequences can be used:
|
||||
.TP
|
||||
.B %p
|
||||
Progress bar.
|
||||
Expands to fill the remaining space. Should only be specified once.
|
||||
Equivalent to
|
||||
.BR \-p .
|
||||
.TP
|
||||
.B %t
|
||||
Elapsed time. Equivalent to
|
||||
.BR \-t .
|
||||
.TP
|
||||
.B %e
|
||||
ETA as time remaining. Equivalent to
|
||||
.BR \-e .
|
||||
.TP
|
||||
.B %I
|
||||
ETA as local time of completion. Equivalent to
|
||||
.BR \-I .
|
||||
.TP
|
||||
.B %r
|
||||
Current data transfer rate. Equivalent to
|
||||
.BR \-r .
|
||||
.TP
|
||||
.B %a
|
||||
Average data transfer rate. Equivalent to
|
||||
.BR \-a .
|
||||
.TP
|
||||
.B %b
|
||||
Bytes transferred so far (or lines if
|
||||
.B \-l
|
||||
was specified). Equivalent to
|
||||
.BR \-b .
|
||||
.TP
|
||||
.B %T
|
||||
Percentage of the transfer buffer in use. Equivalent to
|
||||
.BR \-T .
|
||||
Shows "{----}" if the transfer is being done with
|
||||
.BR splice (2),
|
||||
since splicing to or from pipes does not use the buffer.
|
||||
.TP
|
||||
.B %nA
|
||||
Show the last
|
||||
.B n
|
||||
bytes written (e.g.
|
||||
.B %16A
|
||||
for the last 16 bytes).
|
||||
Shows only dots if the transfer is being done with
|
||||
.BR splice (2),
|
||||
since splicing to or from pipes does not use the buffer.
|
||||
.TP
|
||||
.B %N
|
||||
Name prefix given by
|
||||
.BR -N .
|
||||
Padded to 9 characters with spaces, and suffixed with :.
|
||||
.TP
|
||||
.B %%
|
||||
A single %.
|
||||
.P
|
||||
The format string equivalent of turning on all display switches is
|
||||
.BR "\`%N %b %T %t %r %a %p %e'" .
|
||||
|
||||
|
||||
.SH COMMON SWITCHES
|
||||
Some suggested common switch combinations:
|
||||
|
||||
.TP
|
||||
.B @PACKAGE@ -ptebar
|
||||
Show a progress bar, elapsed time, estimated completion time, byte counter,
|
||||
average rate, and current rate.
|
||||
.TP
|
||||
.B @PACKAGE@ -betlap
|
||||
Show a progress bar, elapsed time, estimated completion time, line counter,
|
||||
and average rate, counting lines instead of bytes.
|
||||
.TP
|
||||
.B @PACKAGE@ -t
|
||||
Show only the elapsed time - useful as a simple timer, e.g.
|
||||
.BR "sleep 10m | pv -t" .
|
||||
.TP
|
||||
.B @PACKAGE@ -pterb
|
||||
The default behaviour: progress bar, elapsed time, estimated completion
|
||||
time, current rate, and byte counter.
|
||||
|
||||
|
||||
.SH EXIT STATUS
|
||||
An exit status of 1 indicates a problem with the
|
||||
.B \-R
|
||||
or
|
||||
.B \-P
|
||||
options.
|
||||
|
||||
Any other exit status is a bitmask of the following:
|
||||
|
||||
.TP
|
||||
.B 2
|
||||
One or more files could not be accessed,
|
||||
.BR stat (2)ed,
|
||||
or opened.
|
||||
.TP
|
||||
.B 4
|
||||
An input file was the same as the output file.
|
||||
.TP
|
||||
.B 8
|
||||
Internal error with closing a file or moving to the next file.
|
||||
.TP
|
||||
.B 16
|
||||
There was an error while transferring data from one or more input files.
|
||||
.TP
|
||||
.B 32
|
||||
A signal was caught that caused an early exit.
|
||||
.TP
|
||||
.B 64
|
||||
Memory allocation failed.
|
||||
|
||||
A zero exit status indicates no problems.
|
||||
|
||||
|
||||
.SH AUTHOR
|
||||
Written by Andrew Wood, with patches submitted by various other people.
|
||||
Please see the package README for a complete list of contributors.
|
||||
|
||||
|
||||
.SH KNOWN PROBLEMS
|
||||
The following problems are known to exist in
|
||||
.BR @PACKAGE@ :
|
||||
.TP
|
||||
.B *
|
||||
The
|
||||
.B -c
|
||||
option does not work properly on Cygwin without
|
||||
.B cygserver
|
||||
running, if started near the bottom of the screen (IPC is needed to handle
|
||||
the terminal scrolling). To fix this, start
|
||||
.B cygserver
|
||||
before using
|
||||
.BR "@PACKAGE@ -c" .
|
||||
.P
|
||||
.TP
|
||||
.B *
|
||||
The
|
||||
.B -R
|
||||
option is not available on Cygwin without
|
||||
.B cygserver
|
||||
running (SYSV IPC is needed). To fix this, start
|
||||
.B cygserver
|
||||
before running the instance of
|
||||
.B @PACKAGE@
|
||||
you want, at runtime, to change the parameters of.
|
||||
.P
|
||||
If you find any other problems, please report them.
|
||||
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Report bugs in
|
||||
.B @PACKAGE@
|
||||
to pv@ivarch.com or use the contact form linked from the
|
||||
.B @PACKAGE@
|
||||
home page: <http://www.ivarch.com/programs/pv.shtml>
|
||||
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR cat (1),
|
||||
.BR dialog (1),
|
||||
.BR splice (2)
|
||||
|
||||
|
||||
.SH LICENSE
|
||||
This is free software, distributed under the ARTISTIC 2.0 license.
|
||||
@@ -0,0 +1,20 @@
|
||||
Before releasing a new version, go through this checklist:
|
||||
|
||||
- check for patches from http://packages.qa.debian.org/p/pv.html
|
||||
- bump doc/VERSION
|
||||
- bump doc/lsm.in
|
||||
- check doc/NEWS is up to date
|
||||
- check doc/spec.in is up to date (changelog)
|
||||
- check manual is up to date
|
||||
- make indent indentclean
|
||||
- make update-po
|
||||
- make test
|
||||
- commit
|
||||
- wipe build directory, re-run generate.sh and configure
|
||||
- make release
|
||||
- make manhtml | tidy -asxhtml | sed -e '1,/<body>/d' -e '/<\/body>/,$d'
|
||||
- update HTML for todo and news
|
||||
- copy and sign tar.gz to HTML directory
|
||||
- submit new release
|
||||
- upload HTML
|
||||
- check validator results for project page and manual
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
Summary: Monitor the progress of data through a pipe
|
||||
Name: @PACKAGE@
|
||||
Version: @VERSION@
|
||||
Release: 1%{?dist}
|
||||
License: Artistic 2.0
|
||||
Group: Development/Tools
|
||||
Source: http://www.ivarch.com/programs/sources/@PACKAGE@-@VERSION@.tar.gz
|
||||
Url: http://www.ivarch.com/programs/pv.shtml
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: gettext
|
||||
|
||||
%description
|
||||
PV ("Pipe Viewer") is a 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.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
%configure
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
|
||||
mkdir -p "$RPM_BUILD_ROOT"%{_bindir}
|
||||
mkdir -p "$RPM_BUILD_ROOT"%{_mandir}/man1
|
||||
mkdir -p "$RPM_BUILD_ROOT"/usr/share/locale
|
||||
|
||||
make DESTDIR="$RPM_BUILD_ROOT" install
|
||||
%find_lang %{name}
|
||||
|
||||
%check
|
||||
make test
|
||||
|
||||
%clean
|
||||
[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
|
||||
|
||||
%files -f %{name}.lang
|
||||
%defattr(-, root, root)
|
||||
%{_bindir}/%{name}
|
||||
%{_mandir}/man1/%{name}.1.gz
|
||||
|
||||
%doc README doc/NEWS doc/TODO doc/COPYING
|
||||
|
||||
%changelog
|
||||
* Fri Jun 30 2017 Andrew Wood <andrew.wood@ivarch.com> 1.6.6-1
|
||||
- (r161) use %llu instead of %Lu for better compatibility (Eric A. Borisch)
|
||||
- (r162) (#1532) fix target buffer size (-B) being ignored (AndCycle, Ilya
|
||||
- Basin, Antoine Beaupré)
|
||||
- (r164) cap read/write sizes, and check elapsed time during read/write
|
||||
- cycles, to avoid display hangs with large buffers or slow media; also
|
||||
- remove select() call from repeated_write function as it slows the
|
||||
- transfer down and the wrapping alarm() means it is unnecessary
|
||||
- (r169) (#1477) use alternate form for transfer counter, such that 13GB
|
||||
- is shown as 13.0GB so it's the same width as 13.1GB (André Stapf)
|
||||
- (r171) cleanup: units corrections in man page, of the form kb -> KiB
|
||||
- (r175) report error in "-d" if process fd directory is unreadable, or if
|
||||
- process disappears before we start the main loop (Jacek Wielemborek)
|
||||
|
||||
* Sun Mar 15 2015 Andrew Wood <andrew.wood@ivarch.com> 1.6.0-1
|
||||
- fix lstat64 support when unavailable - separate patches supplied by Ganael
|
||||
- Laplanche and Peter Korsgaard
|
||||
- (#1506) new option "-D" / "--delay-start" to only show bar after N seconds
|
||||
- (Damon Harper)
|
||||
- new option "--fineta" / "-I" to show ETA as time of day rather than time
|
||||
- remaining - patch supplied by Erkki Seppälä (r147)
|
||||
- (#1509) change ETA (--eta / -e) so that days are given if the hours
|
||||
- remaining are 24 or more (Jacek Wielemborek)
|
||||
- (#1499) repeat read and write attempts on partial buffer fill/empty to
|
||||
- work around post-signal transfer rate drop reported by Ralf Ramsauer
|
||||
- (#1507) do not try to calculate total size in line mode, due to bug
|
||||
- reported by Jacek Wielemborek and Michiel Van Herwegen
|
||||
- cleanup: removed defunct RATS comments and unnecessary copyright notices
|
||||
- clean up displayed lines when using --watchfd PID, when PID exits
|
||||
- output errors on a new line to avoid overwriting transfer bar
|
||||
|
||||
* Tue Aug 26 2014 Andrew Wood <andrew.wood@ivarch.com> 1.5.7-1
|
||||
- show KiB instead of incorrect kiB (Debian bug #706175)
|
||||
- (#1284) do not gzip man page, for non-Linux OSes (Bob Friesenhahn)
|
||||
- work around "awk" bug in tests/016-numeric-timer in decimal "," locales
|
||||
- fix "make rpm" and "make srpm", extend "make release" to sign releases
|
||||
|
||||
* Sun May 4 2014 Andrew Wood <andrew.wood@ivarch.com> 1.5.3-1
|
||||
- remove SPLICE_F_NONBLOCK to fix problem with slow splice() (Jan Seda)
|
||||
|
||||
* Mon Feb 10 2014 Andrew Wood <andrew.wood@ivarch.com> 1.5.2-1
|
||||
- allow "--watchfd" to look at block devices
|
||||
- let "--watchfd PID:FD" work with "--size N"
|
||||
- moved contributors out of the manual as the list was too long
|
||||
- (NB everyone is still listed in the README and always will be)
|
||||
|
||||
* Thu Jan 23 2014 Andrew Wood <andrew.wood@ivarch.com> 1.5.1-1
|
||||
- new option "--watchfd" - suggested by Jacek Wielemborek and "fdwatch"
|
||||
- use non-block flag with splice()
|
||||
- new display option "--buffer-percent", suggested by Kim Krecht
|
||||
- new display option "--last-written", suggested by Kim Krecht
|
||||
- new transfer option "--no-splice"
|
||||
- fix for minor bug which dropped display elements after one empty one
|
||||
- fix for single fd leak on exit (Cristian Ciupitu, Josh Stone)
|
||||
|
||||
* Mon Aug 5 2013 Andrew Wood <andrew.wood@ivarch.com> 1.4.12-1
|
||||
- new option "--null" - patch supplied by Zing Shishak
|
||||
- AIX build fix (add "-lc128") - with help from Pawel Piatek
|
||||
- AIX "-c" fixes - with help from Pawel Piatek
|
||||
- SCO build fix (po2table.sh) - reported by Wouter Pronk
|
||||
- test scripts fix for older distributions - patch from Bryan Dongray
|
||||
- fix for splice() not using stdin - patch from Zev Weiss
|
||||
|
||||
* Tue Jan 22 2013 Andrew Wood <andrew.wood@ivarch.com> 1.4.6-1
|
||||
- added patch from Pawel Piatek to omit O_NOFOLLOW in AIX
|
||||
|
||||
* Thu Jan 10 2013 Andrew Wood <andrew.wood@ivarch.com> 1.4.5-1
|
||||
- updated manual page to show known problem with "-R" on Cygwin
|
||||
|
||||
* Tue Dec 11 2012 Andrew Wood <andrew.wood@ivarch.com> 1.4.4-1
|
||||
- added debugging, see `pv -h' when configure run with "--enable-debugging"
|
||||
- rewrote cursor positioning code used when IPC is unavailable (Cygwin)
|
||||
- fixed cursor positioning cursor read answerback problem (Cygwin/Solaris)
|
||||
- fixed bug causing crash when progress displayed with too-small terminal
|
||||
|
||||
* Thu Dec 6 2012 Andrew Wood <andrew.wood@ivarch.com> 1.4.0-1
|
||||
- new option "--skip-errors" commissioned by Jim Salter
|
||||
- if stdout is a block device, and we don't know the total size, use the
|
||||
- size of that block device as the total (Peter Samuelson)
|
||||
- new option "--stop-at-size" to stop after "--size" bytes
|
||||
- report correct filename on read errors
|
||||
- fix use-after-free bug in remote PID cleanup code
|
||||
- refactored large chunks of code to make it more readable and to replace
|
||||
- most static variables with a state structure
|
||||
|
||||
* Mon Nov 5 2012 Andrew Wood <andrew.wood@ivarch.com> 1.3.9-1
|
||||
- allow "--format" parameters to be sent with "--remote"
|
||||
- configure option "--disable-ipc"
|
||||
- added tests for --numeric with --timer and --bytes
|
||||
- added tests for --remote
|
||||
|
||||
* Mon Oct 29 2012 Andrew Wood <andrew.wood@ivarch.com> 1.3.8-1
|
||||
- new "--pidfile" option to save process ID to a file
|
||||
- integrated patch for --numeric with --timer and --bytes (Sami Liedes)
|
||||
- removed signalling from --remote to prevent accidental process kills
|
||||
- new "--format" option (originally Vladimir Pal / Vladimir Ermakov)
|
||||
|
||||
* Wed Jun 27 2012 Andrew Wood <andrew.wood@ivarch.com> 1.3.4-1
|
||||
- new "--disable-splice" configure script option
|
||||
- fixed line mode size count with multiple files (Moritz Barsnick)
|
||||
- fixes for AIX core dumps (Pawel Piatek)
|
||||
|
||||
* Sat Jun 9 2012 Andrew Wood <andrew.wood@ivarch.com> 1.3.1-1
|
||||
- do not use splice() if the write buffer is not empty (Thomas Rachel)
|
||||
- added test 15 (pipe transfers), and new test script
|
||||
|
||||
* Tue Jun 5 2012 Andrew Wood <andrew.wood@ivarch.com> 1.3.0-1
|
||||
- added Tiger build patch from Olle Jonsson.
|
||||
- fix 1024-boundary display garble (Debian bug #586763).
|
||||
- use splice(2) where available (Debian bug #601683).
|
||||
- added known bugs section of the manual page.
|
||||
- fixed average rate test, 12 (Andrew Macheret).
|
||||
- use IEEE1541 units (Thomas Rachel).
|
||||
- bug with rate limit under 10 fixed (Henry Precheur).
|
||||
- speed up PV line mode (patch: Guillaume Marcais).
|
||||
- remove LD=ld from vars.mk to fix cross-compilation (paintitgray/PV#1291).
|
||||
|
||||
* Tue Dec 14 2010 Andrew Wood <andrew.wood@ivarch.com> 1.2.0-1
|
||||
- Integrated improved SI prefixes and --average-rate (Henry Gebhardt).
|
||||
- Return nonzero if exiting due to SIGTERM (Martin Baum).
|
||||
- Patch from Phil Rutschman to restore terminal properly on exit.
|
||||
- Fix i18n especially for --help (Sebastian Kayser).
|
||||
- Refactored pv_display.
|
||||
- We now have a coherent, documented, exit status.
|
||||
- Modified pipe test and new cksum test from Sebastian Kayser.
|
||||
- Default CFLAGS to just "-O" for non-GCC (Kjetil Torgrim Homme).
|
||||
- LFS compile fix for OS X 10.4 (Alexandre de Verteuil).
|
||||
- Remove DESTDIR / suffix (Sam Nelson, Daniel Pape).
|
||||
- Fixed potential NULL deref in transfer (Elias Pipping / LLVM/Clang).
|
||||
|
||||
* Thu Mar 6 2008 Andrew Wood <andrew.wood@ivarch.com> 1.1.4-1
|
||||
- Trap SIGINT/SIGHUP/SIGTERM so we clean up IPCs on exit (Laszlo Ersek).
|
||||
- Abort if numeric option, eg -L, has non-numeric value (Boris Lohner).
|
||||
- Compilation fixes for Darwin 9 and OS X.
|
||||
|
||||
* Thu Aug 30 2007 Andrew Wood <andrew.wood@ivarch.com> 1.1.0-1
|
||||
- New option "-R" to remotely control another @PACKAGE@ process.
|
||||
- New option "-l" to count lines instead of bytes.
|
||||
- Performance improvement for "-L" (rate) option.
|
||||
- Some Mac OS X fixes, and packaging cleanups.
|
||||
|
||||
* Sat Aug 4 2007 Andrew Wood <andrew.wood@ivarch.com> 1.0.1-1
|
||||
- Changed license from Artistic to Artistic 2.0.
|
||||
- Removed "--license" option.
|
||||
|
||||
* Thu Aug 2 2007 Andrew Wood <andrew.wood@ivarch.com> 1.0.0-1
|
||||
- We now act more like "cat" - just skip unreadable files, don't abort.
|
||||
- Various code cleanups were done.
|
||||
|
||||
* Mon Feb 5 2007 Andrew Wood <andrew.wood@ivarch.com> 0.9.9-1
|
||||
- New option "-B" to set the buffer size, and a workaround for problems
|
||||
- piping to dd(1).
|
||||
|
||||
* Mon Feb 27 2006 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Minor bugfixes, and on the final update, blank out the now-zero ETA.
|
||||
|
||||
* Thu Sep 1 2005 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Terminal locking now uses lockfiles if the terminal itself cannot be locked.
|
||||
|
||||
* Thu Jun 16 2005 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- A minor problem with the spec file was fixed.
|
||||
|
||||
* Mon Nov 15 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- A minor bug in the NLS code was fixed.
|
||||
|
||||
* Sat Nov 6 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Code cleanups and minor usability fixes.
|
||||
|
||||
* Tue Jun 29 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- A port of the terminal locking code to FreeBSD.
|
||||
|
||||
* Sun May 2 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Major reliability improvements to the cursor positioning.
|
||||
|
||||
* Sat Apr 24 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Rate and size parameters can now take suffixes such as "k", "m" etc.
|
||||
|
||||
* Mon Apr 19 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- A bug in the cursor positioning was fixed.
|
||||
|
||||
* Thu Feb 12 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Code cleanups and portability fixes.
|
||||
|
||||
* Sun Feb 8 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- The display buffer is now dynamically allocated, fixing an overflow bug.
|
||||
|
||||
* Wed Jan 14 2004 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- A minor bug triggered when installing the RPM was fixed.
|
||||
|
||||
* Mon Dec 22 2003 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Fixed a minor bug that occasionally reported "resource unavailable".
|
||||
|
||||
* Wed Aug 6 2003 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Block devices now have their size read correctly, so pv /dev/hda1 works
|
||||
- Minor code cleanups (mainly removal of CVS "Id" tags)
|
||||
|
||||
* Sun Aug 3 2003 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- Doing ^Z then "bg" then "fg" now continues displaying
|
||||
|
||||
* Tue Jul 16 2002 Andrew Wood <andrew.wood@ivarch.com>
|
||||
- First draft of spec file created.
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to autogenerate the `configure' script, and rebuild the dependency
|
||||
# list.
|
||||
|
||||
set -e
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
cd autoconf
|
||||
autoconf configure.in > ../configure
|
||||
cd ..
|
||||
chmod 755 configure
|
||||
|
||||
echo > autoconf/make/depend.mk~
|
||||
echo > autoconf/make/filelist.mk~
|
||||
echo > autoconf/make/modules.mk~
|
||||
|
||||
MAKE=make
|
||||
which gmake >/dev/null 2>&1 && MAKE=gmake
|
||||
|
||||
rm -rf .gen
|
||||
mkdir .gen
|
||||
cd .gen
|
||||
sh ../configure
|
||||
$MAKE make
|
||||
$MAKE dep
|
||||
cd ..
|
||||
rm -rf .gen
|
||||
rm -rf autoconf/autom4te.cache
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Replacement getopt function's header file. Include this AFTER config.h.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRARY_GETOPT_H
|
||||
#define _LIBRARY_GETOPT_H 1
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
|
||||
int minigetopt(int, char **, char *);
|
||||
extern char *minioptarg;
|
||||
extern int minioptind, miniopterr, minioptopt;
|
||||
|
||||
#define getopt minigetopt /* Flawfinder: ignore */
|
||||
#define optarg minioptarg
|
||||
#define optind minioptind
|
||||
#define opterr miniopterr
|
||||
#define optopt minioptopt
|
||||
|
||||
#endif /* !HAVE_GETOPT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBRARY_GETOPT_H */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Replacement gettext library header file. Include this within config.h,
|
||||
* like this:
|
||||
*
|
||||
* #ifdef ENABLE_NLS
|
||||
* # include "library/gettext.h"
|
||||
* #else
|
||||
* # define _(String) (String)
|
||||
* # define N_(String) (String)
|
||||
* #endif
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBRARY_GETTEXT_H
|
||||
#define _LIBRARY_GETTEXT_H 1
|
||||
|
||||
#ifdef HAVE_GETTEXT
|
||||
# ifdef HAVE_LIBINTL_H
|
||||
# include <libintl.h>
|
||||
# endif
|
||||
# ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
# endif
|
||||
# define _(String) gettext (String)
|
||||
# define N_(String) (String)
|
||||
#else
|
||||
# define _(String) minigettext (String)
|
||||
# define N_(String) (String)
|
||||
# define setlocale minisetlocale
|
||||
# define bindtextdomain minibindtextdomain
|
||||
# define textdomain minitextdomain
|
||||
# ifndef LC_ALL
|
||||
# define LC_ALL ""
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char *minisetlocale(char *, char *);
|
||||
char *minibindtextdomain(char *, char *);
|
||||
char *minitextdomain(char *);
|
||||
char *minigettext(char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBRARY_GETTEXT_H */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Global program option structure and the parsing function prototype.
|
||||
*/
|
||||
|
||||
#ifndef _OPTIONS_H
|
||||
#define _OPTIONS_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct opts_s;
|
||||
typedef struct opts_s *opts_t;
|
||||
|
||||
struct opts_s { /* structure describing run-time options */
|
||||
char *program_name; /* name the program is running as */
|
||||
unsigned char do_nothing; /* exit-without-doing-anything flag */
|
||||
unsigned char progress; /* progress bar flag */
|
||||
unsigned char timer; /* timer flag */
|
||||
unsigned char eta; /* ETA flag */
|
||||
unsigned char fineta; /* absolute ETA flag */
|
||||
unsigned char rate; /* rate counter flag */
|
||||
unsigned char average_rate; /* average rate counter flag */
|
||||
unsigned char bytes; /* bytes transferred flag */
|
||||
unsigned char bufpercent; /* transfer buffer percentage flag */
|
||||
unsigned int lastwritten; /* show N bytes last written */
|
||||
unsigned char force; /* force-if-not-terminal flag */
|
||||
unsigned char cursor; /* whether to use cursor positioning */
|
||||
unsigned char numeric; /* numeric output only */
|
||||
unsigned char wait; /* wait for transfer before display */
|
||||
unsigned char linemode; /* count lines instead of bytes */
|
||||
unsigned char null; /* lines are null-terminated */
|
||||
unsigned char no_op; /* do nothing other than pipe data */
|
||||
unsigned long long rate_limit; /* rate limit, in bytes per second */
|
||||
unsigned long long buffer_size;/* buffer size, in bytes (0=default) */
|
||||
unsigned int remote; /* PID of pv to update settings of */
|
||||
unsigned long long size; /* total size of data */
|
||||
unsigned char no_splice; /* flag set if never to use splice */
|
||||
unsigned char skip_errors; /* skip read errors flag */
|
||||
unsigned char stop_at_size; /* set if we stop at "size" bytes */
|
||||
double interval; /* interval between updates */
|
||||
double delay_start; /* delay before first display */
|
||||
unsigned int watch_pid; /* process to watch fds of */
|
||||
int watch_fd; /* fd to watch */
|
||||
unsigned int width; /* screen width */
|
||||
unsigned int height; /* screen height */
|
||||
char *name; /* process name, if any */
|
||||
char *format; /* output format, if any */
|
||||
char *pidfile; /* PID file, if any */
|
||||
int argc; /* number of non-option arguments */
|
||||
char **argv; /* array of non-option arguments */
|
||||
};
|
||||
|
||||
extern opts_t opts_parse(int, char **);
|
||||
extern void opts_free(opts_t);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _OPTIONS_H */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Functions internal to the PV library.
|
||||
*/
|
||||
|
||||
#ifndef _PV_INTERNAL_H
|
||||
#define _PV_INTERNAL_H 1
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef _PV_H
|
||||
#include "pv.h"
|
||||
#endif /* _PV_H */
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PV_DISPLAY_PROGRESS 1
|
||||
#define PV_DISPLAY_TIMER 2
|
||||
#define PV_DISPLAY_ETA 4
|
||||
#define PV_DISPLAY_RATE 8
|
||||
#define PV_DISPLAY_AVERAGERATE 16
|
||||
#define PV_DISPLAY_BYTES 32
|
||||
#define PV_DISPLAY_NAME 64
|
||||
#define PV_DISPLAY_BUFPERCENT 128
|
||||
#define PV_DISPLAY_OUTPUTBUF 256
|
||||
#define PV_DISPLAY_FINETA 512
|
||||
|
||||
#define RATE_GRANULARITY 100000 /* usec between -L rate chunks */
|
||||
#define REMOTE_INTERVAL 100000 /* usec between checks for -R */
|
||||
#define BUFFER_SIZE 409600 /* default transfer buffer size */
|
||||
#define BUFFER_SIZE_MAX 524288 /* max auto transfer buffer size */
|
||||
#define MAX_READ_AT_ONCE 524288 /* max to read() in one go */
|
||||
#define MAX_WRITE_AT_ONCE 524288 /* max to write() in one go */
|
||||
#define TRANSFER_READ_TIMEOUT 90000 /* usec to time reads out at */
|
||||
#define TRANSFER_WRITE_TIMEOUT 900000 /* usec to time writes out at */
|
||||
|
||||
#define MAXIMISE_BUFFER_FILL 1
|
||||
|
||||
|
||||
/*
|
||||
* Structure for holding PV internal state. Opaque outside the PV library.
|
||||
*/
|
||||
struct pvstate_s {
|
||||
/***************
|
||||
* Input files *
|
||||
***************/
|
||||
int input_file_count; /* number of input files */
|
||||
const char **input_files; /* input files (0=first) */
|
||||
|
||||
/*******************
|
||||
* Program control *
|
||||
*******************/
|
||||
unsigned char force; /* display even if not on terminal */
|
||||
unsigned char cursor; /* use cursor positioning */
|
||||
unsigned char numeric; /* numeric output only */
|
||||
unsigned char wait; /* wait for data before display */
|
||||
unsigned char linemode; /* count lines instead of bytes */
|
||||
unsigned char null; /* lines are null-terminated */
|
||||
unsigned char no_op; /* do nothing other than pipe data */
|
||||
unsigned char skip_errors; /* skip read errors flag */
|
||||
unsigned char stop_at_size; /* set if we stop at "size" bytes */
|
||||
unsigned char no_splice; /* never use splice() */
|
||||
unsigned long long rate_limit; /* rate limit, in bytes per second */
|
||||
unsigned long long target_buffer_size; /* buffer size (0=default) */
|
||||
unsigned long long size; /* total size of data */
|
||||
double interval; /* interval between updates */
|
||||
double delay_start; /* delay before first display */
|
||||
unsigned int watch_pid; /* process to watch fds of */
|
||||
int watch_fd; /* fd to watch */
|
||||
unsigned int width; /* screen width */
|
||||
unsigned int height; /* screen height */
|
||||
const char *name; /* display name */
|
||||
char default_format[512]; /* default format string */
|
||||
const char *format_string; /* output format string */
|
||||
|
||||
/******************
|
||||
* Program status *
|
||||
******************/
|
||||
const char *program_name; /* program name for error reporting */
|
||||
const char *current_file; /* current file being read */
|
||||
int exit_status; /* exit status to give (0=OK) */
|
||||
|
||||
/*******************
|
||||
* Signal handling *
|
||||
*******************/
|
||||
int pv_sig_old_stderr; /* see pv_sig_ttou() */
|
||||
struct timeval pv_sig_tstp_time; /* see pv_sig_tstp() / __cont() */
|
||||
struct timeval pv_sig_toffset; /* total time spent stopped */
|
||||
volatile sig_atomic_t pv_sig_newsize; /* whether we need to get term size again */
|
||||
volatile sig_atomic_t pv_sig_abort; /* whether we need to abort right now */
|
||||
volatile sig_atomic_t reparse_display; /* whether to re-check format string */
|
||||
struct sigaction pv_sig_old_sigpipe;
|
||||
struct sigaction pv_sig_old_sigttou;
|
||||
struct sigaction pv_sig_old_sigtstp;
|
||||
struct sigaction pv_sig_old_sigcont;
|
||||
struct sigaction pv_sig_old_sigwinch;
|
||||
struct sigaction pv_sig_old_sigint;
|
||||
struct sigaction pv_sig_old_sighup;
|
||||
struct sigaction pv_sig_old_sigterm;
|
||||
|
||||
/*****************
|
||||
* Display state *
|
||||
*****************/
|
||||
long percentage;
|
||||
long double prev_elapsed_sec;
|
||||
long double prev_rate;
|
||||
long double prev_trans;
|
||||
unsigned long long initial_offset;
|
||||
char *display_buffer;
|
||||
long display_buffer_size;
|
||||
int lastoutput_length; /* number of last-output bytes to show */
|
||||
unsigned char lastoutput_buffer[256];
|
||||
int prev_width; /* screen width last time we were called */
|
||||
int prev_length; /* length of last string we output */
|
||||
char str_name[512];
|
||||
char str_transferred[128];
|
||||
char str_bufpercent[128];
|
||||
char str_timer[128];
|
||||
char str_rate[128];
|
||||
char str_average_rate[128];
|
||||
char str_progress[1024];
|
||||
char str_lastoutput[512];
|
||||
char str_eta[128];
|
||||
char str_fineta[128];
|
||||
unsigned long components_used; /* bitmask of components used */
|
||||
struct {
|
||||
const char *string;
|
||||
int length;
|
||||
} format[100];
|
||||
unsigned char display_visible; /* set once anything written to terminal */
|
||||
|
||||
/********************
|
||||
* Cursor/IPC state *
|
||||
********************/
|
||||
#ifdef HAVE_IPC
|
||||
int crs_shmid; /* ID of our shared memory segment */
|
||||
int crs_pvcount; /* number of `pv' processes in total */
|
||||
int crs_pvmax; /* highest number of `pv's seen */
|
||||
int *crs_y_top; /* pointer to Y coord of topmost `pv' */
|
||||
int crs_y_lastread; /* last value of _y_top seen */
|
||||
int crs_y_offset; /* our Y offset from this top position */
|
||||
int crs_needreinit; /* set if we need to reinit cursor pos */
|
||||
int crs_noipc; /* set if we can't use IPC */
|
||||
#endif /* HAVE_IPC */
|
||||
int crs_lock_fd; /* fd of lockfile, -1 if none open */
|
||||
char crs_lock_file[1024];
|
||||
int crs_y_start; /* our initial Y coordinate */
|
||||
|
||||
/*******************
|
||||
* Transfer state *
|
||||
*******************/
|
||||
/*
|
||||
* The transfer buffer is used for moving data from the input files
|
||||
* to the output when splice() is not available.
|
||||
*
|
||||
* If buffer_size is smaller than pv__target_bufsize, then
|
||||
* pv_transfer will try to reallocate transfer_buffer to make
|
||||
* buffer_size equal to pv__target_bufsize.
|
||||
*
|
||||
* Data from the input files is read into the buffer; read_position
|
||||
* is the offset in the buffer that we've read data up to.
|
||||
*
|
||||
* Data is written to the output from the buffer, and write_position
|
||||
* is the offset in the buffer that we've written data up to. It
|
||||
* will always be less than or equal to read_position.
|
||||
*/
|
||||
unsigned char *transfer_buffer; /* data transfer buffer */
|
||||
unsigned long long buffer_size; /* size of buffer */
|
||||
unsigned long read_position; /* amount of data in buffer */
|
||||
unsigned long write_position; /* buffered data written */
|
||||
|
||||
/*
|
||||
* While reading from a file descriptor we keep track of how many
|
||||
* times in a row we've seen errors (read_errors_in_a_row), and
|
||||
* whether or not we have put a warning on stderr about read errors
|
||||
* on this fd (read_error_warning_shown).
|
||||
*
|
||||
* Whenever the active file descriptor changes from
|
||||
* last_read_skip_fd, we reset read_errors_in_a_row and
|
||||
* read_error_warning_shown to 0 for the new file descriptor and set
|
||||
* last_read_skip_fd to the new fd number.
|
||||
*
|
||||
* This way, we're treating each input file separately.
|
||||
*/
|
||||
int last_read_skip_fd;
|
||||
unsigned long read_errors_in_a_row;
|
||||
int read_error_warning_shown;
|
||||
#ifdef HAVE_SPLICE
|
||||
/*
|
||||
* These variables are used to keep track of whether splice() was
|
||||
* used; splice_failed_fd is the file descriptor that splice() last
|
||||
* failed on, so that we don't keep trying to use it on an fd that
|
||||
* doesn't support it, and splice_used is set to 1 if splice() was
|
||||
* used this time within pv_transfer().
|
||||
*/
|
||||
int splice_failed_fd;
|
||||
int splice_used;
|
||||
#endif
|
||||
long to_write; /* max to write this time around */
|
||||
long written; /* bytes sent to stdout this time */
|
||||
};
|
||||
|
||||
|
||||
struct pvwatchfd_s {
|
||||
unsigned int watch_pid; /* PID to watch */
|
||||
int watch_fd; /* fd to watch, -1 = not displayed */
|
||||
char file_fdinfo[4096]; /* path to /proc fdinfo file */
|
||||
char file_fd[4096]; /* path to /proc fd symlink */
|
||||
char file_fdpath[4096]; /* path to file that was opened */
|
||||
char display_name[512]; /* name to show on progress bar */
|
||||
struct stat64 sb_fd; /* stat of fd symlink */
|
||||
struct stat64 sb_fd_link; /* lstat of fd symlink */
|
||||
unsigned long long size; /* size of whole file, 0 if unknown */
|
||||
long long position; /* position last seen at */
|
||||
struct timeval start_time; /* time we started watching the fd */
|
||||
};
|
||||
typedef struct pvwatchfd_s *pvwatchfd_t;
|
||||
|
||||
void pv_error(pvstate_t, char *, ...);
|
||||
|
||||
int pv_main_loop(pvstate_t);
|
||||
void pv_display(pvstate_t, long double, long long, long long);
|
||||
long pv_transfer(pvstate_t, int, int *, int *, unsigned long long, long *);
|
||||
void pv_set_buffer_size(unsigned long long, int);
|
||||
int pv_next_file(pvstate_t, int, int);
|
||||
|
||||
void pv_crs_fini(pvstate_t);
|
||||
void pv_crs_init(pvstate_t);
|
||||
void pv_crs_update(pvstate_t, char *);
|
||||
#ifdef HAVE_IPC
|
||||
void pv_crs_needreinit(pvstate_t);
|
||||
#endif
|
||||
|
||||
void pv_sig_allowpause(void);
|
||||
void pv_sig_checkbg(void);
|
||||
void pv_sig_nopause(void);
|
||||
|
||||
void pv_remote_init(pvstate_t);
|
||||
void pv_remote_check(pvstate_t);
|
||||
void pv_remote_fini(pvstate_t);
|
||||
int pv_remote_set(pvstate_t);
|
||||
|
||||
int pv_watchfd_info(pvstate_t, pvwatchfd_t, int);
|
||||
int pv_watchfd_changed(pvwatchfd_t);
|
||||
long long pv_watchfd_position(pvwatchfd_t);
|
||||
int pv_watchpid_scanfds(pvstate_t, pvstate_t, unsigned int, int *, pvwatchfd_t *, pvstate_t *, int *);
|
||||
void pv_watchpid_setname(pvstate_t, pvwatchfd_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PV_INTERNAL_H */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Functions used across the program.
|
||||
*/
|
||||
|
||||
#ifndef _PV_H
|
||||
#define _PV_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Opaque structure for PV internal state.
|
||||
*/
|
||||
struct pvstate_s;
|
||||
typedef struct pvstate_s *pvstate_t;
|
||||
|
||||
/*
|
||||
* Valid number types for pv_getnum_check().
|
||||
*/
|
||||
typedef enum {
|
||||
PV_NUMTYPE_INTEGER,
|
||||
PV_NUMTYPE_DOUBLE
|
||||
} pv_numtype_t;
|
||||
|
||||
|
||||
/*
|
||||
* Simple string functions for processing numbers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return the given string converted to a double.
|
||||
*/
|
||||
extern double pv_getnum_d(const char *);
|
||||
|
||||
/*
|
||||
* Return the given string converted to an integer.
|
||||
*/
|
||||
extern int pv_getnum_i(const char *);
|
||||
|
||||
/*
|
||||
* Return the given string converted to a long long.
|
||||
*/
|
||||
extern long long pv_getnum_ll(const char *);
|
||||
|
||||
/*
|
||||
* Return zero if the given string is a number of the given type. NB an
|
||||
* integer is both a valid integer and a valid double.
|
||||
*/
|
||||
extern int pv_getnum_check(const char *, pv_numtype_t);
|
||||
|
||||
/*
|
||||
* Main PV functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create a new state structure, and return it, or 0 (NULL) on error.
|
||||
*/
|
||||
extern pvstate_t pv_state_alloc(const char *);
|
||||
|
||||
/*
|
||||
* Set the formatting string, given a set of old-style formatting options.
|
||||
*/
|
||||
extern void pv_state_set_format(pvstate_t state, unsigned char progress,
|
||||
unsigned char timer, unsigned char eta,
|
||||
unsigned char fineta, unsigned char rate,
|
||||
unsigned char average_rate, unsigned char bytes,
|
||||
unsigned char bufpercent,
|
||||
unsigned int lastwritten,
|
||||
const char *name);
|
||||
|
||||
/*
|
||||
* Set the various options.
|
||||
*/
|
||||
extern void pv_state_force_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_cursor_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_numeric_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_wait_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_delay_start_set(pvstate_t, double);
|
||||
extern void pv_state_linemode_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_null_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_no_op_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_skip_errors_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_stop_at_size_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_rate_limit_set(pvstate_t, unsigned long long);
|
||||
extern void pv_state_target_buffer_size_set(pvstate_t, unsigned long long);
|
||||
extern void pv_state_no_splice_set(pvstate_t, unsigned char);
|
||||
extern void pv_state_size_set(pvstate_t, unsigned long long);
|
||||
extern void pv_state_interval_set(pvstate_t, double);
|
||||
extern void pv_state_width_set(pvstate_t, unsigned int);
|
||||
extern void pv_state_height_set(pvstate_t, unsigned int);
|
||||
extern void pv_state_name_set(pvstate_t, const char *);
|
||||
extern void pv_state_format_string_set(pvstate_t, const char *);
|
||||
extern void pv_state_watch_pid_set(pvstate_t, unsigned int);
|
||||
extern void pv_state_watch_fd_set(pvstate_t, int);
|
||||
|
||||
extern void pv_state_inputfiles(pvstate_t, int, const char **);
|
||||
|
||||
/*
|
||||
* Work out the terminal size.
|
||||
*/
|
||||
extern void pv_screensize(unsigned int *width, unsigned int *height);
|
||||
|
||||
/*
|
||||
* Calculate the total size of all input files.
|
||||
*/
|
||||
extern unsigned long long pv_calc_total_size(pvstate_t);
|
||||
|
||||
/*
|
||||
* Set up signal handlers ready for running the main loop.
|
||||
*/
|
||||
extern void pv_sig_init(pvstate_t);
|
||||
|
||||
/*
|
||||
* Enter the main transfer loop, transferring all input files to the output.
|
||||
*/
|
||||
extern int pv_main_loop(pvstate_t);
|
||||
|
||||
/*
|
||||
* Watch the selected file descriptor of the selected process.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
extern void pv_sig_fini(pvstate_t);
|
||||
|
||||
/*
|
||||
* Free a state structure, after which it can no longer be used.
|
||||
*/
|
||||
extern void pv_state_free(pvstate_t);
|
||||
|
||||
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
# if __STDC_VERSION__ < 199901L
|
||||
# if __GNUC__ >= 2
|
||||
# define __func__ __FUNCTION__
|
||||
# else
|
||||
# define __func__ "<unknown>"
|
||||
# endif
|
||||
# endif
|
||||
# define debug(x,...) debugging_output(__func__, __FILE__, __LINE__, x, __VA_ARGS__)
|
||||
#else
|
||||
# define debug(x,...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Output debugging information, if debugging is enabled.
|
||||
*/
|
||||
void debugging_output(const char *, const char *, int, const char *, ...);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PV_H */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Small reimplementation of getopt().
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
|
||||
char *minioptarg = NULL;
|
||||
int minioptind = 0;
|
||||
int miniopterr = 1;
|
||||
int minioptopt = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Minimalist getopt() clone, which handles short options only and doesn't
|
||||
* permute argv[].
|
||||
*/
|
||||
int minigetopt(int argc, char **argv, char *optstring)
|
||||
{
|
||||
static int nextchar = 0;
|
||||
int optchar;
|
||||
int i;
|
||||
|
||||
if ((0 == minioptind) && (argc > 0))
|
||||
minioptind++;
|
||||
|
||||
if ((nextchar > 0) && (0 == argv[minioptind][nextchar])) {
|
||||
minioptind++;
|
||||
nextchar = 0;
|
||||
}
|
||||
|
||||
if (minioptind >= argc)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* End of options if arg doesn't start with "-"
|
||||
*/
|
||||
if (argv[minioptind][0] != '-')
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* End of options if arg is just "-"
|
||||
*/
|
||||
if (0 == argv[minioptind][1])
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* End of options if arg is "--", but don't include the "--" in the
|
||||
* non-option arguments
|
||||
*/
|
||||
if (('-' == argv[minioptind][1]) && (0 == argv[minioptind][2])) {
|
||||
minioptind++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == nextchar)
|
||||
nextchar = 1;
|
||||
|
||||
optchar = argv[minioptind][nextchar++];
|
||||
|
||||
for (i = 0; optstring[i] != 0 && optstring[i] != optchar; i++) {
|
||||
}
|
||||
|
||||
if (0 == optstring[i]) {
|
||||
minioptopt = optchar;
|
||||
if (miniopterr)
|
||||
fprintf(stderr, "%s: invalid option -- %c\n",
|
||||
argv[0], optchar);
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (optstring[i + 1] != ':') {
|
||||
minioptarg = NULL;
|
||||
return optchar;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we've got an option that takes an argument.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Next character isn't 0, so the argument is within this array
|
||||
* element (i.e. "-dFOO").
|
||||
*/
|
||||
if (argv[minioptind][nextchar] != 0) {
|
||||
minioptarg = &(argv[minioptind][nextchar]);
|
||||
nextchar = 0;
|
||||
minioptind++;
|
||||
return optchar;
|
||||
}
|
||||
|
||||
/*
|
||||
* Argument is in the next array element (i.e. "-d FOO").
|
||||
*/
|
||||
nextchar = 0;
|
||||
minioptind++;
|
||||
if (minioptind >= argc) {
|
||||
fprintf(stderr, "%s: option `-%c' requires an argument\n",
|
||||
argv[0], optchar);
|
||||
return ':';
|
||||
}
|
||||
minioptarg = argv[minioptind++];
|
||||
|
||||
return optchar;
|
||||
}
|
||||
|
||||
#endif /* HAVE_GETOPT */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Very minimal (and stupid) implementation of gettext, with a fixed lookup
|
||||
* table.
|
||||
*
|
||||
* This library ONLY handles gettext(), and that only for the basic form (it
|
||||
* translates strings to other strings with no other modification, so %2$d
|
||||
* style constructs are not dealt with). The setlocale(), bindtextdomain(),
|
||||
* and textdomain() functions are ignored.
|
||||
*
|
||||
* To use this library, create a function that, given a language string,
|
||||
* returns a struct msg_table_s[] of msgid and msgstr pairs, with the end
|
||||
* of the table being marked by a NULL msgid. The po2table.sh script will do
|
||||
* this.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef HAVE_GETTEXT
|
||||
|
||||
struct msgtable_s {
|
||||
char *msgid;
|
||||
char *msgstr;
|
||||
};
|
||||
|
||||
#if ENABLE_NLS
|
||||
struct msgtable_s *minigettext__gettable(char *);
|
||||
#else /* ENABLE_NLS */
|
||||
struct msgtable_s *minigettext__gettable(char *a)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
char *minisetlocale(char *a, char *b)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char *minibindtextdomain(char *a, char *b)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char *minitextdomain(char *a)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char *minigettext(char *msgid)
|
||||
{
|
||||
static struct msgtable_s *table = NULL;
|
||||
static int tried_lang = 0;
|
||||
char *lang;
|
||||
int i;
|
||||
|
||||
if (NULL == msgid)
|
||||
return msgid;
|
||||
|
||||
if (0 == tried_lang) {
|
||||
lang = getenv("LANGUAGE");
|
||||
if (lang)
|
||||
table = minigettext__gettable(lang);
|
||||
|
||||
if (NULL == table) {
|
||||
lang = getenv("LANG");
|
||||
if (lang)
|
||||
table = minigettext__gettable(lang);
|
||||
}
|
||||
|
||||
if (NULL == table) {
|
||||
lang = getenv("LC_ALL");
|
||||
if (lang)
|
||||
table = minigettext__gettable(lang);
|
||||
}
|
||||
|
||||
if (NULL == table) {
|
||||
lang = getenv("LC_MESSAGES");
|
||||
if (lang)
|
||||
table = minigettext__gettable(lang);
|
||||
}
|
||||
|
||||
tried_lang = 1;
|
||||
}
|
||||
|
||||
if (NULL == table)
|
||||
return msgid;
|
||||
|
||||
for (i = 0; table[i].msgid; i++) {
|
||||
if (0 == strcmp(table[i].msgid, msgid)) {
|
||||
if (0 == table[i].msgstr)
|
||||
return msgid;
|
||||
if (0 == table[i].msgstr[0])
|
||||
return msgid;
|
||||
return table[i].msgstr;
|
||||
}
|
||||
}
|
||||
|
||||
return msgid;
|
||||
}
|
||||
|
||||
#endif /* HAVE_GETTEXT */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Output debugging information.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "pv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
/*
|
||||
* Output debugging information to the file given in the DEBUG environment
|
||||
* variable, if it is defined.
|
||||
*/
|
||||
void debugging_output(const char *function, const char *file, int line,
|
||||
const char *format, ...)
|
||||
{
|
||||
static int tried_open = 0;
|
||||
static FILE *debugfptr = NULL;
|
||||
char *debugfile;
|
||||
va_list ap;
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
char tbuf[128];
|
||||
|
||||
if (0 == tried_open) {
|
||||
debugfile = getenv("DEBUG");
|
||||
if (NULL != debugfile)
|
||||
debugfptr = fopen(debugfile, "a");
|
||||
tried_open = 1;
|
||||
}
|
||||
|
||||
if (NULL == debugfptr)
|
||||
return;
|
||||
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
tbuf[0] = 0;
|
||||
strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", tm);
|
||||
|
||||
fprintf(debugfptr, "[%s] (%d) %s (%s:%d): ", tbuf, getpid(),
|
||||
function, file, line);
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(debugfptr, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(debugfptr, "\n");
|
||||
fflush(debugfptr);
|
||||
}
|
||||
|
||||
#else /* ! ENABLE_DEBUGGING */
|
||||
|
||||
/*
|
||||
* Stub debugging output function.
|
||||
*/
|
||||
void debugging_output(const char *function, const char *file, int line,
|
||||
const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ENABLE_DEBUGGING */
|
||||
|
||||
/* EOF */
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Output command-line help to stdout.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define N_(String) (String)
|
||||
|
||||
struct optdesc_s {
|
||||
char *optshort;
|
||||
char *optlong;
|
||||
char *param;
|
||||
char *description;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Display command-line help.
|
||||
*/
|
||||
void display_help(void)
|
||||
{
|
||||
struct optdesc_s optlist[] = {
|
||||
{"-p", "--progress", 0,
|
||||
N_("show progress bar")},
|
||||
{"-t", "--timer", 0,
|
||||
N_("show elapsed time")},
|
||||
{"-e", "--eta", 0,
|
||||
N_("show estimated time of arrival (completion)")},
|
||||
{"-I", "--fineta", 0,
|
||||
N_
|
||||
("show absolute estimated time of arrival (completion)")},
|
||||
{"-r", "--rate", 0,
|
||||
N_("show data transfer rate counter")},
|
||||
{"-a", "--average-rate", 0,
|
||||
N_("show data transfer average rate counter")},
|
||||
{"-b", "--bytes", 0,
|
||||
N_("show number of bytes transferred")},
|
||||
{"-T", "--buffer-percent", 0,
|
||||
N_("show percentage of transfer buffer in use")},
|
||||
{"-A", "--last-written", _("NUM"),
|
||||
N_("show NUM bytes last written")},
|
||||
{"-F", "--format", N_("FORMAT"),
|
||||
N_("set output format to FORMAT")},
|
||||
{"-n", "--numeric", 0,
|
||||
N_("output percentages, not visual information")},
|
||||
{"-q", "--quiet", 0,
|
||||
N_("do not output any transfer information at all")},
|
||||
{"", 0, 0, 0},
|
||||
{"-W", "--wait", 0,
|
||||
N_("display nothing until first byte transferred")},
|
||||
{"-D", "--delay-start", N_("SEC"),
|
||||
N_("display nothing until SEC seconds have passed")},
|
||||
{"-s", "--size", N_("SIZE"),
|
||||
N_("set estimated data size to SIZE bytes")},
|
||||
{"-l", "--line-mode", 0,
|
||||
N_("count lines instead of bytes")},
|
||||
{"-0", "--null", 0,
|
||||
N_("lines are null-terminated")},
|
||||
{"-i", "--interval", N_("SEC"),
|
||||
N_("update every SEC seconds")},
|
||||
{"-w", "--width", N_("WIDTH"),
|
||||
N_("assume terminal is WIDTH characters wide")},
|
||||
{"-H", "--height", N_("HEIGHT"),
|
||||
N_("assume terminal is HEIGHT rows high")},
|
||||
{"-N", "--name", N_("NAME"),
|
||||
N_("prefix visual information with NAME")},
|
||||
{"-f", "--force", 0,
|
||||
N_("output even if standard error is not a terminal")},
|
||||
{"-c", "--cursor", 0,
|
||||
N_("use cursor positioning escape sequences")},
|
||||
{"", 0, 0, 0},
|
||||
{"-L", "--rate-limit", N_("RATE"),
|
||||
N_("limit transfer to RATE bytes per second")},
|
||||
{"-B", "--buffer-size", N_("BYTES"),
|
||||
N_("use a buffer size of BYTES")},
|
||||
{"-C", "--no-splice", 0,
|
||||
N_("never use splice(), always use read/write")},
|
||||
{"-E", "--skip-errors", 0,
|
||||
N_("skip read errors in input")},
|
||||
{"-S", "--stop-at-size", 0,
|
||||
N_("stop after --size bytes have been transferred")},
|
||||
#ifdef HAVE_IPC
|
||||
{"-R", "--remote", N_("PID"),
|
||||
N_("update settings of process PID")},
|
||||
#endif /* HAVE_IPC */
|
||||
{"", 0, 0, 0},
|
||||
{"-P", "--pidfile", N_("FILE"),
|
||||
N_("save process ID in FILE")},
|
||||
{"", 0, 0, 0},
|
||||
{"-d", "--watchfd", N_("PID[:FD]"),
|
||||
N_("watch file FD opened by process PID")},
|
||||
{"", 0, 0, 0},
|
||||
{"-h", "--help", 0,
|
||||
N_("show this help and exit")},
|
||||
{"-V", "--version", 0,
|
||||
N_("show version information and exit")},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int i, col1max = 0, tw = 77;
|
||||
char *optbuf;
|
||||
|
||||
printf(_("Usage: %s [OPTION] [FILE]..."), PROGRAM_NAME);
|
||||
printf("\n%s\n\n",
|
||||
_
|
||||
("Concatenate FILE(s), or standard input, to standard output,\n"
|
||||
"with monitoring."));
|
||||
|
||||
for (i = 0; optlist[i].optshort; i++) {
|
||||
int width = 0;
|
||||
char *param;
|
||||
|
||||
width = 2 + strlen(optlist[i].optshort);
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
if (optlist[i].optlong)
|
||||
width += 2 + strlen(optlist[i].optlong);
|
||||
#endif
|
||||
param = optlist[i].param;
|
||||
if (param)
|
||||
param = _(param);
|
||||
if (param)
|
||||
width += 1 + strlen(param);
|
||||
|
||||
if (width > col1max)
|
||||
col1max = width;
|
||||
}
|
||||
|
||||
col1max++;
|
||||
|
||||
optbuf = malloc(col1max + 16);
|
||||
if (NULL == optbuf) {
|
||||
fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; optlist[i].optshort; i++) {
|
||||
char *param;
|
||||
char *description;
|
||||
char *start;
|
||||
char *end;
|
||||
|
||||
if (0 == optlist[i].optshort[0]) {
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
param = optlist[i].param;
|
||||
if (param)
|
||||
param = _(param);
|
||||
description = optlist[i].description;
|
||||
if (description)
|
||||
description = _(description);
|
||||
|
||||
sprintf(optbuf, "%s%s%s%s%s", optlist[i].optshort,
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
optlist[i].optlong ? ", " : "",
|
||||
optlist[i].optlong ? optlist[i].optlong : "",
|
||||
#else
|
||||
"", "",
|
||||
#endif
|
||||
param ? " " : "", param ? param : "");
|
||||
|
||||
printf(" %-*s ", col1max - 2, optbuf);
|
||||
|
||||
if (NULL == description) {
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
start = description;
|
||||
|
||||
while (strlen(start) > tw - col1max) {
|
||||
end = start + tw - col1max;
|
||||
while ((end > start) && (end[0] != ' '))
|
||||
end--;
|
||||
if (end == start) {
|
||||
end = start + tw - col1max;
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
printf("%.*s\n%*s ", (int) (end - start), start,
|
||||
col1max, "");
|
||||
if (end == start)
|
||||
end++;
|
||||
start = end;
|
||||
}
|
||||
|
||||
printf("%s\n", start);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
printf("\n");
|
||||
printf("%s",
|
||||
_
|
||||
("Debugging is enabled; export the DEBUG environment variable to define the\noutput filename.\n"));
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
printf(_("Please report any bugs to %s."), BUG_REPORTS_TO);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Main program entry point - read the command line options, then perform
|
||||
* the appropriate actions.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "options.h"
|
||||
#include "pv.h"
|
||||
|
||||
/* #undef MAKE_STDOUT_NONBLOCKING */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
int pv_remote_set(opts_t);
|
||||
void pv_remote_init(void);
|
||||
void pv_remote_fini(void);
|
||||
|
||||
|
||||
/*
|
||||
* Process command-line arguments and set option flags, then call functions
|
||||
* to initialise, and finally enter the main loop.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct termios t, t_save;
|
||||
opts_t opts;
|
||||
pvstate_t state;
|
||||
int retcode = 0;
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
#endif
|
||||
|
||||
opts = opts_parse(argc, argv);
|
||||
if (NULL == opts) {
|
||||
debug("%s: %d", "exiting with status", 64);
|
||||
return 64;
|
||||
}
|
||||
|
||||
if (opts->do_nothing) {
|
||||
debug("%s", "nothing to do - exiting with status 0");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* -R specified - send the message, then exit.
|
||||
*/
|
||||
if (opts->remote > 0) {
|
||||
retcode = pv_remote_set(opts);
|
||||
opts_free(opts);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate our internal state buffer.
|
||||
*/
|
||||
state = pv_state_alloc(opts->program_name);
|
||||
if (NULL == state) {
|
||||
fprintf(stderr, "%s: %s: %s\n", opts->program_name,
|
||||
_("state allocation failed"), strerror(errno));
|
||||
opts_free(opts);
|
||||
debug("%s: %d", "exiting with status", 64);
|
||||
return 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a PID file if -P was specified.
|
||||
*/
|
||||
if (opts->pidfile != NULL) {
|
||||
FILE *pidfptr;
|
||||
pidfptr = fopen(opts->pidfile, "w");
|
||||
if (NULL == pidfptr) {
|
||||
fprintf(stderr, "%s: %s: %s\n", opts->program_name,
|
||||
opts->pidfile, strerror(errno));
|
||||
pv_state_free(state);
|
||||
opts_free(opts);
|
||||
return 1;
|
||||
}
|
||||
fprintf(pidfptr, "%d\n", getpid());
|
||||
fclose(pidfptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If no files were given, pretend "-" was given (stdin).
|
||||
*/
|
||||
if (0 == opts->argc) {
|
||||
debug("%s", "no files given - adding fake argument `-'");
|
||||
opts->argv[opts->argc++] = "-";
|
||||
}
|
||||
|
||||
/*
|
||||
* Put our list of files into the PV internal state.
|
||||
*/
|
||||
pv_state_inputfiles(state, opts->argc,
|
||||
(const char **) (opts->argv));
|
||||
|
||||
if (0 == opts->watch_pid) {
|
||||
/*
|
||||
* If no size was given, and we're not in line mode, try to
|
||||
* calculate the total size.
|
||||
*/
|
||||
if ((0 == opts->size) && (0 == opts->linemode)) {
|
||||
opts->size = pv_calc_total_size(state);
|
||||
debug("%s: %llu", "no size given - calculated",
|
||||
opts->size);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the size is unknown, we cannot have an ETA.
|
||||
*/
|
||||
if (opts->size < 1) {
|
||||
opts->eta = 0;
|
||||
debug("%s", "size unknown - ETA disabled");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If stderr is not a terminal and we're neither forcing output nor
|
||||
* outputting numerically, we will have nothing to display at all.
|
||||
*/
|
||||
if ((0 == isatty(STDERR_FILENO))
|
||||
&& (0 == opts->force)
|
||||
&& (0 == opts->numeric)) {
|
||||
opts->no_op = 1;
|
||||
debug("%s", "nothing to display - setting no_op");
|
||||
}
|
||||
|
||||
/*
|
||||
* Auto-detect width or height if either are unspecified.
|
||||
*/
|
||||
if ((0 == opts->width) || (0 == opts->height)) {
|
||||
unsigned int width, height;
|
||||
width = 0;
|
||||
height = 0;
|
||||
pv_screensize(&width, &height);
|
||||
if (0 == opts->width) {
|
||||
opts->width = width;
|
||||
debug("%s: %u", "auto-detected terminal width",
|
||||
width);
|
||||
}
|
||||
if (0 == opts->height) {
|
||||
opts->height = height;
|
||||
debug("%s: %u", "auto-detected terminal height",
|
||||
height);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Width and height bounds checking (and defaults).
|
||||
*/
|
||||
if (opts->width < 1)
|
||||
opts->width = 80;
|
||||
if (opts->height < 1)
|
||||
opts->height = 25;
|
||||
if (opts->width > 999999)
|
||||
opts->width = 999999;
|
||||
if (opts->height > 999999)
|
||||
opts->height = 999999;
|
||||
|
||||
/*
|
||||
* Interval must be at least 0.1 second, and at most 10 minutes.
|
||||
*/
|
||||
if (opts->interval < 0.1)
|
||||
opts->interval = 0.1;
|
||||
if (opts->interval > 600)
|
||||
opts->interval = 600;
|
||||
|
||||
/*
|
||||
* Copy parameters from options into main state.
|
||||
*/
|
||||
pv_state_interval_set(state, opts->interval);
|
||||
pv_state_width_set(state, opts->width);
|
||||
pv_state_height_set(state, opts->height);
|
||||
pv_state_no_op_set(state, opts->no_op);
|
||||
pv_state_force_set(state, opts->force);
|
||||
pv_state_cursor_set(state, opts->cursor);
|
||||
pv_state_numeric_set(state, opts->numeric);
|
||||
pv_state_wait_set(state, opts->wait);
|
||||
pv_state_delay_start_set(state, opts->delay_start);
|
||||
pv_state_linemode_set(state, opts->linemode);
|
||||
pv_state_null_set(state, opts->null);
|
||||
pv_state_skip_errors_set(state, opts->skip_errors);
|
||||
pv_state_stop_at_size_set(state, opts->stop_at_size);
|
||||
pv_state_rate_limit_set(state, opts->rate_limit);
|
||||
pv_state_target_buffer_size_set(state, opts->buffer_size);
|
||||
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_format_string_set(state, opts->format);
|
||||
pv_state_watch_pid_set(state, opts->watch_pid);
|
||||
pv_state_watch_fd_set(state, opts->watch_fd);
|
||||
|
||||
pv_state_set_format(state, opts->progress, opts->timer, opts->eta,
|
||||
opts->fineta, opts->rate, opts->average_rate,
|
||||
opts->bytes, opts->bufpercent,
|
||||
opts->lastwritten, opts->name);
|
||||
|
||||
#ifdef MAKE_STDOUT_NONBLOCKING
|
||||
/*
|
||||
* Try and make standard output use non-blocking I/O.
|
||||
*
|
||||
* Note that this can cause problems with (broken) applications
|
||||
* such as dd.
|
||||
*/
|
||||
fcntl(STDOUT_FILENO, F_SETFL,
|
||||
O_NONBLOCK | fcntl(STDOUT_FILENO, F_GETFL));
|
||||
#endif /* MAKE_STDOUT_NONBLOCKING */
|
||||
|
||||
/*
|
||||
* Set terminal option TOSTOP so we get signal SIGTTOU if we try to
|
||||
* write to the terminal while backgrounded.
|
||||
*
|
||||
* Also, save the current terminal attributes for later restoration.
|
||||
*/
|
||||
memset(&t, 0, sizeof(t));
|
||||
tcgetattr(STDERR_FILENO, &t);
|
||||
t_save = t;
|
||||
t.c_lflag |= TOSTOP;
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t);
|
||||
|
||||
if (0 != opts->watch_pid) {
|
||||
if (0 <= opts->watch_fd) {
|
||||
pv_sig_init(state);
|
||||
retcode = pv_watchfd_loop(state);
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t_save);
|
||||
if (opts->pidfile != NULL)
|
||||
remove(opts->pidfile);
|
||||
pv_sig_fini(state);
|
||||
} else {
|
||||
pv_sig_init(state);
|
||||
retcode = pv_watchpid_loop(state);
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t_save);
|
||||
if (opts->pidfile != NULL)
|
||||
remove(opts->pidfile);
|
||||
pv_sig_fini(state);
|
||||
}
|
||||
} else {
|
||||
pv_sig_init(state);
|
||||
pv_remote_init();
|
||||
retcode = pv_main_loop(state);
|
||||
pv_remote_fini();
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t_save);
|
||||
if (opts->pidfile != NULL)
|
||||
remove(opts->pidfile);
|
||||
pv_sig_fini(state);
|
||||
}
|
||||
|
||||
pv_state_free(state);
|
||||
|
||||
opts_free(opts);
|
||||
|
||||
debug("%s: %d", "exiting with status", retcode);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Parse command-line options.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "options.h"
|
||||
#include "library/getopt.h"
|
||||
#include "pv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
void display_help(void);
|
||||
void display_version(void);
|
||||
|
||||
|
||||
/*
|
||||
* Free an opts_t object.
|
||||
*/
|
||||
void opts_free(opts_t opts)
|
||||
{
|
||||
if (!opts)
|
||||
return;
|
||||
if (opts->argv)
|
||||
free(opts->argv);
|
||||
free(opts);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse the given command-line arguments into an opts_t object, handling
|
||||
* "help", "license" and "version" options internally.
|
||||
*
|
||||
* Returns an opts_t, or 0 on error.
|
||||
*
|
||||
* Note that the contents of *argv[] (i.e. the command line parameters)
|
||||
* aren't copied anywhere, just the pointers are copied, so make sure the
|
||||
* command line data isn't overwritten or argv[1] free()d or whatever.
|
||||
*/
|
||||
opts_t opts_parse(int argc, char **argv)
|
||||
{
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"version", 0, 0, 'V'},
|
||||
{"progress", 0, 0, 'p'},
|
||||
{"timer", 0, 0, 't'},
|
||||
{"eta", 0, 0, 'e'},
|
||||
{"fineta", 0, 0, 'I'},
|
||||
{"rate", 0, 0, 'r'},
|
||||
{"average-rate", 0, 0, 'a'},
|
||||
{"bytes", 0, 0, 'b'},
|
||||
{"buffer-percent", 0, 0, 'T'},
|
||||
{"last-written", 1, 0, 'A'},
|
||||
{"force", 0, 0, 'f'},
|
||||
{"numeric", 0, 0, 'n'},
|
||||
{"quiet", 0, 0, 'q'},
|
||||
{"cursor", 0, 0, 'c'},
|
||||
{"wait", 0, 0, 'W'},
|
||||
{"delay-start", 1, 0, 'D'},
|
||||
{"size", 1, 0, 's'},
|
||||
{"line-mode", 0, 0, 'l'},
|
||||
{"null", 0, 0, '0'},
|
||||
{"interval", 1, 0, 'i'},
|
||||
{"width", 1, 0, 'w'},
|
||||
{"height", 1, 0, 'H'},
|
||||
{"name", 1, 0, 'N'},
|
||||
{"format", 1, 0, 'F'},
|
||||
{"rate-limit", 1, 0, 'L'},
|
||||
{"buffer-size", 1, 0, 'B'},
|
||||
{"no-splice", 0, 0, 'C'},
|
||||
{"skip-errors", 0, 0, 'E'},
|
||||
{"stop-at-size", 0, 0, 'S'},
|
||||
{"remote", 1, 0, 'R'},
|
||||
{"pidfile", 1, 0, 'P'},
|
||||
{"watchfd", 1, 0, 'd'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
#endif
|
||||
char *short_options =
|
||||
"hVpteIrabTA:fnqcWD:s:l0i:w:H:N:F:L:B:CESR:P:d:";
|
||||
int c, numopts;
|
||||
unsigned int check_pid;
|
||||
int check_fd;
|
||||
opts_t opts;
|
||||
char *ptr;
|
||||
|
||||
opts = calloc(1, sizeof(*opts));
|
||||
if (!opts) {
|
||||
fprintf(stderr,
|
||||
_("%s: option structure allocation failed (%s)"),
|
||||
argv[0], strerror(errno));
|
||||
fprintf(stderr, "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
opts->program_name = argv[0];
|
||||
ptr = strrchr(opts->program_name, '/');
|
||||
if (NULL != ptr)
|
||||
opts->program_name = &(ptr[1]);
|
||||
|
||||
opts->argc = 0;
|
||||
opts->argv = calloc(argc + 1, sizeof(char *));
|
||||
if (!opts->argv) {
|
||||
fprintf(stderr,
|
||||
_
|
||||
("%s: option structure argv allocation failed (%s)"),
|
||||
opts->program_name, strerror(errno));
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
numopts = 0;
|
||||
|
||||
opts->interval = 1;
|
||||
opts->delay_start = 0;
|
||||
opts->watch_pid = 0;
|
||||
opts->watch_fd = -1;
|
||||
|
||||
do {
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
c = getopt_long(argc, argv,
|
||||
short_options, long_options,
|
||||
&option_index);
|
||||
#else
|
||||
c = getopt(argc, argv, short_options);
|
||||
#endif
|
||||
if (c < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check that any numeric arguments are of the right type.
|
||||
*/
|
||||
switch (c) {
|
||||
case 's':
|
||||
case 'A':
|
||||
case 'w':
|
||||
case 'H':
|
||||
case 'L':
|
||||
case 'B':
|
||||
case 'R':
|
||||
if (pv_getnum_check(optarg, PV_NUMTYPE_INTEGER) !=
|
||||
0) {
|
||||
fprintf(stderr, "%s: -%c: %s\n",
|
||||
opts->program_name, c,
|
||||
_("integer argument expected"));
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
case 'D':
|
||||
if (pv_getnum_check(optarg, PV_NUMTYPE_DOUBLE) !=
|
||||
0) {
|
||||
fprintf(stderr, "%s: -%c: %s\n",
|
||||
opts->program_name, c,
|
||||
_("numeric argument expected"));
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
if (sscanf(optarg, "%u:%d", &check_pid, &check_fd)
|
||||
< 1) {
|
||||
fprintf(stderr, "%s: -%c: %s\n",
|
||||
opts->program_name, c,
|
||||
_
|
||||
("process ID or pid:fd pair expected"));
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
if (check_pid < 1) {
|
||||
fprintf(stderr, "%s: -%c: %s\n",
|
||||
opts->program_name, c,
|
||||
_("invalid process ID"));
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse each command line option.
|
||||
*/
|
||||
switch (c) {
|
||||
case 'h':
|
||||
display_help();
|
||||
opts->do_nothing = 1;
|
||||
return opts;
|
||||
break;
|
||||
case 'V':
|
||||
display_version();
|
||||
opts->do_nothing = 1;
|
||||
return opts;
|
||||
break;
|
||||
case 'p':
|
||||
opts->progress = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 't':
|
||||
opts->timer = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'I':
|
||||
opts->fineta = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'e':
|
||||
opts->eta = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'r':
|
||||
opts->rate = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'a':
|
||||
opts->average_rate = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'b':
|
||||
opts->bytes = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'T':
|
||||
opts->bufpercent = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'A':
|
||||
opts->lastwritten = pv_getnum_i(optarg);
|
||||
numopts++;
|
||||
break;
|
||||
case 'f':
|
||||
opts->force = 1;
|
||||
break;
|
||||
case 'n':
|
||||
opts->numeric = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'q':
|
||||
opts->no_op = 1;
|
||||
numopts++;
|
||||
break;
|
||||
case 'c':
|
||||
opts->cursor = 1;
|
||||
break;
|
||||
case 'W':
|
||||
opts->wait = 1;
|
||||
break;
|
||||
case 'D':
|
||||
opts->delay_start = pv_getnum_d(optarg);
|
||||
break;
|
||||
case 's':
|
||||
opts->size = pv_getnum_ll(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
opts->linemode = 1;
|
||||
break;
|
||||
case '0':
|
||||
opts->null = 1;
|
||||
opts->linemode = 1;
|
||||
break;
|
||||
case 'i':
|
||||
opts->interval = pv_getnum_d(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
opts->width = pv_getnum_i(optarg);
|
||||
break;
|
||||
case 'H':
|
||||
opts->height = pv_getnum_i(optarg);
|
||||
break;
|
||||
case 'N':
|
||||
opts->name = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
opts->rate_limit = pv_getnum_ll(optarg);
|
||||
break;
|
||||
case 'B':
|
||||
opts->buffer_size = pv_getnum_ll(optarg);
|
||||
break;
|
||||
case 'C':
|
||||
opts->no_splice = 1;
|
||||
break;
|
||||
case 'E':
|
||||
opts->skip_errors++;
|
||||
break;
|
||||
case 'S':
|
||||
opts->stop_at_size = 1;
|
||||
break;
|
||||
case 'R':
|
||||
opts->remote = pv_getnum_i(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
opts->pidfile = optarg;
|
||||
break;
|
||||
case 'F':
|
||||
opts->format = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
opts->watch_pid = 0;
|
||||
opts->watch_fd = -1;
|
||||
sscanf(optarg, "%u:%d", &(opts->watch_pid),
|
||||
&(opts->watch_fd));
|
||||
break;
|
||||
default:
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
fprintf(stderr,
|
||||
_("Try `%s --help' for more information."),
|
||||
opts->program_name);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
_("Try `%s -h' for more information."),
|
||||
opts->program_name);
|
||||
#endif
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (c != -1);
|
||||
|
||||
if (0 != opts->watch_pid) {
|
||||
if (opts->linemode || opts->null || opts->stop_at_size
|
||||
|| (opts->skip_errors > 0) || (opts->buffer_size > 0)
|
||||
|| (opts->rate_limit > 0)) {
|
||||
fprintf(stderr,
|
||||
_
|
||||
("%s: cannot use line mode or transfer modifier options when watching file descriptors"),
|
||||
opts->program_name);
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (opts->cursor) {
|
||||
fprintf(stderr,
|
||||
_
|
||||
("%s: cannot use cursor positioning when watching file descriptors"),
|
||||
opts->program_name);
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (0 != opts->remote) {
|
||||
fprintf(stderr,
|
||||
_
|
||||
("%s: cannot use remote control when watching file descriptors"),
|
||||
opts->program_name);
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
fprintf(stderr,
|
||||
_
|
||||
("%s: cannot transfer files when watching file descriptors"),
|
||||
opts->program_name);
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (0 != access("/proc/self/fdinfo", X_OK)) {
|
||||
fprintf(stderr,
|
||||
_
|
||||
("%s: -d: not available on systems without /proc/self/fdinfo"),
|
||||
opts->program_name);
|
||||
fprintf(stderr, "\n");
|
||||
opts_free(opts);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Default options: -pterb
|
||||
*/
|
||||
if (0 == numopts) {
|
||||
opts->progress = 1;
|
||||
opts->timer = 1;
|
||||
opts->eta = 1;
|
||||
opts->rate = 1;
|
||||
opts->bytes = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store remaining command-line arguments.
|
||||
*/
|
||||
while (optind < argc) {
|
||||
opts->argv[opts->argc++] = argv[optind++];
|
||||
}
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Remote-control functions.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "options.h"
|
||||
#include "pv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
struct remote_msg {
|
||||
long mtype;
|
||||
unsigned char progress; /* progress bar flag */
|
||||
unsigned char timer; /* timer flag */
|
||||
unsigned char eta; /* ETA flag */
|
||||
unsigned char fineta; /* absolute ETA flag */
|
||||
unsigned char rate; /* rate counter flag */
|
||||
unsigned char average_rate; /* average rate counter flag */
|
||||
unsigned char bytes; /* bytes transferred flag */
|
||||
unsigned char bufpercent; /* transfer buffer percentage flag */
|
||||
unsigned int lastwritten; /* last-written bytes count */
|
||||
unsigned long long rate_limit; /* rate limit, in bytes per second */
|
||||
unsigned long long buffer_size; /* buffer size, in bytes (0=default) */
|
||||
unsigned long long size; /* total size of data */
|
||||
double interval; /* interval between updates */
|
||||
unsigned int width; /* screen width */
|
||||
unsigned int height; /* screen height */
|
||||
char name[256];
|
||||
char format[256];
|
||||
};
|
||||
|
||||
|
||||
static int remote__msgid = -1;
|
||||
|
||||
|
||||
/*
|
||||
* Return a key for use with msgget() which will be unique to the current
|
||||
* user.
|
||||
*
|
||||
* We can't just use ftok() because the queue needs to be user-specific
|
||||
* so that a user cannot send messages to another user's process, and we
|
||||
* can't easily find out the terminal a given process is connected to in a
|
||||
* cross-platform way.
|
||||
*/
|
||||
static key_t remote__genkey(void)
|
||||
{
|
||||
int uid;
|
||||
key_t key;
|
||||
|
||||
uid = geteuid();
|
||||
if (uid < 0)
|
||||
uid = 0;
|
||||
|
||||
key = ftok("/tmp", 'P') | uid;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a message queue ID that is unique to the current user and the
|
||||
* given process ID, or -1 on error.
|
||||
*/
|
||||
static int remote__msgget(void)
|
||||
{
|
||||
/* Catch SIGSYS in case msgget() raises it, so we get ENOSYS */
|
||||
signal(SIGSYS, SIG_IGN);
|
||||
return msgget(remote__genkey(), IPC_CREAT | 0600);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the options of a remote process by setting up an IPC message queue,
|
||||
* sending a message containing the new options, and then waiting for the
|
||||
* message to be consumed by the remote process.
|
||||
*
|
||||
* Returns nonzero on error.
|
||||
*/
|
||||
int pv_remote_set(opts_t opts)
|
||||
{
|
||||
struct remote_msg msgbuf;
|
||||
struct msqid_ds qbuf;
|
||||
long timeout;
|
||||
int msgid;
|
||||
long initial_qnum;
|
||||
|
||||
/*
|
||||
* Check that the remote process exists.
|
||||
*/
|
||||
if (kill(opts->remote, 0) != 0) {
|
||||
fprintf(stderr, "%s: %d: %s\n", opts->program_name,
|
||||
opts->remote, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure parameters are within sensible bounds.
|
||||
*/
|
||||
if (opts->width < 0)
|
||||
opts->width = 80;
|
||||
if (opts->height < 0)
|
||||
opts->height = 25;
|
||||
if (opts->width > 999999)
|
||||
opts->width = 999999;
|
||||
if (opts->height > 999999)
|
||||
opts->height = 999999;
|
||||
if ((opts->interval != 0) && (opts->interval < 0.1))
|
||||
opts->interval = 0.1;
|
||||
if (opts->interval > 600)
|
||||
opts->interval = 600;
|
||||
|
||||
/*
|
||||
* Copy parameters into message buffer.
|
||||
*/
|
||||
memset(&msgbuf, 0, sizeof(msgbuf));
|
||||
msgbuf.mtype = opts->remote;
|
||||
msgbuf.progress = opts->progress;
|
||||
msgbuf.timer = opts->timer;
|
||||
msgbuf.eta = opts->eta;
|
||||
msgbuf.fineta = opts->fineta;
|
||||
msgbuf.rate = opts->rate;
|
||||
msgbuf.average_rate = opts->average_rate;
|
||||
msgbuf.bytes = opts->bytes;
|
||||
msgbuf.bufpercent = opts->bufpercent;
|
||||
msgbuf.lastwritten = opts->lastwritten;
|
||||
msgbuf.rate_limit = opts->rate_limit;
|
||||
msgbuf.buffer_size = opts->buffer_size;
|
||||
msgbuf.size = opts->size;
|
||||
msgbuf.interval = opts->interval;
|
||||
msgbuf.width = opts->width;
|
||||
msgbuf.height = opts->height;
|
||||
if (opts->name != NULL) {
|
||||
strncpy(msgbuf.name, opts->name, sizeof(msgbuf.name) - 1);
|
||||
}
|
||||
if (opts->format != NULL) {
|
||||
strncpy(msgbuf.format, opts->format,
|
||||
sizeof(msgbuf.format) - 1);
|
||||
}
|
||||
|
||||
msgid = remote__msgget();
|
||||
if (msgid < 0) {
|
||||
fprintf(stderr, "%s: %s\n", opts->program_name,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (msgctl(msgid, IPC_STAT, &qbuf) < 0) {
|
||||
fprintf(stderr, "%s: %s\n", opts->program_name,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
initial_qnum = qbuf.msg_qnum;
|
||||
|
||||
if (msgsnd(msgid, &msgbuf, sizeof(msgbuf) - sizeof(long), 0) != 0) {
|
||||
fprintf(stderr, "%s: %s\n", opts->program_name,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
timeout = 1100000;
|
||||
|
||||
while (timeout > 10000) {
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
timeout -= 10000;
|
||||
|
||||
/*
|
||||
* If we can't stat the queue, it must have been deleted.
|
||||
*/
|
||||
if (msgctl(msgid, IPC_STAT, &qbuf) < 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If the message count is at or below the message count
|
||||
* before we sent our message, assume it was received.
|
||||
*/
|
||||
if (qbuf.msg_qnum <= initial_qnum) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Message not received - delete it.
|
||||
*/
|
||||
if (msgctl(msgid, IPC_STAT, &qbuf) >= 0) {
|
||||
msgrcv(msgid, &msgbuf, sizeof(msgbuf) - sizeof(long),
|
||||
opts->remote, IPC_NOWAIT);
|
||||
/*
|
||||
* If this leaves nothing on the queue, remove the
|
||||
* queue, in case we created one for no reason.
|
||||
*/
|
||||
if (msgctl(msgid, IPC_STAT, &qbuf) >= 0) {
|
||||
if (qbuf.msg_qnum < 1)
|
||||
msgctl(msgid, IPC_RMID, &qbuf);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: %d: %s\n", opts->program_name, opts->remote,
|
||||
_("message not received"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for an IPC remote handling message and, if there is one, replace
|
||||
* the current process's options with those being passed in.
|
||||
*
|
||||
* NB relies on pv_state_set_format() causing the output format to be
|
||||
* reparsed.
|
||||
*/
|
||||
void pv_remote_check(pvstate_t state)
|
||||
{
|
||||
struct remote_msg msgbuf;
|
||||
int got;
|
||||
|
||||
if (remote__msgid < 0)
|
||||
return;
|
||||
|
||||
memset(&msgbuf, 0, sizeof(msgbuf));
|
||||
|
||||
got =
|
||||
msgrcv(remote__msgid, &msgbuf, sizeof(msgbuf) - sizeof(long),
|
||||
getpid(), IPC_NOWAIT);
|
||||
if (got < 0) {
|
||||
/*
|
||||
* If our queue had been deleted, re-create it.
|
||||
*/
|
||||
if (errno != EAGAIN && errno != ENOMSG) {
|
||||
remote__msgid = remote__msgget();
|
||||
}
|
||||
}
|
||||
if (got < 1)
|
||||
return;
|
||||
|
||||
debug("%s", "received remote message");
|
||||
|
||||
pv_state_format_string_set(state, NULL);
|
||||
pv_state_name_set(state, NULL);
|
||||
|
||||
pv_state_set_format(state, msgbuf.progress, msgbuf.timer,
|
||||
msgbuf.eta, msgbuf.fineta, msgbuf.rate,
|
||||
msgbuf.average_rate,
|
||||
msgbuf.bytes, msgbuf.bufpercent,
|
||||
msgbuf.lastwritten,
|
||||
0 ==
|
||||
msgbuf.name[0] ? NULL : strdup(msgbuf.name));
|
||||
|
||||
if (msgbuf.rate_limit > 0)
|
||||
pv_state_rate_limit_set(state, msgbuf.rate_limit);
|
||||
if (msgbuf.buffer_size > 0) {
|
||||
pv_state_target_buffer_size_set(state, msgbuf.buffer_size);
|
||||
}
|
||||
if (msgbuf.size > 0)
|
||||
pv_state_size_set(state, msgbuf.size);
|
||||
if (msgbuf.interval > 0)
|
||||
pv_state_interval_set(state, msgbuf.interval);
|
||||
if (msgbuf.width > 0)
|
||||
pv_state_width_set(state, msgbuf.width);
|
||||
if (msgbuf.height > 0)
|
||||
pv_state_height_set(state, msgbuf.height);
|
||||
if (msgbuf.format[0] != 0)
|
||||
pv_state_format_string_set(state, strdup(msgbuf.format));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise remote message reception handling.
|
||||
*/
|
||||
void pv_remote_init(void)
|
||||
{
|
||||
remote__msgid = remote__msgget();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Clean up after remote message reception handling.
|
||||
*/
|
||||
void pv_remote_fini(void)
|
||||
{
|
||||
if (remote__msgid >= 0) {
|
||||
struct msqid_ds qbuf;
|
||||
msgctl(remote__msgid, IPC_RMID, &qbuf);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !HAVE_IPC */
|
||||
|
||||
/*
|
||||
* Dummy stubs for remote control when we don't have IPC.
|
||||
*/
|
||||
void pv_remote_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void pv_remote_check(pvstate_t state)
|
||||
{
|
||||
}
|
||||
|
||||
void pv_remote_fini(void)
|
||||
{
|
||||
}
|
||||
|
||||
int pv_remote_set(pvstate_t state)
|
||||
{
|
||||
fprintf(stderr, "%s\n", _("IPC not supported on this system"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Output version information to stdout.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/*
|
||||
* Display current package version.
|
||||
*/
|
||||
void display_version(void)
|
||||
{
|
||||
printf(_("%s %s - Copyright %s %s"),
|
||||
PROGRAM_NAME, VERSION, COPYRIGHT_YEAR, COPYRIGHT_HOLDER);
|
||||
printf("\n\n");
|
||||
printf(_("Web site: %s"), PROJECT_HOMEPAGE);
|
||||
printf("\n\n");
|
||||
printf("%s",
|
||||
_("This program is free software, and is being distributed "
|
||||
"under the\nterms of the Artistic License 2.0."));
|
||||
printf("\n\n");
|
||||
printf("%s",
|
||||
_
|
||||
("This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."));
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+452
@@ -0,0 +1,452 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-06-30 22:21+0100\n"
|
||||
"Content-Type: text/plain; charset=iso-8859-15\n"
|
||||
"Date: 1999-06-01 15:18:29+0100\n"
|
||||
"From: Andrew Wood <ivarch@ubik>\n"
|
||||
"Xgettext-Options: --default-domain=pkgbuild --directory=./.pkgdir --add-"
|
||||
"comments --keyword=_ --keyword=N_\n"
|
||||
"Files: src/getopt/getopt.c src/getopt/getopt1.c src/version.c src/main/init."
|
||||
"c src/main/help.c src/main/xpmptr.c src/guts/load.c src/guts/stop.c src/guts/"
|
||||
"configure.c src/guts/make.c src/guts/install.c src/guts/prefs.c src/ui/"
|
||||
"generate.c src/ui/main.c src/ui/xpm.c src/ui/status.c src/ui/activate.c src/"
|
||||
"ui/handlers/main.c src/ui/handlers/package.c src/ui/handlers/prefs.c src/ui/"
|
||||
"handlers/dirsel.c src/ui/handlers/popup.c src/ui/handlers/help.c src/ui/"
|
||||
"textout.c src/ui/report.c src/ui/callback.c src/nls/intl/bindtextdom.c src/"
|
||||
"nls/intl/dcgettext.c src/nls/intl/dgettext.c src/nls/intl/finddomain.c src/"
|
||||
"nls/intl/gettext.c src/nls/intl/loadmsgcat.c src/nls/intl/localealias.c src/"
|
||||
"nls/intl/textdomain.c src/nls/intl-cat/cat-compat.c src/nls/intl-gett/intl-"
|
||||
"compat.c\n"
|
||||
|
||||
#: src/pv/watchpid.c:51 src/pv/watchpid.c:66 src/pv/watchpid.c:76
|
||||
#: src/pv/watchpid.c:107 src/pv/loop.c:519 src/pv/loop.c:580 src/pv/loop.c:632
|
||||
msgid "pid"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:68 src/pv/watchpid.c:78 src/pv/watchpid.c:109
|
||||
msgid "fd"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:112
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:53
|
||||
#, fuzzy
|
||||
msgid "failed to get terminal name"
|
||||
msgstr "Terminal konnte nicht geöffnet werden"
|
||||
|
||||
#: src/pv/cursor.c:96
|
||||
#, fuzzy
|
||||
msgid "failed to open lock file"
|
||||
msgstr "Datei konnte nicht geschlossen werden"
|
||||
|
||||
#: src/pv/cursor.c:129
|
||||
msgid "lock attempt failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:369
|
||||
msgid "failed to open terminal"
|
||||
msgstr "Terminal konnte nicht geöffnet werden"
|
||||
|
||||
#: src/pv/file.c:118
|
||||
#, fuzzy
|
||||
msgid "failed to seek to start of output"
|
||||
msgstr "Dateiinformationen für Ausgabe-Datei konnten nicht gelesen werden"
|
||||
|
||||
#: src/pv/file.c:214
|
||||
msgid "failed to close file"
|
||||
msgstr "Datei konnte nicht geschlossen werden"
|
||||
|
||||
#: src/pv/file.c:237
|
||||
msgid "failed to read file"
|
||||
msgstr "Datei konnte nicht gelesen werden"
|
||||
|
||||
#: src/pv/file.c:247
|
||||
msgid "failed to stat file"
|
||||
msgstr "Dateiinformationen konnten nicht gelesen werden"
|
||||
|
||||
#: src/pv/file.c:256
|
||||
msgid "failed to stat output file"
|
||||
msgstr "Dateiinformationen für Ausgabe-Datei konnten nicht gelesen werden"
|
||||
|
||||
#: src/pv/file.c:279
|
||||
msgid "input file is output file"
|
||||
msgstr "Eingabe-Datei ist Ausgabe-Datei"
|
||||
|
||||
#: src/pv/display.c:117
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:122
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:532 src/pv/transfer.c:679
|
||||
msgid "buffer allocation failed"
|
||||
msgstr "Puffer konnte nicht allokiert werden"
|
||||
|
||||
#: src/pv/display.c:592 src/pv/transfer.c:458
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "B/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:671 src/pv/display.c:676 src/pv/display.c:738
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/transfer.c:341
|
||||
msgid "read failed"
|
||||
msgstr "read-Aufruf fehlgeschlagen"
|
||||
|
||||
#: src/pv/transfer.c:359
|
||||
msgid "warning: read errors detected"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:374
|
||||
msgid "file is not seekable"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:437
|
||||
#, fuzzy
|
||||
msgid "failed to seek past error"
|
||||
msgstr "Dateiinformationen konnten nicht gelesen werden"
|
||||
|
||||
#: src/pv/transfer.c:456
|
||||
msgid "skipped past read error"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:631
|
||||
msgid "write failed"
|
||||
msgstr "write-Aufruf fehlgeschlagen"
|
||||
|
||||
#: src/pv/transfer.c:770
|
||||
msgid "select call failed"
|
||||
msgstr "select-Aufruf fehlgeschlagen"
|
||||
|
||||
#: src/pv/state.c:33
|
||||
msgid "none"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:17
|
||||
#, fuzzy, c-format
|
||||
msgid "%s %s - Copyright %s %s"
|
||||
msgstr "%s %s - Copyright(C) %s %s"
|
||||
|
||||
#: src/main/version.c:20
|
||||
#, c-format
|
||||
msgid "Web site: %s"
|
||||
msgstr "Web-Site: %s"
|
||||
|
||||
#: src/main/version.c:23
|
||||
msgid ""
|
||||
"This program is free software, and is being distributed under the\n"
|
||||
"terms of the Artistic License 2.0."
|
||||
msgstr ""
|
||||
"Dieses Programm ist freie Software und wird unter den Bedingungen\n"
|
||||
"der Artistic License verbreitet."
|
||||
|
||||
#: src/main/version.c:28
|
||||
msgid ""
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
msgstr ""
|
||||
"Dieses Programm wird verbreitet unter der Annahme dass es nützlich ist,\n"
|
||||
"aber OHNE JEGLICHE GARANTIE; insbesondere ohne der impliziten Garantie\n"
|
||||
"einer MARKTGÄNGIGKEIT oder EIGNUNG ZU EINEM BESTIMMTEN ZWECK."
|
||||
|
||||
#: src/main/main.c:73
|
||||
#, fuzzy
|
||||
msgid "state allocation failed"
|
||||
msgstr "Puffer konnte nicht allokiert werden"
|
||||
|
||||
#: src/main/options.c:98
|
||||
#, c-format
|
||||
msgid "%s: option structure allocation failed (%s)"
|
||||
msgstr "%s: `option' konnte nicht allokiert werden (%s)"
|
||||
|
||||
#: src/main/options.c:114
|
||||
#, c-format
|
||||
msgid "%s: option structure argv allocation failed (%s)"
|
||||
msgstr "%s: `option' (argv) konnte nicht allokiert werden (%s)"
|
||||
|
||||
#: src/main/options.c:154
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:165
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:176
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:183
|
||||
msgid "invalid process ID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:317
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "`%s --help' zeigt weitere Informationen an."
|
||||
|
||||
#: src/main/options.c:321
|
||||
#, fuzzy, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "`%s -h' zeigt weitere Informationen an."
|
||||
|
||||
#: src/main/options.c:338
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:348
|
||||
#, c-format
|
||||
msgid "%s: cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:358
|
||||
#, c-format
|
||||
msgid "%s: cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:368
|
||||
#, c-format
|
||||
msgid "%s: cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:378
|
||||
#, c-format
|
||||
msgid "%s: -d: not available on systems without /proc/self/fdinfo"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:218
|
||||
msgid "message not received"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:324
|
||||
msgid "IPC not supported on this system"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:31
|
||||
msgid "show progress bar"
|
||||
msgstr "Fortschritts-Anzeige"
|
||||
|
||||
#: src/main/help.c:33
|
||||
msgid "show elapsed time"
|
||||
msgstr "zeige die verstrichene Zeit an"
|
||||
|
||||
#: src/main/help.c:35
|
||||
msgid "show estimated time of arrival (completion)"
|
||||
msgstr "zeige die erwartete Zeit bis zum Ende an"
|
||||
|
||||
#: src/main/help.c:38
|
||||
#, fuzzy
|
||||
msgid "show absolute estimated time of arrival (completion)"
|
||||
msgstr "zeige die erwartete Zeit bis zum Ende an"
|
||||
|
||||
#: src/main/help.c:40
|
||||
msgid "show data transfer rate counter"
|
||||
msgstr "zeige die Datentransferrate an"
|
||||
|
||||
#: src/main/help.c:42
|
||||
msgid "show data transfer average rate counter"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:44
|
||||
msgid "show number of bytes transferred"
|
||||
msgstr "zeige die Anzahl von Bytes, die transferiert worden sind"
|
||||
|
||||
#: src/main/help.c:46
|
||||
msgid "show percentage of transfer buffer in use"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:47
|
||||
msgid "NUM"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:48
|
||||
msgid "show NUM bytes last written"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:49
|
||||
msgid "FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:50
|
||||
msgid "set output format to FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:52
|
||||
msgid "output percentages, not visual information"
|
||||
msgstr "Ausgabe von Prozent-Angaben statt visueller Darstellung"
|
||||
|
||||
#: src/main/help.c:54
|
||||
msgid "do not output any transfer information at all"
|
||||
msgstr "sämtliche Transferinformationen unterdrücken"
|
||||
|
||||
#: src/main/help.c:57
|
||||
msgid "display nothing until first byte transferred"
|
||||
msgstr "keine Ausgabe bevor das erste Byte übertragen wurde"
|
||||
|
||||
#: src/main/help.c:58 src/main/help.c:66
|
||||
msgid "SEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:59
|
||||
#, fuzzy
|
||||
msgid "display nothing until SEC seconds have passed"
|
||||
msgstr "keine Ausgabe bevor das erste Byte übertragen wurde"
|
||||
|
||||
#: src/main/help.c:60
|
||||
msgid "SIZE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:61
|
||||
msgid "set estimated data size to SIZE bytes"
|
||||
msgstr "setze erwartete Daten-Länge auf SIZE Byte"
|
||||
|
||||
#: src/main/help.c:63
|
||||
msgid "count lines instead of bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:65
|
||||
msgid "lines are null-terminated"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:67
|
||||
msgid "update every SEC seconds"
|
||||
msgstr "aktualisiere Ausgabe nach SEC Sekunden Intervall"
|
||||
|
||||
#: src/main/help.c:68
|
||||
msgid "WIDTH"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:69
|
||||
msgid "assume terminal is WIDTH characters wide"
|
||||
msgstr "setze Terminal-Breite auf WIDTH Zeichen"
|
||||
|
||||
#: src/main/help.c:70
|
||||
msgid "HEIGHT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:71
|
||||
msgid "assume terminal is HEIGHT rows high"
|
||||
msgstr "setze Terminal-Breite auf WIDTH Zeichen"
|
||||
|
||||
#: src/main/help.c:72
|
||||
msgid "NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:73
|
||||
msgid "prefix visual information with NAME"
|
||||
msgstr "setze den NAMEn für visuelle Darstellung"
|
||||
|
||||
#: src/main/help.c:75
|
||||
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:77
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "benutze Escape-Sequenzen zur Cursor-Positionierung"
|
||||
|
||||
#: src/main/help.c:79
|
||||
msgid "RATE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:80
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "beschränke die Transferrate auf RATE Byte pro Sekunde"
|
||||
|
||||
#: src/main/help.c:81
|
||||
msgid "BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:82
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:84
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:86
|
||||
msgid "skip read errors in input"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:88
|
||||
#, fuzzy
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "zeige die Anzahl von Bytes, die transferiert worden sind"
|
||||
|
||||
#: src/main/help.c:90
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:91
|
||||
msgid "update settings of process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:94
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:95
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:97
|
||||
msgid "PID[:FD]"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:98
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:101
|
||||
msgid "show this help and exit"
|
||||
msgstr "zeige diese Hilfe und beende"
|
||||
|
||||
#: src/main/help.c:103
|
||||
msgid "show version information and exit"
|
||||
msgstr "zeige Versionsinformationen und beende"
|
||||
|
||||
#: src/main/help.c:109
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Syntax: %s [OPTION] [DATEI]..."
|
||||
|
||||
#: src/main/help.c:112
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output,\n"
|
||||
"with monitoring."
|
||||
msgstr ""
|
||||
"Verbindet DATEI(en) oder den Standard-Eingabe-Kanal mit dem\n"
|
||||
"Standard-Ausgabe-Kanal und misst den Datenstrom."
|
||||
|
||||
#: src/main/help.c:201
|
||||
msgid ""
|
||||
"Debugging is enabled; export the DEBUG environment variable to define the\n"
|
||||
"output filename.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:205
|
||||
#, c-format
|
||||
msgid "Please report any bugs to %s."
|
||||
msgstr "Bitte senden Sie Fehlerberichte an %s."
|
||||
|
||||
#~ msgid "failed to lock terminal"
|
||||
#~ msgstr "Terminal konnte nicht geöffnet werden"
|
||||
+454
@@ -0,0 +1,454 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-06-30 22:21+0100\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-15\n"
|
||||
"Date: 1999-06-01 15:18:29+0100\n"
|
||||
"From: Andrew Wood <ivarch@ubik>\n"
|
||||
"Xgettext-Options: --default-domain=pkgbuild --directory=./.pkgdir --add-"
|
||||
"comments --keyword=_ --keyword=N_\n"
|
||||
"Files: src/getopt/getopt.c src/getopt/getopt1.c src/version.c src/main/init."
|
||||
"c src/main/help.c src/main/xpmptr.c src/guts/load.c src/guts/stop.c src/guts/"
|
||||
"configure.c src/guts/make.c src/guts/install.c src/guts/prefs.c src/ui/"
|
||||
"generate.c src/ui/main.c src/ui/xpm.c src/ui/status.c src/ui/activate.c src/"
|
||||
"ui/handlers/main.c src/ui/handlers/package.c src/ui/handlers/prefs.c src/ui/"
|
||||
"handlers/dirsel.c src/ui/handlers/popup.c src/ui/handlers/help.c src/ui/"
|
||||
"textout.c src/ui/report.c src/ui/callback.c src/nls/intl/bindtextdom.c src/"
|
||||
"nls/intl/dcgettext.c src/nls/intl/dgettext.c src/nls/intl/finddomain.c src/"
|
||||
"nls/intl/gettext.c src/nls/intl/loadmsgcat.c src/nls/intl/localealias.c src/"
|
||||
"nls/intl/textdomain.c src/nls/intl-cat/cat-compat.c src/nls/intl-gett/intl-"
|
||||
"compat.c\n"
|
||||
|
||||
#: src/pv/watchpid.c:51 src/pv/watchpid.c:66 src/pv/watchpid.c:76
|
||||
#: src/pv/watchpid.c:107 src/pv/loop.c:519 src/pv/loop.c:580 src/pv/loop.c:632
|
||||
msgid "pid"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:68 src/pv/watchpid.c:78 src/pv/watchpid.c:109
|
||||
msgid "fd"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:112
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:53
|
||||
#, fuzzy
|
||||
msgid "failed to get terminal name"
|
||||
msgstr "l'ouverture du terminal a échoué"
|
||||
|
||||
#: src/pv/cursor.c:96
|
||||
#, fuzzy
|
||||
msgid "failed to open lock file"
|
||||
msgstr "la fermeture du fichier a échoué"
|
||||
|
||||
#: src/pv/cursor.c:129
|
||||
msgid "lock attempt failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:369
|
||||
msgid "failed to open terminal"
|
||||
msgstr "l'ouverture du terminal a échoué"
|
||||
|
||||
#: src/pv/file.c:118
|
||||
#, fuzzy
|
||||
msgid "failed to seek to start of output"
|
||||
msgstr "échec à statuer sur le fichier de sortie"
|
||||
|
||||
#: src/pv/file.c:214
|
||||
msgid "failed to close file"
|
||||
msgstr "la fermeture du fichier a échoué"
|
||||
|
||||
#: src/pv/file.c:237
|
||||
msgid "failed to read file"
|
||||
msgstr "la lecture du fichier a échoué"
|
||||
|
||||
#: src/pv/file.c:247
|
||||
msgid "failed to stat file"
|
||||
msgstr "échec à statuer sur le fichier"
|
||||
|
||||
#: src/pv/file.c:256
|
||||
msgid "failed to stat output file"
|
||||
msgstr "échec à statuer sur le fichier de sortie"
|
||||
|
||||
#: src/pv/file.c:279
|
||||
msgid "input file is output file"
|
||||
msgstr "fichiers d'entré et de sortie sont les mêmes"
|
||||
|
||||
#: src/pv/display.c:117
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:122
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:532 src/pv/transfer.c:679
|
||||
msgid "buffer allocation failed"
|
||||
msgstr "l'allocation de mémoire tampon a échoué"
|
||||
|
||||
#: src/pv/display.c:592 src/pv/transfer.c:458
|
||||
msgid "B"
|
||||
msgstr "O"
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
#, fuzzy
|
||||
msgid "B/s"
|
||||
msgstr "O/s"
|
||||
|
||||
#: src/pv/display.c:671 src/pv/display.c:676 src/pv/display.c:738
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/transfer.c:341
|
||||
msgid "read failed"
|
||||
msgstr "la lecture a échoué"
|
||||
|
||||
#: src/pv/transfer.c:359
|
||||
msgid "warning: read errors detected"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:374
|
||||
msgid "file is not seekable"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:437
|
||||
#, fuzzy
|
||||
msgid "failed to seek past error"
|
||||
msgstr "échec à statuer sur le fichier"
|
||||
|
||||
#: src/pv/transfer.c:456
|
||||
msgid "skipped past read error"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:631
|
||||
msgid "write failed"
|
||||
msgstr "l'écriture a échoué"
|
||||
|
||||
#: src/pv/transfer.c:770
|
||||
msgid "select call failed"
|
||||
msgstr "appel de sélection a échoué"
|
||||
|
||||
#: src/pv/state.c:33
|
||||
msgid "none"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:17
|
||||
#, fuzzy, c-format
|
||||
msgid "%s %s - Copyright %s %s"
|
||||
msgstr "%s %s - Copyright(C) %s %s"
|
||||
|
||||
#: src/main/version.c:20
|
||||
#, c-format
|
||||
msgid "Web site: %s"
|
||||
msgstr "Site Web: %s"
|
||||
|
||||
#: src/main/version.c:23
|
||||
msgid ""
|
||||
"This program is free software, and is being distributed under the\n"
|
||||
"terms of the Artistic License 2.0."
|
||||
msgstr ""
|
||||
"Ce programme est un logiciel libre et est distribué sous les termes\n"
|
||||
"anglophone de la Licence Artistique 2.0 (Artistic License 2.0)."
|
||||
|
||||
#: src/main/version.c:28
|
||||
msgid ""
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
msgstr ""
|
||||
"Ce programme est distribué dans l'espoir qu'il sera utile, mais\n"
|
||||
"SANS GARANTIE AUCUNE; ni même de garantie sous-entendu que le\n"
|
||||
"programme soit COMMERCIALISABLE ou APPLICABLE À UNE TÂCHE\n"
|
||||
"PARTICULIÈRE."
|
||||
|
||||
#: src/main/main.c:73
|
||||
#, fuzzy
|
||||
msgid "state allocation failed"
|
||||
msgstr "l'allocation de mémoire tampon a échoué"
|
||||
|
||||
#: src/main/options.c:98
|
||||
#, c-format
|
||||
msgid "%s: option structure allocation failed (%s)"
|
||||
msgstr "%s: l'allocation pour la structure d'une option a echoué (%s)"
|
||||
|
||||
#: src/main/options.c:114
|
||||
#, c-format
|
||||
msgid "%s: option structure argv allocation failed (%s)"
|
||||
msgstr "%s: l'allocation pour la structure de l'option argv a echoué (%s)"
|
||||
|
||||
#: src/main/options.c:154
|
||||
msgid "integer argument expected"
|
||||
msgstr "Valeur entière attendue"
|
||||
|
||||
#: src/main/options.c:165
|
||||
msgid "numeric argument expected"
|
||||
msgstr "Valeur numérique attendue"
|
||||
|
||||
#: src/main/options.c:176
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:183
|
||||
msgid "invalid process ID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:317
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Essayez `%s --help' pour plus d'information."
|
||||
|
||||
#: src/main/options.c:321
|
||||
#, fuzzy, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Essayez `%s -h' pour plus d'information."
|
||||
|
||||
#: src/main/options.c:338
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:348
|
||||
#, c-format
|
||||
msgid "%s: cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:358
|
||||
#, c-format
|
||||
msgid "%s: cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:368
|
||||
#, c-format
|
||||
msgid "%s: cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:378
|
||||
#, c-format
|
||||
msgid "%s: -d: not available on systems without /proc/self/fdinfo"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:218
|
||||
msgid "message not received"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:324
|
||||
msgid "IPC not supported on this system"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:31
|
||||
msgid "show progress bar"
|
||||
msgstr "affiche la barre de progression"
|
||||
|
||||
#: src/main/help.c:33
|
||||
msgid "show elapsed time"
|
||||
msgstr "affiche le temps écoulé"
|
||||
|
||||
#: src/main/help.c:35
|
||||
msgid "show estimated time of arrival (completion)"
|
||||
msgstr "affiche l'heure approximative de l'achèvement de la tâche"
|
||||
|
||||
#: src/main/help.c:38
|
||||
#, fuzzy
|
||||
msgid "show absolute estimated time of arrival (completion)"
|
||||
msgstr "affiche l'heure approximative de l'achèvement de la tâche"
|
||||
|
||||
#: src/main/help.c:40
|
||||
msgid "show data transfer rate counter"
|
||||
msgstr "affiche le taux de tranfert des données"
|
||||
|
||||
#: src/main/help.c:42
|
||||
msgid "show data transfer average rate counter"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:44
|
||||
msgid "show number of bytes transferred"
|
||||
msgstr "affiche le nombre d'octets transférés"
|
||||
|
||||
#: src/main/help.c:46
|
||||
msgid "show percentage of transfer buffer in use"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:47
|
||||
msgid "NUM"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:48
|
||||
msgid "show NUM bytes last written"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:49
|
||||
#, fuzzy
|
||||
msgid "FORMAT"
|
||||
msgstr "TAUX"
|
||||
|
||||
#: src/main/help.c:50
|
||||
msgid "set output format to FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:52
|
||||
msgid "output percentages, not visual information"
|
||||
msgstr "imprime en pourcentage, pas les informations visuelles"
|
||||
|
||||
#: src/main/help.c:54
|
||||
msgid "do not output any transfer information at all"
|
||||
msgstr "n'afficher aucune information de transfert"
|
||||
|
||||
#: src/main/help.c:57
|
||||
msgid "display nothing until first byte transferred"
|
||||
msgstr "ne rien afficher avant qu'au moins un octet soit tranféré"
|
||||
|
||||
#: src/main/help.c:58 src/main/help.c:66
|
||||
msgid "SEC"
|
||||
msgstr "SEC"
|
||||
|
||||
#: src/main/help.c:59
|
||||
#, fuzzy
|
||||
msgid "display nothing until SEC seconds have passed"
|
||||
msgstr "ne rien afficher avant qu'au moins un octet soit tranféré"
|
||||
|
||||
#: src/main/help.c:60
|
||||
msgid "SIZE"
|
||||
msgstr "TAILLE"
|
||||
|
||||
#: src/main/help.c:61
|
||||
msgid "set estimated data size to SIZE bytes"
|
||||
msgstr "ajuste la taille estimée des données à TAILLE octets"
|
||||
|
||||
#: src/main/help.c:63
|
||||
msgid "count lines instead of bytes"
|
||||
msgstr "compte les lignes au lieu des octets"
|
||||
|
||||
#: src/main/help.c:65
|
||||
msgid "lines are null-terminated"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:67
|
||||
msgid "update every SEC seconds"
|
||||
msgstr "mise-à-jour toute les SEC secondes"
|
||||
|
||||
#: src/main/help.c:68
|
||||
msgid "WIDTH"
|
||||
msgstr "LARGEUR"
|
||||
|
||||
#: src/main/help.c:69
|
||||
msgid "assume terminal is WIDTH characters wide"
|
||||
msgstr "présumer la largeur du terminal à LARGEUR caractères"
|
||||
|
||||
#: src/main/help.c:70
|
||||
msgid "HEIGHT"
|
||||
msgstr "HAUTEUR"
|
||||
|
||||
#: src/main/help.c:71
|
||||
msgid "assume terminal is HEIGHT rows high"
|
||||
msgstr "présumer la hauteur du terminal à HAUTEUR lignes"
|
||||
|
||||
#: src/main/help.c:72
|
||||
msgid "NAME"
|
||||
msgstr "NOM"
|
||||
|
||||
#: src/main/help.c:73
|
||||
msgid "prefix visual information with NAME"
|
||||
msgstr "préfixer les informations visuelles avec NOM"
|
||||
|
||||
#: src/main/help.c:75
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr "imprime vers la sortie d'erreur même si ce n'est pas un terminal"
|
||||
|
||||
#: src/main/help.c:77
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "utiliser les séquences d'échappements de positionnement de curseur"
|
||||
|
||||
#: src/main/help.c:79
|
||||
msgid "RATE"
|
||||
msgstr "TAUX"
|
||||
|
||||
#: src/main/help.c:80
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "limite le taux de transfer à TAUX octets par seconde"
|
||||
|
||||
#: src/main/help.c:81
|
||||
msgid "BYTES"
|
||||
msgstr "OCTETS"
|
||||
|
||||
#: src/main/help.c:82
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr "Utiliser une mémoire tampon de OCTETS octets"
|
||||
|
||||
#: src/main/help.c:84
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:86
|
||||
msgid "skip read errors in input"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:88
|
||||
#, fuzzy
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "affiche le nombre d'octets transférés"
|
||||
|
||||
#: src/main/help.c:90
|
||||
msgid "PID"
|
||||
msgstr "PID"
|
||||
|
||||
#: src/main/help.c:91
|
||||
msgid "update settings of process PID"
|
||||
msgstr "mettre-à-jour la configuration du processus PID"
|
||||
|
||||
#: src/main/help.c:94
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:95
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:97
|
||||
msgid "PID[:FD]"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:98
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:101
|
||||
msgid "show this help and exit"
|
||||
msgstr "afficher cette aide puis quitter"
|
||||
|
||||
#: src/main/help.c:103
|
||||
msgid "show version information and exit"
|
||||
msgstr "afficher la version puis quitter"
|
||||
|
||||
#: src/main/help.c:109
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Utilisation : %s [OPTIONS] [FICHIER]..."
|
||||
|
||||
#: src/main/help.c:112
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output,\n"
|
||||
"with monitoring."
|
||||
msgstr ""
|
||||
"Concatène FICHIER(s), ou l'entrée standard, sur la sortie standard\n"
|
||||
"avec monitorage."
|
||||
|
||||
#: src/main/help.c:201
|
||||
msgid ""
|
||||
"Debugging is enabled; export the DEBUG environment variable to define the\n"
|
||||
"output filename.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:205
|
||||
#, c-format
|
||||
msgid "Please report any bugs to %s."
|
||||
msgstr "SVP rapporter touts bogues à %s."
|
||||
|
||||
#~ msgid "failed to lock terminal"
|
||||
#~ msgstr "l'ouverture du terminal a échoué"
|
||||
+491
@@ -0,0 +1,491 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Free Software Foundation, Inc.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-06-30 22:21+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-2\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/pv/watchpid.c:51 src/pv/watchpid.c:66 src/pv/watchpid.c:76
|
||||
#: src/pv/watchpid.c:107 src/pv/loop.c:519 src/pv/loop.c:580 src/pv/loop.c:632
|
||||
msgid "pid"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:68 src/pv/watchpid.c:78 src/pv/watchpid.c:109
|
||||
msgid "fd"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:112
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:53
|
||||
#, fuzzy
|
||||
msgid "failed to get terminal name"
|
||||
msgstr "nie uda³o siê otworzyæ terminala"
|
||||
|
||||
# "Przewidywany czas ukoñczenia" for ETA is too long
|
||||
#: src/pv/cursor.c:96
|
||||
#, fuzzy
|
||||
msgid "failed to open lock file"
|
||||
msgstr "nie uda³o siê zamkn±æ pliku"
|
||||
|
||||
#: src/pv/cursor.c:129
|
||||
msgid "lock attempt failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:369
|
||||
msgid "failed to open terminal"
|
||||
msgstr "nie uda³o siê otworzyæ terminala"
|
||||
|
||||
#: src/pv/file.c:118
|
||||
#, fuzzy
|
||||
msgid "failed to seek to start of output"
|
||||
msgstr "nie uda³o siê wykonaæ operacji stat na pliku wyj¶ciowym"
|
||||
|
||||
# "Przewidywany czas ukoñczenia" for ETA is too long
|
||||
#: src/pv/file.c:214
|
||||
msgid "failed to close file"
|
||||
msgstr "nie uda³o siê zamkn±æ pliku"
|
||||
|
||||
#: src/pv/file.c:237
|
||||
msgid "failed to read file"
|
||||
msgstr "nie uda³o siê odczytaæ pliku"
|
||||
|
||||
#: src/pv/file.c:247
|
||||
msgid "failed to stat file"
|
||||
msgstr "nie uda³o siê wykonaæ operacji stat na pliku"
|
||||
|
||||
#: src/pv/file.c:256
|
||||
msgid "failed to stat output file"
|
||||
msgstr "nie uda³o siê wykonaæ operacji stat na pliku wyj¶ciowym"
|
||||
|
||||
#: src/pv/file.c:279
|
||||
msgid "input file is output file"
|
||||
msgstr "plik wej¶ciowy jest zarazem plikiem wyj¶ciowym"
|
||||
|
||||
#: src/pv/display.c:117
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:122
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:532 src/pv/transfer.c:679
|
||||
msgid "buffer allocation failed"
|
||||
msgstr "nie uda³o siê zaalokowaæ bufora"
|
||||
|
||||
#: src/pv/display.c:592 src/pv/transfer.c:458
|
||||
msgid "B"
|
||||
msgstr "B"
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "/s"
|
||||
msgstr "/s"
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:671 src/pv/display.c:676 src/pv/display.c:738
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/transfer.c:341
|
||||
msgid "read failed"
|
||||
msgstr "b³±d odczytu"
|
||||
|
||||
#: src/pv/transfer.c:359
|
||||
msgid "warning: read errors detected"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:374
|
||||
msgid "file is not seekable"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:437
|
||||
#, fuzzy
|
||||
msgid "failed to seek past error"
|
||||
msgstr "nie uda³o siê wykonaæ operacji stat na pliku"
|
||||
|
||||
#: src/pv/transfer.c:456
|
||||
msgid "skipped past read error"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:631
|
||||
msgid "write failed"
|
||||
msgstr "b³±d zapisu"
|
||||
|
||||
#: src/pv/transfer.c:770
|
||||
msgid "select call failed"
|
||||
msgstr "nie uda³o siê wywo³aæ funkcji select"
|
||||
|
||||
#: src/pv/state.c:33
|
||||
msgid "none"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:17
|
||||
#, fuzzy, c-format
|
||||
msgid "%s %s - Copyright %s %s"
|
||||
msgstr "%s %s - Prawa autorskie (C) %s %s"
|
||||
|
||||
#: src/main/version.c:20
|
||||
#, c-format
|
||||
msgid "Web site: %s"
|
||||
msgstr "Strona WWW: %s"
|
||||
|
||||
#: src/main/version.c:23
|
||||
msgid ""
|
||||
"This program is free software, and is being distributed under the\n"
|
||||
"terms of the Artistic License 2.0."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:28
|
||||
msgid ""
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/main.c:73
|
||||
#, fuzzy
|
||||
msgid "state allocation failed"
|
||||
msgstr "nie uda³o siê zaalokowaæ bufora"
|
||||
|
||||
#: src/main/options.c:98
|
||||
#, c-format
|
||||
msgid "%s: option structure allocation failed (%s)"
|
||||
msgstr "%s: nie uda³o siê zaalokowaæ struktur opcji (%s)"
|
||||
|
||||
#: src/main/options.c:114
|
||||
#, c-format
|
||||
msgid "%s: option structure argv allocation failed (%s)"
|
||||
msgstr "%s: nie uda³o siê zaalokowaæ struktur opcji argv (%s)"
|
||||
|
||||
#: src/main/options.c:154
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:165
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:176
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:183
|
||||
msgid "invalid process ID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:317
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Spróbuj `%s --help' by uzyskaæ wiêcej informacji"
|
||||
|
||||
#: src/main/options.c:321
|
||||
#, fuzzy, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Spróbuj `%s -h' by uzyskaæ wiêcej informacji"
|
||||
|
||||
#: src/main/options.c:338
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:348
|
||||
#, c-format
|
||||
msgid "%s: cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:358
|
||||
#, c-format
|
||||
msgid "%s: cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:368
|
||||
#, c-format
|
||||
msgid "%s: cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:378
|
||||
#, c-format
|
||||
msgid "%s: -d: not available on systems without /proc/self/fdinfo"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:218
|
||||
msgid "message not received"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:324
|
||||
msgid "IPC not supported on this system"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:31
|
||||
msgid "show progress bar"
|
||||
msgstr "poka¿ pasek postêpu"
|
||||
|
||||
#: src/main/help.c:33
|
||||
msgid "show elapsed time"
|
||||
msgstr "poka¿ up³ywaj±cy czas"
|
||||
|
||||
#: src/main/help.c:35
|
||||
msgid "show estimated time of arrival (completion)"
|
||||
msgstr "poka¿ szacowany czas ukoñczenia"
|
||||
|
||||
#: src/main/help.c:38
|
||||
#, fuzzy
|
||||
msgid "show absolute estimated time of arrival (completion)"
|
||||
msgstr "poka¿ szacowany czas ukoñczenia"
|
||||
|
||||
#: src/main/help.c:40
|
||||
msgid "show data transfer rate counter"
|
||||
msgstr "poka¿ licznik prêdko¶ci przesy³ania"
|
||||
|
||||
#: src/main/help.c:42
|
||||
msgid "show data transfer average rate counter"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:44
|
||||
msgid "show number of bytes transferred"
|
||||
msgstr "poka¿ ilo¶æ przes³anych bajtów"
|
||||
|
||||
#: src/main/help.c:46
|
||||
msgid "show percentage of transfer buffer in use"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:47
|
||||
msgid "NUM"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:48
|
||||
msgid "show NUM bytes last written"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:49
|
||||
msgid "FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:50
|
||||
msgid "set output format to FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:52
|
||||
msgid "output percentages, not visual information"
|
||||
msgstr "w¶wietl wyj¶cie procentowo, bez graficznej prezentacji"
|
||||
|
||||
#: src/main/help.c:54
|
||||
msgid "do not output any transfer information at all"
|
||||
msgstr "nie wy¶wietlaj ¿adnych informacji o przesy³aniu"
|
||||
|
||||
#: src/main/help.c:57
|
||||
msgid "display nothing until first byte transferred"
|
||||
msgstr "nie wy¶wietlaj nic a¿ do pierwszego przes³anego bajtu"
|
||||
|
||||
#: src/main/help.c:58 src/main/help.c:66
|
||||
msgid "SEC"
|
||||
msgstr "WARTO¦Æ"
|
||||
|
||||
#: src/main/help.c:59
|
||||
#, fuzzy
|
||||
msgid "display nothing until SEC seconds have passed"
|
||||
msgstr "nie wy¶wietlaj nic a¿ do pierwszego przes³anego bajtu"
|
||||
|
||||
#: src/main/help.c:60
|
||||
msgid "SIZE"
|
||||
msgstr "WARTO¦Æ"
|
||||
|
||||
#: src/main/help.c:61
|
||||
msgid "set estimated data size to SIZE bytes"
|
||||
msgstr "ustaw oczekiwany rozmiar danych na WARTO¦Æ bajtów"
|
||||
|
||||
#: src/main/help.c:63
|
||||
msgid "count lines instead of bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:65
|
||||
msgid "lines are null-terminated"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:67
|
||||
msgid "update every SEC seconds"
|
||||
msgstr "aktualizuj co ka¿de WARTO¦Æ sekund"
|
||||
|
||||
#: src/main/help.c:68
|
||||
msgid "WIDTH"
|
||||
msgstr "WARTO¦Æ"
|
||||
|
||||
#: src/main/help.c:69
|
||||
msgid "assume terminal is WIDTH characters wide"
|
||||
msgstr "przyjmij, ¿e terminal ma szeroko¶æ WARTO¦Æ znaków"
|
||||
|
||||
#: src/main/help.c:70
|
||||
msgid "HEIGHT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:71
|
||||
msgid "assume terminal is HEIGHT rows high"
|
||||
msgstr "przyjmij, ¿e terminal ma szeroko¶æ WARTO¦Æ znaków"
|
||||
|
||||
#: src/main/help.c:72
|
||||
msgid "NAME"
|
||||
msgstr "NAZWA"
|
||||
|
||||
#: src/main/help.c:73
|
||||
msgid "prefix visual information with NAME"
|
||||
msgstr "poprzed¼ informacje prefiksem NAZWA"
|
||||
|
||||
#: src/main/help.c:75
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr "poka¿ wyj¶cie nawet gdy b³êdy nie s± typu terminal"
|
||||
|
||||
#: src/main/help.c:77
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "u¿ywaj sekwencji escape do pozycjonowania"
|
||||
|
||||
#: src/main/help.c:79
|
||||
msgid "RATE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:80
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "ogranicz przesy³ane dane do RATE bajtów na sekundê"
|
||||
|
||||
#: src/main/help.c:81
|
||||
msgid "BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:82
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:84
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:86
|
||||
msgid "skip read errors in input"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:88
|
||||
#, fuzzy
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "poka¿ ilo¶æ przes³anych bajtów"
|
||||
|
||||
#: src/main/help.c:90
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:91
|
||||
msgid "update settings of process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:94
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:95
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:97
|
||||
msgid "PID[:FD]"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:98
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:101
|
||||
msgid "show this help and exit"
|
||||
msgstr "wy¶wietl te informacje z pomoc± i wyjd¼"
|
||||
|
||||
#: src/main/help.c:103
|
||||
msgid "show version information and exit"
|
||||
msgstr "wy¶wietl informacje o wersji i wyjd¼"
|
||||
|
||||
#: src/main/help.c:109
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Sposób u¿ycia: %s [OPCJA] [PLIK]..."
|
||||
|
||||
#: src/main/help.c:112
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output,\n"
|
||||
"with monitoring."
|
||||
msgstr ""
|
||||
"£±czenie PLIK(ów) lub wej¶cia standardowego, do wyj¶cia standardowego\n"
|
||||
"z monitoringiem."
|
||||
|
||||
#: src/main/help.c:201
|
||||
msgid ""
|
||||
"Debugging is enabled; export the DEBUG environment variable to define the\n"
|
||||
"output filename.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:205
|
||||
#, c-format
|
||||
msgid "Please report any bugs to %s."
|
||||
msgstr "Proszê przesy³aæ zg³oszenia b³êdów do %s."
|
||||
|
||||
#~ msgid "failed to lock terminal"
|
||||
#~ msgstr "nie uda³o siê otworzyæ terminala"
|
||||
|
||||
#~ msgid "G"
|
||||
#~ msgstr "GB"
|
||||
|
||||
#~ msgid "M"
|
||||
#~ msgstr "MB"
|
||||
|
||||
#~ msgid "k"
|
||||
#~ msgstr "kB"
|
||||
|
||||
#~ msgid "GB"
|
||||
#~ msgstr "GB"
|
||||
|
||||
#~ msgid "MB"
|
||||
#~ msgstr "MB"
|
||||
|
||||
#~ msgid "kB"
|
||||
#~ msgstr "kB"
|
||||
|
||||
#~ msgid "M/s"
|
||||
#~ msgstr "MB/s"
|
||||
|
||||
#~ msgid "k/s"
|
||||
#~ msgstr "kB/s"
|
||||
|
||||
#~ msgid "/s "
|
||||
#~ msgstr "B/s"
|
||||
|
||||
#~ msgid "GB/s"
|
||||
#~ msgstr "GB/s"
|
||||
|
||||
#~ msgid "MB/s"
|
||||
#~ msgstr "MB/s"
|
||||
|
||||
#~ msgid "kB/s"
|
||||
#~ msgstr "kB/s"
|
||||
|
||||
#~ msgid "For more information, please run `%s --license'."
|
||||
#~ msgstr "By uzyskaæ wiêcej informacji wprowad¼ `%s --license'."
|
||||
|
||||
#~ msgid "For more information, please run `%s -l'."
|
||||
#~ msgstr "By uzyskaæ wiêcej informacji wprowad¼ `%s -l'."
|
||||
|
||||
#~ msgid "show the license this program is distributed under"
|
||||
#~ msgstr "wy¶wietl informacje o licencji pod któr± program jest rozprowadzany"
|
||||
|
||||
#~ msgid "%s %s - Copyright (C) %s %s"
|
||||
#~ msgstr "%s %s - Prawa autorskie (C) %s %s"
|
||||
+446
@@ -0,0 +1,446 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Free Software Foundation, Inc.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-06-30 22:21+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-15\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/pv/watchpid.c:51 src/pv/watchpid.c:66 src/pv/watchpid.c:76
|
||||
#: src/pv/watchpid.c:107 src/pv/loop.c:519 src/pv/loop.c:580 src/pv/loop.c:632
|
||||
msgid "pid"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:68 src/pv/watchpid.c:78 src/pv/watchpid.c:109
|
||||
msgid "fd"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:112
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:53
|
||||
#, fuzzy
|
||||
msgid "failed to get terminal name"
|
||||
msgstr "erro abrindo o terminal"
|
||||
|
||||
#: src/pv/cursor.c:96
|
||||
#, fuzzy
|
||||
msgid "failed to open lock file"
|
||||
msgstr "erro fechando o arquivo"
|
||||
|
||||
#: src/pv/cursor.c:129
|
||||
msgid "lock attempt failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:369
|
||||
msgid "failed to open terminal"
|
||||
msgstr "erro abrindo o terminal"
|
||||
|
||||
#: src/pv/file.c:118
|
||||
#, fuzzy
|
||||
msgid "failed to seek to start of output"
|
||||
msgstr "erro obtendo informações do arquivo de saída"
|
||||
|
||||
#: src/pv/file.c:214
|
||||
msgid "failed to close file"
|
||||
msgstr "erro fechando o arquivo"
|
||||
|
||||
#: src/pv/file.c:237
|
||||
msgid "failed to read file"
|
||||
msgstr "erro lendo o arquivo"
|
||||
|
||||
#: src/pv/file.c:247
|
||||
msgid "failed to stat file"
|
||||
msgstr "erro obtendo informações do arquivo"
|
||||
|
||||
#: src/pv/file.c:256
|
||||
msgid "failed to stat output file"
|
||||
msgstr "erro obtendo informações do arquivo de saída"
|
||||
|
||||
#: src/pv/file.c:279
|
||||
msgid "input file is output file"
|
||||
msgstr "os arquivos de entrada e saída são o mesmo"
|
||||
|
||||
#: src/pv/display.c:117
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:122
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:532 src/pv/transfer.c:679
|
||||
msgid "buffer allocation failed"
|
||||
msgstr "erro alocando o buffer"
|
||||
|
||||
#: src/pv/display.c:592 src/pv/transfer.c:458
|
||||
msgid "B"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "B/s"
|
||||
msgstr "B/s"
|
||||
|
||||
#: src/pv/display.c:671 src/pv/display.c:676 src/pv/display.c:738
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: src/pv/transfer.c:341
|
||||
msgid "read failed"
|
||||
msgstr "erro de leitura"
|
||||
|
||||
#: src/pv/transfer.c:359
|
||||
msgid "warning: read errors detected"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:374
|
||||
msgid "file is not seekable"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:437
|
||||
#, fuzzy
|
||||
msgid "failed to seek past error"
|
||||
msgstr "erro obtendo informações do arquivo"
|
||||
|
||||
#: src/pv/transfer.c:456
|
||||
msgid "skipped past read error"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:631
|
||||
msgid "write failed"
|
||||
msgstr "erro de gravação"
|
||||
|
||||
#: src/pv/transfer.c:770
|
||||
msgid "select call failed"
|
||||
msgstr "erro na chamada da função select"
|
||||
|
||||
#: src/pv/state.c:33
|
||||
msgid "none"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:17
|
||||
#, fuzzy, c-format
|
||||
msgid "%s %s - Copyright %s %s"
|
||||
msgstr "%s %s - Copyright(C) %s %s"
|
||||
|
||||
#: src/main/version.c:20
|
||||
#, c-format
|
||||
msgid "Web site: %s"
|
||||
msgstr "Site: %s"
|
||||
|
||||
#: src/main/version.c:23
|
||||
msgid ""
|
||||
"This program is free software, and is being distributed under the\n"
|
||||
"terms of the Artistic License 2.0."
|
||||
msgstr ""
|
||||
"Este programa é um software livre, distribuído sob os termos da\n"
|
||||
"Licença Artística."
|
||||
|
||||
#: src/main/version.c:28
|
||||
msgid ""
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
msgstr ""
|
||||
"Este programa é distribuído com o intuito de que seja útil,\n"
|
||||
"porém SEM QUAISQUER GARANTIAS; sem inclusive as garantias implícitas de\n"
|
||||
"COMERCIALIZAÇÃO e ADEQUAÇÃO A OBJETIVOS PARTICULARES."
|
||||
|
||||
#: src/main/main.c:73
|
||||
#, fuzzy
|
||||
msgid "state allocation failed"
|
||||
msgstr "erro alocando o buffer"
|
||||
|
||||
#: src/main/options.c:98
|
||||
#, c-format
|
||||
msgid "%s: option structure allocation failed (%s)"
|
||||
msgstr "%s: erro na alocação da estrutura de opções (%s)"
|
||||
|
||||
#: src/main/options.c:114
|
||||
#, c-format
|
||||
msgid "%s: option structure argv allocation failed (%s)"
|
||||
msgstr "%s: erro na alocação da estrutura de opções argv (%s)"
|
||||
|
||||
#: src/main/options.c:154
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:165
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:176
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:183
|
||||
msgid "invalid process ID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:317
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr "Tente `%s --help' para maiores informações."
|
||||
|
||||
#: src/main/options.c:321
|
||||
#, fuzzy, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr "Tente `%s -h' para maiores informações."
|
||||
|
||||
#: src/main/options.c:338
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:348
|
||||
#, c-format
|
||||
msgid "%s: cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:358
|
||||
#, c-format
|
||||
msgid "%s: cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:368
|
||||
#, c-format
|
||||
msgid "%s: cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:378
|
||||
#, c-format
|
||||
msgid "%s: -d: not available on systems without /proc/self/fdinfo"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:218
|
||||
msgid "message not received"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:324
|
||||
msgid "IPC not supported on this system"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:31
|
||||
msgid "show progress bar"
|
||||
msgstr "exibe barra de progressão"
|
||||
|
||||
#: src/main/help.c:33
|
||||
msgid "show elapsed time"
|
||||
msgstr "exibe tempo passado"
|
||||
|
||||
#: src/main/help.c:35
|
||||
msgid "show estimated time of arrival (completion)"
|
||||
msgstr "exibe o tempo estimado de término"
|
||||
|
||||
#: src/main/help.c:38
|
||||
#, fuzzy
|
||||
msgid "show absolute estimated time of arrival (completion)"
|
||||
msgstr "exibe o tempo estimado de término"
|
||||
|
||||
#: src/main/help.c:40
|
||||
msgid "show data transfer rate counter"
|
||||
msgstr "exibe a taxa de transferência"
|
||||
|
||||
#: src/main/help.c:42
|
||||
msgid "show data transfer average rate counter"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:44
|
||||
msgid "show number of bytes transferred"
|
||||
msgstr "exibe a quantidade de bytes transferidos"
|
||||
|
||||
#: src/main/help.c:46
|
||||
msgid "show percentage of transfer buffer in use"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:47
|
||||
msgid "NUM"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:48
|
||||
msgid "show NUM bytes last written"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:49
|
||||
msgid "FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:50
|
||||
msgid "set output format to FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:52
|
||||
msgid "output percentages, not visual information"
|
||||
msgstr "exibe apenas as porcentagens, sem informações visuais"
|
||||
|
||||
#: src/main/help.c:54
|
||||
msgid "do not output any transfer information at all"
|
||||
msgstr "executa programa sem exibir quaisquer informações"
|
||||
|
||||
#: src/main/help.c:57
|
||||
msgid "display nothing until first byte transferred"
|
||||
msgstr "não exibe nada até iniciar o processamento"
|
||||
|
||||
#: src/main/help.c:58 src/main/help.c:66
|
||||
msgid "SEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:59
|
||||
#, fuzzy
|
||||
msgid "display nothing until SEC seconds have passed"
|
||||
msgstr "não exibe nada até iniciar o processamento"
|
||||
|
||||
#: src/main/help.c:60
|
||||
msgid "SIZE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:61
|
||||
msgid "set estimated data size to SIZE bytes"
|
||||
msgstr "seta a quantidade estimada de dados em SIZE bytes"
|
||||
|
||||
#: src/main/help.c:63
|
||||
msgid "count lines instead of bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:65
|
||||
msgid "lines are null-terminated"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:67
|
||||
msgid "update every SEC seconds"
|
||||
msgstr "atualiza informações a cada SEC segundos"
|
||||
|
||||
#: src/main/help.c:68
|
||||
msgid "WIDTH"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:69
|
||||
msgid "assume terminal is WIDTH characters wide"
|
||||
msgstr "assume que terminal possui WIDTH caracteres de largura"
|
||||
|
||||
#: src/main/help.c:70
|
||||
msgid "HEIGHT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:71
|
||||
msgid "assume terminal is HEIGHT rows high"
|
||||
msgstr "assume que terminal possui WIDTH caracteres de largura"
|
||||
|
||||
#: src/main/help.c:72
|
||||
msgid "NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:73
|
||||
msgid "prefix visual information with NAME"
|
||||
msgstr "exibe NAME antes das demais informações"
|
||||
|
||||
#: src/main/help.c:75
|
||||
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:77
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr "utiliza caracteres de escape para posicionar o cursor"
|
||||
|
||||
#: src/main/help.c:79
|
||||
msgid "RATE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:80
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr "limita a transferência a RATE bytes por segundo"
|
||||
|
||||
#: src/main/help.c:81
|
||||
msgid "BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:82
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:84
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:86
|
||||
msgid "skip read errors in input"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:88
|
||||
#, fuzzy
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr "exibe a quantidade de bytes transferidos"
|
||||
|
||||
#: src/main/help.c:90
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:91
|
||||
msgid "update settings of process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:94
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:95
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:97
|
||||
msgid "PID[:FD]"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:98
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:101
|
||||
msgid "show this help and exit"
|
||||
msgstr "exibe esta tela de ajuda e termina"
|
||||
|
||||
#: src/main/help.c:103
|
||||
msgid "show version information and exit"
|
||||
msgstr "exibe a versão e termina"
|
||||
|
||||
#: src/main/help.c:109
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr "Uso: %s [OPÇÕES] [ARQUIVOS]..."
|
||||
|
||||
#: src/main/help.c:112
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output,\n"
|
||||
"with monitoring."
|
||||
msgstr ""
|
||||
"Concatena ARQUIVO(s) ou a entrada padrão e grava na saída padrão,\n"
|
||||
"com monitoramento."
|
||||
|
||||
#: src/main/help.c:201
|
||||
msgid ""
|
||||
"Debugging is enabled; export the DEBUG environment variable to define the\n"
|
||||
"output filename.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:205
|
||||
#, c-format
|
||||
msgid "Please report any bugs to %s."
|
||||
msgstr "Por favor, reporte quaisquer defeitos para %s."
|
||||
|
||||
#~ msgid "failed to lock terminal"
|
||||
#~ msgstr "erro abrindo o terminal"
|
||||
+430
@@ -0,0 +1,430 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-06-30 22:21+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/pv/watchpid.c:51 src/pv/watchpid.c:66 src/pv/watchpid.c:76
|
||||
#: src/pv/watchpid.c:107 src/pv/loop.c:519 src/pv/loop.c:580 src/pv/loop.c:632
|
||||
msgid "pid"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:68 src/pv/watchpid.c:78 src/pv/watchpid.c:109
|
||||
msgid "fd"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/watchpid.c:112
|
||||
msgid "not a regular file or block device"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:53
|
||||
msgid "failed to get terminal name"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:96
|
||||
msgid "failed to open lock file"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:129
|
||||
msgid "lock attempt failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/cursor.c:369
|
||||
msgid "failed to open terminal"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/file.c:118
|
||||
msgid "failed to seek to start of output"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/file.c:214
|
||||
msgid "failed to close file"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/file.c:237
|
||||
msgid "failed to read file"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/file.c:247
|
||||
msgid "failed to stat file"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/file.c:256
|
||||
msgid "failed to stat output file"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/file.c:279
|
||||
msgid "input file is output file"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:117
|
||||
msgid "yzafpnum kMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:122
|
||||
msgid "yzafpnum KMGTPEZY"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:532 src/pv/transfer.c:679
|
||||
msgid "buffer allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:592 src/pv/transfer.c:458
|
||||
msgid "B"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:628 src/pv/display.c:636
|
||||
msgid "B/s"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/display.c:671 src/pv/display.c:676 src/pv/display.c:738
|
||||
msgid "ETA"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:341
|
||||
msgid "read failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:359
|
||||
msgid "warning: read errors detected"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:374
|
||||
msgid "file is not seekable"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:437
|
||||
msgid "failed to seek past error"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:456
|
||||
msgid "skipped past read error"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:631
|
||||
msgid "write failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/transfer.c:770
|
||||
msgid "select call failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/pv/state.c:33
|
||||
msgid "none"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:17
|
||||
#, c-format
|
||||
msgid "%s %s - Copyright %s %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:20
|
||||
#, c-format
|
||||
msgid "Web site: %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:23
|
||||
msgid ""
|
||||
"This program is free software, and is being distributed under the\n"
|
||||
"terms of the Artistic License 2.0."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/version.c:28
|
||||
msgid ""
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/main.c:73
|
||||
msgid "state allocation failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:98
|
||||
#, c-format
|
||||
msgid "%s: option structure allocation failed (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:114
|
||||
#, c-format
|
||||
msgid "%s: option structure argv allocation failed (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:154
|
||||
msgid "integer argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:165
|
||||
msgid "numeric argument expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:176
|
||||
msgid "process ID or pid:fd pair expected"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:183
|
||||
msgid "invalid process ID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:317
|
||||
#, c-format
|
||||
msgid "Try `%s --help' for more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:321
|
||||
#, c-format
|
||||
msgid "Try `%s -h' for more information."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:338
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: cannot use line mode or transfer modifier options when watching file "
|
||||
"descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:348
|
||||
#, c-format
|
||||
msgid "%s: cannot use cursor positioning when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:358
|
||||
#, c-format
|
||||
msgid "%s: cannot use remote control when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:368
|
||||
#, c-format
|
||||
msgid "%s: cannot transfer files when watching file descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/options.c:378
|
||||
#, c-format
|
||||
msgid "%s: -d: not available on systems without /proc/self/fdinfo"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:218
|
||||
msgid "message not received"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/remote.c:324
|
||||
msgid "IPC not supported on this system"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:31
|
||||
msgid "show progress bar"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:33
|
||||
msgid "show elapsed time"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:35
|
||||
msgid "show estimated time of arrival (completion)"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:38
|
||||
msgid "show absolute estimated time of arrival (completion)"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:40
|
||||
msgid "show data transfer rate counter"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:42
|
||||
msgid "show data transfer average rate counter"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:44
|
||||
msgid "show number of bytes transferred"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:46
|
||||
msgid "show percentage of transfer buffer in use"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:47
|
||||
msgid "NUM"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:48
|
||||
msgid "show NUM bytes last written"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:49
|
||||
msgid "FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:50
|
||||
msgid "set output format to FORMAT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:52
|
||||
msgid "output percentages, not visual information"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:54
|
||||
msgid "do not output any transfer information at all"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:57
|
||||
msgid "display nothing until first byte transferred"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:58 src/main/help.c:66
|
||||
msgid "SEC"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:59
|
||||
msgid "display nothing until SEC seconds have passed"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:60
|
||||
msgid "SIZE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:61
|
||||
msgid "set estimated data size to SIZE bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:63
|
||||
msgid "count lines instead of bytes"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:65
|
||||
msgid "lines are null-terminated"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:67
|
||||
msgid "update every SEC seconds"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:68
|
||||
msgid "WIDTH"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:69
|
||||
msgid "assume terminal is WIDTH characters wide"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:70
|
||||
msgid "HEIGHT"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:71
|
||||
msgid "assume terminal is HEIGHT rows high"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:72
|
||||
msgid "NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:73
|
||||
msgid "prefix visual information with NAME"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:75
|
||||
msgid "output even if standard error is not a terminal"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:77
|
||||
msgid "use cursor positioning escape sequences"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:79
|
||||
msgid "RATE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:80
|
||||
msgid "limit transfer to RATE bytes per second"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:81
|
||||
msgid "BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:82
|
||||
msgid "use a buffer size of BYTES"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:84
|
||||
msgid "never use splice(), always use read/write"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:86
|
||||
msgid "skip read errors in input"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:88
|
||||
msgid "stop after --size bytes have been transferred"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:90
|
||||
msgid "PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:91
|
||||
msgid "update settings of process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:94
|
||||
msgid "FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:95
|
||||
msgid "save process ID in FILE"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:97
|
||||
msgid "PID[:FD]"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:98
|
||||
msgid "watch file FD opened by process PID"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:101
|
||||
msgid "show this help and exit"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:103
|
||||
msgid "show version information and exit"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:109
|
||||
#, c-format
|
||||
msgid "Usage: %s [OPTION] [FILE]..."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:112
|
||||
msgid ""
|
||||
"Concatenate FILE(s), or standard input, to standard output,\n"
|
||||
"with monitoring."
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:201
|
||||
msgid ""
|
||||
"Debugging is enabled; export the DEBUG environment variable to define the\n"
|
||||
"output filename.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/main/help.c:205
|
||||
#, c-format
|
||||
msgid "Please report any bugs to %s."
|
||||
msgstr ""
|
||||
+602
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Cursor positioning functions.
|
||||
*
|
||||
* If IPC is available, then a shared memory segment is used to co-ordinate
|
||||
* cursor positioning across multiple instances of `pv'. The shared memory
|
||||
* segment contains an integer which is the original "y" co-ordinate of the
|
||||
* first `pv' process.
|
||||
*
|
||||
* However, some OSes (FreeBSD and MacOS X so far) don't allow locking of a
|
||||
* terminal, so we try to use a lockfile if terminal locking doesn't work,
|
||||
* and finally abort if even that is unavailable.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
char *ttydev;
|
||||
char *tmpdir;
|
||||
int openflags;
|
||||
|
||||
state->crs_lock_fd = -1;
|
||||
|
||||
ttydev = ttyname(fd);
|
||||
if (!ttydev) {
|
||||
if (!state->force) {
|
||||
pv_error(state, "%s: %s",
|
||||
_("failed to get terminal name"),
|
||||
strerror(errno));
|
||||
}
|
||||
/*
|
||||
* If we don't know our terminal name, we can neither do IPC
|
||||
* nor make a lock file, so turn off cursor positioning.
|
||||
*/
|
||||
state->cursor = 0;
|
||||
debug("%s",
|
||||
"ttyname failed - cursor positioning disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
tmpdir = (char *) getenv("TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = (char *) getenv("TMP");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
|
||||
#ifdef HAVE_SNPRINTF
|
||||
snprintf(state->crs_lock_file, sizeof(state->crs_lock_file) - 1,
|
||||
"%s/pv-%s-%i.lock", tmpdir, basename(ttydev),
|
||||
(int) geteuid());
|
||||
#else
|
||||
sprintf(state->crs_lock_file,
|
||||
"%.*s/pv-%8s-%i.lock",
|
||||
sizeof(state->crs_lock_file) - 64, tmpdir,
|
||||
basename(ttydev), (int) geteuid());
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Pawel Piatek - not everyone has O_NOFOLLOW, e.g. AIX doesn't
|
||||
*/
|
||||
#ifdef O_NOFOLLOW
|
||||
openflags = O_RDWR | O_CREAT | O_NOFOLLOW;
|
||||
#else
|
||||
openflags = O_RDWR | O_CREAT;
|
||||
#endif
|
||||
|
||||
state->crs_lock_fd = open(state->crs_lock_file, openflags, 0600);
|
||||
if (state->crs_lock_fd < 0) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
state->crs_lock_file,
|
||||
_("failed to open lock file"), strerror(errno));
|
||||
state->cursor = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
struct flock lock;
|
||||
int lock_fd;
|
||||
|
||||
lock_fd = fd;
|
||||
if (state->crs_lock_fd >= 0)
|
||||
lock_fd = state->crs_lock_fd;
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
while (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
|
||||
if (errno != EINTR) {
|
||||
if (state->crs_lock_fd == -2) {
|
||||
pv_crs_open_lockfile(state, fd);
|
||||
if (state->crs_lock_fd >= 0) {
|
||||
lock_fd = state->crs_lock_fd;
|
||||
}
|
||||
} else {
|
||||
pv_error(state, "%s: %s",
|
||||
_("lock attempt failed"),
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state->crs_lock_fd >= 0) {
|
||||
debug("%s: %s", state->crs_lock_file,
|
||||
"terminal lockfile acquired");
|
||||
} else {
|
||||
debug("%s", "terminal lock acquired");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
struct flock lock;
|
||||
int lock_fd;
|
||||
|
||||
lock_fd = fd;
|
||||
if (state->crs_lock_fd >= 0)
|
||||
lock_fd = state->crs_lock_fd;
|
||||
|
||||
lock.l_type = F_UNLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
fcntl(lock_fd, F_SETLK, &lock);
|
||||
|
||||
if (state->crs_lock_fd >= 0) {
|
||||
debug("%s: %s", state->crs_lock_file,
|
||||
"terminal lockfile released");
|
||||
} else {
|
||||
debug("%s", "terminal lock released");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
/*
|
||||
* Get the current number of processes attached to our shared memory
|
||||
* segment, i.e. find out how many `pv' processes in total are running in
|
||||
* 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)
|
||||
{
|
||||
struct shmid_ds buf;
|
||||
|
||||
buf.shm_nattch = 0;
|
||||
|
||||
shmctl(state->crs_shmid, IPC_STAT, &buf);
|
||||
state->crs_pvcount = buf.shm_nattch;
|
||||
|
||||
if (state->crs_pvcount > state->crs_pvmax)
|
||||
state->crs_pvmax = state->crs_pvcount;
|
||||
|
||||
debug("%s: %d", "pvcount", state->crs_pvcount);
|
||||
}
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
|
||||
/*
|
||||
* Get the current cursor Y co-ordinate by sending the ECMA-48 CPR code to
|
||||
* the terminal connected to the given file descriptor.
|
||||
*/
|
||||
static int pv_crs_get_ypos(int terminalfd)
|
||||
{
|
||||
struct termios tty;
|
||||
struct termios old_tty;
|
||||
char cpr[32];
|
||||
int ypos;
|
||||
int r;
|
||||
#ifdef CURSOR_ANSWERBACK_BYTE_BY_BYTE
|
||||
int got;
|
||||
#endif /* CURSOR_ANSWERBACK_BYTE_BY_BYTE */
|
||||
|
||||
tcgetattr(terminalfd, &tty);
|
||||
tcgetattr(terminalfd, &old_tty);
|
||||
tty.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(terminalfd, TCSANOW | TCSAFLUSH, &tty);
|
||||
|
||||
write(terminalfd, "\033[6n", 4);
|
||||
|
||||
memset(cpr, 0, sizeof(cpr));
|
||||
|
||||
#ifdef CURSOR_ANSWERBACK_BYTE_BY_BYTE
|
||||
/* Read answerback byte by byte - fails on AIX */
|
||||
for (got = 0, r = 0; got < sizeof(cpr) - 2; got += r) {
|
||||
r = read(terminalfd, cpr + got, 1);
|
||||
if (r <= 0) {
|
||||
debug("got=%d, r=%d: %s", got, r, strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (cpr[got] == 'R')
|
||||
break;
|
||||
}
|
||||
|
||||
debug
|
||||
("read answerback message from fd %d, length %d - buf = %02X %02X %02X %02X %02X %02X",
|
||||
terminalfd, got, cpr[0], cpr[1], cpr[2], cpr[3], cpr[4],
|
||||
cpr[5]);
|
||||
|
||||
#else /* !CURSOR_ANSWERBACK_BYTE_BY_BYTE */
|
||||
/* Read answerback in one big lump - may fail on Solaris */
|
||||
r = read(terminalfd, cpr, sizeof(cpr));
|
||||
if (r <= 0) {
|
||||
debug("r=%d: %s", r, strerror(errno));
|
||||
} else {
|
||||
debug
|
||||
("read answerback message from fd %d, length %d - buf = %02X %02X %02X %02X %02X %02X",
|
||||
terminalfd, r, cpr[0], cpr[1], cpr[2], cpr[3], cpr[4],
|
||||
cpr[5]);
|
||||
|
||||
}
|
||||
#endif /* CURSOR_ANSWERBACK_BYTE_BY_BYTE */
|
||||
|
||||
ypos = pv_getnum_i(cpr + 2);
|
||||
|
||||
tcsetattr(terminalfd, TCSANOW | TCSAFLUSH, &old_tty);
|
||||
|
||||
debug("%s: %d", "ypos", ypos);
|
||||
|
||||
return ypos;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
/*
|
||||
* Initialise the IPC data, returning nonzero on error.
|
||||
*
|
||||
* To do this, we attach to the shared memory segment (creating it if it
|
||||
* does not exist). If we are the only process attached to it, then we
|
||||
* initialise it with the current cursor position.
|
||||
*
|
||||
* There is a race condition here: another process could attach before we've
|
||||
* had a chance to check, such that no process ends up getting an "attach
|
||||
* 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)
|
||||
{
|
||||
key_t key;
|
||||
|
||||
/*
|
||||
* Base the key for the shared memory segment on our current tty, so
|
||||
* we don't end up interfering in any way with instances of `pv'
|
||||
* running on another terminal.
|
||||
*/
|
||||
key = ftok(ttyfile, 'p');
|
||||
if (-1 == key) {
|
||||
debug("%s: %s\n", "ftok failed", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
pv_crs_lock(state, terminalfd);
|
||||
if (!state->cursor) {
|
||||
debug("%s", "early return - cursor has been disabled");
|
||||
return 1;
|
||||
}
|
||||
|
||||
state->crs_shmid = shmget(key, sizeof(int), 0600 | IPC_CREAT);
|
||||
if (state->crs_shmid < 0) {
|
||||
debug("%s: %s", "shmget failed", strerror(errno));
|
||||
pv_crs_unlock(state, terminalfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
state->crs_y_top = shmat(state->crs_shmid, 0, 0);
|
||||
|
||||
pv_crs_ipccount(state);
|
||||
|
||||
/*
|
||||
* If nobody else is attached to the shared memory segment, we're
|
||||
* the first, so we need to initialise the shared memory with our
|
||||
* current Y cursor co-ordinate.
|
||||
*/
|
||||
if (state->crs_pvcount < 2) {
|
||||
state->crs_y_start = pv_crs_get_ypos(terminalfd);
|
||||
*(state->crs_y_top) = state->crs_y_start;
|
||||
state->crs_y_lastread = state->crs_y_start;
|
||||
debug("%s", "we are the first to attach");
|
||||
}
|
||||
|
||||
state->crs_y_offset = state->crs_pvcount - 1;
|
||||
if (state->crs_y_offset < 0)
|
||||
state->crs_y_offset = 0;
|
||||
|
||||
/*
|
||||
* If anyone else had attached to the shared memory segment, we need
|
||||
* to read the top Y co-ordinate from it.
|
||||
*/
|
||||
if (state->crs_pvcount > 1) {
|
||||
state->crs_y_start = *(state->crs_y_top);
|
||||
state->crs_y_lastread = state->crs_y_start;
|
||||
debug("%s: %d", "not the first to attach - got top y",
|
||||
state->crs_y_start);
|
||||
}
|
||||
|
||||
pv_crs_unlock(state, terminalfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the terminal for cursor positioning.
|
||||
*/
|
||||
void pv_crs_init(pvstate_t state)
|
||||
{
|
||||
char *ttyfile;
|
||||
int fd;
|
||||
|
||||
state->crs_lock_fd = -2;
|
||||
state->crs_lock_file[0] = 0;
|
||||
|
||||
if (!state->cursor)
|
||||
return;
|
||||
|
||||
debug("%s", "init");
|
||||
|
||||
ttyfile = ttyname(STDERR_FILENO);
|
||||
if (!ttyfile) {
|
||||
debug("%s: %s",
|
||||
"disabling cursor positioning because ttyname failed",
|
||||
strerror(errno));
|
||||
state->cursor = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(ttyfile, O_RDWR);
|
||||
if (fd < 0) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
_("failed to open terminal"), ttyfile,
|
||||
strerror(errno));
|
||||
state->cursor = 0;
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_IPC
|
||||
if (pv_crs_ipcinit(state, ttyfile, fd) != 0) {
|
||||
debug("%s", "ipcinit failed, setting noipc flag");
|
||||
state->crs_noipc = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are not using IPC, then we need to get the current Y
|
||||
* co-ordinate. If we are using IPC, then the pv_crs_ipcinit()
|
||||
* function takes care of this in a more multi-process-friendly way.
|
||||
*/
|
||||
if (state->crs_noipc) {
|
||||
#else /* ! HAVE_IPC */
|
||||
if (1) {
|
||||
#endif /* HAVE_IPC */
|
||||
/*
|
||||
* Get current cursor position + 1.
|
||||
*/
|
||||
pv_crs_lock(state, fd);
|
||||
state->crs_y_start = pv_crs_get_ypos(fd);
|
||||
/*
|
||||
* Move down a line while the terminal is locked, so that
|
||||
* other processes in the pipeline will get a different
|
||||
* initial ypos.
|
||||
*/
|
||||
if (state->crs_y_start > 0)
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
pv_crs_unlock(state, fd);
|
||||
|
||||
if (state->crs_y_start < 1)
|
||||
state->cursor = 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
/*
|
||||
* Set the "we need to reinitialise cursor positioning" flag.
|
||||
*/
|
||||
void pv_crs_needreinit(pvstate_t state)
|
||||
{
|
||||
state->crs_needreinit += 2;
|
||||
if (state->crs_needreinit > 3)
|
||||
state->crs_needreinit = 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
/*
|
||||
* Reinitialise the cursor positioning code (called if we are backgrounded
|
||||
* then foregrounded again).
|
||||
*/
|
||||
void pv_crs_reinit(pvstate_t state)
|
||||
{
|
||||
debug("%s", "reinit");
|
||||
|
||||
pv_crs_lock(state, STDERR_FILENO);
|
||||
|
||||
state->crs_needreinit--;
|
||||
if (state->crs_y_offset < 1)
|
||||
state->crs_needreinit = 0;
|
||||
|
||||
if (state->crs_needreinit > 0) {
|
||||
pv_crs_unlock(state, STDERR_FILENO);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("%s", "reinit full");
|
||||
|
||||
state->crs_y_start = pv_crs_get_ypos(STDERR_FILENO);
|
||||
|
||||
if (state->crs_y_offset < 1)
|
||||
*(state->crs_y_top) = state->crs_y_start;
|
||||
state->crs_y_lastread = state->crs_y_start;
|
||||
|
||||
pv_crs_unlock(state, STDERR_FILENO);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Output a single-line update, moving the cursor to the correct position to
|
||||
* do so.
|
||||
*/
|
||||
void pv_crs_update(pvstate_t state, char *str)
|
||||
{
|
||||
char pos[32];
|
||||
int y;
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
if (!state->crs_noipc) {
|
||||
if (state->crs_needreinit)
|
||||
pv_crs_reinit(state);
|
||||
|
||||
pv_crs_ipccount(state);
|
||||
if (state->crs_y_lastread != *(state->crs_y_top)) {
|
||||
state->crs_y_start = *(state->crs_y_top);
|
||||
state->crs_y_lastread = state->crs_y_start;
|
||||
}
|
||||
|
||||
if (state->crs_needreinit > 0)
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
y = state->crs_y_start;
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
/*
|
||||
* If the screen has scrolled, or is about to scroll, due to
|
||||
* multiple `pv' instances taking us near the bottom of the screen,
|
||||
* scroll the screen (only if we're the first `pv'), and then move
|
||||
* our initial Y co-ordinate up.
|
||||
*/
|
||||
if (((state->crs_y_start + state->crs_pvmax) > state->height)
|
||||
&& (!state->crs_noipc)
|
||||
) {
|
||||
int offs;
|
||||
|
||||
offs =
|
||||
((state->crs_y_start + state->crs_pvmax) -
|
||||
state->height);
|
||||
|
||||
state->crs_y_start -= offs;
|
||||
if (state->crs_y_start < 1)
|
||||
state->crs_y_start = 1;
|
||||
|
||||
debug("%s: %d", "scroll offset", offs);
|
||||
|
||||
/*
|
||||
* Scroll the screen if we're the first `pv'.
|
||||
*/
|
||||
if (0 == state->crs_y_offset) {
|
||||
pv_crs_lock(state, STDERR_FILENO);
|
||||
|
||||
sprintf(pos, "\033[%d;1H", state->height);
|
||||
write(STDERR_FILENO, pos, strlen(pos));
|
||||
for (; offs > 0; offs--) {
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
pv_crs_unlock(state, STDERR_FILENO);
|
||||
|
||||
debug("%s", "we are the first - scrolled screen");
|
||||
}
|
||||
}
|
||||
|
||||
if (!state->crs_noipc)
|
||||
y = state->crs_y_start + state->crs_y_offset;
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
/*
|
||||
* Keep the Y co-ordinate within sensible bounds, so we can never
|
||||
* overflow the "pos" buffer.
|
||||
*/
|
||||
if ((y < 1) || (y > 999999))
|
||||
y = 1;
|
||||
sprintf(pos, "\033[%d;1H", y);
|
||||
|
||||
pv_crs_lock(state, STDERR_FILENO);
|
||||
|
||||
write(STDERR_FILENO, pos, strlen(pos));
|
||||
write(STDERR_FILENO, str, strlen(str));
|
||||
|
||||
pv_crs_unlock(state, STDERR_FILENO);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reposition the cursor to a final position.
|
||||
*/
|
||||
void pv_crs_fini(pvstate_t state)
|
||||
{
|
||||
char pos[32];
|
||||
int y;
|
||||
|
||||
debug("%s", "fini");
|
||||
|
||||
y = state->crs_y_start;
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
if ((state->crs_pvmax > 0) && (!state->crs_noipc))
|
||||
y += state->crs_pvmax - 1;
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
if (y > state->height)
|
||||
y = state->height;
|
||||
|
||||
/*
|
||||
* Absolute bounds check.
|
||||
*/
|
||||
if ((y < 1) || (y > 999999))
|
||||
y = 1;
|
||||
|
||||
sprintf(pos, "\033[%d;1H\n", y);
|
||||
|
||||
pv_crs_lock(state, STDERR_FILENO);
|
||||
|
||||
write(STDERR_FILENO, pos, strlen(pos));
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
pv_crs_ipccount(state);
|
||||
shmdt((void *) state->crs_y_top);
|
||||
|
||||
/*
|
||||
* If we are the last instance detaching from the shared memory,
|
||||
* delete it so it's not left lying around.
|
||||
*/
|
||||
if (state->crs_pvcount < 2)
|
||||
shmctl(state->crs_shmid, IPC_RMID, 0);
|
||||
|
||||
#endif /* HAVE_IPC */
|
||||
|
||||
pv_crs_unlock(state, STDERR_FILENO);
|
||||
|
||||
if (state->crs_lock_fd >= 0) {
|
||||
close(state->crs_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.
|
||||
*/
|
||||
remove(state->crs_lock_file);
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,968 @@
|
||||
/*
|
||||
* Display functions.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
|
||||
/*
|
||||
* Output an error message. If we've displayed anything to the terminal
|
||||
* already, then put a newline before our error so we don't write over what
|
||||
* we've written.
|
||||
*/
|
||||
void pv_error(pvstate_t state, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
if (state->display_visible)
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s: ", state->program_name);
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fill in *width and *height with the current terminal size,
|
||||
* if possible.
|
||||
*/
|
||||
void pv_screensize(unsigned int *width, unsigned int *height)
|
||||
{
|
||||
#ifdef TIOCGWINSZ
|
||||
struct winsize wsz;
|
||||
|
||||
if (isatty(STDERR_FILENO)) {
|
||||
if (0 == ioctl(STDERR_FILENO, TIOCGWINSZ, &wsz)) {
|
||||
*width = wsz.ws_col;
|
||||
*height = wsz.ws_row;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Calculate the percentage transferred so far and return it.
|
||||
*/
|
||||
static long pv__calc_percentage(long long so_far, const long long total)
|
||||
{
|
||||
if (total < 1)
|
||||
return 0;
|
||||
|
||||
so_far *= 100;
|
||||
so_far /= total;
|
||||
|
||||
return (long) so_far;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given how many bytes have been transferred, the total byte count to
|
||||
* transfer, and how long it's taken so far in seconds, return the estimated
|
||||
* number of seconds until completion.
|
||||
*/
|
||||
static long pv__calc_eta(const long long so_far, const long long total,
|
||||
const long elapsed)
|
||||
{
|
||||
long long amount_left;
|
||||
|
||||
if (so_far < 1)
|
||||
return 0;
|
||||
|
||||
amount_left = total - so_far;
|
||||
amount_left *= (long long) elapsed;
|
||||
amount_left /= so_far;
|
||||
|
||||
return (long) amount_left;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a long double value, it is divided or multiplied by the ratio until
|
||||
* a value in the range 1.0 to 999.999... is found. The string "prefix" to
|
||||
* is updated to the corresponding SI prefix.
|
||||
*
|
||||
* If "is_bytes" is 1, then the second byte of "prefix" is set to "i" to
|
||||
* denote MiB etc (IEEE1541). Thus "prefix" should be at least 3 bytes long
|
||||
* (to include the terminating null).
|
||||
*
|
||||
* Submitted by Henry Gebhardt <hsggebhardt@googlemail.com> and then
|
||||
* modified. Further changed after input from Thomas Rachel; changed still
|
||||
* further after Debian bug #706175.
|
||||
*/
|
||||
static void pv__si_prefix(long double *value, char *prefix,
|
||||
const long double ratio, int is_bytes)
|
||||
{
|
||||
static char *pfx_000 = NULL; /* kilo, mega, etc */
|
||||
static char *pfx_024 = NULL; /* kibi, mibi, etc */
|
||||
static char const *pfx_middle_000 = NULL;
|
||||
static char const *pfx_middle_024 = NULL;
|
||||
char *pfx;
|
||||
char const *pfx_middle;
|
||||
char const *i;
|
||||
long double cutoff;
|
||||
|
||||
if (NULL == pfx_000) {
|
||||
pfx_000 = _("yzafpnum kMGTPEZY");
|
||||
pfx_middle_000 = strchr(pfx_000, ' ');
|
||||
}
|
||||
|
||||
if (NULL == pfx_024) {
|
||||
pfx_024 = _("yzafpnum KMGTPEZY");
|
||||
pfx_middle_024 = strchr(pfx_024, ' ');
|
||||
}
|
||||
|
||||
pfx = pfx_000;
|
||||
pfx_middle = pfx_middle_000;
|
||||
if (is_bytes) {
|
||||
pfx = pfx_024;
|
||||
pfx_middle = pfx_middle_024;
|
||||
}
|
||||
|
||||
i = pfx_middle;
|
||||
|
||||
prefix[0] = ' '; /* Make the prefix start blank. */
|
||||
prefix[1] = 0;
|
||||
|
||||
/*
|
||||
* Force an empty prefix if the value is zero to avoid "0yB".
|
||||
*/
|
||||
if (0.0 == *value)
|
||||
return;
|
||||
|
||||
cutoff = ratio * 0.97;
|
||||
|
||||
while ((*value > cutoff) && (*(i += 1) != '\0')) {
|
||||
*value /= ratio;
|
||||
prefix[0] = *i;
|
||||
}
|
||||
|
||||
while ((*value < 1.0) && ((i -= 1) != (pfx - 1))) {
|
||||
*value *= ratio;
|
||||
prefix[0] = *i;
|
||||
}
|
||||
|
||||
if (is_bytes && prefix[0] != ' ') {
|
||||
prefix[1] = 'i';
|
||||
prefix[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Put a string in "buffer" (max length "bufsize") containing "amount"
|
||||
* formatted such that it's 3 or 4 digits followed by an SI suffix and then
|
||||
* whichever of "suffix_basic" or "suffix_bytes" is appropriate (whether
|
||||
* "is_bytes" is 0 for non-byte amounts or 1 for byte amounts). If
|
||||
* "is_bytes" is 1 then the SI units are KiB, MiB etc and the divisor is
|
||||
* 1024 instead of 1000.
|
||||
*
|
||||
* The "format" string is in sprintf format and must contain exactly one %
|
||||
* parameter (a %s) which will expand to the string described above.
|
||||
*/
|
||||
static void pv__sizestr(char *buffer, int bufsize, char *format,
|
||||
long double amount, char *suffix_basic,
|
||||
char *suffix_bytes, int is_bytes)
|
||||
{
|
||||
char sizestr_buffer[256];
|
||||
char si_prefix[8] = " ";
|
||||
long double divider;
|
||||
long double display_amount;
|
||||
char *suffix;
|
||||
|
||||
if (is_bytes) {
|
||||
suffix = suffix_bytes;
|
||||
divider = 1024.0;
|
||||
} else {
|
||||
suffix = suffix_basic;
|
||||
divider = 1000.0;
|
||||
}
|
||||
|
||||
display_amount = amount;
|
||||
|
||||
pv__si_prefix(&display_amount, si_prefix, divider, is_bytes);
|
||||
|
||||
/* Make sure we don't overrun our buffer. */
|
||||
if (display_amount > 100000)
|
||||
display_amount = 100000;
|
||||
|
||||
/* Fix for display of "1.01e+03" instead of "1010" */
|
||||
if (display_amount > 99.9) {
|
||||
sprintf(sizestr_buffer, "%4ld%.2s%.16s",
|
||||
(long) display_amount, si_prefix, suffix);
|
||||
} else {
|
||||
/*
|
||||
* AIX blows up with %4.3Lg%.2s%.16s for some reason, so we
|
||||
* write display_amount separately first.
|
||||
*/
|
||||
char str_disp[64];
|
||||
/* # to get 13.0GB instead of 13GB (#1477) */
|
||||
sprintf(str_disp, "%#4.3Lg", display_amount);
|
||||
sprintf(sizestr_buffer, "%s%.2s%.16s",
|
||||
str_disp, si_prefix, suffix);
|
||||
}
|
||||
|
||||
snprintf(buffer, bufsize, format, sizestr_buffer);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the output format structure, based on the current options.
|
||||
*/
|
||||
static void pv__format_init(pvstate_t state)
|
||||
{
|
||||
const char *formatstr;
|
||||
const char *searchptr;
|
||||
int strpos;
|
||||
int segment;
|
||||
|
||||
if (NULL == state)
|
||||
return;
|
||||
|
||||
state->str_name[0] = 0;
|
||||
state->str_transferred[0] = 0;
|
||||
state->str_timer[0] = 0;
|
||||
state->str_rate[0] = 0;
|
||||
state->str_average_rate[0] = 0;
|
||||
state->str_progress[0] = 0;
|
||||
state->str_eta[0] = 0;
|
||||
memset(state->format, 0, sizeof(state->format));
|
||||
|
||||
if (state->name) {
|
||||
sprintf(state->str_name, "%9.500s:", state->name);
|
||||
}
|
||||
|
||||
formatstr =
|
||||
state->format_string ? state->
|
||||
format_string : state->default_format;
|
||||
|
||||
state->components_used = 0;
|
||||
|
||||
/*
|
||||
* Split the format string into segments. Each segment consists
|
||||
* of a string pointer and a length.
|
||||
*
|
||||
* A length of zero indicates that the segment is a fixed-size
|
||||
* component updated by pv__format(), so it is a pointer to one
|
||||
* of the state->str_* buffers that pv__format() updates.
|
||||
*
|
||||
* A length below zero indicates that the segment is a variable
|
||||
* sized component which will be recalculated by pv__format()
|
||||
* after the length of all fixed-size segments is known, and so
|
||||
* the string is a pointer to another state->str_* buffer
|
||||
* (currently it will only ever be state->str_progress).
|
||||
*
|
||||
* A length above zero indicates that the segment is a constant
|
||||
* string of the given length (not necessarily null terminated).
|
||||
*
|
||||
* In pv__format(), after the state->str_* buffers have all been
|
||||
* filled in, the output string is generated by sticking all of
|
||||
* these segments together.
|
||||
*/
|
||||
segment = 0;
|
||||
for (strpos = 0; formatstr[strpos] != 0 && segment < 99;
|
||||
strpos++, segment++) {
|
||||
if ('%' == formatstr[strpos]) {
|
||||
int num;
|
||||
strpos++;
|
||||
num = 0;
|
||||
while (isdigit(formatstr[strpos])) {
|
||||
num = num * 10;
|
||||
num += formatstr[strpos] - '0';
|
||||
strpos++;
|
||||
}
|
||||
switch (formatstr[strpos]) {
|
||||
case 'p':
|
||||
state->format[segment].string =
|
||||
state->str_progress;
|
||||
state->format[segment].length = -1;
|
||||
state->components_used |=
|
||||
PV_DISPLAY_PROGRESS;
|
||||
break;
|
||||
case 't':
|
||||
state->format[segment].string =
|
||||
state->str_timer;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |= PV_DISPLAY_TIMER;
|
||||
break;
|
||||
case 'e':
|
||||
state->format[segment].string =
|
||||
state->str_eta;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |= PV_DISPLAY_ETA;
|
||||
break;
|
||||
case 'I':
|
||||
state->format[segment].string =
|
||||
state->str_fineta;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |=
|
||||
PV_DISPLAY_FINETA;
|
||||
break;
|
||||
case 'A':
|
||||
state->format[segment].string =
|
||||
state->str_lastoutput;
|
||||
state->format[segment].length = 0;
|
||||
if (num > sizeof(state->lastoutput_buffer))
|
||||
num =
|
||||
sizeof
|
||||
(state->lastoutput_buffer);
|
||||
if (num < 1)
|
||||
num = 1;
|
||||
state->lastoutput_length = num;
|
||||
state->components_used |=
|
||||
PV_DISPLAY_OUTPUTBUF;
|
||||
break;
|
||||
case 'r':
|
||||
state->format[segment].string =
|
||||
state->str_rate;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |= PV_DISPLAY_RATE;
|
||||
break;
|
||||
case 'a':
|
||||
state->format[segment].string =
|
||||
state->str_average_rate;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |=
|
||||
PV_DISPLAY_AVERAGERATE;
|
||||
break;
|
||||
case 'b':
|
||||
state->format[segment].string =
|
||||
state->str_transferred;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |= PV_DISPLAY_BYTES;
|
||||
break;
|
||||
case 'T':
|
||||
state->format[segment].string =
|
||||
state->str_bufpercent;
|
||||
state->format[segment].length = 0;
|
||||
state->components_used |=
|
||||
PV_DISPLAY_BUFPERCENT;
|
||||
break;
|
||||
case 'N':
|
||||
state->format[segment].string =
|
||||
state->str_name;
|
||||
state->format[segment].length =
|
||||
strlen(state->str_name);
|
||||
state->components_used |= PV_DISPLAY_NAME;
|
||||
break;
|
||||
case '%':
|
||||
/* %% => % */
|
||||
state->format[segment].string =
|
||||
&(formatstr[strpos]);
|
||||
state->format[segment].length = 1;
|
||||
break;
|
||||
case 0:
|
||||
/* % at end => just % */
|
||||
state->format[segment].string =
|
||||
&(formatstr[--strpos]);
|
||||
state->format[segment].length = 1;
|
||||
break;
|
||||
default:
|
||||
/* %z (unknown) => %z */
|
||||
state->format[segment].string =
|
||||
&(formatstr[--strpos]);
|
||||
state->format[segment].length = 2;
|
||||
strpos++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int foundlength;
|
||||
searchptr = strchr(&(formatstr[strpos]), '%');
|
||||
if (NULL == searchptr) {
|
||||
foundlength = strlen(&(formatstr[strpos]));
|
||||
} else {
|
||||
foundlength =
|
||||
searchptr - &(formatstr[strpos]);
|
||||
}
|
||||
state->format[segment].string =
|
||||
&(formatstr[strpos]);
|
||||
state->format[segment].length = foundlength;
|
||||
strpos += foundlength - 1;
|
||||
}
|
||||
}
|
||||
|
||||
state->format[segment].string = 0;
|
||||
state->format[segment].length = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the original value x so that it has been clamped between
|
||||
* [min..max]
|
||||
*/
|
||||
static long bound_long(long x, long min, long max)
|
||||
{
|
||||
return x < min ? min : x > max ? max : x;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a pointer to a string (which must not be freed), containing status
|
||||
* information formatted according to the state held within the given
|
||||
* structure, where "elapsed_sec" is the seconds elapsed since the transfer
|
||||
* started, "bytes_since_last" is the number of bytes transferred since the
|
||||
* last update, and "total_bytes" is the total number of bytes transferred
|
||||
* so far.
|
||||
*
|
||||
* If "bytes_since_last" is negative, this is the final update so the rate
|
||||
* is given as an an average over the whole transfer; otherwise the current
|
||||
* rate is shown.
|
||||
*
|
||||
* In line mode, "bytes_since_last" and "total_bytes" are in lines, not bytes.
|
||||
*
|
||||
* If "total_bytes" is negative, then free all allocated memory and return
|
||||
* NULL.
|
||||
*/
|
||||
static char *pv__format(pvstate_t state,
|
||||
long double elapsed_sec,
|
||||
long long bytes_since_last, long long total_bytes)
|
||||
{
|
||||
long double time_since_last, rate, average_rate;
|
||||
long eta;
|
||||
int static_portion_size;
|
||||
int segment;
|
||||
int output_length;
|
||||
int display_string_length;
|
||||
|
||||
/* Quick sanity check - state must exist */
|
||||
if (NULL == state)
|
||||
return NULL;
|
||||
|
||||
/* Negative total transfer - free memory and exit */
|
||||
if (total_bytes < 0) {
|
||||
if (state->display_buffer)
|
||||
free(state->display_buffer);
|
||||
state->display_buffer = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case the time since the last update is very small, we keep
|
||||
* track of amount transferred since the last update, and just keep
|
||||
* adding to that until a reasonable amount of time has passed to
|
||||
* avoid rate spikes or division by zero.
|
||||
*/
|
||||
time_since_last = elapsed_sec - state->prev_elapsed_sec;
|
||||
if (time_since_last <= 0.01) {
|
||||
rate = state->prev_rate;
|
||||
state->prev_trans += bytes_since_last;
|
||||
} else {
|
||||
rate =
|
||||
((long double) bytes_since_last +
|
||||
state->prev_trans) / time_since_last;
|
||||
state->prev_elapsed_sec = elapsed_sec;
|
||||
state->prev_trans = 0;
|
||||
}
|
||||
state->prev_rate = rate;
|
||||
|
||||
/*
|
||||
* We only calculate the overall average rate if this is the last
|
||||
* update or if the average rate display is enabled. Otherwise it's
|
||||
* not worth the extra CPU cycles.
|
||||
*/
|
||||
if ((bytes_since_last < 0)
|
||||
|| ((state->components_used & PV_DISPLAY_AVERAGERATE) != 0)) {
|
||||
/* Sanity check to avoid division by zero */
|
||||
if (elapsed_sec < 0.000001)
|
||||
elapsed_sec = 0.000001;
|
||||
average_rate =
|
||||
(((long double) total_bytes) -
|
||||
((long double) state->initial_offset)) /
|
||||
(long double) elapsed_sec;
|
||||
if (bytes_since_last < 0)
|
||||
rate = average_rate;
|
||||
}
|
||||
|
||||
if (state->size <= 0) {
|
||||
/*
|
||||
* If we don't know the total size of the incoming data,
|
||||
* then for a percentage, we gradually increase the
|
||||
* percentage completion as data arrives, to a maximum of
|
||||
* 200, then reset it - we use this if we can't calculate
|
||||
* it, so that the numeric percentage output will go
|
||||
* 0%-100%, 100%-0%, 0%-100%, and so on.
|
||||
*/
|
||||
if (rate > 0)
|
||||
state->percentage += 2;
|
||||
if (state->percentage > 199)
|
||||
state->percentage = 0;
|
||||
} else if (state->numeric
|
||||
|| ((state->components_used & PV_DISPLAY_PROGRESS) !=
|
||||
0)) {
|
||||
/*
|
||||
* If we do know the total size, and we're going to show
|
||||
* the percentage (numeric mode or a progress bar),
|
||||
* calculate the percentage completion.
|
||||
*/
|
||||
state->percentage =
|
||||
pv__calc_percentage(total_bytes, state->size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reallocate output buffer if width changes.
|
||||
*/
|
||||
if (state->display_buffer != NULL
|
||||
&& state->display_buffer_size < (state->width * 2)) {
|
||||
free(state->display_buffer);
|
||||
state->display_buffer = NULL;
|
||||
state->display_buffer_size = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate output buffer if there isn't one.
|
||||
*/
|
||||
if (NULL == state->display_buffer) {
|
||||
state->display_buffer_size = (2 * state->width) + 80;
|
||||
if (state->name)
|
||||
state->display_buffer_size += strlen(state->name);
|
||||
state->display_buffer =
|
||||
malloc(state->display_buffer_size + 16);
|
||||
if (NULL == state->display_buffer) {
|
||||
pv_error(state, "%s: %s",
|
||||
_("buffer allocation failed"),
|
||||
strerror(errno));
|
||||
state->exit_status |= 64;
|
||||
return NULL;
|
||||
}
|
||||
state->display_buffer[0] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In numeric output mode, our output is just a number.
|
||||
*
|
||||
* Patch from Sami Liedes:
|
||||
* With --timer we prefix the output with the elapsed time.
|
||||
* With --bytes we output the bytes transferred so far instead
|
||||
* of the percentage. (Or lines, if --lines was given with --bytes).
|
||||
*/
|
||||
if (state->numeric) {
|
||||
char numericprefix[128];
|
||||
|
||||
numericprefix[0] = 0;
|
||||
|
||||
if ((state->components_used & PV_DISPLAY_TIMER) != 0)
|
||||
sprintf(numericprefix, "%.4Lf ", elapsed_sec);
|
||||
|
||||
if ((state->components_used & PV_DISPLAY_BYTES) != 0) {
|
||||
sprintf(state->display_buffer, "%.99s%lld\n",
|
||||
numericprefix, total_bytes);
|
||||
} else if (state->percentage > 100) {
|
||||
/* As mentioned above, we go 0-100, then 100-0. */
|
||||
sprintf(state->display_buffer, "%.99s%ld\n",
|
||||
numericprefix, 200 - state->percentage);
|
||||
} else {
|
||||
sprintf(state->display_buffer, "%.99s%ld\n",
|
||||
numericprefix, state->percentage);
|
||||
}
|
||||
|
||||
return state->display_buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, work out what components we will be putting in the output
|
||||
* buffer, and for those that don't depend on the total width
|
||||
* available (i.e. all but the progress bar), prepare their strings
|
||||
* to be placed in the output buffer.
|
||||
*/
|
||||
|
||||
state->str_transferred[0] = 0;
|
||||
state->str_bufpercent[0] = 0;
|
||||
state->str_timer[0] = 0;
|
||||
state->str_rate[0] = 0;
|
||||
state->str_average_rate[0] = 0;
|
||||
state->str_progress[0] = 0;
|
||||
state->str_lastoutput[0] = 0;
|
||||
state->str_eta[0] = 0;
|
||||
state->str_fineta[0] = 0;
|
||||
|
||||
/* If we're showing bytes transferred, set up the display string. */
|
||||
if ((state->components_used & PV_DISPLAY_BYTES) != 0) {
|
||||
pv__sizestr(state->str_transferred,
|
||||
sizeof(state->str_transferred), "%s",
|
||||
(long double) total_bytes, "", _("B"),
|
||||
state->linemode ? 0 : 1);
|
||||
}
|
||||
|
||||
/* Transfer buffer percentage - set up the display string. */
|
||||
if ((state->components_used & PV_DISPLAY_BUFPERCENT) != 0) {
|
||||
if (state->buffer_size > 0)
|
||||
sprintf(state->str_bufpercent, "{%3ld%%}",
|
||||
pv__calc_percentage(state->read_position -
|
||||
state->write_position,
|
||||
state->buffer_size));
|
||||
#ifdef HAVE_SPLICE
|
||||
if (state->splice_used)
|
||||
strcpy(state->str_bufpercent, "{----}");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Timer - set up the display string. */
|
||||
if ((state->components_used & PV_DISPLAY_TIMER) != 0) {
|
||||
/*
|
||||
* Bounds check, so we don't overrun the prefix buffer. This
|
||||
* does mean that the timer will stop at a 100,000 hours,
|
||||
* but since that's 11 years, it shouldn't be a problem.
|
||||
*/
|
||||
if (elapsed_sec > (long double) 360000000.0L)
|
||||
elapsed_sec = (long double) 360000000.0L;
|
||||
|
||||
sprintf(state->str_timer, "%ld:%02ld:%02ld",
|
||||
((long) elapsed_sec) / 3600,
|
||||
(((long) elapsed_sec) / 60) % 60,
|
||||
((long) elapsed_sec) % 60);
|
||||
}
|
||||
|
||||
/* Rate - set up the display string. */
|
||||
if ((state->components_used & PV_DISPLAY_RATE) != 0) {
|
||||
pv__sizestr(state->str_rate, sizeof(state->str_rate),
|
||||
"[%s]", rate, _("/s"), _("B/s"),
|
||||
state->linemode ? 0 : 1);
|
||||
}
|
||||
|
||||
/* Average rate - set up the display string. */
|
||||
if ((state->components_used & PV_DISPLAY_AVERAGERATE) != 0) {
|
||||
pv__sizestr(state->str_average_rate,
|
||||
sizeof(state->str_average_rate), "[%s]",
|
||||
average_rate, _("/s"), _("B/s"),
|
||||
state->linemode ? 0 : 1);
|
||||
}
|
||||
|
||||
/* Last output bytes - set up the display string. */
|
||||
if ((state->components_used & PV_DISPLAY_OUTPUTBUF) != 0) {
|
||||
int idx;
|
||||
for (idx = 0; idx < state->lastoutput_length; idx++) {
|
||||
int c;
|
||||
c = state->lastoutput_buffer[idx];
|
||||
state->str_lastoutput[idx] = isprint(c) ? c : '.';
|
||||
}
|
||||
state->str_lastoutput[idx] = 0;
|
||||
}
|
||||
|
||||
/* ETA (only if size is known) - set up the display string. */
|
||||
if (((state->components_used & PV_DISPLAY_ETA) != 0)
|
||||
&& (state->size > 0)) {
|
||||
eta =
|
||||
pv__calc_eta(total_bytes - state->initial_offset,
|
||||
state->size - state->initial_offset,
|
||||
elapsed_sec);
|
||||
|
||||
/*
|
||||
* Bounds check, so we don't overrun the suffix buffer. This
|
||||
* means the ETA will always be less than 100,000 hours.
|
||||
*/
|
||||
eta = 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.
|
||||
*/
|
||||
if (eta > 86400L) {
|
||||
sprintf(state->str_eta,
|
||||
"%.16s %ld:%02ld:%02ld:%02ld", _("ETA"),
|
||||
eta / 86400, (eta / 3600) % 24,
|
||||
(eta / 60) % 60, eta % 60);
|
||||
} else {
|
||||
sprintf(state->str_eta, "%.16s %ld:%02ld:%02ld",
|
||||
_("ETA"), eta / 3600, (eta / 60) % 60,
|
||||
eta % 60);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is the final update, show a blank space where the
|
||||
* ETA used to be.
|
||||
*/
|
||||
if (bytes_since_last < 0) {
|
||||
int i;
|
||||
for (i = 0; i < sizeof(state->str_eta)
|
||||
&& state->str_eta[i] != 0; i++) {
|
||||
state->str_eta[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ETA as clock time (as above) - set up the display string. */
|
||||
if (((state->components_used & PV_DISPLAY_FINETA) != 0)
|
||||
&& (state->size > 0)) {
|
||||
/*
|
||||
* The ETA may be hidden by a failed ETA string
|
||||
* generation.
|
||||
*/
|
||||
int show_eta = 1;
|
||||
time_t now = time(NULL);
|
||||
time_t then;
|
||||
struct tm *time_ptr;
|
||||
char *time_format = NULL;
|
||||
|
||||
eta =
|
||||
pv__calc_eta(total_bytes - state->initial_offset,
|
||||
state->size - state->initial_offset,
|
||||
elapsed_sec);
|
||||
|
||||
/*
|
||||
* Bounds check, so we don't overrun the suffix buffer. This
|
||||
* means the ETA will always be less than 100,000 hours.
|
||||
*/
|
||||
eta = 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_eta = 0;
|
||||
} else {
|
||||
/* Localtime keeps data stored in a
|
||||
* static buffer that gets overwritten
|
||||
* by time functions. */
|
||||
struct tm time = *time_ptr;
|
||||
|
||||
sprintf(state->str_fineta, "%.16s ", _("ETA"));
|
||||
strftime(state->str_fineta +
|
||||
strlen(state->str_fineta),
|
||||
sizeof(state->str_fineta) - 1 -
|
||||
strlen(state->str_fineta),
|
||||
time_format, &time);
|
||||
}
|
||||
|
||||
if (!show_eta) {
|
||||
int i;
|
||||
for (i = 0; i < sizeof(state->str_fineta)
|
||||
&& state->str_fineta[i] != 0; i++) {
|
||||
state->str_fineta[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now go through all the static portions of the format to work
|
||||
* out how much space will be left for any dynamic portions
|
||||
* (i.e. the progress bar).
|
||||
*/
|
||||
static_portion_size = 0;
|
||||
for (segment = 0; state->format[segment].string; segment++) {
|
||||
if (state->format[segment].length < 0) {
|
||||
continue;
|
||||
} else if (state->format[segment].length > 0) {
|
||||
static_portion_size +=
|
||||
state->format[segment].length;
|
||||
} else {
|
||||
static_portion_size +=
|
||||
strlen(state->format[segment].string);
|
||||
}
|
||||
}
|
||||
|
||||
debug("static_portion_size: %d", static_portion_size);
|
||||
|
||||
/*
|
||||
* Assemble the progress bar now we know how big it should be.
|
||||
*/
|
||||
if ((state->components_used & PV_DISPLAY_PROGRESS) != 0) {
|
||||
char pct[16];
|
||||
int available_width, i;
|
||||
|
||||
strcpy(state->str_progress, "[");
|
||||
|
||||
if (state->size > 0) {
|
||||
if (state->percentage < 0)
|
||||
state->percentage = 0;
|
||||
if (state->percentage > 100000)
|
||||
state->percentage = 100000;
|
||||
sprintf(pct, "%2ld%%", state->percentage);
|
||||
|
||||
available_width =
|
||||
state->width - static_portion_size -
|
||||
strlen(pct) - 3;
|
||||
|
||||
if (available_width < 0)
|
||||
available_width = 0;
|
||||
|
||||
if (available_width >
|
||||
sizeof(state->str_progress) - 16)
|
||||
available_width =
|
||||
sizeof(state->str_progress) - 16;
|
||||
|
||||
for (i = 0;
|
||||
i <
|
||||
(available_width * state->percentage) / 100 -
|
||||
1; i++) {
|
||||
if (i < available_width)
|
||||
strcat(state->str_progress, "=");
|
||||
}
|
||||
if (i < available_width) {
|
||||
strcat(state->str_progress, ">");
|
||||
i++;
|
||||
}
|
||||
for (; i < available_width; i++) {
|
||||
strcat(state->str_progress, " ");
|
||||
}
|
||||
strcat(state->str_progress, "] ");
|
||||
strcat(state->str_progress, pct);
|
||||
} else {
|
||||
int p = state->percentage;
|
||||
|
||||
available_width =
|
||||
state->width - static_portion_size - 5;
|
||||
|
||||
if (available_width < 0)
|
||||
available_width = 0;
|
||||
|
||||
if (available_width >
|
||||
sizeof(state->str_progress) - 16)
|
||||
available_width =
|
||||
sizeof(state->str_progress) - 16;
|
||||
|
||||
debug("available_width: %d", available_width);
|
||||
|
||||
if (p > 100)
|
||||
p = 200 - p;
|
||||
for (i = 0; i < (available_width * p) / 100; i++) {
|
||||
if (i < available_width)
|
||||
strcat(state->str_progress, " ");
|
||||
}
|
||||
strcat(state->str_progress, "<=>");
|
||||
for (; i < available_width; i++) {
|
||||
strcat(state->str_progress, " ");
|
||||
}
|
||||
strcat(state->str_progress, "]");
|
||||
}
|
||||
|
||||
/*
|
||||
* If the progress bar won't fit, drop it.
|
||||
*/
|
||||
if (strlen(state->str_progress) + static_portion_size >
|
||||
state->width)
|
||||
state->str_progress[0] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can now build the output string using the format structure.
|
||||
*/
|
||||
|
||||
state->display_buffer[0] = 0;
|
||||
display_string_length = 0;
|
||||
for (segment = 0; state->format[segment].string; segment++) {
|
||||
int segment_length;
|
||||
if (state->format[segment].length > 0) {
|
||||
segment_length = state->format[segment].length;
|
||||
} else {
|
||||
segment_length =
|
||||
strlen(state->format[segment].string);
|
||||
}
|
||||
/* Skip empty segments */
|
||||
if (segment_length == 0)
|
||||
continue;
|
||||
/*
|
||||
* Truncate segment if it would make the display string
|
||||
* overflow the buffer
|
||||
*/
|
||||
if (segment_length + display_string_length >
|
||||
state->display_buffer_size - 2)
|
||||
segment_length =
|
||||
state->display_buffer_size -
|
||||
display_string_length - 2;
|
||||
if (segment_length < 1)
|
||||
break;
|
||||
/* Skip segment if it would make the display too wide */
|
||||
if (segment_length + display_string_length > state->width)
|
||||
break;
|
||||
strncat(state->display_buffer,
|
||||
state->format[segment].string, segment_length);
|
||||
display_string_length += segment_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the size of our output shrinks, we need to keep appending
|
||||
* spaces at the end, so that we don't leave dangling bits behind.
|
||||
*/
|
||||
output_length = strlen(state->display_buffer);
|
||||
if ((output_length < state->prev_length)
|
||||
&& (state->width >= state->prev_width)) {
|
||||
char spaces[32];
|
||||
int spaces_to_add;
|
||||
spaces_to_add = state->prev_length - output_length;
|
||||
/* Upper boundary on number of spaces */
|
||||
if (spaces_to_add > 15) {
|
||||
spaces_to_add = 15;
|
||||
}
|
||||
output_length += spaces_to_add;
|
||||
spaces[spaces_to_add] = 0;
|
||||
while (--spaces_to_add >= 0) {
|
||||
spaces[spaces_to_add] = ' ';
|
||||
}
|
||||
strcat(state->display_buffer, spaces);
|
||||
}
|
||||
state->prev_width = state->width;
|
||||
state->prev_length = output_length;
|
||||
|
||||
return state->display_buffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Output status information on standard error, where "esec" is the seconds
|
||||
* elapsed since the transfer started, "sl" is the number of bytes transferred
|
||||
* since the last update, and "tot" is the total number of bytes transferred
|
||||
* so far.
|
||||
*
|
||||
* If "sl" is negative, this is the final update so the rate is given as an
|
||||
* an average over the whole transfer; otherwise the current rate is shown.
|
||||
*
|
||||
* In line mode, "sl" and "tot" are in lines, not bytes.
|
||||
*/
|
||||
void pv_display(pvstate_t state, long double esec, long long sl,
|
||||
long long tot)
|
||||
{
|
||||
char *display;
|
||||
|
||||
if (NULL == state)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If the display options need reparsing, do so to generate new
|
||||
* formatting parameters.
|
||||
*/
|
||||
if (state->reparse_display) {
|
||||
pv__format_init(state);
|
||||
state->reparse_display = 0;
|
||||
}
|
||||
|
||||
pv_sig_checkbg();
|
||||
|
||||
display = pv__format(state, esec, sl, tot);
|
||||
if (NULL == display)
|
||||
return;
|
||||
|
||||
if (state->numeric) {
|
||||
write(STDERR_FILENO, display, strlen(display));
|
||||
} else if (state->cursor) {
|
||||
pv_crs_update(state, display);
|
||||
state->display_visible = 1;
|
||||
} else {
|
||||
write(STDERR_FILENO, display, strlen(display));
|
||||
write(STDERR_FILENO, "\r", 1);
|
||||
state->display_visible = 1;
|
||||
}
|
||||
|
||||
debug("%s: [%s]", "display", display);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Functions for opening and closing files.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
/*
|
||||
* Try to work out the total size of all data by adding up the sizes of all
|
||||
* input files. If any of the input files are of indeterminate size (i.e.
|
||||
* they are a pipe), the total size is set to zero.
|
||||
*
|
||||
* Any files that cannot be stat()ed or that access() says we can't read
|
||||
* will cause a warning to be output and will be removed from the list.
|
||||
*
|
||||
* In line mode, any files that pass the above checks will then be read to
|
||||
* determine how many lines they contain, and the total size will be set to
|
||||
* the total line count. Only regular files will be read.
|
||||
*
|
||||
* Returns the total size, or 0 if it is unknown.
|
||||
*/
|
||||
unsigned long long pv_calc_total_size(pvstate_t state)
|
||||
{
|
||||
unsigned long long total;
|
||||
struct stat64 sb;
|
||||
int rc, i, j, fd;
|
||||
|
||||
total = 0;
|
||||
rc = 0;
|
||||
|
||||
/*
|
||||
* No files specified - check stdin.
|
||||
*/
|
||||
if (state->input_file_count < 1) {
|
||||
if (0 == fstat64(STDIN_FILENO, &sb))
|
||||
total = sb.st_size;
|
||||
return total;
|
||||
}
|
||||
|
||||
for (i = 0; i < state->input_file_count; i++) {
|
||||
if (0 == strcmp(state->input_files[i], "-")) {
|
||||
rc = fstat64(STDIN_FILENO, &sb);
|
||||
if (rc != 0) {
|
||||
total = 0;
|
||||
return total;
|
||||
}
|
||||
} else {
|
||||
rc = stat64(state->input_files[i], &sb);
|
||||
if (0 == rc)
|
||||
rc = access(state->input_files[i], R_OK);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
pv_error(state, "%s: %s",
|
||||
state->input_files[i], strerror(errno));
|
||||
for (j = i; j < state->input_file_count - 1; j++) {
|
||||
state->input_files[j] =
|
||||
state->input_files[j + 1];
|
||||
}
|
||||
state->input_file_count--;
|
||||
i--;
|
||||
state->exit_status |= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISBLK(sb.st_mode)) {
|
||||
/*
|
||||
* Get the size of block devices by opening
|
||||
* them and seeking to the end.
|
||||
*/
|
||||
if (0 == strcmp(state->input_files[i], "-")) {
|
||||
fd = open64("/dev/stdin", O_RDONLY);
|
||||
} else {
|
||||
fd = open64(state->input_files[i],
|
||||
O_RDONLY);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
total += lseek64(fd, 0, SEEK_END);
|
||||
close(fd);
|
||||
} else {
|
||||
pv_error(state, "%s: %s",
|
||||
state->input_files[i],
|
||||
strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
}
|
||||
} else if (S_ISREG(sb.st_mode)) {
|
||||
total += sb.st_size;
|
||||
} else {
|
||||
total = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Patch from Peter Samuelson: if we cannot work out the size of the
|
||||
* input, but we are writing to a block device, then use the size of
|
||||
* the output block device.
|
||||
*
|
||||
* Further modified to check that stdout is not in append-only mode
|
||||
* and that we can seek back to the start after getting the size.
|
||||
*/
|
||||
if (total <= 0) {
|
||||
rc = fstat64(STDOUT_FILENO, &sb);
|
||||
if ((0 == rc) && S_ISBLK(sb.st_mode)
|
||||
&& (0 == (fcntl(STDOUT_FILENO, F_GETFL) & O_APPEND))) {
|
||||
total = lseek64(STDOUT_FILENO, 0, SEEK_END);
|
||||
if (lseek64(STDOUT_FILENO, 0, SEEK_SET) != 0) {
|
||||
pv_error(state, "%s: %s: %s", "(stdout)",
|
||||
_
|
||||
("failed to seek to start of output"),
|
||||
strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
}
|
||||
/*
|
||||
* If we worked out a size, then set the
|
||||
* stop-at-size flag to prevent a "no space left on
|
||||
* device" error when we reach the end of the output
|
||||
* device.
|
||||
*/
|
||||
if (total > 0) {
|
||||
state->stop_at_size = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!state->linemode)
|
||||
return total;
|
||||
|
||||
/*
|
||||
* In line mode, we count input lines to work out the total size.
|
||||
*/
|
||||
total = 0;
|
||||
|
||||
for (i = 0; i < state->input_file_count; i++) {
|
||||
fd = -1;
|
||||
|
||||
if (0 == strcmp(state->input_files[i], "-")) {
|
||||
rc = fstat64(STDIN_FILENO, &sb);
|
||||
if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
|
||||
total = 0;
|
||||
return total;
|
||||
}
|
||||
fd = dup(STDIN_FILENO);
|
||||
} else {
|
||||
rc = stat64(state->input_files[i], &sb);
|
||||
if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
|
||||
total = 0;
|
||||
return total;
|
||||
}
|
||||
fd = open64(state->input_files[i], O_RDONLY);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
pv_error(state, "%s: %s", state->input_files[i],
|
||||
strerror(errno));
|
||||
total = 0;
|
||||
state->exit_status |= 2;
|
||||
return total;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
unsigned char scanbuf[1024];
|
||||
int numread, j;
|
||||
|
||||
numread = read(fd, scanbuf, sizeof(scanbuf));
|
||||
if (numread < 0) {
|
||||
pv_error(state, "%s: %s",
|
||||
state->input_files[i],
|
||||
strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
break;
|
||||
} else if (0 == numread) {
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < numread; j++) {
|
||||
if ('\n' == scanbuf[j])
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close the given file descriptor and open the next one, whose number in
|
||||
* the list is "filenum", returning the new file descriptor (or negative on
|
||||
* error). It is an error if the next input file is the same as the file
|
||||
* stdout is pointing to.
|
||||
*
|
||||
* Updates state->current_file in the process.
|
||||
*/
|
||||
int pv_next_file(pvstate_t state, int filenum, int oldfd)
|
||||
{
|
||||
struct stat64 isb;
|
||||
struct stat64 osb;
|
||||
int fd, input_file_is_stdout;
|
||||
|
||||
if (oldfd > 0) {
|
||||
if (close(oldfd)) {
|
||||
pv_error(state, "%s: %s",
|
||||
_("failed to close file"),
|
||||
strerror(errno));
|
||||
state->exit_status |= 8;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (filenum >= state->input_file_count) {
|
||||
state->exit_status |= 8;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (filenum < 0) {
|
||||
state->exit_status |= 8;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == strcmp(state->input_files[filenum], "-")) {
|
||||
fd = STDIN_FILENO;
|
||||
} else {
|
||||
fd = open64(state->input_files[filenum], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
_("failed to read file"),
|
||||
state->input_files[filenum],
|
||||
strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fstat64(fd, &isb)) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
_("failed to stat file"),
|
||||
state->input_files[filenum], strerror(errno));
|
||||
close(fd);
|
||||
state->exit_status |= 2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fstat64(STDOUT_FILENO, &osb)) {
|
||||
pv_error(state, "%s: %s",
|
||||
_("failed to stat output file"), strerror(errno));
|
||||
close(fd);
|
||||
state->exit_status |= 2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that this new input file is not the same as stdout's
|
||||
* destination. This restriction is ignored for anything other
|
||||
* than a regular file or block device.
|
||||
*/
|
||||
input_file_is_stdout = 1;
|
||||
if (isb.st_dev != osb.st_dev)
|
||||
input_file_is_stdout = 0;
|
||||
if (isb.st_ino != osb.st_ino)
|
||||
input_file_is_stdout = 0;
|
||||
if (isatty(fd))
|
||||
input_file_is_stdout = 0;
|
||||
if ((!S_ISREG(isb.st_mode)) && (!S_ISBLK(isb.st_mode)))
|
||||
input_file_is_stdout = 0;
|
||||
|
||||
if (input_file_is_stdout) {
|
||||
pv_error(state, "%s: %s",
|
||||
_("input file is output file"),
|
||||
state->input_files[filenum]);
|
||||
close(fd);
|
||||
state->exit_status |= 4;
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->current_file = state->input_files[filenum];
|
||||
if (0 == strcmp(state->input_files[filenum], "-")) {
|
||||
state->current_file = "(stdin)";
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+780
@@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Main program entry point - read the command line options, then perform
|
||||
* the appropriate actions.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <limits.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
/*
|
||||
* Add the given number of microseconds (which may be negative) to the given
|
||||
* timeval.
|
||||
*/
|
||||
static void pv_timeval_add_usec(struct timeval *val, long usec)
|
||||
{
|
||||
val->tv_usec += usec;
|
||||
while (val->tv_usec < 0) {
|
||||
val->tv_sec--;
|
||||
val->tv_usec += 1000000;
|
||||
}
|
||||
while (val->tv_usec >= 1000000) {
|
||||
val->tv_sec++;
|
||||
val->tv_usec -= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pipe data from a list of files to standard output, giving information
|
||||
* about the transfer on standard error according to the given options.
|
||||
*
|
||||
* Returns nonzero on error.
|
||||
*/
|
||||
int pv_main_loop(pvstate_t state)
|
||||
{
|
||||
long written, lineswritten;
|
||||
long long total_written, since_last, cansend;
|
||||
long double target;
|
||||
int eof_in, eof_out, final_update;
|
||||
struct timeval start_time, next_update, next_ratecheck, cur_time;
|
||||
struct timeval init_time, next_remotecheck;
|
||||
long double elapsed;
|
||||
struct stat64 sb;
|
||||
int fd, n;
|
||||
|
||||
/*
|
||||
* "written" is ALWAYS bytes written by the last transfer.
|
||||
*
|
||||
* "lineswritten" is the lines written by the last transfer,
|
||||
* but is only updated in line mode.
|
||||
*
|
||||
* "total_written" is the total bytes written since the start,
|
||||
* or in line mode, the total lines written since the start.
|
||||
*
|
||||
* "since_last" is the bytes written since the last display,
|
||||
* or in line mode, the lines written since the last display.
|
||||
*
|
||||
* The remaining variables are all unchanged by linemode.
|
||||
*/
|
||||
|
||||
fd = -1;
|
||||
|
||||
pv_crs_init(state);
|
||||
|
||||
eof_in = 0;
|
||||
eof_out = 0;
|
||||
total_written = 0;
|
||||
since_last = 0;
|
||||
state->initial_offset = 0;
|
||||
|
||||
gettimeofday(&start_time, NULL);
|
||||
gettimeofday(&cur_time, NULL);
|
||||
|
||||
next_update.tv_sec = start_time.tv_sec;
|
||||
next_update.tv_usec = start_time.tv_usec;
|
||||
if ((state->delay_start > 0)
|
||||
&& (state->delay_start > state->interval)) {
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 *
|
||||
state->delay_start));
|
||||
} else {
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 * state->interval));
|
||||
}
|
||||
|
||||
next_ratecheck.tv_sec = start_time.tv_sec;
|
||||
next_ratecheck.tv_usec = start_time.tv_usec;
|
||||
next_remotecheck.tv_sec = start_time.tv_sec;
|
||||
next_remotecheck.tv_usec = start_time.tv_usec;
|
||||
|
||||
target = 0;
|
||||
final_update = 0;
|
||||
n = 0;
|
||||
|
||||
fd = pv_next_file(state, n, -1);
|
||||
if (fd < 0) {
|
||||
if (state->cursor)
|
||||
pv_crs_fini(state);
|
||||
return state->exit_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set target buffer size if the initial file's block size can be
|
||||
* read and we weren't given a target buffer size.
|
||||
*/
|
||||
if ((0 == fstat64(fd, &sb)) && (0 == state->target_buffer_size)) {
|
||||
unsigned long long sz;
|
||||
sz = sb.st_blksize * 32;
|
||||
if (sz > BUFFER_SIZE_MAX)
|
||||
sz = BUFFER_SIZE_MAX;
|
||||
state->target_buffer_size = sz;
|
||||
}
|
||||
|
||||
if (0 == state->target_buffer_size)
|
||||
state->target_buffer_size = BUFFER_SIZE;
|
||||
|
||||
while ((!(eof_in && eof_out)) || (!final_update)) {
|
||||
|
||||
cansend = 0;
|
||||
|
||||
/*
|
||||
* Check for remote messages from -R every short while
|
||||
*/
|
||||
if ((cur_time.tv_sec > next_remotecheck.tv_sec)
|
||||
|| (cur_time.tv_sec == next_remotecheck.tv_sec
|
||||
&& cur_time.tv_usec >= next_remotecheck.tv_usec)) {
|
||||
pv_remote_check(state);
|
||||
pv_timeval_add_usec(&next_remotecheck,
|
||||
REMOTE_INTERVAL);
|
||||
}
|
||||
|
||||
if (state->pv_sig_abort)
|
||||
break;
|
||||
|
||||
if (state->rate_limit > 0) {
|
||||
gettimeofday(&cur_time, NULL);
|
||||
if ((cur_time.tv_sec > next_ratecheck.tv_sec)
|
||||
|| (cur_time.tv_sec == next_ratecheck.tv_sec
|
||||
&& cur_time.tv_usec >=
|
||||
next_ratecheck.tv_usec)) {
|
||||
target +=
|
||||
((long double) (state->rate_limit)) /
|
||||
(long double) (1000000 /
|
||||
RATE_GRANULARITY);
|
||||
pv_timeval_add_usec(&next_ratecheck,
|
||||
RATE_GRANULARITY);
|
||||
}
|
||||
cansend = target;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have to stop at "size" bytes, make sure we don't
|
||||
* try to write more than we're allowed to.
|
||||
*/
|
||||
if ((0 < state->size) && (state->stop_at_size)) {
|
||||
if ((state->size < (total_written + cansend))
|
||||
|| ((0 == cansend)
|
||||
&& (0 == state->rate_limit))) {
|
||||
cansend = state->size - total_written;
|
||||
if (0 >= cansend) {
|
||||
eof_in = 1;
|
||||
eof_out = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((0 < state->size) && (state->stop_at_size)
|
||||
&& (0 >= cansend) && eof_in && eof_out) {
|
||||
written = 0;
|
||||
} else {
|
||||
written =
|
||||
pv_transfer(state, fd, &eof_in, &eof_out,
|
||||
cansend, &lineswritten);
|
||||
}
|
||||
|
||||
if (written < 0) {
|
||||
if (state->cursor)
|
||||
pv_crs_fini(state);
|
||||
return state->exit_status;
|
||||
}
|
||||
|
||||
if (state->linemode) {
|
||||
since_last += lineswritten;
|
||||
total_written += lineswritten;
|
||||
if (state->rate_limit > 0)
|
||||
target -= lineswritten;
|
||||
} else {
|
||||
since_last += written;
|
||||
total_written += written;
|
||||
if (state->rate_limit > 0)
|
||||
target -= written;
|
||||
}
|
||||
|
||||
if (eof_in && eof_out && n < (state->input_file_count - 1)) {
|
||||
n++;
|
||||
fd = pv_next_file(state, n, fd);
|
||||
if (fd < 0) {
|
||||
if (state->cursor)
|
||||
pv_crs_fini(state);
|
||||
return state->exit_status;
|
||||
}
|
||||
eof_in = 0;
|
||||
eof_out = 0;
|
||||
}
|
||||
|
||||
gettimeofday(&cur_time, NULL);
|
||||
|
||||
if (eof_in && eof_out) {
|
||||
final_update = 1;
|
||||
if ((state->display_visible)
|
||||
|| (0 == state->delay_start))
|
||||
next_update.tv_sec = cur_time.tv_sec - 1;
|
||||
}
|
||||
|
||||
if (state->no_op)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If -W was given, we don't output anything until we have
|
||||
* written a byte (or line, in line mode), at which point
|
||||
* we then count time as if we started when the first byte
|
||||
* was received.
|
||||
*/
|
||||
if (state->wait) {
|
||||
if (state->linemode) {
|
||||
if (lineswritten < 1)
|
||||
continue;
|
||||
} else {
|
||||
if (written < 1)
|
||||
continue;
|
||||
}
|
||||
|
||||
state->wait = 0;
|
||||
|
||||
/*
|
||||
* Reset the timer offset counter now that data
|
||||
* transfer has begun, otherwise if we had been
|
||||
* stopped and started (with ^Z / SIGTSTOP)
|
||||
* previously (while waiting for data), the timers
|
||||
* will be wrongly offset.
|
||||
*
|
||||
* While we reset the offset counter we must disable
|
||||
* SIGTSTOP so things don't mess up.
|
||||
*/
|
||||
pv_sig_nopause();
|
||||
gettimeofday(&start_time, NULL);
|
||||
state->pv_sig_toffset.tv_sec = 0;
|
||||
state->pv_sig_toffset.tv_usec = 0;
|
||||
pv_sig_allowpause();
|
||||
|
||||
next_update.tv_sec = start_time.tv_sec;
|
||||
next_update.tv_usec = start_time.tv_usec;
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 *
|
||||
state->interval));
|
||||
}
|
||||
|
||||
if ((cur_time.tv_sec < next_update.tv_sec)
|
||||
|| (cur_time.tv_sec == next_update.tv_sec
|
||||
&& cur_time.tv_usec < next_update.tv_usec)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 * state->interval));
|
||||
|
||||
if (next_update.tv_sec < cur_time.tv_sec) {
|
||||
next_update.tv_sec = cur_time.tv_sec;
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
} else if (next_update.tv_sec == cur_time.tv_sec
|
||||
&& next_update.tv_usec < cur_time.tv_usec) {
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
}
|
||||
|
||||
init_time.tv_sec =
|
||||
start_time.tv_sec + state->pv_sig_toffset.tv_sec;
|
||||
init_time.tv_usec =
|
||||
start_time.tv_usec + state->pv_sig_toffset.tv_usec;
|
||||
if (init_time.tv_usec >= 1000000) {
|
||||
init_time.tv_sec++;
|
||||
init_time.tv_usec -= 1000000;
|
||||
}
|
||||
if (init_time.tv_usec < 0) {
|
||||
init_time.tv_sec--;
|
||||
init_time.tv_usec += 1000000;
|
||||
}
|
||||
|
||||
elapsed = cur_time.tv_sec - init_time.tv_sec;
|
||||
elapsed +=
|
||||
(cur_time.tv_usec - init_time.tv_usec) / 1000000.0;
|
||||
|
||||
if (final_update)
|
||||
since_last = -1;
|
||||
|
||||
if (state->pv_sig_newsize) {
|
||||
state->pv_sig_newsize = 0;
|
||||
pv_screensize(&(state->width), &(state->height));
|
||||
}
|
||||
|
||||
pv_display(state, elapsed, since_last, total_written);
|
||||
|
||||
since_last = 0;
|
||||
}
|
||||
|
||||
if (state->cursor) {
|
||||
pv_crs_fini(state);
|
||||
} else {
|
||||
if ((!state->numeric) && (!state->no_op)
|
||||
&& (state->display_visible))
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
if (state->pv_sig_abort)
|
||||
state->exit_status |= 32;
|
||||
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
return state->exit_status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Watch the progress of file descriptor state->watch_fd in process
|
||||
* state->watch_pid and show details about the transfer on standard error
|
||||
* according to the given options.
|
||||
*
|
||||
* Returns nonzero on error.
|
||||
*/
|
||||
int pv_watchfd_loop(pvstate_t state)
|
||||
{
|
||||
struct pvwatchfd_s info;
|
||||
long long position_now, total_written, since_last;
|
||||
struct timeval next_update, cur_time;
|
||||
struct timeval init_time, next_remotecheck;
|
||||
long double elapsed;
|
||||
int ended;
|
||||
int first_check;
|
||||
int rc;
|
||||
|
||||
info.watch_pid = state->watch_pid;
|
||||
info.watch_fd = state->watch_fd;
|
||||
rc = pv_watchfd_info(state, &info, 0);
|
||||
if (0 != rc) {
|
||||
state->exit_status |= 2;
|
||||
return state->exit_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a size if one was passed, otherwise use the total size
|
||||
* calculated.
|
||||
*/
|
||||
if (0 >= state->size)
|
||||
state->size = info.size;
|
||||
|
||||
if (state->size < 1) {
|
||||
char *fmt;
|
||||
while (NULL != (fmt = strstr(state->default_format, "%e"))) {
|
||||
debug("%s", "zero size - removing ETA");
|
||||
/* strlen-1 here to include trailing NUL */
|
||||
memmove(fmt, fmt + 2, strlen(fmt) - 1);
|
||||
state->reparse_display = 1;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&(info.start_time), NULL);
|
||||
gettimeofday(&cur_time, NULL);
|
||||
|
||||
next_update.tv_sec = info.start_time.tv_sec;
|
||||
next_update.tv_usec = info.start_time.tv_usec;
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 * state->interval));
|
||||
|
||||
next_remotecheck.tv_sec = info.start_time.tv_sec;
|
||||
next_remotecheck.tv_usec = info.start_time.tv_usec;
|
||||
|
||||
ended = 0;
|
||||
total_written = 0;
|
||||
since_last = 0;
|
||||
first_check = 1;
|
||||
|
||||
while (!ended) {
|
||||
/*
|
||||
* Check for remote messages from -R every short while
|
||||
*/
|
||||
if ((cur_time.tv_sec > next_remotecheck.tv_sec)
|
||||
|| (cur_time.tv_sec == next_remotecheck.tv_sec
|
||||
&& cur_time.tv_usec >= next_remotecheck.tv_usec)) {
|
||||
pv_remote_check(state);
|
||||
pv_timeval_add_usec(&next_remotecheck,
|
||||
REMOTE_INTERVAL);
|
||||
}
|
||||
|
||||
if (state->pv_sig_abort)
|
||||
break;
|
||||
|
||||
position_now = pv_watchfd_position(&info);
|
||||
|
||||
if (position_now < 0) {
|
||||
ended = 1;
|
||||
} else {
|
||||
since_last += position_now - total_written;
|
||||
total_written = position_now;
|
||||
if (first_check) {
|
||||
state->initial_offset = position_now;
|
||||
first_check = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&cur_time, NULL);
|
||||
|
||||
if (ended) {
|
||||
ended = 1;
|
||||
next_update.tv_sec = cur_time.tv_sec - 1;
|
||||
}
|
||||
|
||||
if ((cur_time.tv_sec < next_update.tv_sec)
|
||||
|| (cur_time.tv_sec == next_update.tv_sec
|
||||
&& cur_time.tv_usec < next_update.tv_usec)) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 50000;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
continue;
|
||||
}
|
||||
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 * state->interval));
|
||||
|
||||
if (next_update.tv_sec < cur_time.tv_sec) {
|
||||
next_update.tv_sec = cur_time.tv_sec;
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
} else if (next_update.tv_sec == cur_time.tv_sec
|
||||
&& next_update.tv_usec < cur_time.tv_usec) {
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
}
|
||||
|
||||
init_time.tv_sec =
|
||||
info.start_time.tv_sec + state->pv_sig_toffset.tv_sec;
|
||||
init_time.tv_usec =
|
||||
info.start_time.tv_usec +
|
||||
state->pv_sig_toffset.tv_usec;
|
||||
if (init_time.tv_usec >= 1000000) {
|
||||
init_time.tv_sec++;
|
||||
init_time.tv_usec -= 1000000;
|
||||
}
|
||||
if (init_time.tv_usec < 0) {
|
||||
init_time.tv_sec--;
|
||||
init_time.tv_usec += 1000000;
|
||||
}
|
||||
|
||||
elapsed = cur_time.tv_sec - init_time.tv_sec;
|
||||
elapsed +=
|
||||
(cur_time.tv_usec - init_time.tv_usec) / 1000000.0;
|
||||
|
||||
if (ended)
|
||||
since_last = -1;
|
||||
|
||||
if (state->pv_sig_newsize) {
|
||||
state->pv_sig_newsize = 0;
|
||||
pv_screensize(&(state->width), &(state->height));
|
||||
}
|
||||
|
||||
pv_display(state, elapsed, since_last, total_written);
|
||||
|
||||
since_last = 0;
|
||||
}
|
||||
|
||||
if (!state->numeric)
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
|
||||
if (state->pv_sig_abort)
|
||||
state->exit_status |= 32;
|
||||
|
||||
return state->exit_status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Watch the progress of all file descriptors in process state->watch_pid
|
||||
* and show details about the transfers on standard error according to the
|
||||
* given options.
|
||||
*
|
||||
* Returns nonzero on error.
|
||||
*/
|
||||
int pv_watchpid_loop(pvstate_t state)
|
||||
{
|
||||
struct pvstate_s state_copy;
|
||||
const char *original_format_string;
|
||||
char new_format_string[512] = { 0, };
|
||||
struct pvwatchfd_s *info_array = NULL;
|
||||
struct pvstate_s *state_array = NULL;
|
||||
int array_length = 0;
|
||||
int fd_to_idx[FD_SETSIZE] = { 0, };
|
||||
struct timeval next_update, cur_time, next_remotecheck;
|
||||
int idx;
|
||||
int prev_displayed_lines, blank_lines;
|
||||
int first_pass = 1;
|
||||
|
||||
/*
|
||||
* Make sure the process exists first, so we can give an error if
|
||||
* it's not there at the start.
|
||||
*/
|
||||
if (kill(state->watch_pid, 0) != 0) {
|
||||
pv_error(state, "%s %u: %s",
|
||||
_("pid"), state->watch_pid, strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a copy of our state, ready to change in preparation for
|
||||
* duplication.
|
||||
*/
|
||||
memcpy(&state_copy, state, sizeof(state_copy));
|
||||
|
||||
/*
|
||||
* Make sure there's a format string, and then insert %N into it if
|
||||
* it's not present.
|
||||
*/
|
||||
original_format_string =
|
||||
state->format_string ? state->
|
||||
format_string : state->default_format;
|
||||
if (NULL == strstr(original_format_string, "%N")) {
|
||||
snprintf(new_format_string, sizeof(new_format_string) - 1,
|
||||
"%%N %s", original_format_string);
|
||||
} else {
|
||||
snprintf(new_format_string, sizeof(new_format_string) - 1,
|
||||
"%s", original_format_string);
|
||||
}
|
||||
state_copy.format_string = NULL;
|
||||
snprintf(state_copy.default_format,
|
||||
sizeof(state_copy.default_format) - 1, "%s",
|
||||
new_format_string);
|
||||
|
||||
/*
|
||||
* Get things ready for the main loop.
|
||||
*/
|
||||
|
||||
gettimeofday(&cur_time, NULL);
|
||||
|
||||
next_remotecheck.tv_sec = cur_time.tv_sec;
|
||||
next_remotecheck.tv_usec = cur_time.tv_usec;
|
||||
|
||||
next_update.tv_sec = cur_time.tv_sec;
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 * state->interval));
|
||||
|
||||
for (idx = 0; idx < FD_SETSIZE; idx++) {
|
||||
fd_to_idx[idx] = -1;
|
||||
}
|
||||
|
||||
prev_displayed_lines = 0;
|
||||
|
||||
while (1) {
|
||||
int rc, fd, displayed_lines;
|
||||
|
||||
if (state->pv_sig_abort)
|
||||
break;
|
||||
|
||||
gettimeofday(&cur_time, NULL);
|
||||
|
||||
if (kill(state->watch_pid, 0) != 0) {
|
||||
if (first_pass) {
|
||||
pv_error(state, "%s %u: %s",
|
||||
_("pid"), state->watch_pid,
|
||||
strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
if (NULL != info_array)
|
||||
free(info_array);
|
||||
if (NULL != state_array)
|
||||
free(state_array);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((cur_time.tv_sec < next_update.tv_sec)
|
||||
|| (cur_time.tv_sec == next_update.tv_sec
|
||||
&& cur_time.tv_usec < next_update.tv_usec)) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 50000;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
continue;
|
||||
}
|
||||
|
||||
pv_timeval_add_usec(&next_update,
|
||||
(long) (1000000.0 * state->interval));
|
||||
|
||||
if (next_update.tv_sec < cur_time.tv_sec) {
|
||||
next_update.tv_sec = cur_time.tv_sec;
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
} else if (next_update.tv_sec == cur_time.tv_sec
|
||||
&& next_update.tv_usec < cur_time.tv_usec) {
|
||||
next_update.tv_usec = cur_time.tv_usec;
|
||||
}
|
||||
|
||||
if (state->pv_sig_newsize) {
|
||||
state->pv_sig_newsize = 0;
|
||||
pv_screensize(&(state->width), &(state->height));
|
||||
for (idx = 0; idx < array_length; idx++) {
|
||||
state_array[idx].width = state->width;
|
||||
state_array[idx].height = state->height;
|
||||
pv_watchpid_setname(state,
|
||||
&(info_array[idx]));
|
||||
state_array[idx].reparse_display = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pv_watchpid_scanfds(state, &state_copy,
|
||||
state->watch_pid, &array_length,
|
||||
&info_array, &state_array,
|
||||
fd_to_idx);
|
||||
if (rc != 0) {
|
||||
if (first_pass) {
|
||||
pv_error(state, "%s %u: %s",
|
||||
_("pid"), state->watch_pid,
|
||||
strerror(errno));
|
||||
state->exit_status |= 2;
|
||||
if (NULL != info_array)
|
||||
free(info_array);
|
||||
if (NULL != state_array)
|
||||
free(state_array);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
first_pass = 0;
|
||||
displayed_lines = 0;
|
||||
|
||||
for (fd = 0; fd < FD_SETSIZE; fd++) {
|
||||
long long position_now, since_last;
|
||||
struct timeval init_time;
|
||||
long double elapsed;
|
||||
|
||||
if (displayed_lines >= state->height)
|
||||
break;
|
||||
|
||||
idx = fd_to_idx[fd];
|
||||
|
||||
if (idx < 0)
|
||||
continue;
|
||||
|
||||
if (info_array[idx].watch_fd < 0) {
|
||||
/*
|
||||
* Non-displayable fd - just remove if
|
||||
* changed
|
||||
*/
|
||||
if (pv_watchfd_changed(&(info_array[idx]))) {
|
||||
fd_to_idx[fd] = -1;
|
||||
info_array[idx].watch_pid = 0;
|
||||
debug("%s %d: %s", "fd", fd,
|
||||
"removing");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Displayable fd - display, or remove if changed
|
||||
*/
|
||||
|
||||
position_now =
|
||||
pv_watchfd_position(&(info_array[idx]));
|
||||
|
||||
if (position_now < 0) {
|
||||
fd_to_idx[fd] = -1;
|
||||
info_array[idx].watch_pid = 0;
|
||||
debug("%s %d: %s", "fd", fd, "removing");
|
||||
continue;
|
||||
}
|
||||
|
||||
since_last =
|
||||
position_now - info_array[idx].position;
|
||||
info_array[idx].position = position_now;
|
||||
|
||||
init_time.tv_sec =
|
||||
info_array[idx].start_time.tv_sec +
|
||||
state->pv_sig_toffset.tv_sec;
|
||||
init_time.tv_usec =
|
||||
info_array[idx].start_time.tv_usec +
|
||||
state->pv_sig_toffset.tv_usec;
|
||||
if (init_time.tv_usec >= 1000000) {
|
||||
init_time.tv_sec++;
|
||||
init_time.tv_usec -= 1000000;
|
||||
}
|
||||
if (init_time.tv_usec < 0) {
|
||||
init_time.tv_sec--;
|
||||
init_time.tv_usec += 1000000;
|
||||
}
|
||||
|
||||
elapsed = cur_time.tv_sec - init_time.tv_sec;
|
||||
elapsed +=
|
||||
(cur_time.tv_usec -
|
||||
init_time.tv_usec) / 1000000.0;
|
||||
|
||||
if (displayed_lines > 0) {
|
||||
debug("%s", "adding newline");
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
debug("%s %d [%d]: %Lf / %Ld / %Ld", "fd", fd, idx,
|
||||
elapsed, since_last, position_now);
|
||||
|
||||
pv_display(&(state_array[idx]), elapsed,
|
||||
since_last, position_now);
|
||||
displayed_lines++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write blank lines if we're writing fewer lines than last
|
||||
* time.
|
||||
*/
|
||||
blank_lines = prev_displayed_lines - displayed_lines;
|
||||
prev_displayed_lines = displayed_lines;
|
||||
|
||||
if (blank_lines > 0)
|
||||
debug("%s: %d", "adding blank lines", blank_lines);
|
||||
|
||||
while (blank_lines > 0) {
|
||||
int x;
|
||||
if (displayed_lines > 0)
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
for (x = 0; x < state->width; x++)
|
||||
write(STDERR_FILENO, " ", 1);
|
||||
write(STDERR_FILENO, "\r", 1);
|
||||
blank_lines--;
|
||||
displayed_lines++;
|
||||
}
|
||||
|
||||
debug("%s: %d", "displayed lines", displayed_lines);
|
||||
|
||||
while (displayed_lines > 1) {
|
||||
write(STDERR_FILENO, "\033[A", 3);
|
||||
displayed_lines--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up our displayed lines on exit.
|
||||
*/
|
||||
blank_lines = prev_displayed_lines;
|
||||
while (blank_lines > 0) {
|
||||
int x;
|
||||
for (x = 0; x < state->width; x++)
|
||||
write(STDERR_FILENO, " ", 1);
|
||||
write(STDERR_FILENO, "\r", 1);
|
||||
blank_lines--;
|
||||
if (blank_lines > 0)
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
}
|
||||
while (prev_displayed_lines > 1) {
|
||||
write(STDERR_FILENO, "\033[A", 3);
|
||||
prev_displayed_lines--;
|
||||
}
|
||||
|
||||
if (NULL != info_array)
|
||||
free(info_array);
|
||||
if (NULL != state_array)
|
||||
free(state_array);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Functions for converting strings to numbers.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "pv.h"
|
||||
|
||||
|
||||
/*
|
||||
* This function is used instead of the macro from <ctype.h> because
|
||||
* including <ctype.h> causes weird versioned glibc dependencies on certain
|
||||
* Red Hat systems, complicating package management.
|
||||
*/
|
||||
static int pv__isdigit(char c)
|
||||
{
|
||||
return ((c >= '0') && (c <= '9'));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the numeric value of "str", as a long long.
|
||||
*/
|
||||
long long pv_getnum_ll(const char *str)
|
||||
{
|
||||
long long n = 0;
|
||||
long long decimal = 0;
|
||||
int decdivisor = 1;
|
||||
int shift = 0;
|
||||
|
||||
if (0 == str)
|
||||
return n;
|
||||
|
||||
while (str[0] != 0 && (!pv__isdigit(str[0])))
|
||||
str++;
|
||||
|
||||
for (; pv__isdigit(str[0]); str++) {
|
||||
n = n * 10;
|
||||
n += (str[0] - '0');
|
||||
}
|
||||
|
||||
/*
|
||||
* If a decimal value was given, skip the decimal part.
|
||||
*/
|
||||
if (('.' == str[0]) || (',' == str[0])) {
|
||||
str++;
|
||||
for (; pv__isdigit(str[0]); str++) {
|
||||
if (decdivisor < 10000) {
|
||||
decimal = decimal * 10;
|
||||
decimal += (str[0] - '0');
|
||||
decdivisor = decdivisor * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse any units given (K=KiB=*1024, M=MiB=1024KiB, G=GiB=1024MiB,
|
||||
* T=TiB=1024GiB).
|
||||
*/
|
||||
if (str[0]) {
|
||||
while ((' ' == str[0]) || ('\t' == str[0]))
|
||||
str++;
|
||||
switch (str[0]) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
shift = 10;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
shift = 20;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
shift = 30;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
shift = 40;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary left-shift the supplied number by "shift" times, i.e.
|
||||
* apply the given units (KiB, MiB, etc) to it, but never shift left
|
||||
* more than 30 at a time to avoid overflows.
|
||||
*/
|
||||
while (shift > 0) {
|
||||
int shiftby;
|
||||
|
||||
shiftby = shift;
|
||||
if (shiftby > 30)
|
||||
shiftby = 30;
|
||||
|
||||
n = n << shiftby;
|
||||
decimal = decimal << shiftby;
|
||||
shift -= shiftby;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add any decimal component.
|
||||
*/
|
||||
decimal = decimal / decdivisor;
|
||||
n += decimal;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the numeric value of "str", as a double.
|
||||
*/
|
||||
double pv_getnum_d(const char *str)
|
||||
{
|
||||
double n = 0.0;
|
||||
double step = 1;
|
||||
|
||||
if (0 == str)
|
||||
return n;
|
||||
|
||||
while (str[0] != 0 && (!pv__isdigit(str[0])))
|
||||
str++;
|
||||
|
||||
for (; pv__isdigit(str[0]); str++) {
|
||||
n = n * 10;
|
||||
n += (str[0] - '0');
|
||||
}
|
||||
|
||||
if ((str[0] != '.') && (str[0] != ','))
|
||||
return n;
|
||||
|
||||
str++;
|
||||
|
||||
for (; pv__isdigit(str[0]) && step < 1000000; str++) {
|
||||
step = step * 10;
|
||||
n += (str[0] - '0') / step;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the numeric value of "str", as an int.
|
||||
*/
|
||||
int pv_getnum_i(const char *str)
|
||||
{
|
||||
return (int) pv_getnum_ll(str);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return nonzero if the given string is not a valid number of the given
|
||||
* type.
|
||||
*/
|
||||
int pv_getnum_check(const char *str, pv_numtype_t type)
|
||||
{
|
||||
if (0 == str)
|
||||
return 1;
|
||||
|
||||
while ((' ' == str[0]) || ('\t' == str[0]))
|
||||
str++;
|
||||
|
||||
if (!pv__isdigit(str[0]))
|
||||
return 1;
|
||||
|
||||
for (; pv__isdigit(str[0]); str++);
|
||||
|
||||
if (('.' == str[0]) || (',' == str[0])) {
|
||||
if (type == PV_NUMTYPE_INTEGER)
|
||||
return 1;
|
||||
str++;
|
||||
for (; pv__isdigit(str[0]); str++);
|
||||
}
|
||||
|
||||
if (0 == str[0])
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Suffixes are not allowed for doubles, only for integers.
|
||||
*/
|
||||
if (type == PV_NUMTYPE_DOUBLE)
|
||||
return 1;
|
||||
|
||||
while ((' ' == str[0]) || ('\t' == str[0]))
|
||||
str++;
|
||||
switch (str[0]) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 't':
|
||||
case 'T':
|
||||
str++;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (str[0] != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Signal handling functions.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
void pv_crs_needreinit(pvstate_t);
|
||||
#endif
|
||||
|
||||
static pvstate_t pv_sig_state = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Handle SIGTTOU (tty output for background process) by redirecting stderr
|
||||
* to /dev/null, so that we can be stopped and backgrounded without messing
|
||||
* up the terminal. We store the old stderr file descriptor so that on a
|
||||
* subsequent SIGCONT we can try writing to the terminal again, in case we
|
||||
* get backgrounded and later get foregrounded again.
|
||||
*/
|
||||
static void pv_sig_ttou(int s)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (-1 == pv_sig_state->pv_sig_old_stderr)
|
||||
pv_sig_state->pv_sig_old_stderr = dup(STDERR_FILENO);
|
||||
|
||||
dup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle SIGTSTP (stop typed at tty) by storing the time the signal
|
||||
* happened for later use by pv_sig_cont(), and then stopping the process.
|
||||
*/
|
||||
static void pv_sig_tstp(int s)
|
||||
{
|
||||
gettimeofday(&(pv_sig_state->pv_sig_tstp_time), NULL);
|
||||
raise(SIGSTOP);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle SIGCONT (continue if stopped) by adding the elapsed time since the
|
||||
* last SIGTSTP to the elapsed time offset, and by trying to write to the
|
||||
* terminal again (by replacing the /dev/null stderr with the old stderr).
|
||||
*/
|
||||
static void pv_sig_cont(int s)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct termios t;
|
||||
|
||||
pv_sig_state->pv_sig_newsize = 1;
|
||||
|
||||
if (0 == pv_sig_state->pv_sig_tstp_time.tv_sec) {
|
||||
tcgetattr(STDERR_FILENO, &t);
|
||||
t.c_lflag |= TOSTOP;
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t);
|
||||
#ifdef HAVE_IPC
|
||||
pv_crs_needreinit(pv_sig_state);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
pv_sig_state->pv_sig_toffset.tv_sec +=
|
||||
(tv.tv_sec - pv_sig_state->pv_sig_tstp_time.tv_sec);
|
||||
pv_sig_state->pv_sig_toffset.tv_usec +=
|
||||
(tv.tv_usec - pv_sig_state->pv_sig_tstp_time.tv_usec);
|
||||
if (pv_sig_state->pv_sig_toffset.tv_usec >= 1000000) {
|
||||
pv_sig_state->pv_sig_toffset.tv_sec++;
|
||||
pv_sig_state->pv_sig_toffset.tv_usec -= 1000000;
|
||||
}
|
||||
if (pv_sig_state->pv_sig_toffset.tv_usec < 0) {
|
||||
pv_sig_state->pv_sig_toffset.tv_sec--;
|
||||
pv_sig_state->pv_sig_toffset.tv_usec += 1000000;
|
||||
}
|
||||
|
||||
pv_sig_state->pv_sig_tstp_time.tv_sec = 0;
|
||||
pv_sig_state->pv_sig_tstp_time.tv_usec = 0;
|
||||
|
||||
if (pv_sig_state->pv_sig_old_stderr != -1) {
|
||||
dup2(pv_sig_state->pv_sig_old_stderr, STDERR_FILENO);
|
||||
close(pv_sig_state->pv_sig_old_stderr);
|
||||
pv_sig_state->pv_sig_old_stderr = -1;
|
||||
}
|
||||
|
||||
tcgetattr(STDERR_FILENO, &t);
|
||||
t.c_lflag |= TOSTOP;
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t);
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
pv_crs_needreinit(pv_sig_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle SIGWINCH (window size changed) by setting a flag.
|
||||
*/
|
||||
static void pv_sig_winch(int s)
|
||||
{
|
||||
pv_sig_state->pv_sig_newsize = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle termination signals by setting the abort flag.
|
||||
*/
|
||||
static void pv_sig_term(int s)
|
||||
{
|
||||
pv_sig_state->pv_sig_abort = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise signal handling.
|
||||
*/
|
||||
void pv_sig_init(pvstate_t state)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
pv_sig_state = state;
|
||||
|
||||
pv_sig_state->pv_sig_old_stderr = -1;
|
||||
pv_sig_state->pv_sig_tstp_time.tv_sec = 0;
|
||||
pv_sig_state->pv_sig_tstp_time.tv_usec = 0;
|
||||
pv_sig_state->pv_sig_toffset.tv_sec = 0;
|
||||
pv_sig_state->pv_sig_toffset.tv_usec = 0;
|
||||
|
||||
/*
|
||||
* Ignore SIGPIPE, so we don't die if stdout is a pipe and the other
|
||||
* end closes unexpectedly.
|
||||
*/
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGPIPE, &sa, &(pv_sig_state->pv_sig_old_sigpipe));
|
||||
|
||||
/*
|
||||
* Handle SIGTTOU by continuing with output switched off, so that we
|
||||
* can be stopped and backgrounded without messing up the terminal.
|
||||
*/
|
||||
sa.sa_handler = pv_sig_ttou;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTTOU, &sa, &(pv_sig_state->pv_sig_old_sigttou));
|
||||
|
||||
/*
|
||||
* Handle SIGTSTP by storing the time the signal happened for later
|
||||
* use by pv_sig_cont(), and then stopping the process.
|
||||
*/
|
||||
sa.sa_handler = pv_sig_tstp;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTSTP, &sa, &(pv_sig_state->pv_sig_old_sigtstp));
|
||||
|
||||
/*
|
||||
* Handle SIGCONT by adding the elapsed time since the last SIGTSTP
|
||||
* to the elapsed time offset, and by trying to write to the
|
||||
* terminal again.
|
||||
*/
|
||||
sa.sa_handler = pv_sig_cont;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGCONT, &sa, &(pv_sig_state->pv_sig_old_sigcont));
|
||||
|
||||
/*
|
||||
* Handle SIGWINCH by setting a flag to let the main loop know it
|
||||
* has to reread the terminal size.
|
||||
*/
|
||||
sa.sa_handler = pv_sig_winch;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGWINCH, &sa, &(pv_sig_state->pv_sig_old_sigwinch));
|
||||
|
||||
/*
|
||||
* Handle SIGINT, SIGHUP, SIGTERM by setting a flag to let the
|
||||
* main loop know it should quit now.
|
||||
*/
|
||||
sa.sa_handler = pv_sig_term;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa, &(pv_sig_state->pv_sig_old_sigint));
|
||||
|
||||
sa.sa_handler = pv_sig_term;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGHUP, &sa, &(pv_sig_state->pv_sig_old_sighup));
|
||||
|
||||
sa.sa_handler = pv_sig_term;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTERM, &sa, &(pv_sig_state->pv_sig_old_sigterm));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down signal handling.
|
||||
*/
|
||||
void pv_sig_fini(pvstate_t state)
|
||||
{
|
||||
sigaction(SIGPIPE, &(pv_sig_state->pv_sig_old_sigpipe), NULL);
|
||||
sigaction(SIGTTOU, &(pv_sig_state->pv_sig_old_sigttou), NULL);
|
||||
sigaction(SIGTSTP, &(pv_sig_state->pv_sig_old_sigtstp), NULL);
|
||||
sigaction(SIGCONT, &(pv_sig_state->pv_sig_old_sigcont), NULL);
|
||||
sigaction(SIGWINCH, &(pv_sig_state->pv_sig_old_sigwinch), NULL);
|
||||
sigaction(SIGINT, &(pv_sig_state->pv_sig_old_sigint), NULL);
|
||||
sigaction(SIGHUP, &(pv_sig_state->pv_sig_old_sighup), NULL);
|
||||
sigaction(SIGTERM, &(pv_sig_state->pv_sig_old_sigterm), NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Stop reacting to SIGTSTP and SIGCONT.
|
||||
*/
|
||||
void pv_sig_nopause(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGCONT, &sa, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start catching SIGTSTP and SIGCONT again.
|
||||
*/
|
||||
void pv_sig_allowpause(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = pv_sig_tstp;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
|
||||
sa.sa_handler = pv_sig_cont;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGCONT, &sa, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If we have redirected stderr to /dev/null, check every second or so to
|
||||
* see whether we can write to the terminal again - this is so that if we
|
||||
* get backgrounded, then foregrounded again, we start writing to the
|
||||
* terminal again.
|
||||
*/
|
||||
void pv_sig_checkbg(void)
|
||||
{
|
||||
static time_t next_check = 0;
|
||||
struct termios t;
|
||||
|
||||
if (time(NULL) < next_check)
|
||||
return;
|
||||
|
||||
next_check = time(NULL) + 1;
|
||||
|
||||
if (-1 == pv_sig_state->pv_sig_old_stderr)
|
||||
return;
|
||||
|
||||
dup2(pv_sig_state->pv_sig_old_stderr, STDERR_FILENO);
|
||||
close(pv_sig_state->pv_sig_old_stderr);
|
||||
pv_sig_state->pv_sig_old_stderr = -1;
|
||||
|
||||
tcgetattr(STDERR_FILENO, &t);
|
||||
t.c_lflag |= TOSTOP;
|
||||
tcsetattr(STDERR_FILENO, TCSANOW, &t);
|
||||
|
||||
#ifdef HAVE_IPC
|
||||
pv_crs_needreinit(pv_sig_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* State management functions.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* Create a new state structure, and return it, or 0 (NULL) on error.
|
||||
*/
|
||||
pvstate_t pv_state_alloc(const char *program_name)
|
||||
{
|
||||
pvstate_t state;
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
if (0 == state)
|
||||
return 0;
|
||||
|
||||
state->program_name = program_name;
|
||||
state->watch_pid = 0;
|
||||
state->watch_fd = -1;
|
||||
#ifdef HAVE_IPC
|
||||
state->crs_shmid = -1;
|
||||
state->crs_pvcount = 1;
|
||||
#endif /* HAVE_IPC */
|
||||
state->crs_lock_fd = -1;
|
||||
|
||||
state->reparse_display = 1;
|
||||
state->current_file = _("none");
|
||||
#ifdef HAVE_SPLICE
|
||||
state->splice_failed_fd = -1;
|
||||
#endif /* HAVE_SPLICE */
|
||||
state->display_visible = 0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free a state structure, after which it can no longer be used.
|
||||
*/
|
||||
void pv_state_free(pvstate_t state)
|
||||
{
|
||||
if (0 == state)
|
||||
return;
|
||||
|
||||
if (state->display_buffer)
|
||||
free(state->display_buffer);
|
||||
state->display_buffer = NULL;
|
||||
|
||||
if (state->transfer_buffer)
|
||||
free(state->transfer_buffer);
|
||||
state->transfer_buffer = NULL;
|
||||
|
||||
free(state);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the formatting string, given a set of old-style formatting options.
|
||||
*/
|
||||
void pv_state_set_format(pvstate_t state, unsigned char progress,
|
||||
unsigned char timer, unsigned char eta,
|
||||
unsigned char fineta, unsigned char rate,
|
||||
unsigned char average_rate, unsigned char bytes,
|
||||
unsigned char bufpercent,
|
||||
unsigned int lastwritten, const char *name)
|
||||
{
|
||||
#define PV_ADDFORMAT(x,y) if (x) { \
|
||||
if (state->default_format[0] != 0) \
|
||||
strcat(state->default_format, " "); \
|
||||
strcat(state->default_format, y); \
|
||||
}
|
||||
|
||||
state->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];
|
||||
sprintf(buf, "%%%uA", lastwritten);
|
||||
PV_ADDFORMAT(lastwritten, buf);
|
||||
}
|
||||
|
||||
state->name = name;
|
||||
state->reparse_display = 1;
|
||||
}
|
||||
|
||||
|
||||
void pv_state_force_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->force = val;
|
||||
}
|
||||
|
||||
void pv_state_cursor_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->cursor = val;
|
||||
};
|
||||
|
||||
void pv_state_numeric_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->numeric = val;
|
||||
};
|
||||
|
||||
void pv_state_wait_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->wait = val;
|
||||
};
|
||||
|
||||
void pv_state_delay_start_set(pvstate_t state, double val)
|
||||
{
|
||||
state->delay_start = val;
|
||||
};
|
||||
|
||||
void pv_state_linemode_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->linemode = val;
|
||||
};
|
||||
|
||||
void pv_state_null_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->null = val;
|
||||
};
|
||||
|
||||
void pv_state_no_op_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->no_op = val;
|
||||
};
|
||||
|
||||
void pv_state_skip_errors_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->skip_errors = val;
|
||||
};
|
||||
|
||||
void pv_state_stop_at_size_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->stop_at_size = val;
|
||||
};
|
||||
|
||||
void pv_state_rate_limit_set(pvstate_t state, unsigned long long val)
|
||||
{
|
||||
state->rate_limit = val;
|
||||
};
|
||||
|
||||
void pv_state_target_buffer_size_set(pvstate_t state,
|
||||
unsigned long long val)
|
||||
{
|
||||
state->target_buffer_size = val;
|
||||
};
|
||||
|
||||
void pv_state_no_splice_set(pvstate_t state, unsigned char val)
|
||||
{
|
||||
state->no_splice = val;
|
||||
};
|
||||
|
||||
void pv_state_size_set(pvstate_t state, unsigned long long val)
|
||||
{
|
||||
state->size = val;
|
||||
};
|
||||
|
||||
void pv_state_interval_set(pvstate_t state, double val)
|
||||
{
|
||||
state->interval = val;
|
||||
};
|
||||
|
||||
void pv_state_width_set(pvstate_t state, unsigned int val)
|
||||
{
|
||||
state->width = val;
|
||||
};
|
||||
|
||||
void pv_state_height_set(pvstate_t state, unsigned int val)
|
||||
{
|
||||
state->height = val;
|
||||
};
|
||||
|
||||
void pv_state_name_set(pvstate_t state, const char *val)
|
||||
{
|
||||
state->name = val;
|
||||
};
|
||||
|
||||
void pv_state_format_string_set(pvstate_t state, const char *val)
|
||||
{
|
||||
state->format_string = val;
|
||||
};
|
||||
|
||||
void pv_state_watch_pid_set(pvstate_t state, unsigned int val)
|
||||
{
|
||||
state->watch_pid = val;
|
||||
};
|
||||
|
||||
void pv_state_watch_fd_set(pvstate_t state, int val)
|
||||
{
|
||||
state->watch_fd = val;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Set the array of input files.
|
||||
*/
|
||||
void pv_state_inputfiles(pvstate_t state, int input_file_count,
|
||||
const char **input_files)
|
||||
{
|
||||
state->input_file_count = input_file_count;
|
||||
state->input_files = input_files;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
* Functions for transferring between file descriptors.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
||||
/*
|
||||
* Read up to "count" bytes from file descriptor "fd" into the buffer "buf",
|
||||
* and return the number of bytes read, like read().
|
||||
*
|
||||
* Unlike read(), if we have read less than "count" bytes, we check to see
|
||||
* if there's any more to read, and keep trying, to make sure we fill the
|
||||
* buffer as full as we can.
|
||||
*
|
||||
* We stop retrying if the time elapsed since this function was entered
|
||||
* reaches TRANSFER_READ_TIMEOUT microseconds.
|
||||
*/
|
||||
static ssize_t pv__transfer_read_repeated(int fd, void *buf, size_t count)
|
||||
{
|
||||
struct timeval start_time;
|
||||
ssize_t total_read;
|
||||
|
||||
gettimeofday(&start_time, NULL);
|
||||
|
||||
total_read = 0;
|
||||
|
||||
while (count > 0) {
|
||||
ssize_t nread;
|
||||
struct timeval now;
|
||||
long elapsed_usec;
|
||||
|
||||
nread =
|
||||
read(fd, buf,
|
||||
count >
|
||||
MAX_READ_AT_ONCE ? MAX_READ_AT_ONCE : count);
|
||||
if (nread < 0)
|
||||
return nread;
|
||||
|
||||
total_read += nread;
|
||||
buf += nread;
|
||||
count -= nread;
|
||||
|
||||
if (0 == nread)
|
||||
return total_read;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
elapsed_usec =
|
||||
1000000 * (now.tv_sec - start_time.tv_sec) +
|
||||
(now.tv_usec - start_time.tv_usec);
|
||||
if (elapsed_usec > TRANSFER_READ_TIMEOUT) {
|
||||
debug("%s %d: %s (%ld %s)", "fd", fd,
|
||||
"stopping read - timer expired",
|
||||
elapsed_usec, "usec elapsed");
|
||||
return total_read;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
fd_set readfds;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(fd, &readfds);
|
||||
|
||||
debug("%s %d: %s (%ld %s, %ld %s)", "fd", fd,
|
||||
"trying another read after partial buffer fill",
|
||||
nread, "read", count, "remaining");
|
||||
|
||||
if (select(fd + 1, &readfds, NULL, NULL, &tv) < 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write up to "count" bytes to file descriptor "fd" from the buffer "buf",
|
||||
* and return the number of bytes written, like write().
|
||||
*
|
||||
* Unlike write(), if we have written less than "count" bytes, we check to
|
||||
* see if we can write any more, and keep trying, to make sure we empty the
|
||||
* buffer as much as we can.
|
||||
*
|
||||
* We stop retrying if the time elapsed since this function was entered
|
||||
* reaches TRANSFER_WRITE_TIMEOUT microseconds.
|
||||
*/
|
||||
static ssize_t pv__transfer_write_repeated(int fd, void *buf, size_t count)
|
||||
{
|
||||
struct timeval start_time;
|
||||
ssize_t total_written;
|
||||
|
||||
gettimeofday(&start_time, NULL);
|
||||
|
||||
total_written = 0;
|
||||
|
||||
while (count > 0) {
|
||||
ssize_t nwritten;
|
||||
struct timeval now;
|
||||
long elapsed_usec;
|
||||
size_t asked_to_write;
|
||||
|
||||
asked_to_write = count >
|
||||
MAX_WRITE_AT_ONCE ? MAX_WRITE_AT_ONCE : count;
|
||||
|
||||
nwritten = write(fd, buf, asked_to_write);
|
||||
if (nwritten < 0) {
|
||||
if ((EINTR == errno) || (EAGAIN == errno)) {
|
||||
/*
|
||||
* Interrupted by a signal - probably our
|
||||
* alarm() - so just return what we've
|
||||
* written so far.
|
||||
*/
|
||||
return total_written;
|
||||
} else {
|
||||
/*
|
||||
* Legitimate error - return negative.
|
||||
*/
|
||||
return nwritten;
|
||||
}
|
||||
}
|
||||
|
||||
total_written += nwritten;
|
||||
buf += nwritten;
|
||||
count -= nwritten;
|
||||
|
||||
if (0 == nwritten)
|
||||
return total_written;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
elapsed_usec =
|
||||
1000000 * (now.tv_sec - start_time.tv_sec) +
|
||||
(now.tv_usec - start_time.tv_usec);
|
||||
if (elapsed_usec > TRANSFER_WRITE_TIMEOUT) {
|
||||
debug("%s %d: %s (%ld %s)", "fd", fd,
|
||||
"stopping write - timer expired",
|
||||
elapsed_usec, "usec elapsed");
|
||||
return total_written;
|
||||
}
|
||||
|
||||
/*
|
||||
* Running the select() here seems to make PV eat a lot of
|
||||
* CPU in some cases, so instead we just go round the loop
|
||||
* again and rely on our alarm() to interrupt us if we run
|
||||
* out of time - also on our gettimeofday() check.
|
||||
*/
|
||||
if (count > 0) {
|
||||
fd_set writefds;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(fd, &writefds);
|
||||
|
||||
debug("%s %d: %s (%ld %s, %ld %s)", "fd", fd,
|
||||
"trying another write after partial buffer flush",
|
||||
nwritten, "written", count, "remaining");
|
||||
|
||||
# if 0 /* disabled after 1.6.0 - see comment above */
|
||||
if (select(fd + 1, NULL, &writefds, NULL, &tv) < 1)
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
return total_written;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read some data from the given file descriptor. Returns zero if there was
|
||||
* a transient error and we need to return 0 from pv_transfer, otherwise
|
||||
* returns 1.
|
||||
*
|
||||
* At most, the number of bytes read will be the number of bytes remaining
|
||||
* in the input buffer. If state->rate_limit is >0, and/or "allowed" is >0,
|
||||
* then the maximum number of bytes read will be the number remaining unused
|
||||
* in the input buffer or the value of "allowed", whichever is smaller.
|
||||
*
|
||||
* If splice() was successfully used, sets state->splice_used to 1; if it
|
||||
* failed, then state->splice_failed_fd is updated to the current fd so
|
||||
* splice() won't be tried again until the next input file.
|
||||
*
|
||||
* Updates state->read_position by the number of bytes read, unless splice()
|
||||
* was used, in which case it does not since there's nothing in the buffer
|
||||
* (and it also adds the bytes to state->written since they've been written
|
||||
* to the output).
|
||||
*
|
||||
* On read error, updates state->exit_status, and if allowed by
|
||||
* state->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 1. If all data in the buffer has been written at this
|
||||
* point, then also sets *eof_out.
|
||||
*/
|
||||
static int pv__transfer_read(pvstate_t state, int fd,
|
||||
int *eof_in, int *eof_out,
|
||||
unsigned long long allowed,
|
||||
long *lineswritten)
|
||||
{
|
||||
unsigned long bytes_can_read;
|
||||
unsigned long amount_to_skip;
|
||||
long amount_skipped;
|
||||
long orig_offset;
|
||||
long skip_offset;
|
||||
ssize_t nread;
|
||||
#ifdef HAVE_SPLICE
|
||||
size_t bytes_to_splice;
|
||||
#endif /* HAVE_SPLICE */
|
||||
|
||||
bytes_can_read = state->buffer_size - state->read_position;
|
||||
|
||||
#ifdef HAVE_SPLICE
|
||||
state->splice_used = 0;
|
||||
if ((!state->linemode) && (!state->no_splice)
|
||||
&& (fd != state->splice_failed_fd)
|
||||
&& (0 == state->to_write)) {
|
||||
if (state->rate_limit || allowed != 0)
|
||||
bytes_to_splice = allowed;
|
||||
else
|
||||
bytes_to_splice = bytes_can_read;
|
||||
|
||||
nread = splice(fd, NULL, STDOUT_FILENO, NULL,
|
||||
bytes_to_splice, SPLICE_F_MORE);
|
||||
|
||||
state->splice_used = 1;
|
||||
if ((nread < 0) && (EINVAL == errno)) {
|
||||
debug("%s %d: %s", "fd", fd,
|
||||
"splice failed with EINVAL - disabling");
|
||||
state->splice_failed_fd = fd;
|
||||
state->splice_used = 0;
|
||||
/*
|
||||
* Fall through to read() below.
|
||||
*/
|
||||
} else if (nread > 0) {
|
||||
state->written = nread;
|
||||
} else if ((-1 == nread) && (EAGAIN == errno)) {
|
||||
/* nothing read yet - do nothing */
|
||||
} else {
|
||||
/* EOF might not really be EOF, it seems */
|
||||
state->splice_used = 0;
|
||||
}
|
||||
}
|
||||
if (0 == state->splice_used) {
|
||||
nread =
|
||||
pv__transfer_read_repeated(fd,
|
||||
state->transfer_buffer +
|
||||
state->read_position,
|
||||
bytes_can_read);
|
||||
}
|
||||
#else
|
||||
nread =
|
||||
pv__transfer_read_repeated(fd,
|
||||
state->transfer_buffer +
|
||||
state->read_position,
|
||||
bytes_can_read);
|
||||
#endif /* HAVE_SPLICE */
|
||||
|
||||
|
||||
if (0 == nread) {
|
||||
/*
|
||||
* If read returned 0, we've reached the end of this input
|
||||
* file. If we've also written all the data in the transfer
|
||||
* buffer, we set eof_out as well, so that the main loop can
|
||||
* move on to the next input file.
|
||||
*/
|
||||
*eof_in = 1;
|
||||
if (state->write_position >= state->read_position)
|
||||
*eof_out = 1;
|
||||
return 1;
|
||||
} else if (nread > 0) {
|
||||
/*
|
||||
* Read returned >0, so we successfully read data - clear
|
||||
* the error counter and update our record of how much data
|
||||
* we've got in the buffer.
|
||||
*/
|
||||
state->read_errors_in_a_row = 0;
|
||||
#ifdef HAVE_SPLICE
|
||||
/*
|
||||
* If we used splice(), there isn't any more data in the
|
||||
* buffer than there was before.
|
||||
*/
|
||||
if (0 == state->splice_used)
|
||||
state->read_position += nread;
|
||||
#else
|
||||
state->read_position += nread;
|
||||
#endif /* HAVE_SPLICE */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reach this point, nread<0, so there was an error.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If a read error occurred but it was EINTR or EAGAIN, just wait a
|
||||
* bit and then return zero, since this was a transient error.
|
||||
*/
|
||||
if ((EINTR == errno) || (EAGAIN == errno)) {
|
||||
struct timeval tv;
|
||||
debug("%s %d: %s: %s", "fd", fd,
|
||||
"transient error - waiting briefly",
|
||||
strerror(errno));
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The read error is not transient, so update the program's final
|
||||
* exit status, regardless of whether we're skipping errors, and
|
||||
* increment the error counter.
|
||||
*/
|
||||
state->exit_status |= 16;
|
||||
state->read_errors_in_a_row++;
|
||||
|
||||
/*
|
||||
* If we aren't skipping errors, show the error and pretend we
|
||||
* reached the end of this file.
|
||||
*/
|
||||
if (0 == state->skip_errors) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
state->current_file,
|
||||
_("read failed"), strerror(errno));
|
||||
*eof_in = 1;
|
||||
if (state->write_position >= state->read_position) {
|
||||
*eof_out = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to skip past the error.
|
||||
*/
|
||||
|
||||
amount_skipped = -1;
|
||||
|
||||
if (!state->read_error_warning_shown) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
state->current_file,
|
||||
_
|
||||
("warning: read errors detected"),
|
||||
strerror(errno));
|
||||
state->read_error_warning_shown = 1;
|
||||
}
|
||||
|
||||
orig_offset = lseek64(fd, 0, SEEK_CUR);
|
||||
|
||||
/*
|
||||
* If the file is not seekable, we can't skip past the error, so we
|
||||
* will have to abandon the attempt and pretend we reached the end
|
||||
* of the file.
|
||||
*/
|
||||
if (0 > orig_offset) {
|
||||
pv_error(state, "%s: %s: %s",
|
||||
state->current_file,
|
||||
_("file is not seekable"), strerror(errno));
|
||||
*eof_in = 1;
|
||||
if (state->write_position >= state->read_position) {
|
||||
*eof_out = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (state->read_errors_in_a_row < 10) {
|
||||
amount_to_skip = state->read_errors_in_a_row < 5 ? 1 : 2;
|
||||
} else if (state->read_errors_in_a_row < 20) {
|
||||
amount_to_skip = 1 << (state->read_errors_in_a_row - 10);
|
||||
} else {
|
||||
amount_to_skip = 512;
|
||||
}
|
||||
|
||||
/*
|
||||
* Round the skip amount down to the start of the next block of the
|
||||
* skip amount size. For instance if the skip amount is 512, but
|
||||
* our file offset is 257, we'll jump to 512 instead of 769.
|
||||
*/
|
||||
if (amount_to_skip > 1) {
|
||||
skip_offset = orig_offset + amount_to_skip;
|
||||
skip_offset -= (skip_offset % amount_to_skip);
|
||||
if (skip_offset > orig_offset) {
|
||||
amount_to_skip = skip_offset - orig_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trim the skip amount so we wouldn't read too much.
|
||||
*/
|
||||
if (amount_to_skip > bytes_can_read)
|
||||
amount_to_skip = bytes_can_read;
|
||||
|
||||
skip_offset = lseek64(fd, orig_offset + amount_to_skip, SEEK_SET);
|
||||
|
||||
/*
|
||||
* If the skip we just tried didn't work, try only skipping 1 byte
|
||||
* in case we were trying to go past the end of the input file.
|
||||
*/
|
||||
if (skip_offset < 0) {
|
||||
amount_to_skip = 1;
|
||||
skip_offset =
|
||||
lseek64(fd, orig_offset + amount_to_skip, SEEK_SET);
|
||||
}
|
||||
|
||||
if (skip_offset < 0) {
|
||||
/*
|
||||
* Failed to skip - lseek() returned an error, so mark the
|
||||
* file as having ended.
|
||||
*/
|
||||
*eof_in = 1;
|
||||
/*
|
||||
* EINVAL means the file has ended since we've tried to go
|
||||
* past the end of it, so we don't bother with a warning
|
||||
* since it just means we've reached the end anyway.
|
||||
*/
|
||||
if (EINVAL != errno) {
|
||||
pv_error(state,
|
||||
"%s: %s: %s",
|
||||
state->current_file,
|
||||
_
|
||||
("failed to seek past error"),
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
amount_skipped = skip_offset - orig_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we succeeded in skipping some bytes, zero the equivalent part
|
||||
* of the transfer buffer, and update the buffer position.
|
||||
*/
|
||||
if (amount_skipped > 0) {
|
||||
memset(state->transfer_buffer +
|
||||
state->read_position, 0, amount_skipped);
|
||||
state->read_position += amount_skipped;
|
||||
if (state->skip_errors < 2) {
|
||||
pv_error(state, "%s: %s: %ld - %ld (%ld %s)",
|
||||
state->current_file,
|
||||
_
|
||||
("skipped past read error"),
|
||||
orig_offset,
|
||||
skip_offset, amount_skipped, _("B"));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Failed to skip - mark file as ended.
|
||||
*/
|
||||
*eof_in = 1;
|
||||
if (state->write_position >= state->read_position) {
|
||||
*eof_out = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write state->to_write bytes of data from the transfer buffer to stdout.
|
||||
* Returns zero if there was a transient error and we need to return 0 from
|
||||
* pv_transfer, otherwise returns 1.
|
||||
*
|
||||
* Updates state->write_position by moving it on by the number of bytes
|
||||
* written; adds the number of bytes written to state->written; sets
|
||||
* *eof_out on stdout EOF or when the write position catches up with the
|
||||
* read position AND *eof_in is 1 (meaning we've reached the end of data).
|
||||
*
|
||||
* On error, sets *eof_out to 1, sets state->written to -1, and updates
|
||||
* state->exit_status.
|
||||
*/
|
||||
static int pv__transfer_write(pvstate_t state, int fd,
|
||||
int *eof_in, int *eof_out,
|
||||
long *lineswritten)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
alarm(1);
|
||||
|
||||
nwritten = pv__transfer_write_repeated(STDOUT_FILENO,
|
||||
state->transfer_buffer +
|
||||
state->write_position,
|
||||
state->to_write);
|
||||
|
||||
alarm(0);
|
||||
|
||||
if (0 == nwritten) {
|
||||
/*
|
||||
* Write returned 0 - EOF on stdout.
|
||||
*/
|
||||
*eof_out = 1;
|
||||
return 1;
|
||||
} else if (nwritten > 0) {
|
||||
/*
|
||||
* Write returned >0 - data successfully written.
|
||||
*/
|
||||
if ((state->linemode) && (lineswritten != NULL)) {
|
||||
/*
|
||||
* Guillaume Marcais: use strchr to count \n
|
||||
*/
|
||||
unsigned char save;
|
||||
char *ptr;
|
||||
long lines = 0;
|
||||
|
||||
save =
|
||||
state->transfer_buffer[state->write_position +
|
||||
nwritten];
|
||||
state->transfer_buffer[state->write_position +
|
||||
nwritten] = 0;
|
||||
ptr =
|
||||
(char *) (state->transfer_buffer +
|
||||
state->write_position - 1);
|
||||
|
||||
if (state->null) {
|
||||
for (ptr++;
|
||||
ptr -
|
||||
(char *) state->transfer_buffer -
|
||||
state->write_position < nwritten;
|
||||
ptr++) {
|
||||
if (*ptr == '\0')
|
||||
++lines;
|
||||
}
|
||||
} else {
|
||||
while ((ptr =
|
||||
strchr((char *) (ptr + 1), '\n')))
|
||||
++lines;
|
||||
}
|
||||
|
||||
*lineswritten += lines;
|
||||
state->transfer_buffer[state->write_position +
|
||||
nwritten] = save;
|
||||
}
|
||||
|
||||
state->write_position += nwritten;
|
||||
state->written += nwritten;
|
||||
|
||||
/*
|
||||
* If we're monitoring the output, update our copy of the
|
||||
* last few bytes we've written.
|
||||
*/
|
||||
if (((state->components_used & PV_DISPLAY_OUTPUTBUF) != 0)
|
||||
&& (nwritten > 0)) {
|
||||
long new_portion_length, old_portion_length;
|
||||
|
||||
new_portion_length = nwritten;
|
||||
if (new_portion_length > state->lastoutput_length)
|
||||
new_portion_length =
|
||||
state->lastoutput_length;
|
||||
|
||||
old_portion_length =
|
||||
state->lastoutput_length - new_portion_length;
|
||||
|
||||
/*
|
||||
* Make room for the new portion.
|
||||
*/
|
||||
if (old_portion_length > 0) {
|
||||
memmove(state->lastoutput_buffer,
|
||||
state->lastoutput_buffer +
|
||||
new_portion_length,
|
||||
old_portion_length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the new data in.
|
||||
*/
|
||||
memcpy(state->lastoutput_buffer +
|
||||
old_portion_length,
|
||||
state->transfer_buffer +
|
||||
state->write_position - new_portion_length,
|
||||
new_portion_length);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've written all the data in the buffer, reset the
|
||||
* read pointer to the start, and if the input file is at
|
||||
* EOF, set eof_out as well to indicate that we've written
|
||||
* everything for this input file.
|
||||
*/
|
||||
if (state->write_position >= state->read_position) {
|
||||
state->write_position = 0;
|
||||
state->read_position = 0;
|
||||
if (*eof_in)
|
||||
*eof_out = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reach this point, nwritten<0, so there was an error.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If a write error occurred but it was EINTR or EAGAIN, just wait a
|
||||
* bit and then return zero, since this was a transient error.
|
||||
*/
|
||||
if ((EINTR == errno) || (EAGAIN == errno)) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGPIPE means we've finished. Don't output an error because it's
|
||||
* not really our error to report.
|
||||
*/
|
||||
if (EPIPE == errno) {
|
||||
*eof_in = 1;
|
||||
*eof_out = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv_error(state, "%s: %s", _("write failed"), strerror(errno));
|
||||
state->exit_status |= 16;
|
||||
*eof_out = 1;
|
||||
state->written = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Transfer some data from "fd" to standard output, timing out after 9/100
|
||||
* of a second. If state->rate_limit is >0, and/or "allowed" is >0, only up
|
||||
* to "allowed" bytes can be written. The variables that "eof_in" and
|
||||
* "eof_out" point to are used to flag that we've finished reading and
|
||||
* writing respectively.
|
||||
*
|
||||
* Returns the number of bytes written, or negative on error (in which case
|
||||
* state->exit_status is updated). In line mode, the number of lines written
|
||||
* will be put into *lineswritten.
|
||||
*/
|
||||
long pv_transfer(pvstate_t state, int fd, int *eof_in, int *eof_out,
|
||||
unsigned long long allowed, long *lineswritten)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
int max_fd;
|
||||
int n;
|
||||
|
||||
if (NULL == state)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Reinitialise the error skipping variables if the file descriptor
|
||||
* has changed since the last time we were called.
|
||||
*/
|
||||
if (fd != state->last_read_skip_fd) {
|
||||
state->last_read_skip_fd = fd;
|
||||
state->read_errors_in_a_row = 0;
|
||||
state->read_error_warning_shown = 0;
|
||||
}
|
||||
|
||||
if (NULL == state->transfer_buffer) {
|
||||
state->buffer_size = state->target_buffer_size;
|
||||
state->transfer_buffer =
|
||||
(unsigned char *) malloc(state->buffer_size + 32);
|
||||
if (NULL == state->transfer_buffer) {
|
||||
pv_error(state, "%s: %s",
|
||||
_("buffer allocation failed"),
|
||||
strerror(errno));
|
||||
state->exit_status |= 64;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reallocate the buffer if the buffer size has changed mid-transfer.
|
||||
*/
|
||||
if (state->buffer_size < state->target_buffer_size) {
|
||||
unsigned char *newptr;
|
||||
newptr =
|
||||
realloc(state->transfer_buffer,
|
||||
state->target_buffer_size + 32);
|
||||
if (NULL == newptr) {
|
||||
/*
|
||||
* Reset target if realloc failed so we don't keep
|
||||
* trying to realloc over and over.
|
||||
*/
|
||||
debug("realloc: %s", strerror(errno));
|
||||
state->target_buffer_size = state->buffer_size;
|
||||
} else {
|
||||
debug("%s: %ld", "buffer resized",
|
||||
state->buffer_size);
|
||||
state->transfer_buffer = newptr;
|
||||
state->buffer_size = state->target_buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state->linemode) && (lineswritten != NULL))
|
||||
*lineswritten = 0;
|
||||
|
||||
if ((*eof_in) && (*eof_out))
|
||||
return 0;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 90000;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
|
||||
max_fd = 0;
|
||||
|
||||
/*
|
||||
* If the input file is not at EOF and there's room in the buffer,
|
||||
* look for incoming data from it.
|
||||
*/
|
||||
if ((!(*eof_in)) && (state->read_position < state->buffer_size)) {
|
||||
FD_SET(fd, &readfds);
|
||||
if (fd > max_fd)
|
||||
max_fd = fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out how much we're allowed to write, based on the amount of
|
||||
* data left in the buffer. If rate limiting is active or "allowed"
|
||||
* is >0, then this puts an upper limit on how much we're allowed to
|
||||
* write.
|
||||
*/
|
||||
state->to_write = state->read_position - state->write_position;
|
||||
if ((state->rate_limit > 0) || (allowed > 0)) {
|
||||
if (state->to_write > allowed) {
|
||||
state->to_write = allowed;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we don't think we've finished writing and there's anything
|
||||
* we're allowed to write, look for the stdout becoming writable.
|
||||
*/
|
||||
if ((!(*eof_out)) && (state->to_write > 0)) {
|
||||
FD_SET(STDOUT_FILENO, &writefds);
|
||||
if (STDOUT_FILENO > max_fd)
|
||||
max_fd = STDOUT_FILENO;
|
||||
}
|
||||
|
||||
n = select(max_fd + 1, &readfds, &writefds, NULL, &tv);
|
||||
|
||||
if (n < 0) {
|
||||
/*
|
||||
* Ignore transient errors by returning 0 immediately.
|
||||
*/
|
||||
if (EINTR == errno)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Any other error is a problem and we must report back.
|
||||
*/
|
||||
pv_error(state, "%s: %s: %d: %s",
|
||||
state->current_file,
|
||||
_("select call failed"), n, strerror(errno));
|
||||
|
||||
state->exit_status |= 16;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->written = 0;
|
||||
|
||||
/*
|
||||
* If there is data to read, try to read some in. Return early if
|
||||
* there was a transient read error.
|
||||
*
|
||||
* NB this can update state->written because of splice().
|
||||
*/
|
||||
if (FD_ISSET(fd, &readfds)) {
|
||||
if (pv__transfer_read
|
||||
(state, fd, eof_in, eof_out, allowed,
|
||||
lineswritten) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In line mode, only write up to and including the last newline,
|
||||
* so that we're writing output line-by-line.
|
||||
*/
|
||||
if ((state->to_write > 0) && (state->linemode) && !(state->null)) {
|
||||
/*
|
||||
* Guillaume Marcais: use strrchr to find last \n
|
||||
*/
|
||||
unsigned char save;
|
||||
char *start;
|
||||
char *end;
|
||||
|
||||
save =
|
||||
state->transfer_buffer[state->write_position +
|
||||
state->to_write];
|
||||
state->transfer_buffer[state->write_position +
|
||||
state->to_write] = 0;
|
||||
|
||||
start =
|
||||
(char *) (state->transfer_buffer +
|
||||
state->write_position);
|
||||
end = strrchr(start, '\n');
|
||||
state->transfer_buffer[state->write_position +
|
||||
state->to_write] = save;
|
||||
|
||||
if (end != NULL) {
|
||||
state->to_write = (end - start) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is data to write, and stdout is ready to receive it, and
|
||||
* we didn't use splice() this time, write some data. Return early
|
||||
* if there was a transient write error.
|
||||
*/
|
||||
if (FD_ISSET(STDOUT_FILENO, &writefds)
|
||||
#ifdef HAVE_SPLICE
|
||||
&& (0 == state->splice_used)
|
||||
#endif /* HAVE_SPLICE */
|
||||
&& (state->read_position > state->write_position)
|
||||
&& (state->to_write > 0)) {
|
||||
if (pv__transfer_write
|
||||
(state, fd, eof_in, eof_out, lineswritten) == 0)
|
||||
return 0;
|
||||
}
|
||||
#ifdef MAXIMISE_BUFFER_FILL
|
||||
/*
|
||||
* Rotate the written bytes out of the buffer so that it can be
|
||||
* filled up completely by the next read.
|
||||
*/
|
||||
if (state->write_position > 0) {
|
||||
if (state->write_position < state->read_position) {
|
||||
memmove(state->transfer_buffer,
|
||||
state->transfer_buffer +
|
||||
state->write_position,
|
||||
state->read_position -
|
||||
state->write_position);
|
||||
state->read_position -= state->write_position;
|
||||
state->write_position = 0;
|
||||
} else {
|
||||
state->write_position = 0;
|
||||
state->read_position = 0;
|
||||
}
|
||||
}
|
||||
#endif /* MAXIMISE_BUFFER_FILL */
|
||||
|
||||
return state->written;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Functions for watching file descriptors in other processes.
|
||||
*/
|
||||
|
||||
#include "pv-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <limits.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
|
||||
/*
|
||||
* Fill in the given information structure with the file paths and stat
|
||||
* details of the given file descriptor within the given process (given
|
||||
* within the info structure).
|
||||
*
|
||||
* Returns nonzero on error - error codes are:
|
||||
*
|
||||
* -1 - info or state were NULL
|
||||
* 1 - process does not exist
|
||||
* 2 - readlink on /proc/pid/fd/N failed
|
||||
* 3 - stat or lstat on /proc/pid/fd/N failed
|
||||
* 4 - file descriptor is not opened on a regular file
|
||||
*
|
||||
* If "automatic" is nonzero, then this fd was picked automatically, and so
|
||||
* if it's not readable or not a regular file, no error is displayed and the
|
||||
* function just returns an error code.
|
||||
*/
|
||||
int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, int automatic)
|
||||
{
|
||||
if (NULL == state)
|
||||
return -1;
|
||||
if (NULL == info)
|
||||
return -1;
|
||||
|
||||
if (kill(info->watch_pid, 0) != 0) {
|
||||
if (!automatic)
|
||||
pv_error(state, "%s %u: %s",
|
||||
_("pid"),
|
||||
info->watch_pid, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(info->file_fdinfo, sizeof(info->file_fdinfo) - 1,
|
||||
"/proc/%u/fdinfo/%d", info->watch_pid, info->watch_fd);
|
||||
snprintf(info->file_fd, sizeof(info->file_fd) - 1,
|
||||
"/proc/%u/fd/%d", info->watch_pid, info->watch_fd);
|
||||
|
||||
if (readlink
|
||||
(info->file_fd, info->file_fdpath,
|
||||
sizeof(info->file_fdpath) - 1) < 0) {
|
||||
if (!automatic)
|
||||
pv_error(state, "%s %u: %s %d: %s",
|
||||
_("pid"),
|
||||
info->watch_pid,
|
||||
_("fd"), info->watch_fd, strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!((0 == stat64(info->file_fd, &(info->sb_fd)))
|
||||
&& (0 == lstat64(info->file_fd, &(info->sb_fd_link))))) {
|
||||
if (!automatic)
|
||||
pv_error(state, "%s %u: %s %d: %s: %s",
|
||||
_("pid"),
|
||||
info->watch_pid,
|
||||
_("fd"),
|
||||
info->watch_fd, info->file_fdpath,
|
||||
strerror(errno));
|
||||
return 3;
|
||||
}
|
||||
|
||||
info->size = 0;
|
||||
|
||||
if (S_ISBLK(info->sb_fd.st_mode)) {
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Get the size of block devices by opening
|
||||
* them and seeking to the end.
|
||||
*/
|
||||
fd = open64(info->file_fdpath, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
info->size = lseek64(fd, 0, SEEK_END);
|
||||
close(fd);
|
||||
} else {
|
||||
info->size = 0;
|
||||
}
|
||||
} else if (S_ISREG(info->sb_fd.st_mode)) {
|
||||
if ((info->sb_fd_link.st_mode & S_IWUSR) == 0) {
|
||||
info->size = info->sb_fd.st_size;
|
||||
}
|
||||
} else {
|
||||
if (!automatic)
|
||||
pv_error(state, "%s %u: %s %d: %s: %s",
|
||||
_("pid"),
|
||||
info->watch_pid,
|
||||
_("fd"),
|
||||
info->watch_fd,
|
||||
info->file_fdpath,
|
||||
_("not a regular file or block device"));
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return nonzero if the given file descriptor has changed in some way since
|
||||
* we started looking at it (i.e. changed destination or permissions).
|
||||
*/
|
||||
int pv_watchfd_changed(pvwatchfd_t info)
|
||||
{
|
||||
struct stat64 sb_fd, sb_fd_link;
|
||||
|
||||
if ((0 == stat64(info->file_fd, &sb_fd))
|
||||
&& (0 == lstat64(info->file_fd, &sb_fd_link))) {
|
||||
if ((sb_fd.st_dev != info->sb_fd.st_dev)
|
||||
|| (sb_fd.st_ino != info->sb_fd.st_ino)
|
||||
|| (sb_fd_link.st_mode != info->sb_fd_link.st_mode)
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the current file position of the given file descriptor, or -1 if
|
||||
* the fd has closed or has changed in some way.
|
||||
*/
|
||||
long long pv_watchfd_position(pvwatchfd_t info)
|
||||
{
|
||||
long long position;
|
||||
FILE *fptr;
|
||||
|
||||
if (pv_watchfd_changed(info))
|
||||
return -1;
|
||||
|
||||
fptr = fopen(info->file_fdinfo, "r");
|
||||
if (NULL == fptr)
|
||||
return -1;
|
||||
position = -1;
|
||||
fscanf(fptr, "pos: %llu", &position);
|
||||
fclose(fptr);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Scan the given process and update the arrays with any new file
|
||||
* descriptors.
|
||||
*
|
||||
* 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, pvstate_t pristine,
|
||||
unsigned int watch_pid, int *array_length_ptr,
|
||||
pvwatchfd_t * info_array_ptr,
|
||||
pvstate_t * state_array_ptr, int *fd_to_idx)
|
||||
{
|
||||
char fd_dir[512] = { 0, };
|
||||
DIR *dptr;
|
||||
struct dirent *d;
|
||||
int array_length = 0;
|
||||
struct pvwatchfd_s *info_array = NULL;
|
||||
struct pvstate_s *state_array = NULL;
|
||||
|
||||
snprintf(fd_dir, sizeof(fd_dir) - 1, "/proc/%u/fd", watch_pid);
|
||||
dptr = opendir(fd_dir);
|
||||
if (NULL == dptr)
|
||||
return 1;
|
||||
|
||||
array_length = *array_length_ptr;
|
||||
info_array = *info_array_ptr;
|
||||
state_array = *state_array_ptr;
|
||||
|
||||
while ((d = readdir(dptr)) != NULL) {
|
||||
int fd, check_idx, use_idx, rc;
|
||||
long long position_now;
|
||||
|
||||
fd = -1;
|
||||
if (sscanf(d->d_name, "%d", &fd) != 1)
|
||||
continue;
|
||||
if ((fd < 0) || (fd >= FD_SETSIZE))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Skip if this fd is already known to us.
|
||||
*/
|
||||
if (fd_to_idx[fd] != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if there's an empty slot we can re-use. An empty slot
|
||||
* has a watch_pid of 0.
|
||||
*/
|
||||
use_idx = -1;
|
||||
for (check_idx = 0; check_idx < array_length; check_idx++) {
|
||||
if (info_array[check_idx].watch_pid == 0) {
|
||||
use_idx = check_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's no empty slot, extend the arrays.
|
||||
*/
|
||||
if (use_idx < 0) {
|
||||
struct pvwatchfd_s *new_info_array;
|
||||
struct pvstate_s *new_state_array;
|
||||
|
||||
array_length++;
|
||||
use_idx = array_length - 1;
|
||||
|
||||
if (NULL == info_array) {
|
||||
new_info_array =
|
||||
malloc(array_length *
|
||||
sizeof(*info_array));
|
||||
} else {
|
||||
new_info_array =
|
||||
realloc(info_array,
|
||||
array_length *
|
||||
sizeof(*info_array));
|
||||
}
|
||||
if (NULL == new_info_array)
|
||||
return 2;
|
||||
info_array = new_info_array;
|
||||
*info_array_ptr = info_array;
|
||||
info_array[use_idx].watch_pid = 0;
|
||||
|
||||
if (NULL == state_array) {
|
||||
new_state_array =
|
||||
malloc(array_length *
|
||||
sizeof(*state_array));
|
||||
} else {
|
||||
new_state_array =
|
||||
realloc(state_array,
|
||||
array_length *
|
||||
sizeof(*state_array));
|
||||
}
|
||||
if (NULL == new_state_array)
|
||||
return 2;
|
||||
state_array = new_state_array;
|
||||
*state_array_ptr = state_array;
|
||||
|
||||
*array_length_ptr = array_length;
|
||||
|
||||
for (check_idx = 0; check_idx < array_length;
|
||||
check_idx++) {
|
||||
state_array[check_idx].name =
|
||||
info_array[check_idx].display_name;
|
||||
state_array[check_idx].reparse_display = 1;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s: %d => index %d", "found new fd", fd, use_idx);
|
||||
|
||||
/*
|
||||
* Initialise the details of this new entry.
|
||||
*/
|
||||
memcpy(&(state_array[use_idx]), pristine,
|
||||
sizeof(*pristine));
|
||||
memset(&(info_array[use_idx]), 0,
|
||||
sizeof(info_array[use_idx]));
|
||||
|
||||
info_array[use_idx].watch_pid = watch_pid;
|
||||
info_array[use_idx].watch_fd = fd;
|
||||
rc = pv_watchfd_info(state, &(info_array[use_idx]), 1);
|
||||
|
||||
/*
|
||||
* Lookup failed - mark this slot as being free for re-use.
|
||||
*/
|
||||
if ((rc != 0) && (rc != 4)) {
|
||||
info_array[use_idx].watch_pid = 0;
|
||||
debug("%s %d: %s: %d", "fd", fd,
|
||||
"lookup failed - marking slot for re-use",
|
||||
use_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
fd_to_idx[fd] = use_idx;
|
||||
|
||||
/*
|
||||
* Not displayable - set fd to -1 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;
|
||||
}
|
||||
|
||||
state_array[use_idx].size = info_array[use_idx].size;
|
||||
if (state_array[use_idx].size < 1) {
|
||||
char *fmt;
|
||||
while (NULL !=
|
||||
(fmt =
|
||||
strstr(state_array[use_idx].default_format,
|
||||
"%e"))) {
|
||||
debug("%s", "zero size - removing ETA");
|
||||
/* strlen-1 here to include trailing NUL */
|
||||
memmove(fmt, fmt + 2, strlen(fmt) - 1);
|
||||
state_array[use_idx].reparse_display = 1;
|
||||
}
|
||||
}
|
||||
|
||||
state_array[use_idx].name =
|
||||
info_array[use_idx].display_name;
|
||||
|
||||
pv_watchpid_setname(state, &(info_array[use_idx]));
|
||||
|
||||
state_array[use_idx].reparse_display = 1;
|
||||
|
||||
gettimeofday(&(info_array[use_idx].start_time), NULL);
|
||||
|
||||
state_array[use_idx].initial_offset = 0;
|
||||
info_array[use_idx].position = 0;
|
||||
|
||||
position_now = pv_watchfd_position(&(info_array[use_idx]));
|
||||
if (position_now >= 0) {
|
||||
state_array[use_idx].initial_offset = position_now;
|
||||
info_array[use_idx].position = position_now;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the display name for the given watched file descriptor, truncating at
|
||||
* the relevant places according to the current screen width.
|
||||
*/
|
||||
void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
|
||||
{
|
||||
int path_length, max_display_length;
|
||||
|
||||
memset(info->display_name, 0, sizeof(info->display_name));
|
||||
|
||||
path_length = strlen(info->file_fdpath);
|
||||
|
||||
max_display_length = (state->width / 2) - 6;
|
||||
if (max_display_length >= path_length) {
|
||||
snprintf(info->display_name,
|
||||
sizeof(info->display_name) - 1, "%4d:%s",
|
||||
info->watch_fd, info->file_fdpath);
|
||||
} else {
|
||||
int prefix_length, suffix_length;
|
||||
|
||||
prefix_length = max_display_length / 4;
|
||||
suffix_length = max_display_length - prefix_length - 3;
|
||||
|
||||
snprintf(info->display_name,
|
||||
sizeof(info->display_name) - 1, "%4d:%.*s...%.*s",
|
||||
info->watch_fd, prefix_length, info->file_fdpath,
|
||||
suffix_length,
|
||||
info->file_fdpath + path_length - suffix_length);
|
||||
}
|
||||
|
||||
debug("%s: %d: [%s]", "set name for fd", info->watch_fd,
|
||||
info->display_name);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that data can be just passed straight through.
|
||||
|
||||
VALUE=`echo TESTING | $PROG 2>/dev/null` || exit 1
|
||||
test "$VALUE" = "TESTING"
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the update interval can be set.
|
||||
|
||||
sleep 1 | $PROG -f -i 0.1 >/dev/null 2>$TMP1
|
||||
|
||||
# There should be more than 6 lines of output.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | wc -l | tr -d ' '`
|
||||
test $NUM -gt 6
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# A simple test of rate limiting.
|
||||
|
||||
# Transfer 102 bytes at 100 bytes/sec. It should take at least 1 second.
|
||||
#
|
||||
START=`date +%S`
|
||||
dd if=/dev/zero bs=102 count=1 2>/dev/null | $PROG -L 100 2>/dev/null | cat >/dev/null
|
||||
END=`date +%S`
|
||||
|
||||
test $START -ne $END
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the progress bar moves when data is coming in.
|
||||
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null \
|
||||
| $PROG -f -p -i 0.1 -L 500 >/dev/null 2>$TMP1
|
||||
|
||||
# There should be more than 2 different lines of output.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | sort | uniq -u | wc -l | tr -d ' '`
|
||||
test $NUM -gt 2
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the elapsed time counter does count up.
|
||||
|
||||
# Transfer a zero amount of data, but take 3 seconds to do it.
|
||||
#
|
||||
(sleep 3 | $PROG -f -t >/dev/null) 2>&1 | tr '\r' '\n' > $TMP1
|
||||
|
||||
# Count the number of different timer values; it should be >1.
|
||||
#
|
||||
NUM=`sort < $TMP1 | uniq -u | wc -l | tr -d ' '`
|
||||
test $NUM -gt 1
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the estimated time counter counts.
|
||||
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null \
|
||||
| $PROG -f -e -s 100 -i 0.1 -L 25 >/dev/null 2>$TMP1
|
||||
|
||||
# Count the number of different ETA values there have been.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | tr -d ' ' | sed '/^$/d' | sort | uniq | wc -l | tr -d ' '`
|
||||
|
||||
# 3 or less - not OK, since it should have taken 4 seconds.
|
||||
#
|
||||
test $NUM -gt 3 || exit 1
|
||||
|
||||
# 8 or more - not OK, since even on a heavily loaded system that's too long.
|
||||
#
|
||||
test $NUM -lt 8
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the estimated time counter can show the end time of day.
|
||||
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null \
|
||||
| $PROG -f -I -s 100 -i 0.1 -L 25 >/dev/null 2>$TMP1
|
||||
|
||||
# Count the number of different ETA values there have been.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | tr -d ' ' | sed '/^$/d' | sort | uniq | wc -l | tr -d ' '`
|
||||
|
||||
# There should be at least 1 line of output.
|
||||
#
|
||||
test $NUM -gt 0 || exit 1
|
||||
|
||||
# 8 or more different values - not OK.
|
||||
#
|
||||
test $NUM -lt 8
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the transfer rate counter changes.
|
||||
|
||||
# Transfer 200 bytes as two 100-byte blocks with a 2-second gap between.
|
||||
#
|
||||
(dd if=/dev/zero bs=100 count=1 2>/dev/null;
|
||||
sleep 2;
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null;
|
||||
) | $PROG -f -i 0.5 -r >/dev/null 2>$TMP1
|
||||
|
||||
# Count the number of different rates output.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | sort | uniq -u | wc -l | tr -d ' '`
|
||||
|
||||
# There should be more than 2 different rates counted (around 100 bytes/sec
|
||||
# for the each block, 0 bytes/sec for the gap in the middle, and around 50
|
||||
# bytes/sec for the average time reported at the end).
|
||||
#
|
||||
test $NUM -gt 2
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the byte counter counts.
|
||||
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null \
|
||||
| LANG=C $PROG -f -b >/dev/null 2>$TMP1
|
||||
NUM=`tr '\r' '\n' < $TMP1 | tr -d ' '`
|
||||
test "$NUM" = "100B"
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that numeric output outputs some percentages.
|
||||
|
||||
# Process 100 bytes at 100 bytes per second, updating every 0.1 seconds for
|
||||
# around 10 output lines.
|
||||
#
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null \
|
||||
| $PROG -s 100 -n -i 0.1 -L 100 >/dev/null 2>$TMP1
|
||||
|
||||
# The number of output lines should be >8 and <13, and the final percentage
|
||||
# should be 100.
|
||||
#
|
||||
test `wc -l < $TMP1` -gt 8
|
||||
test `wc -l < $TMP1` -lt 13
|
||||
test `sed -n '$p' < $TMP1` -eq 100
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the -q option shuts everything up.
|
||||
|
||||
dd if=/dev/zero bs=1000 count=5 2>/dev/null \
|
||||
| $PROG -f -q -i 0.1 -L 5000 >/dev/null 2>$TMP1
|
||||
test ! -s $TMP1
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that there is no SIGPIPE or dropped data on bigger data transfers.
|
||||
|
||||
# We nead GNU head. On some platforms it is named ghead instead of head.
|
||||
HEAD=head
|
||||
for p in `echo $PATH | tr ':' '\n'`
|
||||
do
|
||||
if test -x $p/ghead
|
||||
then
|
||||
HEAD=$p/ghead
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Don't use dd. See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=324308
|
||||
COUNT1=100000000
|
||||
#COUNT2=`$PROG -B 100000 -q /dev/zero | $HEAD -c $COUNT1 | wc -c | tr -d ' '`
|
||||
# Remove \n to fix the test on AIX
|
||||
COUNT2=`$PROG -B 100000 -q /dev/zero | $HEAD -c $COUNT1 | tr -d '\n' | wc -c | tr -d ' '`
|
||||
|
||||
#echo "[$COUNT1] [$COUNT2]"
|
||||
|
||||
test "x$COUNT1" = "x$COUNT2"
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Transfer a large chunk of data through pv and check data correctness
|
||||
# afterwards.
|
||||
|
||||
rm -f $TMP1 $TMP2 2>/dev/null
|
||||
|
||||
# exit on non-zero return codes
|
||||
set -e
|
||||
|
||||
# generate some data
|
||||
dd if=/dev/urandom of=$TMP1 bs=1024 count=10240 2>/dev/null
|
||||
|
||||
CKSUM1=`cksum $TMP1 | awk '{print $1}'`
|
||||
|
||||
# read through pv and test afterwards
|
||||
$PROG -B 100000 -q $TMP1 > $TMP2
|
||||
|
||||
CKSUM2=`cksum $TMP2 | awk '{print $1}'`
|
||||
|
||||
test "x$CKSUM1" = "x$CKSUM2"
|
||||
|
||||
# clean up
|
||||
rm -f $TMP1 $TMP2 2>/dev/null
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the average transfer rate counter changes, but not more than it
|
||||
# should.
|
||||
|
||||
# Transfer 210 bytes as 100 bytes, a 1 second gap, 110 bytes, and another 1
|
||||
# second gap.
|
||||
#
|
||||
(dd if=/dev/zero bs=100 count=1 2>/dev/null;
|
||||
sleep 1;
|
||||
dd if=/dev/zero bs=110 count=1 2>/dev/null;
|
||||
sleep 1;
|
||||
) | $PROG -f -i 0.5 -a >/dev/null 2>$TMP1
|
||||
|
||||
# Count the number of rates output that are below 80.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | tr -dc '0-9.\n' | sed '/^$/d' | awk '$1<80{print}' | wc -l | tr -d ' '`
|
||||
|
||||
# Nearly all of the output rates should be above 80 since the average rate
|
||||
# will always be around 100 bytes per second, except for pauses.
|
||||
#
|
||||
test $NUM -lt 2
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that the bytes count doesn't increase the line length as it passes
|
||||
# 1MiB, described here:
|
||||
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=586763
|
||||
|
||||
# Transfer 1500kB of data in a bursty fashion.
|
||||
#
|
||||
(dd if=/dev/zero bs=1k count=999;
|
||||
sleep 1;
|
||||
dd if=/dev/zero bs=1k count=1;
|
||||
sleep 1;
|
||||
dd if=/dev/zero bs=1k count=500;
|
||||
sleep 1;
|
||||
) 2>/dev/null | ($PROG -btef -s 1500k >/dev/null) 2>$TMP1
|
||||
|
||||
# Count how many different line lengths we've seen.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | awk '{x=length($0);if(x>0)print length($0)}' | sort | uniq | wc -l`
|
||||
|
||||
# There should only be one length (not counting 0).
|
||||
#
|
||||
test $NUM -eq 1 || { echo; tr '\r' '\n' < $TMP1; exit 1; }
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Same as test 13 (1mboundary) but for rate, not bytes transferred.
|
||||
|
||||
# Transfer 1500kB of data in a bursty fashion.
|
||||
#
|
||||
(dd if=/dev/zero bs=1k count=999;
|
||||
sleep 1;
|
||||
dd if=/dev/zero bs=1k count=1;
|
||||
sleep 1;
|
||||
dd if=/dev/zero bs=3 count=1;
|
||||
sleep 1;
|
||||
dd if=/dev/zero bs=1k count=500;
|
||||
sleep 1;
|
||||
) 2>/dev/null | ($PROG -rtef -s 1500k >/dev/null) 2>$TMP1
|
||||
|
||||
# Count how many different line lengths we've seen.
|
||||
#
|
||||
NUM=`tr '\r' '\n' < $TMP1 | awk '{x=length($0);if(x>0)print length($0)}' | sort | uniq | wc -l`
|
||||
|
||||
# There should only be one length (not counting 0).
|
||||
#
|
||||
test $NUM -eq 1 || { echo; tr '\r' '\n' < $TMP1; exit 1; }
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Transfer a large chunk of data through pv using pipes, sending it in a
|
||||
# bursty fashion, and check data correctness afterwards.
|
||||
|
||||
rm -f $TMP1 $TMP2 2>/dev/null
|
||||
|
||||
# exit on non-zero return codes
|
||||
set -e
|
||||
|
||||
# generate some data
|
||||
dd if=/dev/urandom of=$TMP1 bs=1024 count=10240 2>/dev/null
|
||||
|
||||
CKSUM1=`cksum $TMP1 | awk '{print $1}'`
|
||||
|
||||
# read through pv and test afterwards
|
||||
(
|
||||
dd if=$TMP1 bs=1 count=9000
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1 skip=9000 count=1240
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1024 skip=10 count=1014
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1024 skip=1024 count=1024
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1024 skip=2048
|
||||
) 2>/dev/null | $PROG -q -L 2M | cat > $TMP2
|
||||
|
||||
CKSUM2=`cksum $TMP2 | awk '{print $1}'`
|
||||
|
||||
test "x$CKSUM1" = "x$CKSUM2"
|
||||
|
||||
# same again but with one less pipe
|
||||
(
|
||||
dd if=$TMP1 bs=1 count=9000
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1 skip=9000 count=1240
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1024 skip=10 count=1014
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1024 skip=1024 count=1024
|
||||
sleep 1
|
||||
dd if=$TMP1 bs=1024 skip=2048
|
||||
) 2>/dev/null | $PROG -q -L 2M > $TMP2
|
||||
|
||||
CKSUM2=`cksum $TMP2 | awk '{print $1}'`
|
||||
|
||||
test "x$CKSUM1" = "x$CKSUM2"
|
||||
|
||||
# clean up
|
||||
rm -f $TMP1 $TMP2 2>/dev/null
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that numeric output gives a timer when used with -t.
|
||||
|
||||
# Process 100 bytes at 100 bytes per second, updating every 0.1 seconds for
|
||||
# around 10 output lines.
|
||||
#
|
||||
dd if=/dev/zero bs=100 count=1 2>/dev/null \
|
||||
| $PROG -s 100 -n -t -i 0.1 -L 100 >/dev/null 2>$TMP1
|
||||
|
||||
# The number of output lines should be >8 and <13, and the number of
|
||||
# different elapsed times should be at least 7. The last percentage should
|
||||
# be 100.
|
||||
#
|
||||
test `wc -l < $TMP1` -gt 8
|
||||
test `wc -l < $TMP1` -lt 13
|
||||
test `tr , . < "$TMP1" | awk '{print int(10*$1)}' | sort -n | uniq | wc -l` -gt 7
|
||||
test `sed -n '$p' < $TMP1 | awk '{print $2}'` -eq 100
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Check that numeric output gives a byte count instead of a percentage when
|
||||
# used with -b.
|
||||
|
||||
# Process 500 bytes at 500 bytes per second, updating every 0.1 seconds for
|
||||
# around 10 output lines.
|
||||
#
|
||||
dd if=/dev/zero bs=500 count=1 2>/dev/null \
|
||||
| $PROG -s 500 -n -b -i 0.1 -L 500 >/dev/null 2>$TMP1
|
||||
|
||||
# The number of output lines should be >8 and <13, and the final byte count
|
||||
# should be 500.
|
||||
#
|
||||
test `wc -l < $TMP1` -gt 8
|
||||
test `wc -l < $TMP1` -lt 13
|
||||
test `sed -n '$p' < $TMP1` -eq 500
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Try changing the format of a transfer remotely.
|
||||
|
||||
# Do nothing if IPC is not supported.
|
||||
if ! $PROG -h | grep -Eq "^ -R,"; then
|
||||
echo "SKIPPED" | tr "\n" ' '
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f $TMP1 $TMP2 $TMP3 $TMP4 2>/dev/null
|
||||
|
||||
# Exit on non-zero return codes.
|
||||
set -e
|
||||
|
||||
# Generate an empty test file.
|
||||
dd if=/dev/zero of=$TMP1 bs=1024 count=10240 2>/dev/null
|
||||
|
||||
(
|
||||
sleep 1
|
||||
$PROG -R `cat $TMP4` -a
|
||||
sleep 2
|
||||
$PROG -R `cat $TMP4` -L 10M
|
||||
) &
|
||||
|
||||
$PROG -L 2M -f -P $TMP4 $TMP1 > $TMP2 2>$TMP3
|
||||
|
||||
# Make sure there is more than one length of line (excluding blank lines).
|
||||
line_lengths=`tr '\r' '\n' < "$TMP3" | awk '{print length($0)}' | grep -Fvx 0 | sort -n | uniq | wc -l`
|
||||
test $line_lengths -gt 1
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Try repeatedly messaging a transfer process, and make sure the data stays
|
||||
# intact.
|
||||
|
||||
# Do nothing if IPC is not supported.
|
||||
if ! $PROG -h | grep -Eq "^ -R,"; then
|
||||
echo "SKIPPED" | tr "\n" ' '
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f $TMP1 $TMP2 $TMP3 $TMP4 2>/dev/null
|
||||
|
||||
# Exit on non-zero return codes.
|
||||
set -e
|
||||
|
||||
# Generate some data.
|
||||
dd if=/dev/urandom of=$TMP1 bs=1024 count=10240 2>/dev/null
|
||||
|
||||
# Run a few remote control commands in the background.
|
||||
#
|
||||
echo FAIL > $TMP3
|
||||
(
|
||||
set +e
|
||||
sleep 2
|
||||
for x in 1 2 3; do
|
||||
$PROG -R `cat $TMP4` -apterb || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
$PROG -R `cat $TMP4` -p || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
$PROG -R `cat $TMP4` -N "test" || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
$PROG -R `cat $TMP4` -F "%e" || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
$PROG -R `cat $TMP4` -N "." || exit 1
|
||||
(usleep 200000 || sleep 1) 2>/dev/null
|
||||
done
|
||||
$PROG -R `cat $TMP4` -L 10M
|
||||
echo OK > $TMP3
|
||||
) &
|
||||
|
||||
# Run our data transfer.
|
||||
$PROG -L 100k -i 0.1 -f -P $TMP4 $TMP1 > $TMP2 2>/dev/null
|
||||
|
||||
# Check our remote control calls ran OK.
|
||||
BGSTATUS=`cat $TMP3`
|
||||
test "x$BGSTATUS" = "xOK"
|
||||
|
||||
# Check data integrity.
|
||||
CKSUM1=`cksum $TMP1 | awk '{print $1}'`
|
||||
CKSUM2=`cksum $TMP2 | awk '{print $1}'`
|
||||
test "x$CKSUM1" = "x$CKSUM2"
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Make sure -S stops at the given size.
|
||||
|
||||
rm -f $TMP1 $TMP2 2>/dev/null
|
||||
|
||||
# exit on non-zero return codes
|
||||
set -e
|
||||
|
||||
# generate some data
|
||||
dd if=/dev/urandom of=$TMP1 bs=1024 count=10 2>/dev/null
|
||||
|
||||
# read through pv and test afterwards
|
||||
$PROG -S -s 5120 -q $TMP1 > $TMP2
|
||||
|
||||
CKSUM2=`cksum $TMP2 | awk '{print $1}'`
|
||||
|
||||
# take the first 5120 bytes of TMP1 and cksum them
|
||||
rm -f $TMP2
|
||||
dd if=$TMP1 of=$TMP2 bs=1024 count=5 2>/dev/null
|
||||
CKSUM1=`cksum $TMP2 | awk '{print $1}'`
|
||||
|
||||
test "x$CKSUM1" = "x$CKSUM2"
|
||||
|
||||
# clean up
|
||||
rm -f $TMP1 $TMP2 2>/dev/null
|
||||
|
||||
# EOF
|
||||
Reference in New Issue
Block a user