├── INSTALL
├── README
├── README.md
├── autoconf
├── Makefile.in
├── configure.in
├── header.in
├── make
│ ├── depend.mk~
│ ├── filelist.mk~
│ ├── link.mk
│ ├── modules.mk~
│ ├── package.mk
│ ├── rules.mk
│ ├── unreal.mk
│ └── vars.mk
└── scripts
│ ├── benchmark.sh
│ ├── depend.sh
│ ├── index.sh
│ ├── install.sh
│ ├── makemake.sh
│ ├── mkinstalldirs
│ ├── po2table.sh
│ └── run-test.sh
├── configure
├── doc
├── COPYING
├── INSTALL
├── NEWS
├── PACKAGE
├── TODO
├── VERSION
├── lsm
├── lsm.in
├── pv.spec
├── quickref.1.in
├── release-checklist
└── spec.in
├── src
├── include
│ ├── library
│ │ ├── getopt.h
│ │ └── gettext.h
│ ├── options.h
│ ├── pv-internal.h
│ └── pv.h
├── library
│ ├── getopt.c
│ └── gettext.c
├── main
│ ├── debug.c
│ ├── help.c
│ ├── main.c
│ ├── options.c
│ ├── remote.c
│ └── version.c
├── nls
│ ├── de.po
│ ├── fr.po
│ ├── pl.po
│ ├── pt.po
│ └── pv.pot
└── pv
│ ├── cursor.c
│ ├── display.c
│ ├── file.c
│ ├── loop.c
│ ├── number.c
│ ├── signal.c
│ ├── state.c
│ ├── transfer.c
│ └── watchpid.c
└── tests
├── 000-cat
├── 001-interval
├── 002-rate
├── 003-progress
├── 004-timer
├── 005-eta
├── 005a-eta
├── 005b-fineta
├── 006-ratecount
├── 007-bytes
├── 008-numeric
├── 009-quiet
├── 010-pipe
├── 011-cksum
├── 012-averagerate
├── 013-1mboundary
├── 014-1mboundary2
├── 015-cksumpipe
├── 016-numeric-timer
├── 017-numeric-bytes
├── 018-remote-format
├── 019-remote-cksum
└── 020-stop-at-size
/INSTALL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/INSTALL
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/README
--------------------------------------------------------------------------------
/autoconf/Makefile.in:
--------------------------------------------------------------------------------
1 | #
2 | # Files from which this is generated (inside directory `autoconf/make'):
3 | #
4 | # package.mk # package name and distribution details
5 | # vars.mk # compilation, shell and linking variables
6 | # filelist.mk~ # lists of files
7 | # unreal.mk # phony targets
8 | # modules.mk~ # module linking rules
9 | # rules.mk # compilation rules
10 | # link.mk # real top-level targets
11 | # depend.mk~ # dependencies
12 | #
13 | #
14 |
15 |
--------------------------------------------------------------------------------
/autoconf/configure.in:
--------------------------------------------------------------------------------
1 | dnl Process this file with autoconf to produce a configure script.
2 |
3 | AC_INIT(src/main/version.c)
4 |
5 | dnl We're using C.
6 | dnl
7 | AC_LANG_C
8 |
9 | dnl Output a header file.
10 | dnl
11 | AC_CONFIG_HEADER(src/include/config.h:autoconf/header.in)
12 |
13 | dnl Set directory to check for Configure scripts in.
14 | dnl
15 | AC_CONFIG_AUX_DIR(autoconf/scripts)
16 |
17 | dnl Read in package details.
18 | dnl
19 | PACKAGE=`cat $srcdir/doc/PACKAGE`
20 | VERSION=`cat $srcdir/doc/VERSION`
21 | UCPACKAGE=`tr a-z A-Z < $srcdir/doc/PACKAGE`
22 | AC_SUBST(PACKAGE)
23 | AC_SUBST(VERSION)
24 | AC_SUBST(UCPACKAGE)
25 | AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
26 | AC_DEFINE_UNQUOTED(PROGRAM_NAME, "$PACKAGE")
27 | AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
28 |
29 | dnl Check for compile-time options.
30 | dnl
31 | AC_ARG_ENABLE(debugging,
32 | [ --enable-debugging compile with debugging support],
33 | if test "$enable_debugging" = "yes"; then
34 | CFLAGS="-g -Wall"
35 | AC_DEFINE(ENABLE_DEBUGGING)
36 | fi
37 | )
38 | AC_ARG_ENABLE(profiling,
39 | [ --enable-profiling compile with profiling support],
40 | if test "$enable_profiling" = "yes"; then
41 | CFLAGS="-pg $CFLAGS"
42 | fi
43 | )
44 | LFS_SUPPORT="no"
45 | AC_ARG_ENABLE(lfs, [ --disable-lfs disable LFS support],
46 | if test "$enable_lfs" = "yes"; then
47 | LFS_SUPPORT="yes"
48 | fi,
49 | LFS_SUPPORT="yes"
50 | )
51 | STATIC_NLS="no"
52 | AC_ARG_ENABLE(static-nls, [ --enable-static-nls hardcode NLS with no support files],
53 | if test "$enable_static_nls" = "yes"; then
54 | STATIC_NLS="yes"
55 | fi,
56 | STATIC_NLS="no"
57 | )
58 | NLS_SUPPORT="no"
59 | AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support],
60 | if test "$enable_nls" = "yes"; then
61 | NLS_SUPPORT="yes"
62 | fi,
63 | NLS_SUPPORT="yes"
64 | )
65 | SPLICE_SUPPORT="no"
66 | AC_ARG_ENABLE(splice, [ --disable-splice do not use splice system call],
67 | if test "$enable_splice" = "yes"; then
68 | SPLICE_SUPPORT="yes"
69 | fi,
70 | SPLICE_SUPPORT="yes"
71 | )
72 | IPC_SUPPORT="no"
73 | AC_ARG_ENABLE(ipc, [ --disable-ipc turn off IPC messaging],
74 | if test "$enable_ipc" = "yes"; then
75 | IPC_SUPPORT="yes"
76 | fi,
77 | IPC_SUPPORT="yes"
78 | )
79 |
80 | dnl Check for various programs.
81 | dnl
82 | CFLAGS=${CFLAGS:-"-O"}
83 | AC_PROG_CC
84 | AC_PROG_INSTALL
85 | AC_PROG_MAKE_SET
86 |
87 | dnl AIX needs -lc128
88 | dnl
89 | AC_EGREP_CPP([yes], [#ifdef _AIX
90 | yes
91 | #endif
92 | ], [LIBS="$LIBS -lc128"])
93 |
94 | dnl NLS stuff.
95 | dnl
96 | ALL_LINGUAS="de fr pl pt"
97 | if test "$NLS_SUPPORT" = "yes"; then
98 | AC_DEFINE(ENABLE_NLS)
99 | AC_PATH_PROG(MSGFMT, msgfmt, NOMSGFMT)
100 | AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
101 | AC_PATH_PROG(XGETTEXT, xgettext, xgettext)
102 | if test "x$MSGFMT" = "xNOMSGFMT"; then
103 | MSGFMT=""
104 | STATIC_NLS="yes"
105 | fi
106 | if test "$STATIC_NLS" = "yes"; then
107 | CATALOGS=""
108 | NLSOBJ="src/nls/table.o"
109 | else
110 | AC_CHECK_LIB(intl, main)
111 | AC_CHECK_LIB(i, main)
112 | fi
113 | CATOBJEXT=.mo
114 | INSTOBJEXT=.mo
115 | for lang in $ALL_LINGUAS; do
116 | GMOFILES="$GMOFILES $lang.gmo"
117 | POFILES="$POFILES \$(srcdir)/src/nls/$lang.po"
118 | CATALOGS="$CATALOGS src/nls/$lang$CATOBJEXT";
119 | done
120 | if test "$STATIC_NLS" = "yes"; then
121 | CATALOGS=""
122 | else
123 | AC_CHECK_FUNC(gettext,
124 | [AC_DEFINE(HAVE_GETTEXT)
125 | NLSOBJ=""
126 | ], [CATALOGS=""; NLSOBJ="src/nls/table.o"
127 | ]
128 | )
129 | fi
130 | fi
131 | AC_CHECK_HEADERS(libintl.h)
132 | AC_CHECK_HEADERS(locale.h)
133 | AC_SUBST(MSGFMT)
134 | AC_SUBST(GMSGFMT)
135 | AC_SUBST(XGETTEXT)
136 | AC_SUBST(CATOBJEXT)
137 | AC_SUBST(INSTOBJEXT)
138 | AC_SUBST(GMOFILES)
139 | AC_SUBST(POFILES)
140 | AC_SUBST(CATALOGS)
141 | AC_SUBST(NLSOBJ)
142 |
143 | dnl Getopt checks.
144 | dnl
145 | AC_CHECK_FUNCS(getopt_long getopt)
146 | AC_CHECK_HEADERS(getopt.h)
147 |
148 | dnl LFS checks.
149 | dnl
150 | if test "$LFS_SUPPORT" = "yes"; then
151 | AC_CHECK_FUNCS(open64, AC_DEFINE(ENABLE_LARGEFILE))
152 | fi
153 |
154 | dnl Check for various header files and set various other macros.
155 | dnl
156 | AC_DEFINE(HAVE_CONFIG_H)
157 | AC_HEADER_STDC
158 | AC_CHECK_FUNCS(memcpy basename snprintf stat64)
159 | AC_CHECK_HEADERS(limits.h)
160 |
161 | if test "$IPC_SUPPORT" = "yes"; then
162 | AC_CHECK_HEADERS(sys/ipc.h sys/param.h libgen.h)
163 | fi
164 |
165 | if test "$SPLICE_SUPPORT" = "yes"; then
166 | AC_CHECK_FUNCS(splice)
167 | fi
168 |
169 | test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
170 | AC_SUBST(INSTALL_DATA)
171 |
172 | dnl Fudging for separate build directories.
173 | dnl
174 | subdirs=""
175 | for i in `find $srcdir/src -type d -print | sed s,$srcdir/,,`; do
176 | subdirs="$subdirs $i"
177 | done
178 |
179 | dnl Stitch together the Makefile fragments.
180 | dnl
181 | mk_segments="autoconf/Makefile.in"
182 | for i in vars.mk package.mk filelist.mk~ unreal.mk modules.mk~ \
183 | rules.mk link.mk depend.mk~; do
184 | mk_segments="$mk_segments:autoconf/make/$i"
185 | done
186 |
187 | dnl Output files (and create build directory structure too).
188 | dnl
189 | AC_OUTPUT(Makefile:$mk_segments doc/lsm:doc/lsm.in
190 | doc/quickref.1:doc/quickref.1.in
191 | doc/$PACKAGE.spec:doc/spec.in
192 | src/.dummy:doc/NEWS,
193 | rm -f src/.dummy
194 | for i in $subdirs; do
195 | test -d $i || mkdir $i
196 | done
197 | , subdirs="$subdirs")
198 |
199 | dnl EOF
200 |
--------------------------------------------------------------------------------
/autoconf/header.in:
--------------------------------------------------------------------------------
1 | /*!NOINDEX*/
2 | /* Define if you have standard C headers. */
3 | #undef STDC_HEADERS
4 |
5 | /* Define if you have "config.h" (yes, you have). */
6 | #undef HAVE_CONFIG_H
7 |
8 | /* Various other header files. */
9 | #undef HAVE_GETOPT_H
10 | #undef HAVE_LIMITS_H
11 | #undef HAVE_SYS_IPC_H
12 | #undef HAVE_SYS_PARAM_H
13 | #undef HAVE_LIBGEN_H
14 |
15 | /* Functions. */
16 | #undef HAVE_GETOPT
17 | #undef HAVE_GETOPT_LONG
18 | #undef HAVE_MEMCPY
19 | #undef HAVE_BASENAME
20 | #undef HAVE_SNPRINTF
21 | #undef HAVE_STAT64
22 |
23 | #undef HAVE_SPLICE
24 | #ifdef HAVE_SPLICE
25 | # define _GNU_SOURCE 1
26 | #endif
27 | /* NB the above must come before NLS, as NLS includes other system headers. */
28 |
29 | /* NLS stuff. */
30 | #undef ENABLE_NLS
31 | #undef HAVE_LIBINTL_H
32 | #undef HAVE_LOCALE_H
33 | #undef HAVE_GETTEXT
34 | #ifdef ENABLE_NLS
35 | # include "library/gettext.h"
36 | #else
37 | # define _(String) (String)
38 | # define N_(String) (String)
39 | #endif
40 |
41 | /* The name of the program. */
42 | #define PROGRAM_NAME "progname"
43 |
44 | /* The name of the package. */
45 | #define PACKAGE ""
46 |
47 | /* The current package version. */
48 | #define VERSION "0.0.0"
49 |
50 | /* Various identification and legal stuff. */
51 | #define COPYRIGHT_YEAR _("2015")
52 | #define COPYRIGHT_HOLDER _("Andrew Wood ")
53 | #define PROJECT_HOMEPAGE "http://www.ivarch.com/programs/" PROGRAM_NAME ".shtml"
54 | #define BUG_REPORTS_TO _("")
55 |
56 | /* LFS support. */
57 | #undef ENABLE_LARGEFILE
58 | #ifdef ENABLE_LARGEFILE
59 | # define __USE_LARGEFILE64 1
60 | # define _LARGEFILE64_SOURCE 1
61 | #else
62 | /*
63 | * Some Macs have stat64 despite not having open64 while others don't have
64 | * either, so here even if we don't have open64 or LFS is disabled, we have
65 | * to check whether stat64 exists and only redefine it if it doesn't
66 | * otherwise some Macs fail to compile.
67 | */
68 | # ifdef __APPLE__
69 | # ifndef HAVE_STAT64
70 | # define stat64 stat
71 | # define fstat64 fstat
72 | # define lstat64 lstat
73 | # endif
74 | # elif (defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))
75 | # else
76 | # define stat64 stat
77 | # define fstat64 fstat
78 | # define lstat64 lstat
79 | # endif
80 | # define open64 open
81 | # define lseek64 lseek
82 | #endif
83 |
84 | #undef HAVE_IPC
85 | #ifdef HAVE_SYS_IPC_H
86 | #define HAVE_IPC 1
87 | #endif
88 |
89 | #undef CURSOR_ANSWERBACK_BYTE_BY_BYTE
90 | #ifndef _AIX
91 | #define CURSOR_ANSWERBACK_BYTE_BY_BYTE 1
92 | #endif
93 |
94 | /* Support for debugging output. */
95 | #undef ENABLE_DEBUGGING
96 |
97 | /* EOF */
98 |
--------------------------------------------------------------------------------
/autoconf/make/depend.mk~:
--------------------------------------------------------------------------------
1 | #
2 | # Dependencies.
3 | #
4 |
5 | src/library/getopt.d src/library/getopt.o: src/library/getopt.c src/include/config.h src/include/library/gettext.h
6 | src/library/gettext.d src/library/gettext.o: src/library/gettext.c src/include/config.h src/include/library/gettext.h
7 | 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
8 | 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
9 | 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
10 | 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
11 | 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
12 | 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
13 | 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
14 | 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
15 | 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
16 | src/main/version.d src/main/version.o: src/main/version.c src/include/config.h src/include/library/gettext.h
17 | 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
18 | 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
19 | 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
20 | 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
21 | src/main/help.d src/main/help.o: src/main/help.c src/include/config.h src/include/library/gettext.h
22 |
--------------------------------------------------------------------------------
/autoconf/make/filelist.mk~:
--------------------------------------------------------------------------------
1 | # Automatically generated file listings
2 | #
3 | # Creation time: Fri Jun 30 22:23:37 BST 2017
4 |
5 | allsrc = src/library/getopt.c \
6 | src/library/gettext.c \
7 | src/pv/signal.c \
8 | src/pv/watchpid.c \
9 | src/pv/cursor.c \
10 | src/pv/file.c \
11 | src/pv/display.c \
12 | src/pv/loop.c \
13 | src/pv/number.c \
14 | src/pv/transfer.c \
15 | src/pv/state.c \
16 | src/main/version.c \
17 | src/main/debug.c \
18 | src/main/main.c \
19 | src/main/options.c \
20 | src/main/remote.c \
21 | src/main/help.c
22 |
23 | allobj = src/library/getopt.o \
24 | src/library/gettext.o \
25 | src/pv/signal.o \
26 | src/pv/watchpid.o \
27 | src/pv/cursor.o \
28 | src/pv/file.o \
29 | src/pv/display.o \
30 | src/pv/loop.o \
31 | src/pv/number.o \
32 | src/pv/transfer.o \
33 | src/pv/state.o \
34 | src/main/version.o \
35 | src/main/debug.o \
36 | src/main/main.o \
37 | src/main/options.o \
38 | src/main/remote.o \
39 | src/main/help.o \
40 | src/library.o \
41 | src/pv.o \
42 | src/nls.o \
43 | src/main.o
44 |
45 | alldep = src/library/getopt.d \
46 | src/library/gettext.d \
47 | src/pv/signal.d \
48 | src/pv/watchpid.d \
49 | src/pv/cursor.d \
50 | src/pv/file.d \
51 | src/pv/display.d \
52 | src/pv/loop.d \
53 | src/pv/number.d \
54 | src/pv/transfer.d \
55 | src/pv/state.d \
56 | src/main/version.d \
57 | src/main/debug.d \
58 | src/main/main.d \
59 | src/main/options.d \
60 | src/main/remote.d \
61 | src/main/help.d
62 |
63 |
--------------------------------------------------------------------------------
/autoconf/make/link.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Targets.
3 | #
4 |
5 | $(package): src/main.o src/library.o src/pv.o @NLSOBJ@
6 | $(CC) $(LINKFLAGS) $(CFLAGS) -o $@ src/main.o src/library.o src/pv.o @NLSOBJ@ $(LIBS)
7 |
8 | $(package)-static: src/main.o src/library.o src/pv.o @NLSOBJ@
9 | $(CC) $(LINKFLAGS) $(CFLAGS) -static -o $@ src/main.o src/library.o src/pv.o @NLSOBJ@ $(LIBS)
10 |
11 | # EOF
12 |
--------------------------------------------------------------------------------
/autoconf/make/modules.mk~:
--------------------------------------------------------------------------------
1 | # Automatically generated module linking rules
2 | #
3 | # Creation time: Fri Jun 30 22:23:37 BST 2017
4 |
5 | src/library.o: src/library/getopt.o src/library/gettext.o
6 | $(LD) $(LDFLAGS) -o $@ src/library/getopt.o src/library/gettext.o
7 |
8 | 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
9 | $(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
10 |
11 | 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
12 | $(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
13 |
14 |
15 |
--------------------------------------------------------------------------------
/autoconf/make/package.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Package name, version, and distribution files.
3 | #
4 |
5 | package = @PACKAGE@
6 | version = @VERSION@
7 | PACKAGE = @PACKAGE@
8 |
9 | distfiles = \
10 | $(srcdir)/README \
11 | $(srcdir)/autoconf \
12 | $(srcdir)/configure \
13 | $(srcdir)/doc \
14 | $(srcdir)/src \
15 | $(srcdir)/tests
16 |
17 | # EOF
18 |
--------------------------------------------------------------------------------
/autoconf/make/rules.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Compilation rules.
3 | #
4 |
5 | .SUFFIXES: .c .d .o
6 |
7 | .c.o:
8 | $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
9 |
10 | .c.d:
11 | sh $(srcdir)/autoconf/scripts/depend.sh \
12 | $(CC) $< $(<:%.c=%) $(srcdir) $(CFLAGS) $(CPPFLAGS) > $@
13 |
14 | #
15 | # NLS stuff
16 | #
17 |
18 | %.mo: %.po
19 | $(MSGFMT) -o $@ $<
20 | @touch $@
21 | @chmod 644 $@
22 |
23 | %.gmo: %.po
24 | rm -f $@
25 | $(GMSGFMT) -o $@ $<
26 | @touch $@
27 | @chmod 644 $@
28 |
29 | $(srcdir)/src/nls/$(PACKAGE).pot: $(allsrc)
30 | $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(srcdir) \
31 | --add-comments --keyword=_ --keyword=N_ \
32 | $(allsrc)
33 | if cmp -s $(PACKAGE).po $@; then \
34 | rm -f $(PACKAGE).po; \
35 | else \
36 | rm -f $@; \
37 | mv $(PACKAGE).po $@; \
38 | chmod 644 $@; \
39 | fi
40 |
41 | src/nls/table.c: $(POFILES)
42 | sh $(srcdir)/autoconf/scripts/po2table.sh $(POFILES) > src/nls/table.c
43 |
44 |
--------------------------------------------------------------------------------
/autoconf/make/unreal.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Rules for all phony targets.
3 | #
4 |
5 | .PHONY: all help make dep depend test check \
6 | clean depclean indentclean distclean cvsclean svnclean \
7 | index manhtml indent update-po \
8 | doc dist release \
9 | install uninstall \
10 | rpm srpm
11 |
12 | all: $(alltarg) $(CATALOGS)
13 |
14 | help:
15 | @echo 'This Makefile has the following utility targets:'
16 | @echo
17 | @echo ' all build all binary targets'
18 | @echo ' install install compiled package and manual'
19 | @echo ' uninstall uninstall the package'
20 | @echo ' check / test run standardised tests on the compiled binary'
21 | @echo
22 | @echo 'Developer targets:'
23 | @echo
24 | @echo ' make rebuild the Makefile (after adding new files)'
25 | @echo ' dep / depend rebuild .d (dependency) files'
26 | @echo ' clean remove .o (object) and .c~ (backup) files'
27 | @echo ' depclean remove .d (dependency) files'
28 | @echo ' indentclean remove files left over from "make indent"'
29 | @echo ' distclean remove everything not distributed'
30 | @echo ' cvsclean remove everything not in CVS/SVN'
31 | @echo
32 | @echo ' index generate an HTML index of source code'
33 | @echo ' manhtml output HTML man page to stdout'
34 | @echo ' indent reformat all source files with "indent"'
35 | @echo ' update-po update the .po files'
36 | @echo
37 | @echo ' dist create a source tarball for distribution'
38 | @echo ' rpm build a binary RPM (passes $$RPMFLAGS to RPM)'
39 | @echo ' srpm build a source RPM (passes $$RPMFLAGS to RPM)'
40 | @echo ' release dist+rpm+srpm'
41 | @echo
42 |
43 | make:
44 | echo > $(srcdir)/autoconf/make/filelist.mk~
45 | echo > $(srcdir)/autoconf/make/modules.mk~
46 | cd $(srcdir); \
47 | bash autoconf/scripts/makemake.sh \
48 | autoconf/make/filelist.mk~ \
49 | autoconf/make/modules.mk~
50 | sh ./config.status
51 |
52 | dep depend: $(alldep)
53 | echo '#' > $(srcdir)/autoconf/make/depend.mk~
54 | echo '# Dependencies.' >> $(srcdir)/autoconf/make/depend.mk~
55 | echo '#' >> $(srcdir)/autoconf/make/depend.mk~
56 | echo >> $(srcdir)/autoconf/make/depend.mk~
57 | cat $(alldep) >> $(srcdir)/autoconf/make/depend.mk~
58 | sh ./config.status
59 |
60 | clean:
61 | rm -f $(allobj)
62 |
63 | depclean:
64 | rm -f $(alldep)
65 |
66 | indentclean:
67 | cd $(srcdir) && for FILE in $(allsrc); do rm -f ./$${FILE}~; done
68 |
69 | update-po: $(srcdir)/src/nls/$(PACKAGE).pot
70 | catalogs='$(CATALOGS)'; \
71 | for cat in $$catalogs; do \
72 | lang=$(srcdir)/`echo $$cat | sed 's/$(CATOBJEXT)$$//'`; \
73 | mv $$lang.po $$lang.old.po; \
74 | if $(MSGMERGE) $$lang.old.po $(srcdir)/src/nls/$(PACKAGE).pot > $$lang.po; then \
75 | rm -f $$lang.old.po; \
76 | else \
77 | echo "msgmerge for $$cat failed!"; \
78 | rm -f $$lang.po; \
79 | mv $$lang.old.po $$lang.po; \
80 | chmod 644 $$lang.po; \
81 | fi; \
82 | done
83 |
84 | distclean: clean depclean
85 | rm -f $(alltarg) src/include/config.h
86 | rm -rf $(package)-$(version).tar* $(package)-$(version) $(package)-$(version)-*.rpm
87 | rm -f *.html config.*
88 | rm Makefile
89 |
90 | cvsclean svnclean: distclean
91 | rm -f doc/lsm
92 | rm -f doc/$(package).spec
93 | rm -f doc/quickref.1
94 | rm -f configure
95 | rm -f src/nls/*.gmo src/nls/*.mo
96 | echo > $(srcdir)/autoconf/make/depend.mk~
97 | echo > $(srcdir)/autoconf/make/filelist.mk~
98 | echo > $(srcdir)/autoconf/make/modules.mk~
99 |
100 | doc:
101 | :
102 |
103 | index:
104 | (cd $(srcdir); sh autoconf/scripts/index.sh $(srcdir)) > index.html
105 |
106 | manhtml:
107 | @man2html ./doc/quickref.1 \
108 | | sed -e '1,/]*> ||ig' \
110 | -e 's|]*>\([^<]*\)|\1|ig' \
111 | -e '/\)|\1
|ig' \
112 | -e 's/
//ig' \
113 | -e 's/<[0-9A-Za-z_.-]\+@[0-9A-Za-z_.-]\+>//g' \
114 | -e 's|\(http://.*\)|\1|ig' \
115 | | sed -e '1,/
Index/,/
$(package)-$(version).tar.bz2
198 | -grep -Fq '%_gpg_name' ~/.rpmmacros 2>/dev/null && rpm --addsign *.rpm
199 | -gpg --list-secret-keys 2>&1 | grep -Fq 'uid' && gpg -ab *.tar.gz && rename .asc .txt *.tar.gz.asc
200 | -gpg --list-secret-keys 2>&1 | grep -Fq 'uid' && gpg -ab *.tar.bz2 && rename .asc .txt *.tar.bz2.asc
201 | chmod 644 $(package)-$(version)*
202 |
--------------------------------------------------------------------------------
/autoconf/make/vars.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Variables for Make.
3 | #
4 |
5 | srcdir = @srcdir@
6 |
7 | prefix = @prefix@
8 | exec_prefix = @exec_prefix@
9 | bindir = @bindir@
10 | infodir = @infodir@
11 | mandir = @mandir@
12 | etcdir = @prefix@/etc
13 | datadir = @datadir@
14 | sbindir = @sbindir@
15 |
16 | VPATH = $(srcdir)
17 |
18 | localedir = $(datadir)/locale
19 | gnulocaledir = $(prefix)/share/locale
20 |
21 | CATALOGS = @CATALOGS@
22 | POFILES = @POFILES@
23 | GMSGFMT = @GMSGFMT@
24 | MSGFMT = @MSGFMT@
25 | XGETTEXT = @XGETTEXT@
26 | MSGMERGE = msgmerge
27 | CATOBJEXT = @CATOBJEXT@
28 | INSTOBJEXT = @INSTOBJEXT@
29 |
30 | @SET_MAKE@
31 | SHELL = /bin/sh
32 | CC = @CC@
33 | INSTALL = @INSTALL@
34 | INSTALL_DATA = @INSTALL_DATA@
35 | UNINSTALL = rm -f
36 |
37 | LDFLAGS = -r
38 | LINKFLAGS = @LDFLAGS@
39 | DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\"
40 | CFLAGS = @CFLAGS@
41 | CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/src/include -Isrc/include $(DEFS)
42 | LIBS = @LIBS@
43 |
44 | alltarg = @PACKAGE@
45 |
46 | # EOF
47 |
--------------------------------------------------------------------------------
/autoconf/scripts/benchmark.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Benchmark the read/write performance of pv by looking at the number of
4 | # read() and write() calls and the average amount of data transferred each
5 | # time, as suggested by Ville Herva .
6 | #
7 |
8 | test_input=`mktemp /tmp/pvbench1XXXXXX`
9 | strace_output=`mktemp /tmp/pvbench2XXXXXX`
10 |
11 | trap "rm -f ${test_input} ${strace_output}" 0
12 |
13 | pv=${pv:-./pv}
14 | test -x ${pv} || pv=pv
15 |
16 | dd if=/dev/zero of=${test_input} bs=1k count=1k >/dev/null 2>&1
17 |
18 | echo -e "Buf(k)\tRate(k)\tReads\tRsize\tWrites\tWsize"
19 |
20 | for ((buffer=100; buffer<=1000; buffer+=100)); do
21 | for ((rate=0; rate<=1000; rate+=100)); do
22 | rateparm="-L ${rate}k"
23 | test ${rate} -eq 0 && rateparm=""
24 | strace -tt -o ${strace_output} \
25 | ${pv} ${rateparm} -B ${buffer}k \
26 | -f < ${test_input} > /dev/null 2>&1
27 | rdata=$(
28 | awk '$2~/^read\(0,/{c++;t+=$NF}END{print c "\t" t/c}' \
29 | ${strace_output}
30 | )
31 | wdata=$(
32 | awk '$2~/^write\(1,/{c++;t+=$NF}END{print c "\t" t/c}' \
33 | ${strace_output}
34 | )
35 | echo -e "${buffer}\t${rate}\t${rdata}\t${wdata}"
36 | done
37 | done
38 |
39 | # EOF
40 |
--------------------------------------------------------------------------------
/autoconf/scripts/depend.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Generate dependencies for a C source file.
4 | #
5 |
6 | CC=$1
7 | shift
8 | file=$1
9 | shift
10 | stem=$1
11 | shift
12 | srcdir=$1
13 | abssrc=`echo $srcdir | sed ':1
14 | s,^\./,,g
15 | t1'`
16 | shift
17 |
18 | abssrc=`echo "$abssrc" | sed 's,\\.,\\\\.,g'`
19 | srcdir=`echo "$srcdir" | sed 's,\\.,\\\\.,g'`
20 |
21 | $CC -M -MG $* $file \
22 | | sed -e 's, /[^ ]*,,g' -e "s,^.*\.o:,${stem}.d ${stem}.o:," \
23 | -e '/^ \\$/d' -e 's/ \\$//' \
24 | -e 's,'"$srcdir"'/,,g' -e 's,'"$abssrc"'/,,g' \
25 | | tr '\n' ' ' \
26 | | tr -s ' '
27 |
28 | echo
29 |
30 | # EOF
31 |
--------------------------------------------------------------------------------
/autoconf/scripts/index.sh:
--------------------------------------------------------------------------------
1 | #!/bin/ash
2 | #
3 | # Script to generate an HTML index of all C code from the current directory
4 | # downwards (skipping directories ending in ~). The header comment in each
5 | # file is listed, and each function's prototype and comment are given. A
6 | # list of "TODO:" comments is also generated.
7 | #
8 | # Outputs the HTML on standard output.
9 | #
10 | # If a parameter is given, it is the prefix to put before any "view file"
11 | # links, eg ".." to link to "../dir/file.c" instead of "dir/file.c".
12 | #
13 | # Skips any files containing the string !NOINDEX.
14 | #
15 | # Requires ctags and cproto.
16 | #
17 |
18 | OFFS=$1
19 |
20 |
21 | # Convert the given string to HTML-escaped values (<, >, & escaped) on
22 | # stdout.
23 | #
24 | html_safe () {
25 | echo "$*" \
26 | | sed -e 's|&|\&|g;s|<|\<|g;s|>|\>|g'
27 | }
28 |
29 |
30 | # Convert the given string to HTML-escaped values (<, >, & escaped) on
31 | # stdout, also adding a
to the end of each line.
32 | #
33 | html_safebr () {
34 | echo "$*" \
35 | | sed -e 's|&|\&|g;s|<|\<|g;s|>|\>|g;s/$/
/'
36 | }
37 |
38 | ALLFILES=`find . -name '*~' -prune -o -type f -name '*.c' \
39 | -exec grep -FL '!NOINDEX' /dev/null '{}' ';'`
40 |
41 | CTAGDATA=`echo "$ALLFILES" \
42 | | ctags -nRf- -L- --c-types=f \
43 | | sed 's/ .\// /;s/;" .*$//'`
44 |
45 | FILELIST=`echo "$CTAGDATA" | cut -d ' ' -f 2 | sort | uniq`
46 |
47 | echo ''
48 | echo 'Source Code Index'
49 | echo ''
50 | echo ''
51 | echo '
'
56 |
57 | echo ''
58 | echo ''
59 | echo "$FILELIST" \
60 | | sed -e \
61 | 's|^.*$|\0
|'
62 | echo '
'
63 |
64 | for FILE in $FILELIST; do
65 |
66 | DIR=`dirname $FILE`
67 | FUNCDEFS=`cproto -f1 -I. -Isrc/include -I$DIR $FILE 2>/dev/null \
68 | | sed -n 's/^.*[ *]\([^ *(]*\)(.*$/\1/p'`
69 | FILEHEAD="`sed -n -e \
70 | '1,/\*\//{/\/\*/,/\*\//{s/^[\/ *]//;s/^\*[\/]*//;p;};}' \
71 | < $FILE`"
72 | FILESHORTDESC=`echo "$FILEHEAD" | sed -n '1,/^ *$/{/^ *[^ ]*/p;}'`
73 | FILELONGDESC=`echo "$FILEHEAD" | sed '1,/^ *$/d'`
74 |
75 | echo '
'
76 | echo ''
77 | echo ''
78 | echo ''"$FILE"' | '
79 | echo ' - | '
80 | echo ''`html_safe "$FILESHORTDESC"`' | '
81 | echo '
'
82 | echo '[View File]
'
83 | echo ''
84 | echo "`html_safebr "$FILELONGDESC"`"
85 | echo '
'
86 |
87 | if [ -n "$FUNCDEFS" ]; then
88 | echo 'Functions defined:
'
89 | echo ''
90 | echo "$FUNCDEFS" \
91 | | sed 's|^.*$|\0|' \
92 | | sed 's/^//;s|$|
|'
93 | echo '
'
94 | fi
95 |
96 | echo '['
97 | echo 'Top |'
98 | echo 'To Do |'
99 | echo 'Functions ]
'
100 | done
101 |
102 | echo ''
103 | echo ''
104 | echo "$CTAGDATA" | while read FUNC FILE LINENUM REST; do
105 | echo -n ''
106 | echo -n ''"$FUNC"'
'
107 | echo '['"$FILE"'
] '
108 | done
109 | echo '
'
110 |
111 | echo "$CTAGDATA" | while read FUNC FILE LINENUM REST; do
112 |
113 | FUNCDEF=`sed -n "$LINENUM,/{/p" < $FILE \
114 | | tr '\n' ' ' \
115 | | tr -d '{'`
116 |
117 | LASTCOMLINE=`sed -n '1,'"$LINENUM"'{/\/\*/=;}' < $FILE | sed -n '$p'`
118 | [ -z "$LASTCOMLINE" ] && LASTCOMLINE=1
119 | LASTENDFUNCLINE=`sed -n '1,'"$LINENUM"'{/}/=;}' < $FILE | sed -n '$p'`
120 | [ -z "$LASTENDFUNCLINE" ] && LASTENDFUNCLINE=1
121 | FUNCHEAD="`sed -n -e \
122 | "$LASTCOMLINE,"'/\*\//{h;s/^[\/ *]//;s/^\*[\/]*//;p;x;/\*\//q;}' \
123 | < $FILE`"
124 | [ "$LASTCOMLINE" -le "$LASTENDFUNCLINE" ] && FUNCHEAD=""
125 |
126 | echo '
'
127 | echo ''
128 | echo -n ''
129 | echo -n "$FUNC"'
'
130 | echo -n '['
131 | echo "$FILE"'
]'
132 | echo '
'
133 |
134 | echo ''"`html_safe "$FUNCDEF"`"'
'
135 |
136 | echo ''
137 | echo "`html_safebr "$FUNCHEAD"`"
138 | echo '
'
139 |
140 | echo '['
141 | echo 'Top |'
142 | echo 'To Do |'
143 | echo 'Files ]
'
144 | done
145 |
146 | echo ''
147 | echo ''
148 | for FILE in $FILELIST; do
149 |
150 | TODOLINES=`sed -n \
151 | -e '/\/\*.*\*\//!{/\/\*/,/\*\//{/TODO:/{=;};};}' \
152 | -e '/\/\*.*\*\//{/TODO:/{=;};}' \
153 | < $FILE`
154 |
155 | [ -z "$TODOLINES" ] && continue
156 |
157 | echo -n ''
158 | echo ''"$FILE"'
'
159 | echo ''
160 |
161 | for NUM in $TODOLINES; do
162 | TODO=`sed -n "$NUM"'{s/^.*TODO://;s/\*\/.*$//;p;}' < $FILE`
163 | echo "- [$NUM] `html_safe "$TODO"`
"
164 | done
165 |
166 | echo '
'
167 | done
168 |
169 | echo ''
170 |
171 | # EOF
172 |
--------------------------------------------------------------------------------
/autoconf/scripts/install.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | #
3 | # install - install a program, script, or datafile
4 | # This comes from X11R5 (mit/util/scripts/install.sh).
5 | #
6 | # Copyright 1991 by the Massachusetts Institute of Technology
7 | #
8 | # Permission to use, copy, modify, distribute, and sell this software and its
9 | # documentation for any purpose is hereby granted without fee, provided that
10 | # the above copyright notice appear in all copies and that both that
11 | # copyright notice and this permission notice appear in supporting
12 | # documentation, and that the name of M.I.T. not be used in advertising or
13 | # publicity pertaining to distribution of the software without specific,
14 | # written prior permission. M.I.T. makes no representations about the
15 | # suitability of this software for any purpose. It is provided "as is"
16 | # without express or implied warranty.
17 | #
18 | # Calling this script install-sh is preferred over install.sh, to prevent
19 | # `make' implicit rules from creating a file called install from it
20 | # when there is no Makefile.
21 | #
22 | # This script is compatible with the BSD install script, but was written
23 | # from scratch. It can only install one file at a time, a restriction
24 | # shared with many OS's install programs.
25 |
26 |
27 | # set DOITPROG to echo to test this script
28 |
29 | # Don't use :- since 4.3BSD and earlier shells don't like it.
30 | doit="${DOITPROG-}"
31 |
32 |
33 | # put in absolute paths if you don't have them in your path; or use env. vars.
34 |
35 | mvprog="${MVPROG-mv}"
36 | cpprog="${CPPROG-cp}"
37 | chmodprog="${CHMODPROG-chmod}"
38 | chownprog="${CHOWNPROG-chown}"
39 | chgrpprog="${CHGRPPROG-chgrp}"
40 | stripprog="${STRIPPROG-strip}"
41 | rmprog="${RMPROG-rm}"
42 | mkdirprog="${MKDIRPROG-mkdir}"
43 |
44 | transformbasename=""
45 | transform_arg=""
46 | instcmd="$mvprog"
47 | chmodcmd="$chmodprog 0755"
48 | chowncmd=""
49 | chgrpcmd=""
50 | stripcmd=""
51 | rmcmd="$rmprog -f"
52 | mvcmd="$mvprog"
53 | src=""
54 | dst=""
55 | dir_arg=""
56 |
57 | while [ x"$1" != x ]; do
58 | case $1 in
59 | -c) instcmd="$cpprog"
60 | shift
61 | continue;;
62 |
63 | -d) dir_arg=true
64 | shift
65 | continue;;
66 |
67 | -m) chmodcmd="$chmodprog $2"
68 | shift
69 | shift
70 | continue;;
71 |
72 | -o) chowncmd="$chownprog $2"
73 | shift
74 | shift
75 | continue;;
76 |
77 | -g) chgrpcmd="$chgrpprog $2"
78 | shift
79 | shift
80 | continue;;
81 |
82 | -s) stripcmd="$stripprog"
83 | shift
84 | continue;;
85 |
86 | -t=*) transformarg=`echo $1 | sed 's/-t=//'`
87 | shift
88 | continue;;
89 |
90 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
91 | shift
92 | continue;;
93 |
94 | *) if [ x"$src" = x ]
95 | then
96 | src=$1
97 | else
98 | # this colon is to work around a 386BSD /bin/sh bug
99 | :
100 | dst=$1
101 | fi
102 | shift
103 | continue;;
104 | esac
105 | done
106 |
107 | if [ x"$src" = x ]
108 | then
109 | echo "install: no input file specified"
110 | exit 1
111 | else
112 | true
113 | fi
114 |
115 | if [ x"$dir_arg" != x ]; then
116 | dst=$src
117 | src=""
118 |
119 | if [ -d $dst ]; then
120 | instcmd=:
121 | else
122 | instcmd=mkdir
123 | fi
124 | else
125 |
126 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command
127 | # might cause directories to be created, which would be especially bad
128 | # if $src (and thus $dsttmp) contains '*'.
129 |
130 | if [ -f $src -o -d $src ]
131 | then
132 | true
133 | else
134 | echo "install: $src does not exist"
135 | exit 1
136 | fi
137 |
138 | if [ x"$dst" = x ]
139 | then
140 | echo "install: no destination specified"
141 | exit 1
142 | else
143 | true
144 | fi
145 |
146 | # If destination is a directory, append the input filename; if your system
147 | # does not like double slashes in filenames, you may need to add some logic
148 |
149 | if [ -d $dst ]
150 | then
151 | dst="$dst"/`basename $src`
152 | else
153 | true
154 | fi
155 | fi
156 |
157 | ## this sed command emulates the dirname command
158 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
159 |
160 | # Make sure that the destination directory exists.
161 | # this part is taken from Noah Friedman's mkinstalldirs script
162 |
163 | # Skip lots of stat calls in the usual case.
164 | if [ ! -d "$dstdir" ]; then
165 | defaultIFS='
166 | '
167 | IFS="${IFS-${defaultIFS}}"
168 |
169 | oIFS="${IFS}"
170 | # Some sh's can't handle IFS=/ for some reason.
171 | IFS='%'
172 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
173 | IFS="${oIFS}"
174 |
175 | pathcomp=''
176 |
177 | while [ $# -ne 0 ] ; do
178 | pathcomp="${pathcomp}${1}"
179 | shift
180 |
181 | if [ ! -d "${pathcomp}" ] ;
182 | then
183 | $mkdirprog "${pathcomp}"
184 | else
185 | true
186 | fi
187 |
188 | pathcomp="${pathcomp}/"
189 | done
190 | fi
191 |
192 | if [ x"$dir_arg" != x ]
193 | then
194 | $doit $instcmd $dst &&
195 |
196 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
197 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
198 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
199 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
200 | else
201 |
202 | # If we're going to rename the final executable, determine the name now.
203 |
204 | if [ x"$transformarg" = x ]
205 | then
206 | dstfile=`basename $dst`
207 | else
208 | dstfile=`basename $dst $transformbasename |
209 | sed $transformarg`$transformbasename
210 | fi
211 |
212 | # don't allow the sed command to completely eliminate the filename
213 |
214 | if [ x"$dstfile" = x ]
215 | then
216 | dstfile=`basename $dst`
217 | else
218 | true
219 | fi
220 |
221 | # Make a temp file name in the proper directory.
222 |
223 | dsttmp=$dstdir/#inst.$$#
224 |
225 | # Move or copy the file name to the temp name
226 |
227 | $doit $instcmd $src $dsttmp &&
228 |
229 | trap "rm -f ${dsttmp}" 0 &&
230 |
231 | # and set any options; do chmod last to preserve setuid bits
232 |
233 | # If any of these fail, we abort the whole thing. If we want to
234 | # ignore errors from any of these, just make sure not to ignore
235 | # errors from the above "$doit $instcmd $src $dsttmp" command.
236 |
237 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
238 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
239 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
240 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
241 |
242 | # Now rename the file to the real destination.
243 |
244 | $doit $rmcmd -f $dstdir/$dstfile &&
245 | $doit $mvcmd $dsttmp $dstdir/$dstfile
246 |
247 | fi &&
248 |
249 |
250 | exit 0
251 |
--------------------------------------------------------------------------------
/autoconf/scripts/makemake.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Generate Makefile dependencies inclusion and module target file "depend.mk~"
4 | # by scanning the directory "src" for files ending in ".c" and ".d", and for
5 | # subdirectories not starting with "_".
6 | #
7 | # Modules live inside subdirectories called [^_]* - i.e. a directory "foo" will
8 | # have a rule created which links all code inside it to "foo.o".
9 | #
10 | # The directory "src/include" is never scanned; neither are CVS or SVN
11 | # directories.
12 | #
13 |
14 | outlist=$1
15 | outlink=$2
16 |
17 | FIND=find
18 | GREP=grep
19 | which gfind 2>/dev/null | grep /gfind >/dev/null && FIND=gfind
20 | which ggrep 2>/dev/null | grep /ggrep >/dev/null && GREP=ggrep
21 |
22 | echo '# Automatically generated file listings' > $outlist
23 | echo '#' >> $outlist
24 | echo "# Creation time: `date`" >> $outlist
25 | echo >> $outlist
26 |
27 | echo '# Automatically generated module linking rules' > $outlink
28 | echo '#' >> $outlink
29 | echo "# Creation time: `date`" >> $outlink
30 | echo >> $outlink
31 |
32 | echo -n "Scanning for source files: "
33 |
34 | allsrc=`$FIND src -type f -name "*.c" -print`
35 | allobj=`echo $allsrc | tr ' ' '\n' | sed 's/\.c$/.o/'`
36 | alldep=`echo $allsrc | tr ' ' '\n' | sed 's/\.c$/.d/'`
37 |
38 | echo `echo $allsrc | wc -w | tr -d ' '` found
39 |
40 | echo -n "Scanning for modules: "
41 |
42 | modules=`$FIND src -type d -print \
43 | | $GREP -v '^src$' \
44 | | $GREP -v '/_' \
45 | | $GREP -v '^src/include' \
46 | | $GREP -v 'CVS' \
47 | | $GREP -v '.svn' \
48 | | while read DIR; do \
49 | CONTENT=\$(/bin/ls -d \$DIR/* \
50 | | $GREP -v '.po$' \
51 | | $GREP -v '.gmo$' \
52 | | $GREP -v '.mo$' \
53 | | $GREP -v '.h$' \
54 | | sed -n '$p'); \
55 | [ -n "\$CONTENT" ] || continue; \
56 | echo \$DIR; \
57 | done
58 | `
59 |
60 | echo up to `echo $modules | wc -w | tr -d ' '` found
61 |
62 | echo "Writing module linking rules"
63 |
64 | echo -n [
65 | for i in $modules; do echo -n ' '; done
66 | echo -n -e ']\r['
67 |
68 | for i in $modules; do
69 | echo -n '.'
70 | allobj="$allobj $i.o"
71 | deps=""
72 | for j in $i/*.c; do
73 | [ -f $j ] || continue
74 | newobj=`echo $j | sed -e 's@\.c$@.o@'`
75 | deps="$deps $newobj"
76 | done
77 | for j in $i/*; do
78 | [ -d "$j" ] || continue
79 | [ `basename $j` = "CVS" ] && continue
80 | [ `basename $j` = ".svn" ] && continue
81 | CONTENT=`/bin/ls -d $j/* \
82 | | $GREP -v '.po$' \
83 | | $GREP -v '.gmo$' \
84 | | $GREP -v '.mo$' \
85 | | $GREP -v '.h$' \
86 | | sed -n '$p'`
87 | [ -n "$CONTENT" ] || continue
88 | deps="$deps $j.o"
89 | done
90 | [ -n "$deps" ] || continue
91 | echo "$i.o: $deps" >> $outlink
92 | echo ' $(LD) $(LDFLAGS) -o $@' "$deps" >> $outlink
93 | echo >> $outlink
94 | done
95 |
96 | echo ']'
97 |
98 | echo "Listing source, object and dependency files"
99 |
100 | echo -n "allsrc = " >> $outlist
101 | echo $allsrc | sed 's,src/nls/cat-id-tbl.c,,' | sed -e 's/ / \\!/g'\
102 | | tr '!' '\n' >> $outlist
103 | echo >> $outlist
104 | echo -n "allobj = " >> $outlist
105 | echo $allobj | sed -e 's/ / \\!/g' | tr '!' '\n' >> $outlist
106 | echo >> $outlist
107 | echo -n "alldep = " >> $outlist
108 | echo $alldep | sed -e 's/ / \\!/g' | tr '!' '\n' >> $outlist
109 |
110 | echo >> $outlist
111 | echo >> $outlink
112 |
113 | # EOF
114 |
--------------------------------------------------------------------------------
/autoconf/scripts/mkinstalldirs:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # mkinstalldirs --- make directory hierarchy
3 | # Author: Noah Friedman
4 | # Created: 1993-05-16
5 | # Last modified: 1994-03-25
6 | # Public domain
7 |
8 | errstatus=0
9 |
10 | for file in ${1+"$@"} ; do
11 | set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
12 | shift
13 |
14 | pathcomp=
15 | for d in ${1+"$@"} ; do
16 | pathcomp="$pathcomp$d"
17 | case "$pathcomp" in
18 | -* ) pathcomp=./$pathcomp ;;
19 | esac
20 |
21 | if test ! -d "$pathcomp"; then
22 | echo "mkdir $pathcomp" 1>&2
23 | mkdir "$pathcomp" || errstatus=$?
24 | chmod 755 $pathcomp 2>/dev/null
25 | fi
26 |
27 | pathcomp="$pathcomp/"
28 | done
29 | done
30 |
31 | exit $errstatus
32 |
33 | # mkinstalldirs ends here
34 |
--------------------------------------------------------------------------------
/autoconf/scripts/po2table.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Messy script to convert all of the given .po files to a single C file on
4 | # stdout.
5 |
6 | cat <
15 |
16 | struct msgtable_s {
17 | char *msgid;
18 | char *msgstr;
19 | };
20 |
21 |
22 | struct msgtable_s *minigettext__gettable(char *lang)
23 | {
24 | if (0 == lang)
25 | return 0;
26 |
27 | EOF
28 |
29 | for POFILE in $*; do
30 | LANG=`basename "$POFILE" | sed 's/.po$//'`
31 | echo " if (strncmp(lang, \"$LANG\", 2) == 0) {"
32 | echo " static struct msgtable_s data[] = {";
33 |
34 | awk 'BEGIN{i=0;s=0;}
35 | /^msgid[ ]+/ {
36 | if (s) print " }, ";
37 | print " {";
38 | print " " substr($0,7);
39 | i=1;
40 | s=0;
41 | }
42 | /^msgstr[ ]+/ {
43 | print " ,";
44 | i=0;s=1;
45 | print " " substr($0,8);
46 | }
47 | /^[ ]*"/ {
48 | if (i||s) print " " $0;
49 | }
50 | END {if (i||s) print " }\n";}
51 | ' < "$POFILE"
52 | echo ' , { 0, 0 } };'
53 | echo " return data;"
54 | echo " }"
55 | done
56 |
57 | cat </dev/null` || TMP1=.tmp1
17 | TMP2=`mktemp 2>/dev/null` || TMP2=.tmp2
18 | TMP3=`mktemp 2>/dev/null` || TMP3=.tmp3
19 | TMP4=`mktemp 2>/dev/null` || TMP4=.tmp4
20 |
21 | export PROG TMP1 TMP2 TMP3 TMP4 # variables used by test scripts
22 |
23 | FAIL=0
24 |
25 | test -n "$TESTS" || TESTS=`ls "$SRCDIR/tests" | sort -n`
26 |
27 | for SCRIPT in $TESTS; do
28 | test -f "$SCRIPT" || SCRIPT="$SRCDIR/tests/$SCRIPT"
29 | test -f "$SCRIPT" || SCRIPT=`ls "$SRCDIR/tests/$SCRIPT"*`
30 | test -f "$SCRIPT" || continue
31 |
32 | echo `basename "$SCRIPT"`: " " | cut -b1-20 | sed 's/-/ - /' | tr "\n" ' '
33 |
34 | STATUS=0
35 | sh -e "$SCRIPT" || STATUS=1
36 | test $STATUS -eq 1 && FAIL=1
37 |
38 | test $STATUS -eq 1 && echo "FAILED" || echo "OK"
39 | done
40 |
41 | rm -f $TMP1 $TMP2 $TMP3 $TMP4
42 |
43 | exit $FAIL
44 |
45 | # EOF
46 |
--------------------------------------------------------------------------------
/doc/COPYING:
--------------------------------------------------------------------------------
1 | This package is free software, and is being distributed under the terms
2 | of the Artistic License 2.0.
3 |
4 | ----------------------------------------------------------
5 |
6 | Artistic License 2.0
7 |
8 | Copyright (c) 2000-2006, The Perl Foundation.
9 |
10 | Everyone is permitted to copy and distribute verbatim copies of this
11 | license document, but changing it is not allowed. Preamble
12 |
13 | This license establishes the terms under which a given free software
14 | Package may be copied, modified, distributed, and/or redistributed. The
15 | intent is that the Copyright Holder maintains some artistic control
16 | over the development of that Package while still keeping the Package
17 | available as open source and free software.
18 |
19 | You are always permitted to make arrangements wholly outside of this
20 | license directly with the Copyright Holder of a given Package. If the
21 | terms of this license do not permit the full use that you propose to
22 | make of the Package, you should contact the Copyright Holder and seek
23 | a different licensing arrangement. Definitions
24 |
25 | "Copyright Holder" means the individual(s) or organization(s) named in
26 | the copyright notice for the entire Package.
27 |
28 | "Contributor" means any party that has contributed code or other material
29 | to the Package, in accordance with the Copyright Holder's procedures.
30 |
31 | "You" and "your" means any person who would like to copy, distribute,
32 | or modify the Package.
33 |
34 | "Package" means the collection of files distributed by the Copyright
35 | Holder, and derivatives of that collection and/or of those files. A given
36 | Package may consist of either the Standard Version, or a Modified Version.
37 |
38 | "Distribute" means providing a copy of the Package or making it accessible
39 | to anyone else, or in the case of a company or organization, to others
40 | outside of your company or organization.
41 |
42 | "Distributor Fee" means any fee that you charge for Distributing this
43 | Package or providing support for this Package to another party. It does
44 | not mean licensing fees.
45 |
46 | "Standard Version" refers to the Package if it has not been modified,
47 | or has been modified only in ways explicitly requested by the Copyright
48 | Holder.
49 |
50 | "Modified Version" means the Package, if it has been changed, and such
51 | changes were not explicitly requested by the Copyright Holder.
52 |
53 | "Original License" means this Artistic License as Distributed with the
54 | Standard Version of the Package, in its current version or as it may be
55 | modified by The Perl Foundation in the future.
56 |
57 | "Source" form means the source code, documentation source, and
58 | configuration files for the Package.
59 |
60 | "Compiled" form means the compiled bytecode, object code, binary, or any
61 | other form resulting from mechanical transformation or translation of
62 | the Source form. Permission for Use and Modification Without Distribution
63 |
64 | (1) You are permitted to use the Standard Version and create and use
65 | Modified Versions for any purpose without restriction, provided that you
66 | do not Distribute the Modified Version. Permissions for Redistribution
67 | of the Standard Version
68 |
69 | (2) You may Distribute verbatim copies of the Source form of the Standard
70 | Version of this Package in any medium without restriction, either gratis
71 | or for a Distributor Fee, provided that you duplicate all of the original
72 | copyright notices and associated disclaimers. At your discretion, such
73 | verbatim copies may or may not include a Compiled form of the Package.
74 |
75 | (3) You may apply any bug fixes, portability changes, and other
76 | modifications made available from the Copyright Holder. The resulting
77 | Package will still be considered the Standard Version, and as such will
78 | be subject to the Original License. Distribution of Modified Versions
79 | of the Package as Source
80 |
81 | (4) You may Distribute your Modified Version as Source (either gratis
82 | or for a Distributor Fee, and with or without a Compiled form of the
83 | Modified Version) provided that you clearly document how it differs
84 | from the Standard Version, including, but not limited to, documenting
85 | any non-standard features, executables, or modules, and provided that
86 | you do at least ONE of the following:
87 |
88 | (a) make the Modified Version available to the Copyright Holder of the
89 | Standard Version, under the Original License, so that the Copyright Holder
90 | may include your modifications in the Standard Version.
91 | (b) ensure that installation of your Modified Version does not prevent the
92 | user installing or running the Standard Version. In addition, the Modified
93 | Version must bear a name that is different from the name of the Standard
94 | Version.
95 | (c) allow anyone who receives a copy of the Modified Version to make
96 | the Source form of the Modified Version available to others under
97 | (i) the Original License or
98 | (ii) a license that permits the licensee to freely copy, modify and
99 | redistribute the Modified Version using the same licensing terms that apply
100 | to the copy that the licensee received, and requires that the Source form of
101 | the Modified Version, and of any works derived from it, be made freely
102 | available in that license fees are prohibited but Distributor Fees are
103 | allowed. Distribution of Compiled Forms of the Standard Version or Modified
104 | Versions without the Source
105 |
106 | (5) You may Distribute Compiled forms of the Standard Version without
107 | the Source, provided that you include complete instructions on how to
108 | get the Source of the Standard Version. Such instructions must be valid
109 | at the time of your distribution. If these instructions, at any time
110 | while you are carrying out such distribution, become invalid, you must
111 | provide new instructions on demand or cease further distribution. If
112 | you provide valid instructions or cease distribution within thirty days
113 | after you become aware that the instructions are invalid, then you do
114 | not forfeit any of your rights under this license.
115 |
116 | (6) You may Distribute a Modified Version in Compiled form without the
117 | Source, provided that you comply with Section 4 with respect to the
118 | Source of the Modified Version. Aggregating or Linking the Package
119 |
120 | (7) You may aggregate the Package (either the Standard Version or
121 | Modified Version) with other packages and Distribute the resulting
122 | aggregation provided that you do not charge a licensing fee for the
123 | Package. Distributor Fees are permitted, and licensing fees for other
124 | components in the aggregation are permitted. The terms of this license
125 | apply to the use and Distribution of the Standard or Modified Versions
126 | as included in the aggregation.
127 |
128 | (8) You are permitted to link Modified and Standard Versions with other
129 | works, to embed the Package in a larger work of your own, or to build
130 | stand-alone binary or bytecode versions of applications that include the
131 | Package, and Distribute the result without restriction, provided the
132 | result does not expose a direct interface to the Package. Items That
133 | are Not Considered Part of a Modified Version
134 |
135 | (9) Works (including, but not limited to, modules and scripts) that
136 | merely extend or make use of the Package, do not, by themselves, cause
137 | the Package to be a Modified Version. In addition, such works are not
138 | considered parts of the Package itself, and are not subject to the terms
139 | of this license. General Provisions
140 |
141 | (10) Any use, modification, and distribution of the Standard or Modified
142 | Versions is governed by this Artistic License. By using, modifying or
143 | distributing the Package, you accept this license. Do not use, modify,
144 | or distribute the Package, if you do not accept this license.
145 |
146 | (11) If your Modified Version has been derived from a Modified Version
147 | made by someone other than you, you are nevertheless required to ensure
148 | that your Modified Version complies with the requirements of this license.
149 |
150 | (12) This license does not grant you the right to use any trademark,
151 | service mark, tradename, or logo of the Copyright Holder.
152 |
153 | (13) This license includes the non-exclusive, worldwide, free-of-charge
154 | patent license to make, have made, use, offer to sell, sell, import
155 | and otherwise transfer the Package with respect to any patent claims
156 | licensable by the Copyright Holder that are necessarily infringed by the
157 | Package. If you institute patent litigation (including a cross-claim or
158 | counterclaim) against any party alleging that the Package constitutes
159 | direct or contributory patent infringement, then this Artistic License
160 | to you shall terminate on the date that such litigation is filed.
161 |
162 | (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT
163 | HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED
164 | WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
165 | PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT
166 | PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER
167 | OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
168 | CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
169 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
170 |
171 | ----------------------------------------------------------
172 |
--------------------------------------------------------------------------------
/doc/INSTALL:
--------------------------------------------------------------------------------
1 | Basic Installation
2 | ==================
3 |
4 | These are generic installation instructions.
5 |
6 | The `configure' shell script attempts to guess correct values for
7 | various system-dependent variables used during compilation. It uses
8 | those values to create a `Makefile' in each directory of the package.
9 | It may also create one or more `.h' files containing system-dependent
10 | definitions. Finally, it creates a shell script `config.status' that
11 | you can run in the future to recreate the current configuration, a file
12 | `config.cache' that saves the results of its tests to speed up
13 | reconfiguring, and a file `config.log' containing compiler output
14 | (useful mainly for debugging `configure').
15 |
16 | If you need to do unusual things to compile the package, please try
17 | to figure out how `configure' could check whether to do them, and mail
18 | diffs or instructions to the address given in the `README' so they can
19 | be considered for the next release. If at some point `config.cache'
20 | contains results you don't want to keep, you may remove or edit it.
21 |
22 | The file `configure.in' is used to create `configure' by a program
23 | called `autoconf'. You only need `configure.in' if you want to change
24 | it or regenerate `configure' using a newer version of `autoconf'.
25 |
26 | The simplest way to compile this package is:
27 |
28 | 1. `cd' to the directory containing the package's source code and type
29 | `./configure' to configure the package for your system. If you're
30 | using `csh' on an old version of System V, you might need to type
31 | `sh ./configure' instead to prevent `csh' from trying to execute
32 | `configure' itself.
33 |
34 | Running `configure' takes awhile. While running, it prints some
35 | messages telling which features it is checking for.
36 |
37 | 2. Type `make' to compile the package.
38 |
39 | 3. Optionally, type `make check' to run any self-tests that come with
40 | the package.
41 |
42 | 4. Type `make install' to install the programs and any data files and
43 | documentation.
44 |
45 | 5. You can remove the program binaries and object files from the
46 | source code directory by typing `make clean'. To also remove the
47 | files that `configure' created (so you can compile the package for
48 | a different kind of computer), type `make distclean'. There is
49 | also a `make maintainer-clean' target, but that is intended mainly
50 | for the package's developers. If you use it, you may have to get
51 | all sorts of other programs in order to regenerate files that came
52 | with the distribution.
53 |
54 | Compilers and Options
55 | =====================
56 |
57 | Some systems require unusual options for compilation or linking that
58 | the `configure' script does not know about. You can give `configure'
59 | initial values for variables by setting them in the environment. Using
60 | a Bourne-compatible shell, you can do that on the command line like
61 | this:
62 | CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
63 |
64 | Or on systems that have the `env' program, you can do it like this:
65 | env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
66 |
67 | Compiling For Multiple Architectures
68 | ====================================
69 |
70 | You can compile the package for more than one kind of computer at the
71 | same time, by placing the object files for each architecture in their
72 | own directory. To do this, you must use a version of `make' that
73 | supports the `VPATH' variable, such as GNU `make'. `cd' to the
74 | directory where you want the object files and executables to go and run
75 | the `configure' script. `configure' automatically checks for the
76 | source code in the directory that `configure' is in and in `..'.
77 |
78 | If you have to use a `make' that does not supports the `VPATH'
79 | variable, you have to compile the package for one architecture at a time
80 | in the source code directory. After you have installed the package for
81 | one architecture, use `make distclean' before reconfiguring for another
82 | architecture.
83 |
84 | Installation Names
85 | ==================
86 |
87 | By default, `make install' will install the package's files in
88 | `/usr/local/bin', `/usr/local/man', etc. You can specify an
89 | installation prefix other than `/usr/local' by giving `configure' the
90 | option `--prefix=PATH'.
91 |
92 | You can specify separate installation prefixes for
93 | architecture-specific files and architecture-independent files. If you
94 | give `configure' the option `--exec-prefix=PATH', the package will use
95 | PATH as the prefix for installing programs and libraries.
96 | Documentation and other data files will still use the regular prefix.
97 |
98 | In addition, if you use an unusual directory layout you can give
99 | options like `--bindir=PATH' to specify different values for particular
100 | kinds of files. Run `configure --help' for a list of the directories
101 | you can set and what kinds of files go in them.
102 |
103 | If the package supports it, you can cause programs to be installed
104 | with an extra prefix or suffix on their names by giving `configure' the
105 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
106 |
107 | Optional Features
108 | =================
109 |
110 | Some packages pay attention to `--enable-FEATURE' options to
111 | `configure', where FEATURE indicates an optional part of the package.
112 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE
113 | is something like `gnu-as' or `x' (for the X Window System). The
114 | `README' should mention any `--enable-' and `--with-' options that the
115 | package recognizes.
116 |
117 | For packages that use the X Window System, `configure' can usually
118 | find the X include and library files automatically, but if it doesn't,
119 | you can use the `configure' options `--x-includes=DIR' and
120 | `--x-libraries=DIR' to specify their locations.
121 |
122 | Specifying the System Type
123 | ==========================
124 |
125 | There may be some features `configure' can not figure out
126 | automatically, but needs to determine by the type of host the package
127 | will run on. Usually `configure' can figure that out, but if it prints
128 | a message saying it can not guess the host type, give it the
129 | `--host=TYPE' option. TYPE can either be a short name for the system
130 | type, such as `sun4', or a canonical name with three fields:
131 | CPU-COMPANY-SYSTEM
132 |
133 | See the file `config.sub' for the possible values of each field. If
134 | `config.sub' isn't included in this package, then this package doesn't
135 | need to know the host type.
136 |
137 | If you are building compiler tools for cross-compiling, you can also
138 | use the `--target=TYPE' option to select the type of system they will
139 | produce code for and the `--build=TYPE' option to select the type of
140 | system on which you are compiling the package.
141 |
142 | Sharing Defaults
143 | ================
144 |
145 | If you want to set default values for `configure' scripts to share,
146 | you can create a site shell script called `config.site' that gives
147 | default values for variables like `CC', `cache_file', and `prefix'.
148 | `configure' looks for `PREFIX/share/config.site' if it exists, then
149 | `PREFIX/etc/config.site' if it exists. Or, you can set the
150 | `CONFIG_SITE' environment variable to the location of the site script.
151 | A warning: not all `configure' scripts look for a site script.
152 |
153 | Operation Controls
154 | ==================
155 |
156 | `configure' recognizes the following options to control how it
157 | operates.
158 |
159 | `--cache-file=FILE'
160 | Use and save the results of the tests in FILE instead of
161 | `./config.cache'. Set FILE to `/dev/null' to disable caching, for
162 | debugging `configure'.
163 |
164 | `--help'
165 | Print a summary of the options to `configure', and exit.
166 |
167 | `--quiet'
168 | `--silent'
169 | `-q'
170 | Do not print messages saying which checks are being made. To
171 | suppress all normal output, redirect it to `/dev/null' (any error
172 | messages will still be shown).
173 |
174 | `--srcdir=DIR'
175 | Look for the package's source code in directory DIR. Usually
176 | `configure' can determine that directory automatically.
177 |
178 | `--version'
179 | Print the version of Autoconf used to generate the `configure'
180 | script, and exit.
181 |
182 | `configure' also accepts some other, not widely useful, options.
183 |
184 |
--------------------------------------------------------------------------------
/doc/NEWS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/doc/NEWS
--------------------------------------------------------------------------------
/doc/PACKAGE:
--------------------------------------------------------------------------------
1 | pv
2 |
--------------------------------------------------------------------------------
/doc/TODO:
--------------------------------------------------------------------------------
1 | Things still to do:
2 |
3 | - allow -E to take a block size argument so errors cause a skip to the
4 | next block (Anthony DeRobertis)
5 | - (#1559) momentary ETA option (Luc Gommans)
6 | - (#1556) correct German translations (Richard Fonfara)
7 | - (#1557) use clock_gettime() in ETA calculation (Mateju Miroslav)
8 | - (#1561) show days in same format in ETA as in elapsed time
9 | - (#1562) allow -r with -l and -n to output lines/sec (Roland Kletzing)
10 | - (#1563) make -B imply -C (Johannes Gerer)
11 | - document zsh <() incompatibility (frederik@ofb.net - Frederik Eaton)
12 | - do not check terminal in -q/-n mode (zsh <(pv -n) fails)
13 | - if -w/-H was specified, ignore SIGWINCH
14 | - option to enable O_DIRECT (Romain Kang, Jacek Wielemborek)
15 | - use posix_fadvise() like cat(1) does (Jacek Wielemborek)
16 | - (#1508) add watchfd tests
17 | - (#1534) allow multiple -d options
18 | - (#1533) one-shot option (Jacek Wielemborek)
19 | - (#1505) option to switch rate to per minute if really slow
20 | - (#1510) option "--progress-from FILE", read last number and use it as bytes read:
21 | pv --progress-from <( while sleep 1; do du -sb somedir; done ) -s 123g
22 | (Jacek Wielemborek)
23 | - (#1476) (Debian #507682) adjustable averaging window for rate display
24 | - (#1286) option for process title (Martin Sarsale) as "pv - name:FooProcess -xyz - transferred: 1.3GB - 500KB/s - running: 10:15:30s"
25 | - (#1290) look at effect of O_SYNC or fsync on performance
26 | - (#1281) option (-x?) to use xterm title line for status (Joachim Haga)
27 | - (#1287) if the first pv exits, should the second become IPC leader?
28 | - (#1560) use Unicode for more granular progress bar (Alexander Petrossian)
29 |
30 | - add development support for http://clang-analyzer.llvm.org/
31 | - stats for avg/min/max/stddev throughput (Venky.N.Iyer)
32 | - pv-ify a command line (Will Entriken) - "pv FOO | BAR | BAZ"
33 | - get more translations
34 |
35 | Any assistance would be appreciated.
36 |
--------------------------------------------------------------------------------
/doc/VERSION:
--------------------------------------------------------------------------------
1 | 1.6.6
2 |
--------------------------------------------------------------------------------
/doc/lsm:
--------------------------------------------------------------------------------
1 | Begin3
2 | Title: pv
3 | Version: 1.6.6
4 | Entered-date: 30JUN17
5 | Description: A tool for monitoring the progress of data through a
6 | pipeline. It can be inserted into any normal pipeline
7 | between two processes to give a visual indication of how
8 | quickly data is passing through, how long it has taken, how
9 | near to completion it is, and an estimate of how long it
10 | will be until completion.
11 | Keywords: progress bar, console, pipe, transfer rate
12 | Author: Andrew Wood
13 | Maintained-by: Andrew Wood
14 | Primary-site: http://www.ivarch.com/programs/pv.shtml
15 | Alternate-site:
16 | Original-site:
17 | Platforms:
18 | Copying-policy: Artistic 2.0
19 | End
20 |
--------------------------------------------------------------------------------
/doc/lsm.in:
--------------------------------------------------------------------------------
1 | Begin3
2 | Title: @PACKAGE@
3 | Version: @VERSION@
4 | Entered-date: 30JUN17
5 | Description: A tool for monitoring the progress of data through a
6 | pipeline. It can be inserted into any normal pipeline
7 | between two processes to give a visual indication of how
8 | quickly data is passing through, how long it has taken, how
9 | near to completion it is, and an estimate of how long it
10 | will be until completion.
11 | Keywords: progress bar, console, pipe, transfer rate
12 | Author: Andrew Wood
13 | Maintained-by: Andrew Wood
14 | Primary-site: http://www.ivarch.com/programs/@PACKAGE@.shtml
15 | Alternate-site:
16 | Original-site:
17 | Platforms:
18 | Copying-policy: Artistic 2.0
19 | End
20 |
--------------------------------------------------------------------------------
/doc/pv.spec:
--------------------------------------------------------------------------------
1 | Summary: Monitor the progress of data through a pipe
2 | Name: pv
3 | Version: 1.6.6
4 | Release: 1
5 | License: Artistic 2.0
6 | Group: Development/Tools
7 | Source: http://www.ivarch.com/programs/sources/pv-1.6.6.tar.gz
8 | Url: http://www.ivarch.com/programs/pv.shtml
9 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
10 | BuildRequires: gettext
11 |
12 | %description
13 | PV ("Pipe Viewer") is a tool for monitoring the progress of data through a
14 | pipeline. It can be inserted into any normal pipeline between two processes
15 | to give a visual indication of how quickly data is passing through, how long
16 | it has taken, how near to completion it is, and an estimate of how long it
17 | will be until completion.
18 |
19 | %prep
20 | %setup -q
21 |
22 | %build
23 | %configure
24 | make %{?_smp_mflags}
25 |
26 | %install
27 | [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
28 | mkdir -p "$RPM_BUILD_ROOT"%{_bindir}
29 | mkdir -p "$RPM_BUILD_ROOT"%{_mandir}/man1
30 | mkdir -p "$RPM_BUILD_ROOT"/usr/share/locale
31 |
32 | make DESTDIR="$RPM_BUILD_ROOT" install
33 | %find_lang %{name}
34 |
35 | %check
36 | make test
37 |
38 | %clean
39 | [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
40 |
41 | %files -f %{name}.lang
42 | %defattr(-, root, root)
43 | %{_bindir}/%{name}
44 | %{_mandir}/man1/%{name}.1.gz
45 |
46 | %doc README doc/NEWS doc/TODO doc/COPYING
47 |
48 | %changelog
49 | * Fri Jun 30 2017 Andrew Wood 1.6.6-1
50 | - (r161) use %llu instead of %Lu for better compatibility (Eric A. Borisch)
51 | - (r162) (#1532) fix target buffer size (-B) being ignored (AndCycle, Ilya
52 | - Basin, Antoine Beaupré)
53 | - (r164) cap read/write sizes, and check elapsed time during read/write
54 | - cycles, to avoid display hangs with large buffers or slow media; also
55 | - remove select() call from repeated_write function as it slows the
56 | - transfer down and the wrapping alarm() means it is unnecessary
57 | - (r169) (#1477) use alternate form for transfer counter, such that 13GB
58 | - is shown as 13.0GB so it's the same width as 13.1GB (André Stapf)
59 | - (r171) cleanup: units corrections in man page, of the form kb -> KiB
60 | - (r175) report error in "-d" if process fd directory is unreadable, or if
61 | - process disappears before we start the main loop (Jacek Wielemborek)
62 |
63 | * Sun Mar 15 2015 Andrew Wood 1.6.0-1
64 | - fix lstat64 support when unavailable - separate patches supplied by Ganael
65 | - Laplanche and Peter Korsgaard
66 | - (#1506) new option "-D" / "--delay-start" to only show bar after N seconds
67 | - (Damon Harper)
68 | - new option "--fineta" / "-I" to show ETA as time of day rather than time
69 | - remaining - patch supplied by Erkki Seppälä (r147)
70 | - (#1509) change ETA (--eta / -e) so that days are given if the hours
71 | - remaining are 24 or more (Jacek Wielemborek)
72 | - (#1499) repeat read and write attempts on partial buffer fill/empty to
73 | - work around post-signal transfer rate drop reported by Ralf Ramsauer
74 | - (#1507) do not try to calculate total size in line mode, due to bug
75 | - reported by Jacek Wielemborek and Michiel Van Herwegen
76 | - cleanup: removed defunct RATS comments and unnecessary copyright notices
77 | - clean up displayed lines when using --watchfd PID, when PID exits
78 | - output errors on a new line to avoid overwriting transfer bar
79 |
80 | * Tue Aug 26 2014 Andrew Wood 1.5.7-1
81 | - show KiB instead of incorrect kiB (Debian bug #706175)
82 | - (#1284) do not gzip man page, for non-Linux OSes (Bob Friesenhahn)
83 | - work around "awk" bug in tests/016-numeric-timer in decimal "," locales
84 | - fix "make rpm" and "make srpm", extend "make release" to sign releases
85 |
86 | * Sun May 4 2014 Andrew Wood 1.5.3-1
87 | - remove SPLICE_F_NONBLOCK to fix problem with slow splice() (Jan Seda)
88 |
89 | * Mon Feb 10 2014 Andrew Wood 1.5.2-1
90 | - allow "--watchfd" to look at block devices
91 | - let "--watchfd PID:FD" work with "--size N"
92 | - moved contributors out of the manual as the list was too long
93 | - (NB everyone is still listed in the README and always will be)
94 |
95 | * Thu Jan 23 2014 Andrew Wood 1.5.1-1
96 | - new option "--watchfd" - suggested by Jacek Wielemborek and "fdwatch"
97 | - use non-block flag with splice()
98 | - new display option "--buffer-percent", suggested by Kim Krecht
99 | - new display option "--last-written", suggested by Kim Krecht
100 | - new transfer option "--no-splice"
101 | - fix for minor bug which dropped display elements after one empty one
102 | - fix for single fd leak on exit (Cristian Ciupitu, Josh Stone)
103 |
104 | * Mon Aug 5 2013 Andrew Wood 1.4.12-1
105 | - new option "--null" - patch supplied by Zing Shishak
106 | - AIX build fix (add "-lc128") - with help from Pawel Piatek
107 | - AIX "-c" fixes - with help from Pawel Piatek
108 | - SCO build fix (po2table.sh) - reported by Wouter Pronk
109 | - test scripts fix for older distributions - patch from Bryan Dongray
110 | - fix for splice() not using stdin - patch from Zev Weiss
111 |
112 | * Tue Jan 22 2013 Andrew Wood 1.4.6-1
113 | - added patch from Pawel Piatek to omit O_NOFOLLOW in AIX
114 |
115 | * Thu Jan 10 2013 Andrew Wood 1.4.5-1
116 | - updated manual page to show known problem with "-R" on Cygwin
117 |
118 | * Tue Dec 11 2012 Andrew Wood 1.4.4-1
119 | - added debugging, see `pv -h' when configure run with "--enable-debugging"
120 | - rewrote cursor positioning code used when IPC is unavailable (Cygwin)
121 | - fixed cursor positioning cursor read answerback problem (Cygwin/Solaris)
122 | - fixed bug causing crash when progress displayed with too-small terminal
123 |
124 | * Thu Dec 6 2012 Andrew Wood 1.4.0-1
125 | - new option "--skip-errors" commissioned by Jim Salter
126 | - if stdout is a block device, and we don't know the total size, use the
127 | - size of that block device as the total (Peter Samuelson)
128 | - new option "--stop-at-size" to stop after "--size" bytes
129 | - report correct filename on read errors
130 | - fix use-after-free bug in remote PID cleanup code
131 | - refactored large chunks of code to make it more readable and to replace
132 | - most static variables with a state structure
133 |
134 | * Mon Nov 5 2012 Andrew Wood 1.3.9-1
135 | - allow "--format" parameters to be sent with "--remote"
136 | - configure option "--disable-ipc"
137 | - added tests for --numeric with --timer and --bytes
138 | - added tests for --remote
139 |
140 | * Mon Oct 29 2012 Andrew Wood 1.3.8-1
141 | - new "--pidfile" option to save process ID to a file
142 | - integrated patch for --numeric with --timer and --bytes (Sami Liedes)
143 | - removed signalling from --remote to prevent accidental process kills
144 | - new "--format" option (originally Vladimir Pal / Vladimir Ermakov)
145 |
146 | * Wed Jun 27 2012 Andrew Wood 1.3.4-1
147 | - new "--disable-splice" configure script option
148 | - fixed line mode size count with multiple files (Moritz Barsnick)
149 | - fixes for AIX core dumps (Pawel Piatek)
150 |
151 | * Sat Jun 9 2012 Andrew Wood 1.3.1-1
152 | - do not use splice() if the write buffer is not empty (Thomas Rachel)
153 | - added test 15 (pipe transfers), and new test script
154 |
155 | * Tue Jun 5 2012 Andrew Wood 1.3.0-1
156 | - added Tiger build patch from Olle Jonsson.
157 | - fix 1024-boundary display garble (Debian bug #586763).
158 | - use splice(2) where available (Debian bug #601683).
159 | - added known bugs section of the manual page.
160 | - fixed average rate test, 12 (Andrew Macheret).
161 | - use IEEE1541 units (Thomas Rachel).
162 | - bug with rate limit under 10 fixed (Henry Precheur).
163 | - speed up PV line mode (patch: Guillaume Marcais).
164 | - remove LD=ld from vars.mk to fix cross-compilation (paintitgray/PV#1291).
165 |
166 | * Tue Dec 14 2010 Andrew Wood 1.2.0-1
167 | - Integrated improved SI prefixes and --average-rate (Henry Gebhardt).
168 | - Return nonzero if exiting due to SIGTERM (Martin Baum).
169 | - Patch from Phil Rutschman to restore terminal properly on exit.
170 | - Fix i18n especially for --help (Sebastian Kayser).
171 | - Refactored pv_display.
172 | - We now have a coherent, documented, exit status.
173 | - Modified pipe test and new cksum test from Sebastian Kayser.
174 | - Default CFLAGS to just "-O" for non-GCC (Kjetil Torgrim Homme).
175 | - LFS compile fix for OS X 10.4 (Alexandre de Verteuil).
176 | - Remove DESTDIR / suffix (Sam Nelson, Daniel Pape).
177 | - Fixed potential NULL deref in transfer (Elias Pipping / LLVM/Clang).
178 |
179 | * Thu Mar 6 2008 Andrew Wood 1.1.4-1
180 | - Trap SIGINT/SIGHUP/SIGTERM so we clean up IPCs on exit (Laszlo Ersek).
181 | - Abort if numeric option, eg -L, has non-numeric value (Boris Lohner).
182 | - Compilation fixes for Darwin 9 and OS X.
183 |
184 | * Thu Aug 30 2007 Andrew Wood 1.1.0-1
185 | - New option "-R" to remotely control another pv process.
186 | - New option "-l" to count lines instead of bytes.
187 | - Performance improvement for "-L" (rate) option.
188 | - Some Mac OS X fixes, and packaging cleanups.
189 |
190 | * Sat Aug 4 2007 Andrew Wood 1.0.1-1
191 | - Changed license from Artistic to Artistic 2.0.
192 | - Removed "--license" option.
193 |
194 | * Thu Aug 2 2007 Andrew Wood 1.0.0-1
195 | - We now act more like "cat" - just skip unreadable files, don't abort.
196 | - Various code cleanups were done.
197 |
198 | * Mon Feb 5 2007 Andrew Wood 0.9.9-1
199 | - New option "-B" to set the buffer size, and a workaround for problems
200 | - piping to dd(1).
201 |
202 | * Mon Feb 27 2006 Andrew Wood
203 | - Minor bugfixes, and on the final update, blank out the now-zero ETA.
204 |
205 | * Thu Sep 1 2005 Andrew Wood
206 | - Terminal locking now uses lockfiles if the terminal itself cannot be locked.
207 |
208 | * Thu Jun 16 2005 Andrew Wood
209 | - A minor problem with the spec file was fixed.
210 |
211 | * Mon Nov 15 2004 Andrew Wood
212 | - A minor bug in the NLS code was fixed.
213 |
214 | * Sat Nov 6 2004 Andrew Wood
215 | - Code cleanups and minor usability fixes.
216 |
217 | * Tue Jun 29 2004 Andrew Wood
218 | - A port of the terminal locking code to FreeBSD.
219 |
220 | * Sun May 2 2004 Andrew Wood
221 | - Major reliability improvements to the cursor positioning.
222 |
223 | * Sat Apr 24 2004 Andrew Wood
224 | - Rate and size parameters can now take suffixes such as "k", "m" etc.
225 |
226 | * Mon Apr 19 2004 Andrew Wood
227 | - A bug in the cursor positioning was fixed.
228 |
229 | * Thu Feb 12 2004 Andrew Wood
230 | - Code cleanups and portability fixes.
231 |
232 | * Sun Feb 8 2004 Andrew Wood
233 | - The display buffer is now dynamically allocated, fixing an overflow bug.
234 |
235 | * Wed Jan 14 2004 Andrew Wood
236 | - A minor bug triggered when installing the RPM was fixed.
237 |
238 | * Mon Dec 22 2003 Andrew Wood
239 | - Fixed a minor bug that occasionally reported "resource unavailable".
240 |
241 | * Wed Aug 6 2003 Andrew Wood
242 | - Block devices now have their size read correctly, so pv /dev/hda1 works
243 | - Minor code cleanups (mainly removal of CVS "Id" tags)
244 |
245 | * Sun Aug 3 2003 Andrew Wood
246 | - Doing ^Z then "bg" then "fg" now continues displaying
247 |
248 | * Tue Jul 16 2002 Andrew Wood
249 | - First draft of spec file created.
250 |
--------------------------------------------------------------------------------
/doc/release-checklist:
--------------------------------------------------------------------------------
1 | Before releasing a new version, go through this checklist:
2 |
3 | - check for patches from http://packages.qa.debian.org/p/pv.html
4 | - bump doc/VERSION
5 | - bump doc/lsm.in
6 | - check doc/NEWS is up to date
7 | - check doc/spec.in is up to date (changelog)
8 | - check manual is up to date
9 | - make indent indentclean
10 | - make update-po
11 | - make test
12 | - commit to SVN
13 | - wipe build directory, re-run generate.sh and configure
14 | - make release
15 | - make manhtml | tidy -asxhtml | sed -e '1,//d' -e '/<\/body>/,$d'
16 | - update HTML for todo and news
17 | - copy and sign tar.gz to HTML directory
18 | - submit new release to Sourceforge
19 | - upload HTML
20 | - check validator results for project page and manual
21 |
--------------------------------------------------------------------------------
/doc/spec.in:
--------------------------------------------------------------------------------
1 | Summary: Monitor the progress of data through a pipe
2 | Name: @PACKAGE@
3 | Version: @VERSION@
4 | Release: 1%{?dist}
5 | License: Artistic 2.0
6 | Group: Development/Tools
7 | Source: http://www.ivarch.com/programs/sources/@PACKAGE@-@VERSION@.tar.gz
8 | Url: http://www.ivarch.com/programs/pv.shtml
9 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
10 | BuildRequires: gettext
11 |
12 | %description
13 | PV ("Pipe Viewer") is a tool for monitoring the progress of data through a
14 | pipeline. It can be inserted into any normal pipeline between two processes
15 | to give a visual indication of how quickly data is passing through, how long
16 | it has taken, how near to completion it is, and an estimate of how long it
17 | will be until completion.
18 |
19 | %prep
20 | %setup -q
21 |
22 | %build
23 | %configure
24 | make %{?_smp_mflags}
25 |
26 | %install
27 | [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
28 | mkdir -p "$RPM_BUILD_ROOT"%{_bindir}
29 | mkdir -p "$RPM_BUILD_ROOT"%{_mandir}/man1
30 | mkdir -p "$RPM_BUILD_ROOT"/usr/share/locale
31 |
32 | make DESTDIR="$RPM_BUILD_ROOT" install
33 | %find_lang %{name}
34 |
35 | %check
36 | make test
37 |
38 | %clean
39 | [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"
40 |
41 | %files -f %{name}.lang
42 | %defattr(-, root, root)
43 | %{_bindir}/%{name}
44 | %{_mandir}/man1/%{name}.1.gz
45 |
46 | %doc README doc/NEWS doc/TODO doc/COPYING
47 |
48 | %changelog
49 | * Fri Jun 30 2017 Andrew Wood 1.6.6-1
50 | - (r161) use %llu instead of %Lu for better compatibility (Eric A. Borisch)
51 | - (r162) (#1532) fix target buffer size (-B) being ignored (AndCycle, Ilya
52 | - Basin, Antoine Beaupré)
53 | - (r164) cap read/write sizes, and check elapsed time during read/write
54 | - cycles, to avoid display hangs with large buffers or slow media; also
55 | - remove select() call from repeated_write function as it slows the
56 | - transfer down and the wrapping alarm() means it is unnecessary
57 | - (r169) (#1477) use alternate form for transfer counter, such that 13GB
58 | - is shown as 13.0GB so it's the same width as 13.1GB (André Stapf)
59 | - (r171) cleanup: units corrections in man page, of the form kb -> KiB
60 | - (r175) report error in "-d" if process fd directory is unreadable, or if
61 | - process disappears before we start the main loop (Jacek Wielemborek)
62 |
63 | * Sun Mar 15 2015 Andrew Wood 1.6.0-1
64 | - fix lstat64 support when unavailable - separate patches supplied by Ganael
65 | - Laplanche and Peter Korsgaard
66 | - (#1506) new option "-D" / "--delay-start" to only show bar after N seconds
67 | - (Damon Harper)
68 | - new option "--fineta" / "-I" to show ETA as time of day rather than time
69 | - remaining - patch supplied by Erkki Seppälä (r147)
70 | - (#1509) change ETA (--eta / -e) so that days are given if the hours
71 | - remaining are 24 or more (Jacek Wielemborek)
72 | - (#1499) repeat read and write attempts on partial buffer fill/empty to
73 | - work around post-signal transfer rate drop reported by Ralf Ramsauer
74 | - (#1507) do not try to calculate total size in line mode, due to bug
75 | - reported by Jacek Wielemborek and Michiel Van Herwegen
76 | - cleanup: removed defunct RATS comments and unnecessary copyright notices
77 | - clean up displayed lines when using --watchfd PID, when PID exits
78 | - output errors on a new line to avoid overwriting transfer bar
79 |
80 | * Tue Aug 26 2014 Andrew Wood 1.5.7-1
81 | - show KiB instead of incorrect kiB (Debian bug #706175)
82 | - (#1284) do not gzip man page, for non-Linux OSes (Bob Friesenhahn)
83 | - work around "awk" bug in tests/016-numeric-timer in decimal "," locales
84 | - fix "make rpm" and "make srpm", extend "make release" to sign releases
85 |
86 | * Sun May 4 2014 Andrew Wood 1.5.3-1
87 | - remove SPLICE_F_NONBLOCK to fix problem with slow splice() (Jan Seda)
88 |
89 | * Mon Feb 10 2014 Andrew Wood 1.5.2-1
90 | - allow "--watchfd" to look at block devices
91 | - let "--watchfd PID:FD" work with "--size N"
92 | - moved contributors out of the manual as the list was too long
93 | - (NB everyone is still listed in the README and always will be)
94 |
95 | * Thu Jan 23 2014 Andrew Wood 1.5.1-1
96 | - new option "--watchfd" - suggested by Jacek Wielemborek and "fdwatch"
97 | - use non-block flag with splice()
98 | - new display option "--buffer-percent", suggested by Kim Krecht
99 | - new display option "--last-written", suggested by Kim Krecht
100 | - new transfer option "--no-splice"
101 | - fix for minor bug which dropped display elements after one empty one
102 | - fix for single fd leak on exit (Cristian Ciupitu, Josh Stone)
103 |
104 | * Mon Aug 5 2013 Andrew Wood 1.4.12-1
105 | - new option "--null" - patch supplied by Zing Shishak
106 | - AIX build fix (add "-lc128") - with help from Pawel Piatek
107 | - AIX "-c" fixes - with help from Pawel Piatek
108 | - SCO build fix (po2table.sh) - reported by Wouter Pronk
109 | - test scripts fix for older distributions - patch from Bryan Dongray
110 | - fix for splice() not using stdin - patch from Zev Weiss
111 |
112 | * Tue Jan 22 2013 Andrew Wood 1.4.6-1
113 | - added patch from Pawel Piatek to omit O_NOFOLLOW in AIX
114 |
115 | * Thu Jan 10 2013 Andrew Wood 1.4.5-1
116 | - updated manual page to show known problem with "-R" on Cygwin
117 |
118 | * Tue Dec 11 2012 Andrew Wood 1.4.4-1
119 | - added debugging, see `pv -h' when configure run with "--enable-debugging"
120 | - rewrote cursor positioning code used when IPC is unavailable (Cygwin)
121 | - fixed cursor positioning cursor read answerback problem (Cygwin/Solaris)
122 | - fixed bug causing crash when progress displayed with too-small terminal
123 |
124 | * Thu Dec 6 2012 Andrew Wood 1.4.0-1
125 | - new option "--skip-errors" commissioned by Jim Salter
126 | - if stdout is a block device, and we don't know the total size, use the
127 | - size of that block device as the total (Peter Samuelson)
128 | - new option "--stop-at-size" to stop after "--size" bytes
129 | - report correct filename on read errors
130 | - fix use-after-free bug in remote PID cleanup code
131 | - refactored large chunks of code to make it more readable and to replace
132 | - most static variables with a state structure
133 |
134 | * Mon Nov 5 2012 Andrew Wood 1.3.9-1
135 | - allow "--format" parameters to be sent with "--remote"
136 | - configure option "--disable-ipc"
137 | - added tests for --numeric with --timer and --bytes
138 | - added tests for --remote
139 |
140 | * Mon Oct 29 2012 Andrew Wood 1.3.8-1
141 | - new "--pidfile" option to save process ID to a file
142 | - integrated patch for --numeric with --timer and --bytes (Sami Liedes)
143 | - removed signalling from --remote to prevent accidental process kills
144 | - new "--format" option (originally Vladimir Pal / Vladimir Ermakov)
145 |
146 | * Wed Jun 27 2012 Andrew Wood 1.3.4-1
147 | - new "--disable-splice" configure script option
148 | - fixed line mode size count with multiple files (Moritz Barsnick)
149 | - fixes for AIX core dumps (Pawel Piatek)
150 |
151 | * Sat Jun 9 2012 Andrew Wood 1.3.1-1
152 | - do not use splice() if the write buffer is not empty (Thomas Rachel)
153 | - added test 15 (pipe transfers), and new test script
154 |
155 | * Tue Jun 5 2012 Andrew Wood 1.3.0-1
156 | - added Tiger build patch from Olle Jonsson.
157 | - fix 1024-boundary display garble (Debian bug #586763).
158 | - use splice(2) where available (Debian bug #601683).
159 | - added known bugs section of the manual page.
160 | - fixed average rate test, 12 (Andrew Macheret).
161 | - use IEEE1541 units (Thomas Rachel).
162 | - bug with rate limit under 10 fixed (Henry Precheur).
163 | - speed up PV line mode (patch: Guillaume Marcais).
164 | - remove LD=ld from vars.mk to fix cross-compilation (paintitgray/PV#1291).
165 |
166 | * Tue Dec 14 2010 Andrew Wood 1.2.0-1
167 | - Integrated improved SI prefixes and --average-rate (Henry Gebhardt).
168 | - Return nonzero if exiting due to SIGTERM (Martin Baum).
169 | - Patch from Phil Rutschman to restore terminal properly on exit.
170 | - Fix i18n especially for --help (Sebastian Kayser).
171 | - Refactored pv_display.
172 | - We now have a coherent, documented, exit status.
173 | - Modified pipe test and new cksum test from Sebastian Kayser.
174 | - Default CFLAGS to just "-O" for non-GCC (Kjetil Torgrim Homme).
175 | - LFS compile fix for OS X 10.4 (Alexandre de Verteuil).
176 | - Remove DESTDIR / suffix (Sam Nelson, Daniel Pape).
177 | - Fixed potential NULL deref in transfer (Elias Pipping / LLVM/Clang).
178 |
179 | * Thu Mar 6 2008 Andrew Wood 1.1.4-1
180 | - Trap SIGINT/SIGHUP/SIGTERM so we clean up IPCs on exit (Laszlo Ersek).
181 | - Abort if numeric option, eg -L, has non-numeric value (Boris Lohner).
182 | - Compilation fixes for Darwin 9 and OS X.
183 |
184 | * Thu Aug 30 2007 Andrew Wood 1.1.0-1
185 | - New option "-R" to remotely control another @PACKAGE@ process.
186 | - New option "-l" to count lines instead of bytes.
187 | - Performance improvement for "-L" (rate) option.
188 | - Some Mac OS X fixes, and packaging cleanups.
189 |
190 | * Sat Aug 4 2007 Andrew Wood 1.0.1-1
191 | - Changed license from Artistic to Artistic 2.0.
192 | - Removed "--license" option.
193 |
194 | * Thu Aug 2 2007 Andrew Wood 1.0.0-1
195 | - We now act more like "cat" - just skip unreadable files, don't abort.
196 | - Various code cleanups were done.
197 |
198 | * Mon Feb 5 2007 Andrew Wood 0.9.9-1
199 | - New option "-B" to set the buffer size, and a workaround for problems
200 | - piping to dd(1).
201 |
202 | * Mon Feb 27 2006 Andrew Wood
203 | - Minor bugfixes, and on the final update, blank out the now-zero ETA.
204 |
205 | * Thu Sep 1 2005 Andrew Wood
206 | - Terminal locking now uses lockfiles if the terminal itself cannot be locked.
207 |
208 | * Thu Jun 16 2005 Andrew Wood
209 | - A minor problem with the spec file was fixed.
210 |
211 | * Mon Nov 15 2004 Andrew Wood
212 | - A minor bug in the NLS code was fixed.
213 |
214 | * Sat Nov 6 2004 Andrew Wood
215 | - Code cleanups and minor usability fixes.
216 |
217 | * Tue Jun 29 2004 Andrew Wood
218 | - A port of the terminal locking code to FreeBSD.
219 |
220 | * Sun May 2 2004 Andrew Wood
221 | - Major reliability improvements to the cursor positioning.
222 |
223 | * Sat Apr 24 2004 Andrew Wood
224 | - Rate and size parameters can now take suffixes such as "k", "m" etc.
225 |
226 | * Mon Apr 19 2004 Andrew Wood
227 | - A bug in the cursor positioning was fixed.
228 |
229 | * Thu Feb 12 2004 Andrew Wood
230 | - Code cleanups and portability fixes.
231 |
232 | * Sun Feb 8 2004 Andrew Wood
233 | - The display buffer is now dynamically allocated, fixing an overflow bug.
234 |
235 | * Wed Jan 14 2004 Andrew Wood
236 | - A minor bug triggered when installing the RPM was fixed.
237 |
238 | * Mon Dec 22 2003 Andrew Wood
239 | - Fixed a minor bug that occasionally reported "resource unavailable".
240 |
241 | * Wed Aug 6 2003 Andrew Wood
242 | - Block devices now have their size read correctly, so pv /dev/hda1 works
243 | - Minor code cleanups (mainly removal of CVS "Id" tags)
244 |
245 | * Sun Aug 3 2003 Andrew Wood
246 | - Doing ^Z then "bg" then "fg" now continues displaying
247 |
248 | * Tue Jul 16 2002 Andrew Wood
249 | - First draft of spec file created.
250 |
--------------------------------------------------------------------------------
/src/include/library/getopt.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Replacement getopt function's header file. Include this AFTER config.h.
3 | */
4 |
5 | #ifndef _LIBRARY_GETOPT_H
6 | #define _LIBRARY_GETOPT_H 1
7 |
8 | #ifdef HAVE_GETOPT_H
9 | #include
10 | #endif
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | #ifndef HAVE_GETOPT
17 |
18 | int minigetopt(int, char **, char *);
19 | extern char *minioptarg;
20 | extern int minioptind, miniopterr, minioptopt;
21 |
22 | #define getopt minigetopt /* Flawfinder: ignore */
23 | #define optarg minioptarg
24 | #define optind minioptind
25 | #define opterr miniopterr
26 | #define optopt minioptopt
27 |
28 | #endif /* !HAVE_GETOPT */
29 |
30 | #ifdef __cplusplus
31 | }
32 | #endif
33 |
34 | #endif /* _LIBRARY_GETOPT_H */
35 |
36 | /* EOF */
37 |
--------------------------------------------------------------------------------
/src/include/library/gettext.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Replacement gettext library header file. Include this within config.h,
3 | * like this:
4 | *
5 | * #ifdef ENABLE_NLS
6 | * # include "library/gettext.h"
7 | * #else
8 | * # define _(String) (String)
9 | * # define N_(String) (String)
10 | * #endif
11 | *
12 | */
13 |
14 | #ifndef _LIBRARY_GETTEXT_H
15 | #define _LIBRARY_GETTEXT_H 1
16 |
17 | #ifdef HAVE_GETTEXT
18 | # ifdef HAVE_LIBINTL_H
19 | # include
20 | # endif
21 | # ifdef HAVE_LOCALE_H
22 | # include
23 | # endif
24 | # define _(String) gettext (String)
25 | # define N_(String) (String)
26 | #else
27 | # define _(String) minigettext (String)
28 | # define N_(String) (String)
29 | # define setlocale minisetlocale
30 | # define bindtextdomain minibindtextdomain
31 | # define textdomain minitextdomain
32 | # ifndef LC_ALL
33 | # define LC_ALL ""
34 | # endif
35 | #endif
36 |
37 | #ifdef __cplusplus
38 | extern "C" {
39 | #endif
40 |
41 | char *minisetlocale(char *, char *);
42 | char *minibindtextdomain(char *, char *);
43 | char *minitextdomain(char *);
44 | char *minigettext(char *);
45 |
46 | #ifdef __cplusplus
47 | }
48 | #endif
49 |
50 | #endif /* _LIBRARY_GETTEXT_H */
51 |
52 | /* EOF */
53 |
--------------------------------------------------------------------------------
/src/include/options.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Global program option structure and the parsing function prototype.
3 | */
4 |
5 | #ifndef _OPTIONS_H
6 | #define _OPTIONS_H 1
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | struct opts_s;
13 | typedef struct opts_s *opts_t;
14 |
15 | struct opts_s { /* structure describing run-time options */
16 | char *program_name; /* name the program is running as */
17 | unsigned char do_nothing; /* exit-without-doing-anything flag */
18 | unsigned char progress; /* progress bar flag */
19 | unsigned char timer; /* timer flag */
20 | unsigned char eta; /* ETA flag */
21 | unsigned char fineta; /* absolute ETA flag */
22 | unsigned char rate; /* rate counter flag */
23 | unsigned char average_rate; /* average rate counter flag */
24 | unsigned char bytes; /* bytes transferred flag */
25 | unsigned char bufpercent; /* transfer buffer percentage flag */
26 | unsigned int lastwritten; /* show N bytes last written */
27 | unsigned char force; /* force-if-not-terminal flag */
28 | unsigned char cursor; /* whether to use cursor positioning */
29 | unsigned char numeric; /* numeric output only */
30 | unsigned char wait; /* wait for transfer before display */
31 | unsigned char linemode; /* count lines instead of bytes */
32 | unsigned char null; /* lines are null-terminated */
33 | unsigned char no_op; /* do nothing other than pipe data */
34 | unsigned long long rate_limit; /* rate limit, in bytes per second */
35 | unsigned long long buffer_size;/* buffer size, in bytes (0=default) */
36 | unsigned int remote; /* PID of pv to update settings of */
37 | unsigned long long size; /* total size of data */
38 | unsigned char no_splice; /* flag set if never to use splice */
39 | unsigned char skip_errors; /* skip read errors flag */
40 | unsigned char stop_at_size; /* set if we stop at "size" bytes */
41 | double interval; /* interval between updates */
42 | double delay_start; /* delay before first display */
43 | unsigned int watch_pid; /* process to watch fds of */
44 | int watch_fd; /* fd to watch */
45 | unsigned int width; /* screen width */
46 | unsigned int height; /* screen height */
47 | char *name; /* process name, if any */
48 | char *format; /* output format, if any */
49 | char *pidfile; /* PID file, if any */
50 | int argc; /* number of non-option arguments */
51 | char **argv; /* array of non-option arguments */
52 | };
53 |
54 | extern opts_t opts_parse(int, char **);
55 | extern void opts_free(opts_t);
56 |
57 |
58 | #ifdef __cplusplus
59 | }
60 | #endif
61 |
62 | #endif /* _OPTIONS_H */
63 |
64 | /* EOF */
65 |
--------------------------------------------------------------------------------
/src/include/pv-internal.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Functions internal to the PV library.
3 | */
4 |
5 | #ifndef _PV_INTERNAL_H
6 | #define _PV_INTERNAL_H 1
7 |
8 | #ifdef HAVE_CONFIG_H
9 | #include "config.h"
10 | #endif
11 |
12 | #ifndef _PV_H
13 | #include "pv.h"
14 | #endif /* _PV_H */
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #ifdef __cplusplus
22 | extern "C" {
23 | #endif
24 |
25 | #define PV_DISPLAY_PROGRESS 1
26 | #define PV_DISPLAY_TIMER 2
27 | #define PV_DISPLAY_ETA 4
28 | #define PV_DISPLAY_RATE 8
29 | #define PV_DISPLAY_AVERAGERATE 16
30 | #define PV_DISPLAY_BYTES 32
31 | #define PV_DISPLAY_NAME 64
32 | #define PV_DISPLAY_BUFPERCENT 128
33 | #define PV_DISPLAY_OUTPUTBUF 256
34 | #define PV_DISPLAY_FINETA 512
35 |
36 | #define RATE_GRANULARITY 100000 /* usec between -L rate chunks */
37 | #define REMOTE_INTERVAL 100000 /* usec between checks for -R */
38 | #define BUFFER_SIZE 409600 /* default transfer buffer size */
39 | #define BUFFER_SIZE_MAX 524288 /* max auto transfer buffer size */
40 | #define MAX_READ_AT_ONCE 524288 /* max to read() in one go */
41 | #define MAX_WRITE_AT_ONCE 524288 /* max to write() in one go */
42 | #define TRANSFER_READ_TIMEOUT 90000 /* usec to time reads out at */
43 | #define TRANSFER_WRITE_TIMEOUT 900000 /* usec to time writes out at */
44 |
45 | #define MAXIMISE_BUFFER_FILL 1
46 |
47 |
48 | /*
49 | * Structure for holding PV internal state. Opaque outside the PV library.
50 | */
51 | struct pvstate_s {
52 | /***************
53 | * Input files *
54 | ***************/
55 | int input_file_count; /* number of input files */
56 | const char **input_files; /* input files (0=first) */
57 |
58 | /*******************
59 | * Program control *
60 | *******************/
61 | unsigned char force; /* display even if not on terminal */
62 | unsigned char cursor; /* use cursor positioning */
63 | unsigned char numeric; /* numeric output only */
64 | unsigned char wait; /* wait for data before display */
65 | unsigned char linemode; /* count lines instead of bytes */
66 | unsigned char null; /* lines are null-terminated */
67 | unsigned char no_op; /* do nothing other than pipe data */
68 | unsigned char skip_errors; /* skip read errors flag */
69 | unsigned char stop_at_size; /* set if we stop at "size" bytes */
70 | unsigned char no_splice; /* never use splice() */
71 | unsigned long long rate_limit; /* rate limit, in bytes per second */
72 | unsigned long long target_buffer_size; /* buffer size (0=default) */
73 | unsigned long long size; /* total size of data */
74 | double interval; /* interval between updates */
75 | double delay_start; /* delay before first display */
76 | unsigned int watch_pid; /* process to watch fds of */
77 | int watch_fd; /* fd to watch */
78 | unsigned int width; /* screen width */
79 | unsigned int height; /* screen height */
80 | const char *name; /* display name */
81 | char default_format[512]; /* default format string */
82 | const char *format_string; /* output format string */
83 |
84 | /******************
85 | * Program status *
86 | ******************/
87 | const char *program_name; /* program name for error reporting */
88 | const char *current_file; /* current file being read */
89 | int exit_status; /* exit status to give (0=OK) */
90 |
91 | /*******************
92 | * Signal handling *
93 | *******************/
94 | int pv_sig_old_stderr; /* see pv_sig_ttou() */
95 | struct timeval pv_sig_tstp_time; /* see pv_sig_tstp() / __cont() */
96 | struct timeval pv_sig_toffset; /* total time spent stopped */
97 | volatile sig_atomic_t pv_sig_newsize; /* whether we need to get term size again */
98 | volatile sig_atomic_t pv_sig_abort; /* whether we need to abort right now */
99 | volatile sig_atomic_t reparse_display; /* whether to re-check format string */
100 | struct sigaction pv_sig_old_sigpipe;
101 | struct sigaction pv_sig_old_sigttou;
102 | struct sigaction pv_sig_old_sigtstp;
103 | struct sigaction pv_sig_old_sigcont;
104 | struct sigaction pv_sig_old_sigwinch;
105 | struct sigaction pv_sig_old_sigint;
106 | struct sigaction pv_sig_old_sighup;
107 | struct sigaction pv_sig_old_sigterm;
108 |
109 | /*****************
110 | * Display state *
111 | *****************/
112 | long percentage;
113 | long double prev_elapsed_sec;
114 | long double prev_rate;
115 | long double prev_trans;
116 | unsigned long long initial_offset;
117 | char *display_buffer;
118 | long display_buffer_size;
119 | int lastoutput_length; /* number of last-output bytes to show */
120 | unsigned char lastoutput_buffer[256];
121 | int prev_width; /* screen width last time we were called */
122 | int prev_length; /* length of last string we output */
123 | char str_name[512];
124 | char str_transferred[128];
125 | char str_bufpercent[128];
126 | char str_timer[128];
127 | char str_rate[128];
128 | char str_average_rate[128];
129 | char str_progress[1024];
130 | char str_lastoutput[512];
131 | char str_eta[128];
132 | char str_fineta[128];
133 | unsigned long components_used; /* bitmask of components used */
134 | struct {
135 | const char *string;
136 | int length;
137 | } format[100];
138 | unsigned char display_visible; /* set once anything written to terminal */
139 |
140 | /********************
141 | * Cursor/IPC state *
142 | ********************/
143 | #ifdef HAVE_IPC
144 | int crs_shmid; /* ID of our shared memory segment */
145 | int crs_pvcount; /* number of `pv' processes in total */
146 | int crs_pvmax; /* highest number of `pv's seen */
147 | int *crs_y_top; /* pointer to Y coord of topmost `pv' */
148 | int crs_y_lastread; /* last value of _y_top seen */
149 | int crs_y_offset; /* our Y offset from this top position */
150 | int crs_needreinit; /* set if we need to reinit cursor pos */
151 | int crs_noipc; /* set if we can't use IPC */
152 | #endif /* HAVE_IPC */
153 | int crs_lock_fd; /* fd of lockfile, -1 if none open */
154 | char crs_lock_file[1024];
155 | int crs_y_start; /* our initial Y coordinate */
156 |
157 | /*******************
158 | * Transfer state *
159 | *******************/
160 | /*
161 | * The transfer buffer is used for moving data from the input files
162 | * to the output when splice() is not available.
163 | *
164 | * If buffer_size is smaller than pv__target_bufsize, then
165 | * pv_transfer will try to reallocate transfer_buffer to make
166 | * buffer_size equal to pv__target_bufsize.
167 | *
168 | * Data from the input files is read into the buffer; read_position
169 | * is the offset in the buffer that we've read data up to.
170 | *
171 | * Data is written to the output from the buffer, and write_position
172 | * is the offset in the buffer that we've written data up to. It
173 | * will always be less than or equal to read_position.
174 | */
175 | unsigned char *transfer_buffer; /* data transfer buffer */
176 | unsigned long long buffer_size; /* size of buffer */
177 | unsigned long read_position; /* amount of data in buffer */
178 | unsigned long write_position; /* buffered data written */
179 |
180 | /*
181 | * While reading from a file descriptor we keep track of how many
182 | * times in a row we've seen errors (read_errors_in_a_row), and
183 | * whether or not we have put a warning on stderr about read errors
184 | * on this fd (read_error_warning_shown).
185 | *
186 | * Whenever the active file descriptor changes from
187 | * last_read_skip_fd, we reset read_errors_in_a_row and
188 | * read_error_warning_shown to 0 for the new file descriptor and set
189 | * last_read_skip_fd to the new fd number.
190 | *
191 | * This way, we're treating each input file separately.
192 | */
193 | int last_read_skip_fd;
194 | unsigned long read_errors_in_a_row;
195 | int read_error_warning_shown;
196 | #ifdef HAVE_SPLICE
197 | /*
198 | * These variables are used to keep track of whether splice() was
199 | * used; splice_failed_fd is the file descriptor that splice() last
200 | * failed on, so that we don't keep trying to use it on an fd that
201 | * doesn't support it, and splice_used is set to 1 if splice() was
202 | * used this time within pv_transfer().
203 | */
204 | int splice_failed_fd;
205 | int splice_used;
206 | #endif
207 | long to_write; /* max to write this time around */
208 | long written; /* bytes sent to stdout this time */
209 | };
210 |
211 |
212 | struct pvwatchfd_s {
213 | unsigned int watch_pid; /* PID to watch */
214 | int watch_fd; /* fd to watch, -1 = not displayed */
215 | char file_fdinfo[4096]; /* path to /proc fdinfo file */
216 | char file_fd[4096]; /* path to /proc fd symlink */
217 | char file_fdpath[4096]; /* path to file that was opened */
218 | char display_name[512]; /* name to show on progress bar */
219 | struct stat64 sb_fd; /* stat of fd symlink */
220 | struct stat64 sb_fd_link; /* lstat of fd symlink */
221 | unsigned long long size; /* size of whole file, 0 if unknown */
222 | long long position; /* position last seen at */
223 | struct timeval start_time; /* time we started watching the fd */
224 | };
225 | typedef struct pvwatchfd_s *pvwatchfd_t;
226 |
227 | void pv_error(pvstate_t, char *, ...);
228 |
229 | int pv_main_loop(pvstate_t);
230 | void pv_display(pvstate_t, long double, long long, long long);
231 | long pv_transfer(pvstate_t, int, int *, int *, unsigned long long, long *);
232 | void pv_set_buffer_size(unsigned long long, int);
233 | int pv_next_file(pvstate_t, int, int);
234 |
235 | void pv_crs_fini(pvstate_t);
236 | void pv_crs_init(pvstate_t);
237 | void pv_crs_update(pvstate_t, char *);
238 | #ifdef HAVE_IPC
239 | void pv_crs_needreinit(pvstate_t);
240 | #endif
241 |
242 | void pv_sig_allowpause(void);
243 | void pv_sig_checkbg(void);
244 | void pv_sig_nopause(void);
245 |
246 | void pv_remote_init(pvstate_t);
247 | void pv_remote_check(pvstate_t);
248 | void pv_remote_fini(pvstate_t);
249 | int pv_remote_set(pvstate_t);
250 |
251 | int pv_watchfd_info(pvstate_t, pvwatchfd_t, int);
252 | int pv_watchfd_changed(pvwatchfd_t);
253 | long long pv_watchfd_position(pvwatchfd_t);
254 | int pv_watchpid_scanfds(pvstate_t, pvstate_t, unsigned int, int *, pvwatchfd_t *, pvstate_t *, int *);
255 | void pv_watchpid_setname(pvstate_t, pvwatchfd_t);
256 |
257 | #ifdef __cplusplus
258 | }
259 | #endif
260 |
261 | #endif /* _PV_INTERNAL_H */
262 |
263 | /* EOF */
264 |
--------------------------------------------------------------------------------
/src/include/pv.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Functions used across the program.
3 | */
4 |
5 | #ifndef _PV_H
6 | #define _PV_H 1
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | /*
13 | * Opaque structure for PV internal state.
14 | */
15 | struct pvstate_s;
16 | typedef struct pvstate_s *pvstate_t;
17 |
18 | /*
19 | * Valid number types for pv_getnum_check().
20 | */
21 | typedef enum {
22 | PV_NUMTYPE_INTEGER,
23 | PV_NUMTYPE_DOUBLE
24 | } pv_numtype_t;
25 |
26 |
27 | /*
28 | * Simple string functions for processing numbers.
29 | */
30 |
31 | /*
32 | * Return the given string converted to a double.
33 | */
34 | extern double pv_getnum_d(const char *);
35 |
36 | /*
37 | * Return the given string converted to an integer.
38 | */
39 | extern int pv_getnum_i(const char *);
40 |
41 | /*
42 | * Return the given string converted to a long long.
43 | */
44 | extern long long pv_getnum_ll(const char *);
45 |
46 | /*
47 | * Return zero if the given string is a number of the given type. NB an
48 | * integer is both a valid integer and a valid double.
49 | */
50 | extern int pv_getnum_check(const char *, pv_numtype_t);
51 |
52 | /*
53 | * Main PV functions.
54 | */
55 |
56 | /*
57 | * Create a new state structure, and return it, or 0 (NULL) on error.
58 | */
59 | extern pvstate_t pv_state_alloc(const char *);
60 |
61 | /*
62 | * Set the formatting string, given a set of old-style formatting options.
63 | */
64 | extern void pv_state_set_format(pvstate_t state, unsigned char progress,
65 | unsigned char timer, unsigned char eta,
66 | unsigned char fineta, unsigned char rate,
67 | unsigned char average_rate, unsigned char bytes,
68 | unsigned char bufpercent,
69 | unsigned int lastwritten,
70 | const char *name);
71 |
72 | /*
73 | * Set the various options.
74 | */
75 | extern void pv_state_force_set(pvstate_t, unsigned char);
76 | extern void pv_state_cursor_set(pvstate_t, unsigned char);
77 | extern void pv_state_numeric_set(pvstate_t, unsigned char);
78 | extern void pv_state_wait_set(pvstate_t, unsigned char);
79 | extern void pv_state_delay_start_set(pvstate_t, double);
80 | extern void pv_state_linemode_set(pvstate_t, unsigned char);
81 | extern void pv_state_null_set(pvstate_t, unsigned char);
82 | extern void pv_state_no_op_set(pvstate_t, unsigned char);
83 | extern void pv_state_skip_errors_set(pvstate_t, unsigned char);
84 | extern void pv_state_stop_at_size_set(pvstate_t, unsigned char);
85 | extern void pv_state_rate_limit_set(pvstate_t, unsigned long long);
86 | extern void pv_state_target_buffer_size_set(pvstate_t, unsigned long long);
87 | extern void pv_state_no_splice_set(pvstate_t, unsigned char);
88 | extern void pv_state_size_set(pvstate_t, unsigned long long);
89 | extern void pv_state_interval_set(pvstate_t, double);
90 | extern void pv_state_width_set(pvstate_t, unsigned int);
91 | extern void pv_state_height_set(pvstate_t, unsigned int);
92 | extern void pv_state_name_set(pvstate_t, const char *);
93 | extern void pv_state_format_string_set(pvstate_t, const char *);
94 | extern void pv_state_watch_pid_set(pvstate_t, unsigned int);
95 | extern void pv_state_watch_fd_set(pvstate_t, int);
96 |
97 | extern void pv_state_inputfiles(pvstate_t, int, const char **);
98 |
99 | /*
100 | * Work out the terminal size.
101 | */
102 | extern void pv_screensize(unsigned int *width, unsigned int *height);
103 |
104 | /*
105 | * Calculate the total size of all input files.
106 | */
107 | extern unsigned long long pv_calc_total_size(pvstate_t);
108 |
109 | /*
110 | * Set up signal handlers ready for running the main loop.
111 | */
112 | extern void pv_sig_init(pvstate_t);
113 |
114 | /*
115 | * Enter the main transfer loop, transferring all input files to the output.
116 | */
117 | extern int pv_main_loop(pvstate_t);
118 |
119 | /*
120 | * Watch the selected file descriptor of the selected process.
121 | */
122 | extern int pv_watchfd_loop(pvstate_t);
123 |
124 | /*
125 | * Watch the selected process.
126 | */
127 | extern int pv_watchpid_loop(pvstate_t);
128 |
129 | /*
130 | * Shut down signal handlers after running the main loop.
131 | */
132 | extern void pv_sig_fini(pvstate_t);
133 |
134 | /*
135 | * Free a state structure, after which it can no longer be used.
136 | */
137 | extern void pv_state_free(pvstate_t);
138 |
139 |
140 | #ifdef ENABLE_DEBUGGING
141 | # if __STDC_VERSION__ < 199901L
142 | # if __GNUC__ >= 2
143 | # define __func__ __FUNCTION__
144 | # else
145 | # define __func__ ""
146 | # endif
147 | # endif
148 | # define debug(x,...) debugging_output(__func__, __FILE__, __LINE__, x, __VA_ARGS__)
149 | #else
150 | # define debug(x,...) do { } while (0)
151 | #endif
152 |
153 | /*
154 | * Output debugging information, if debugging is enabled.
155 | */
156 | void debugging_output(const char *, const char *, int, const char *, ...);
157 |
158 |
159 | #ifdef __cplusplus
160 | }
161 | #endif
162 |
163 | #endif /* _PV_H */
164 |
165 | /* EOF */
166 |
--------------------------------------------------------------------------------
/src/library/getopt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Small reimplementation of getopt().
3 | */
4 |
5 | #include "config.h"
6 | #include
7 | #include
8 | #include
9 |
10 | #ifndef HAVE_GETOPT
11 |
12 | char *minioptarg = NULL;
13 | int minioptind = 0;
14 | int miniopterr = 1;
15 | int minioptopt = 0;
16 |
17 |
18 | /*
19 | * Minimalist getopt() clone, which handles short options only and doesn't
20 | * permute argv[].
21 | */
22 | int minigetopt(int argc, char **argv, char *optstring)
23 | {
24 | static int nextchar = 0;
25 | int optchar;
26 | int i;
27 |
28 | if ((0 == minioptind) && (argc > 0))
29 | minioptind++;
30 |
31 | if ((nextchar > 0) && (0 == argv[minioptind][nextchar])) {
32 | minioptind++;
33 | nextchar = 0;
34 | }
35 |
36 | if (minioptind >= argc)
37 | return -1;
38 |
39 | /*
40 | * End of options if arg doesn't start with "-"
41 | */
42 | if (argv[minioptind][0] != '-')
43 | return -1;
44 |
45 | /*
46 | * End of options if arg is just "-"
47 | */
48 | if (0 == argv[minioptind][1])
49 | return -1;
50 |
51 | /*
52 | * End of options if arg is "--", but don't include the "--" in the
53 | * non-option arguments
54 | */
55 | if (('-' == argv[minioptind][1]) && (0 == argv[minioptind][2])) {
56 | minioptind++;
57 | return -1;
58 | }
59 |
60 | if (0 == nextchar)
61 | nextchar = 1;
62 |
63 | optchar = argv[minioptind][nextchar++];
64 |
65 | for (i = 0; optstring[i] != 0 && optstring[i] != optchar; i++) {
66 | }
67 |
68 | if (0 == optstring[i]) {
69 | minioptopt = optchar;
70 | if (miniopterr)
71 | fprintf(stderr, "%s: invalid option -- %c\n",
72 | argv[0], optchar);
73 | return '?';
74 | }
75 |
76 | if (optstring[i + 1] != ':') {
77 | minioptarg = NULL;
78 | return optchar;
79 | }
80 |
81 | /*
82 | * At this point we've got an option that takes an argument.
83 | */
84 |
85 | /*
86 | * Next character isn't 0, so the argument is within this array
87 | * element (i.e. "-dFOO").
88 | */
89 | if (argv[minioptind][nextchar] != 0) {
90 | minioptarg = &(argv[minioptind][nextchar]);
91 | nextchar = 0;
92 | minioptind++;
93 | return optchar;
94 | }
95 |
96 | /*
97 | * Argument is in the next array element (i.e. "-d FOO").
98 | */
99 | nextchar = 0;
100 | minioptind++;
101 | if (minioptind >= argc) {
102 | fprintf(stderr, "%s: option `-%c' requires an argument\n",
103 | argv[0], optchar);
104 | return ':';
105 | }
106 | minioptarg = argv[minioptind++];
107 |
108 | return optchar;
109 | }
110 |
111 | #endif /* HAVE_GETOPT */
112 |
113 | /* EOF */
114 |
--------------------------------------------------------------------------------
/src/library/gettext.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Very minimal (and stupid) implementation of gettext, with a fixed lookup
3 | * table.
4 | *
5 | * This library ONLY handles gettext(), and that only for the basic form (it
6 | * translates strings to other strings with no other modification, so %2$d
7 | * style constructs are not dealt with). The setlocale(), bindtextdomain(),
8 | * and textdomain() functions are ignored.
9 | *
10 | * To use this library, create a function that, given a language string,
11 | * returns a struct msg_table_s[] of msgid and msgstr pairs, with the end
12 | * of the table being marked by a NULL msgid. The po2table.sh script will do
13 | * this.
14 | */
15 |
16 | #include "config.h"
17 | #include
18 | #include
19 | #include
20 |
21 | #ifndef HAVE_GETTEXT
22 |
23 | struct msgtable_s {
24 | char *msgid;
25 | char *msgstr;
26 | };
27 |
28 | #if ENABLE_NLS
29 | struct msgtable_s *minigettext__gettable(char *);
30 | #else /* ENABLE_NLS */
31 | struct msgtable_s *minigettext__gettable(char *a)
32 | {
33 | return NULL;
34 | }
35 | #endif /* ENABLE_NLS */
36 |
37 | char *minisetlocale(char *a, char *b)
38 | {
39 | return NULL;
40 | }
41 |
42 |
43 | char *minibindtextdomain(char *a, char *b)
44 | {
45 | return NULL;
46 | }
47 |
48 |
49 | char *minitextdomain(char *a)
50 | {
51 | return NULL;
52 | }
53 |
54 |
55 | char *minigettext(char *msgid)
56 | {
57 | static struct msgtable_s *table = NULL;
58 | static int tried_lang = 0;
59 | char *lang;
60 | int i;
61 |
62 | if (NULL == msgid)
63 | return msgid;
64 |
65 | if (0 == tried_lang) {
66 | lang = getenv("LANGUAGE");
67 | if (lang)
68 | table = minigettext__gettable(lang);
69 |
70 | if (NULL == table) {
71 | lang = getenv("LANG");
72 | if (lang)
73 | table = minigettext__gettable(lang);
74 | }
75 |
76 | if (NULL == table) {
77 | lang = getenv("LC_ALL");
78 | if (lang)
79 | table = minigettext__gettable(lang);
80 | }
81 |
82 | if (NULL == table) {
83 | lang = getenv("LC_MESSAGES");
84 | if (lang)
85 | table = minigettext__gettable(lang);
86 | }
87 |
88 | tried_lang = 1;
89 | }
90 |
91 | if (NULL == table)
92 | return msgid;
93 |
94 | for (i = 0; table[i].msgid; i++) {
95 | if (0 == strcmp(table[i].msgid, msgid)) {
96 | if (0 == table[i].msgstr)
97 | return msgid;
98 | if (0 == table[i].msgstr[0])
99 | return msgid;
100 | return table[i].msgstr;
101 | }
102 | }
103 |
104 | return msgid;
105 | }
106 |
107 | #endif /* HAVE_GETTEXT */
108 |
109 | /* EOF */
110 |
--------------------------------------------------------------------------------
/src/main/debug.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Output debugging information.
3 | */
4 |
5 | #ifdef HAVE_CONFIG_H
6 | #include "config.h"
7 | #endif
8 | #include "pv.h"
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 |
18 | #ifdef ENABLE_DEBUGGING
19 | /*
20 | * Output debugging information to the file given in the DEBUG environment
21 | * variable, if it is defined.
22 | */
23 | void debugging_output(const char *function, const char *file, int line,
24 | const char *format, ...)
25 | {
26 | static int tried_open = 0;
27 | static FILE *debugfptr = NULL;
28 | char *debugfile;
29 | va_list ap;
30 | time_t t;
31 | struct tm *tm;
32 | char tbuf[128];
33 |
34 | if (0 == tried_open) {
35 | debugfile = getenv("DEBUG");
36 | if (NULL != debugfile)
37 | debugfptr = fopen(debugfile, "a");
38 | tried_open = 1;
39 | }
40 |
41 | if (NULL == debugfptr)
42 | return;
43 |
44 | time(&t);
45 | tm = localtime(&t);
46 | tbuf[0] = 0;
47 | strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", tm);
48 |
49 | fprintf(debugfptr, "[%s] (%d) %s (%s:%d): ", tbuf, getpid(),
50 | function, file, line);
51 |
52 | va_start(ap, format);
53 | vfprintf(debugfptr, format, ap);
54 | va_end(ap);
55 |
56 | fprintf(debugfptr, "\n");
57 | fflush(debugfptr);
58 | }
59 |
60 | #else /* ! ENABLE_DEBUGGING */
61 |
62 | /*
63 | * Stub debugging output function.
64 | */
65 | void debugging_output(const char *function, const char *file, int line,
66 | const char *format, ...)
67 | {
68 | }
69 |
70 | #endif /* ENABLE_DEBUGGING */
71 |
72 | /* EOF */
73 |
--------------------------------------------------------------------------------
/src/main/help.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Output command-line help to stdout.
3 | */
4 |
5 | #ifdef HAVE_CONFIG_H
6 | #include "config.h"
7 | #endif
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #define N_(String) (String)
15 |
16 | struct optdesc_s {
17 | char *optshort;
18 | char *optlong;
19 | char *param;
20 | char *description;
21 | };
22 |
23 |
24 | /*
25 | * Display command-line help.
26 | */
27 | void display_help(void)
28 | {
29 | struct optdesc_s optlist[] = {
30 | {"-p", "--progress", 0,
31 | N_("show progress bar")},
32 | {"-t", "--timer", 0,
33 | N_("show elapsed time")},
34 | {"-e", "--eta", 0,
35 | N_("show estimated time of arrival (completion)")},
36 | {"-I", "--fineta", 0,
37 | N_
38 | ("show absolute estimated time of arrival (completion)")},
39 | {"-r", "--rate", 0,
40 | N_("show data transfer rate counter")},
41 | {"-a", "--average-rate", 0,
42 | N_("show data transfer average rate counter")},
43 | {"-b", "--bytes", 0,
44 | N_("show number of bytes transferred")},
45 | {"-T", "--buffer-percent", 0,
46 | N_("show percentage of transfer buffer in use")},
47 | {"-A", "--last-written", _("NUM"),
48 | N_("show NUM bytes last written")},
49 | {"-F", "--format", N_("FORMAT"),
50 | N_("set output format to FORMAT")},
51 | {"-n", "--numeric", 0,
52 | N_("output percentages, not visual information")},
53 | {"-q", "--quiet", 0,
54 | N_("do not output any transfer information at all")},
55 | {"", 0, 0, 0},
56 | {"-W", "--wait", 0,
57 | N_("display nothing until first byte transferred")},
58 | {"-D", "--delay-start", N_("SEC"),
59 | N_("display nothing until SEC seconds have passed")},
60 | {"-s", "--size", N_("SIZE"),
61 | N_("set estimated data size to SIZE bytes")},
62 | {"-l", "--line-mode", 0,
63 | N_("count lines instead of bytes")},
64 | {"-0", "--null", 0,
65 | N_("lines are null-terminated")},
66 | {"-i", "--interval", N_("SEC"),
67 | N_("update every SEC seconds")},
68 | {"-w", "--width", N_("WIDTH"),
69 | N_("assume terminal is WIDTH characters wide")},
70 | {"-H", "--height", N_("HEIGHT"),
71 | N_("assume terminal is HEIGHT rows high")},
72 | {"-N", "--name", N_("NAME"),
73 | N_("prefix visual information with NAME")},
74 | {"-f", "--force", 0,
75 | N_("output even if standard error is not a terminal")},
76 | {"-c", "--cursor", 0,
77 | N_("use cursor positioning escape sequences")},
78 | {"", 0, 0, 0},
79 | {"-L", "--rate-limit", N_("RATE"),
80 | N_("limit transfer to RATE bytes per second")},
81 | {"-B", "--buffer-size", N_("BYTES"),
82 | N_("use a buffer size of BYTES")},
83 | {"-C", "--no-splice", 0,
84 | N_("never use splice(), always use read/write")},
85 | {"-E", "--skip-errors", 0,
86 | N_("skip read errors in input")},
87 | {"-S", "--stop-at-size", 0,
88 | N_("stop after --size bytes have been transferred")},
89 | #ifdef HAVE_IPC
90 | {"-R", "--remote", N_("PID"),
91 | N_("update settings of process PID")},
92 | #endif /* HAVE_IPC */
93 | {"", 0, 0, 0},
94 | {"-P", "--pidfile", N_("FILE"),
95 | N_("save process ID in FILE")},
96 | {"", 0, 0, 0},
97 | {"-d", "--watchfd", N_("PID[:FD]"),
98 | N_("watch file FD opened by process PID")},
99 | {"", 0, 0, 0},
100 | {"-h", "--help", 0,
101 | N_("show this help and exit")},
102 | {"-V", "--version", 0,
103 | N_("show version information and exit")},
104 | {0, 0, 0, 0}
105 | };
106 | int i, col1max = 0, tw = 77;
107 | char *optbuf;
108 |
109 | printf(_("Usage: %s [OPTION] [FILE]..."), PROGRAM_NAME);
110 | printf("\n%s\n\n",
111 | _
112 | ("Concatenate FILE(s), or standard input, to standard output,\n"
113 | "with monitoring."));
114 |
115 | for (i = 0; optlist[i].optshort; i++) {
116 | int width = 0;
117 | char *param;
118 |
119 | width = 2 + strlen(optlist[i].optshort);
120 | #ifdef HAVE_GETOPT_LONG
121 | if (optlist[i].optlong)
122 | width += 2 + strlen(optlist[i].optlong);
123 | #endif
124 | param = optlist[i].param;
125 | if (param)
126 | param = _(param);
127 | if (param)
128 | width += 1 + strlen(param);
129 |
130 | if (width > col1max)
131 | col1max = width;
132 | }
133 |
134 | col1max++;
135 |
136 | optbuf = malloc(col1max + 16);
137 | if (NULL == optbuf) {
138 | fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno));
139 | exit(1);
140 | }
141 |
142 | for (i = 0; optlist[i].optshort; i++) {
143 | char *param;
144 | char *description;
145 | char *start;
146 | char *end;
147 |
148 | if (0 == optlist[i].optshort[0]) {
149 | printf("\n");
150 | continue;
151 | }
152 |
153 | param = optlist[i].param;
154 | if (param)
155 | param = _(param);
156 | description = optlist[i].description;
157 | if (description)
158 | description = _(description);
159 |
160 | sprintf(optbuf, "%s%s%s%s%s", optlist[i].optshort,
161 | #ifdef HAVE_GETOPT_LONG
162 | optlist[i].optlong ? ", " : "",
163 | optlist[i].optlong ? optlist[i].optlong : "",
164 | #else
165 | "", "",
166 | #endif
167 | param ? " " : "", param ? param : "");
168 |
169 | printf(" %-*s ", col1max - 2, optbuf);
170 |
171 | if (NULL == description) {
172 | printf("\n");
173 | continue;
174 | }
175 |
176 | start = description;
177 |
178 | while (strlen(start) > tw - col1max) {
179 | end = start + tw - col1max;
180 | while ((end > start) && (end[0] != ' '))
181 | end--;
182 | if (end == start) {
183 | end = start + tw - col1max;
184 | } else {
185 | end++;
186 | }
187 | printf("%.*s\n%*s ", (int) (end - start), start,
188 | col1max, "");
189 | if (end == start)
190 | end++;
191 | start = end;
192 | }
193 |
194 | printf("%s\n", start);
195 | }
196 |
197 | #ifdef ENABLE_DEBUGGING
198 | printf("\n");
199 | printf("%s",
200 | _
201 | ("Debugging is enabled; export the DEBUG environment variable to define the\noutput filename.\n"));
202 | #endif
203 |
204 | printf("\n");
205 | printf(_("Please report any bugs to %s."), BUG_REPORTS_TO);
206 | printf("\n");
207 | }
208 |
209 | /* EOF */
210 |
--------------------------------------------------------------------------------
/src/main/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Main program entry point - read the command line options, then perform
3 | * the appropriate actions.
4 | */
5 |
6 | #ifdef HAVE_CONFIG_H
7 | #include "config.h"
8 | #endif
9 | #include "options.h"
10 | #include "pv.h"
11 |
12 | /* #undef MAKE_STDOUT_NONBLOCKING */
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 |
24 | int pv_remote_set(opts_t);
25 | void pv_remote_init(void);
26 | void pv_remote_fini(void);
27 |
28 |
29 | /*
30 | * Process command-line arguments and set option flags, then call functions
31 | * to initialise, and finally enter the main loop.
32 | */
33 | int main(int argc, char **argv)
34 | {
35 | struct termios t, t_save;
36 | opts_t opts;
37 | pvstate_t state;
38 | int retcode = 0;
39 |
40 | #ifdef ENABLE_NLS
41 | setlocale(LC_ALL, "");
42 | bindtextdomain(PACKAGE, LOCALEDIR);
43 | textdomain(PACKAGE);
44 | #endif
45 |
46 | opts = opts_parse(argc, argv);
47 | if (NULL == opts) {
48 | debug("%s: %d", "exiting with status", 64);
49 | return 64;
50 | }
51 |
52 | if (opts->do_nothing) {
53 | debug("%s", "nothing to do - exiting with status 0");
54 | opts_free(opts);
55 | return 0;
56 | }
57 |
58 | /*
59 | * -R specified - send the message, then exit.
60 | */
61 | if (opts->remote > 0) {
62 | retcode = pv_remote_set(opts);
63 | opts_free(opts);
64 | return retcode;
65 | }
66 |
67 | /*
68 | * Allocate our internal state buffer.
69 | */
70 | state = pv_state_alloc(opts->program_name);
71 | if (NULL == state) {
72 | fprintf(stderr, "%s: %s: %s\n", opts->program_name,
73 | _("state allocation failed"), strerror(errno));
74 | opts_free(opts);
75 | debug("%s: %d", "exiting with status", 64);
76 | return 64;
77 | }
78 |
79 | /*
80 | * Write a PID file if -P was specified.
81 | */
82 | if (opts->pidfile != NULL) {
83 | FILE *pidfptr;
84 | pidfptr = fopen(opts->pidfile, "w");
85 | if (NULL == pidfptr) {
86 | fprintf(stderr, "%s: %s: %s\n", opts->program_name,
87 | opts->pidfile, strerror(errno));
88 | pv_state_free(state);
89 | opts_free(opts);
90 | return 1;
91 | }
92 | fprintf(pidfptr, "%d\n", getpid());
93 | fclose(pidfptr);
94 | }
95 |
96 | /*
97 | * If no files were given, pretend "-" was given (stdin).
98 | */
99 | if (0 == opts->argc) {
100 | debug("%s", "no files given - adding fake argument `-'");
101 | opts->argv[opts->argc++] = "-";
102 | }
103 |
104 | /*
105 | * Put our list of files into the PV internal state.
106 | */
107 | pv_state_inputfiles(state, opts->argc,
108 | (const char **) (opts->argv));
109 |
110 | if (0 == opts->watch_pid) {
111 | /*
112 | * If no size was given, and we're not in line mode, try to
113 | * calculate the total size.
114 | */
115 | if ((0 == opts->size) && (0 == opts->linemode)) {
116 | opts->size = pv_calc_total_size(state);
117 | debug("%s: %llu", "no size given - calculated",
118 | opts->size);
119 | }
120 |
121 | /*
122 | * If the size is unknown, we cannot have an ETA.
123 | */
124 | if (opts->size < 1) {
125 | opts->eta = 0;
126 | debug("%s", "size unknown - ETA disabled");
127 | }
128 | }
129 |
130 | /*
131 | * If stderr is not a terminal and we're neither forcing output nor
132 | * outputting numerically, we will have nothing to display at all.
133 | */
134 | if ((0 == isatty(STDERR_FILENO))
135 | && (0 == opts->force)
136 | && (0 == opts->numeric)) {
137 | opts->no_op = 1;
138 | debug("%s", "nothing to display - setting no_op");
139 | }
140 |
141 | /*
142 | * Auto-detect width or height if either are unspecified.
143 | */
144 | if ((0 == opts->width) || (0 == opts->height)) {
145 | unsigned int width, height;
146 | width = 0;
147 | height = 0;
148 | pv_screensize(&width, &height);
149 | if (0 == opts->width) {
150 | opts->width = width;
151 | debug("%s: %u", "auto-detected terminal width",
152 | width);
153 | }
154 | if (0 == opts->height) {
155 | opts->height = height;
156 | debug("%s: %u", "auto-detected terminal height",
157 | height);
158 | }
159 | }
160 |
161 | /*
162 | * Width and height bounds checking (and defaults).
163 | */
164 | if (opts->width < 1)
165 | opts->width = 80;
166 | if (opts->height < 1)
167 | opts->height = 25;
168 | if (opts->width > 999999)
169 | opts->width = 999999;
170 | if (opts->height > 999999)
171 | opts->height = 999999;
172 |
173 | /*
174 | * Interval must be at least 0.1 second, and at most 10 minutes.
175 | */
176 | if (opts->interval < 0.1)
177 | opts->interval = 0.1;
178 | if (opts->interval > 600)
179 | opts->interval = 600;
180 |
181 | /*
182 | * Copy parameters from options into main state.
183 | */
184 | pv_state_interval_set(state, opts->interval);
185 | pv_state_width_set(state, opts->width);
186 | pv_state_height_set(state, opts->height);
187 | pv_state_no_op_set(state, opts->no_op);
188 | pv_state_force_set(state, opts->force);
189 | pv_state_cursor_set(state, opts->cursor);
190 | pv_state_numeric_set(state, opts->numeric);
191 | pv_state_wait_set(state, opts->wait);
192 | pv_state_delay_start_set(state, opts->delay_start);
193 | pv_state_linemode_set(state, opts->linemode);
194 | pv_state_null_set(state, opts->null);
195 | pv_state_skip_errors_set(state, opts->skip_errors);
196 | pv_state_stop_at_size_set(state, opts->stop_at_size);
197 | pv_state_rate_limit_set(state, opts->rate_limit);
198 | pv_state_target_buffer_size_set(state, opts->buffer_size);
199 | pv_state_no_splice_set(state, opts->no_splice);
200 | pv_state_size_set(state, opts->size);
201 | pv_state_name_set(state, opts->name);
202 | pv_state_format_string_set(state, opts->format);
203 | pv_state_watch_pid_set(state, opts->watch_pid);
204 | pv_state_watch_fd_set(state, opts->watch_fd);
205 |
206 | pv_state_set_format(state, opts->progress, opts->timer, opts->eta,
207 | opts->fineta, opts->rate, opts->average_rate,
208 | opts->bytes, opts->bufpercent,
209 | opts->lastwritten, opts->name);
210 |
211 | #ifdef MAKE_STDOUT_NONBLOCKING
212 | /*
213 | * Try and make standard output use non-blocking I/O.
214 | *
215 | * Note that this can cause problems with (broken) applications
216 | * such as dd.
217 | */
218 | fcntl(STDOUT_FILENO, F_SETFL,
219 | O_NONBLOCK | fcntl(STDOUT_FILENO, F_GETFL));
220 | #endif /* MAKE_STDOUT_NONBLOCKING */
221 |
222 | /*
223 | * Set terminal option TOSTOP so we get signal SIGTTOU if we try to
224 | * write to the terminal while backgrounded.
225 | *
226 | * Also, save the current terminal attributes for later restoration.
227 | */
228 | memset(&t, 0, sizeof(t));
229 | tcgetattr(STDERR_FILENO, &t);
230 | t_save = t;
231 | t.c_lflag |= TOSTOP;
232 | tcsetattr(STDERR_FILENO, TCSANOW, &t);
233 |
234 | if (0 != opts->watch_pid) {
235 | if (0 <= opts->watch_fd) {
236 | pv_sig_init(state);
237 | retcode = pv_watchfd_loop(state);
238 | tcsetattr(STDERR_FILENO, TCSANOW, &t_save);
239 | if (opts->pidfile != NULL)
240 | remove(opts->pidfile);
241 | pv_sig_fini(state);
242 | } else {
243 | pv_sig_init(state);
244 | retcode = pv_watchpid_loop(state);
245 | tcsetattr(STDERR_FILENO, TCSANOW, &t_save);
246 | if (opts->pidfile != NULL)
247 | remove(opts->pidfile);
248 | pv_sig_fini(state);
249 | }
250 | } else {
251 | pv_sig_init(state);
252 | pv_remote_init();
253 | retcode = pv_main_loop(state);
254 | pv_remote_fini();
255 | tcsetattr(STDERR_FILENO, TCSANOW, &t_save);
256 | if (opts->pidfile != NULL)
257 | remove(opts->pidfile);
258 | pv_sig_fini(state);
259 | }
260 |
261 | pv_state_free(state);
262 |
263 | opts_free(opts);
264 |
265 | debug("%s: %d", "exiting with status", retcode);
266 |
267 | return retcode;
268 | }
269 |
270 | /* EOF */
271 |
--------------------------------------------------------------------------------
/src/main/options.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Parse command-line options.
3 | */
4 |
5 | #ifdef HAVE_CONFIG_H
6 | #include "config.h"
7 | #endif
8 | #include "options.h"
9 | #include "library/getopt.h"
10 | #include "pv.h"
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 |
19 | void display_help(void);
20 | void display_version(void);
21 |
22 |
23 | /*
24 | * Free an opts_t object.
25 | */
26 | void opts_free(opts_t opts)
27 | {
28 | if (!opts)
29 | return;
30 | if (opts->argv)
31 | free(opts->argv);
32 | free(opts);
33 | }
34 |
35 |
36 | /*
37 | * Parse the given command-line arguments into an opts_t object, handling
38 | * "help", "license" and "version" options internally.
39 | *
40 | * Returns an opts_t, or 0 on error.
41 | *
42 | * Note that the contents of *argv[] (i.e. the command line parameters)
43 | * aren't copied anywhere, just the pointers are copied, so make sure the
44 | * command line data isn't overwritten or argv[1] free()d or whatever.
45 | */
46 | opts_t opts_parse(int argc, char **argv)
47 | {
48 | #ifdef HAVE_GETOPT_LONG
49 | struct option long_options[] = {
50 | {"help", 0, 0, 'h'},
51 | {"version", 0, 0, 'V'},
52 | {"progress", 0, 0, 'p'},
53 | {"timer", 0, 0, 't'},
54 | {"eta", 0, 0, 'e'},
55 | {"fineta", 0, 0, 'I'},
56 | {"rate", 0, 0, 'r'},
57 | {"average-rate", 0, 0, 'a'},
58 | {"bytes", 0, 0, 'b'},
59 | {"buffer-percent", 0, 0, 'T'},
60 | {"last-written", 1, 0, 'A'},
61 | {"force", 0, 0, 'f'},
62 | {"numeric", 0, 0, 'n'},
63 | {"quiet", 0, 0, 'q'},
64 | {"cursor", 0, 0, 'c'},
65 | {"wait", 0, 0, 'W'},
66 | {"delay-start", 1, 0, 'D'},
67 | {"size", 1, 0, 's'},
68 | {"line-mode", 0, 0, 'l'},
69 | {"null", 0, 0, '0'},
70 | {"interval", 1, 0, 'i'},
71 | {"width", 1, 0, 'w'},
72 | {"height", 1, 0, 'H'},
73 | {"name", 1, 0, 'N'},
74 | {"format", 1, 0, 'F'},
75 | {"rate-limit", 1, 0, 'L'},
76 | {"buffer-size", 1, 0, 'B'},
77 | {"no-splice", 0, 0, 'C'},
78 | {"skip-errors", 0, 0, 'E'},
79 | {"stop-at-size", 0, 0, 'S'},
80 | {"remote", 1, 0, 'R'},
81 | {"pidfile", 1, 0, 'P'},
82 | {"watchfd", 1, 0, 'd'},
83 | {0, 0, 0, 0}
84 | };
85 | int option_index = 0;
86 | #endif
87 | char *short_options =
88 | "hVpteIrabTA:fnqcWD:s:l0i:w:H:N:F:L:B:CESR:P:d:";
89 | int c, numopts;
90 | unsigned int check_pid;
91 | int check_fd;
92 | opts_t opts;
93 | char *ptr;
94 |
95 | opts = calloc(1, sizeof(*opts));
96 | if (!opts) {
97 | fprintf(stderr,
98 | _("%s: option structure allocation failed (%s)"),
99 | argv[0], strerror(errno));
100 | fprintf(stderr, "\n");
101 | return 0;
102 | }
103 |
104 | opts->program_name = argv[0];
105 | ptr = strrchr(opts->program_name, '/');
106 | if (NULL != ptr)
107 | opts->program_name = &(ptr[1]);
108 |
109 | opts->argc = 0;
110 | opts->argv = calloc(argc + 1, sizeof(char *));
111 | if (!opts->argv) {
112 | fprintf(stderr,
113 | _
114 | ("%s: option structure argv allocation failed (%s)"),
115 | opts->program_name, strerror(errno));
116 | fprintf(stderr, "\n");
117 | opts_free(opts);
118 | return 0;
119 | }
120 |
121 | numopts = 0;
122 |
123 | opts->interval = 1;
124 | opts->delay_start = 0;
125 | opts->watch_pid = 0;
126 | opts->watch_fd = -1;
127 |
128 | do {
129 | #ifdef HAVE_GETOPT_LONG
130 | c = getopt_long(argc, argv,
131 | short_options, long_options,
132 | &option_index);
133 | #else
134 | c = getopt(argc, argv, short_options);
135 | #endif
136 | if (c < 0)
137 | continue;
138 |
139 | /*
140 | * Check that any numeric arguments are of the right type.
141 | */
142 | switch (c) {
143 | case 's':
144 | case 'A':
145 | case 'w':
146 | case 'H':
147 | case 'L':
148 | case 'B':
149 | case 'R':
150 | if (pv_getnum_check(optarg, PV_NUMTYPE_INTEGER) !=
151 | 0) {
152 | fprintf(stderr, "%s: -%c: %s\n",
153 | opts->program_name, c,
154 | _("integer argument expected"));
155 | opts_free(opts);
156 | return 0;
157 | }
158 | break;
159 | case 'i':
160 | case 'D':
161 | if (pv_getnum_check(optarg, PV_NUMTYPE_DOUBLE) !=
162 | 0) {
163 | fprintf(stderr, "%s: -%c: %s\n",
164 | opts->program_name, c,
165 | _("numeric argument expected"));
166 | opts_free(opts);
167 | return 0;
168 | }
169 | break;
170 | case 'd':
171 | if (sscanf(optarg, "%u:%d", &check_pid, &check_fd)
172 | < 1) {
173 | fprintf(stderr, "%s: -%c: %s\n",
174 | opts->program_name, c,
175 | _
176 | ("process ID or pid:fd pair expected"));
177 | opts_free(opts);
178 | return 0;
179 | }
180 | if (check_pid < 1) {
181 | fprintf(stderr, "%s: -%c: %s\n",
182 | opts->program_name, c,
183 | _("invalid process ID"));
184 | opts_free(opts);
185 | return 0;
186 | }
187 | break;
188 | default:
189 | break;
190 | }
191 |
192 | /*
193 | * Parse each command line option.
194 | */
195 | switch (c) {
196 | case 'h':
197 | display_help();
198 | opts->do_nothing = 1;
199 | return opts;
200 | break;
201 | case 'V':
202 | display_version();
203 | opts->do_nothing = 1;
204 | return opts;
205 | break;
206 | case 'p':
207 | opts->progress = 1;
208 | numopts++;
209 | break;
210 | case 't':
211 | opts->timer = 1;
212 | numopts++;
213 | break;
214 | case 'I':
215 | opts->fineta = 1;
216 | numopts++;
217 | break;
218 | case 'e':
219 | opts->eta = 1;
220 | numopts++;
221 | break;
222 | case 'r':
223 | opts->rate = 1;
224 | numopts++;
225 | break;
226 | case 'a':
227 | opts->average_rate = 1;
228 | numopts++;
229 | break;
230 | case 'b':
231 | opts->bytes = 1;
232 | numopts++;
233 | break;
234 | case 'T':
235 | opts->bufpercent = 1;
236 | numopts++;
237 | break;
238 | case 'A':
239 | opts->lastwritten = pv_getnum_i(optarg);
240 | numopts++;
241 | break;
242 | case 'f':
243 | opts->force = 1;
244 | break;
245 | case 'n':
246 | opts->numeric = 1;
247 | numopts++;
248 | break;
249 | case 'q':
250 | opts->no_op = 1;
251 | numopts++;
252 | break;
253 | case 'c':
254 | opts->cursor = 1;
255 | break;
256 | case 'W':
257 | opts->wait = 1;
258 | break;
259 | case 'D':
260 | opts->delay_start = pv_getnum_d(optarg);
261 | break;
262 | case 's':
263 | opts->size = pv_getnum_ll(optarg);
264 | break;
265 | case 'l':
266 | opts->linemode = 1;
267 | break;
268 | case '0':
269 | opts->null = 1;
270 | opts->linemode = 1;
271 | break;
272 | case 'i':
273 | opts->interval = pv_getnum_d(optarg);
274 | break;
275 | case 'w':
276 | opts->width = pv_getnum_i(optarg);
277 | break;
278 | case 'H':
279 | opts->height = pv_getnum_i(optarg);
280 | break;
281 | case 'N':
282 | opts->name = optarg;
283 | break;
284 | case 'L':
285 | opts->rate_limit = pv_getnum_ll(optarg);
286 | break;
287 | case 'B':
288 | opts->buffer_size = pv_getnum_ll(optarg);
289 | break;
290 | case 'C':
291 | opts->no_splice = 1;
292 | break;
293 | case 'E':
294 | opts->skip_errors++;
295 | break;
296 | case 'S':
297 | opts->stop_at_size = 1;
298 | break;
299 | case 'R':
300 | opts->remote = pv_getnum_i(optarg);
301 | break;
302 | case 'P':
303 | opts->pidfile = optarg;
304 | break;
305 | case 'F':
306 | opts->format = optarg;
307 | break;
308 | case 'd':
309 | opts->watch_pid = 0;
310 | opts->watch_fd = -1;
311 | sscanf(optarg, "%u:%d", &(opts->watch_pid),
312 | &(opts->watch_fd));
313 | break;
314 | default:
315 | #ifdef HAVE_GETOPT_LONG
316 | fprintf(stderr,
317 | _("Try `%s --help' for more information."),
318 | opts->program_name);
319 | #else
320 | fprintf(stderr,
321 | _("Try `%s -h' for more information."),
322 | opts->program_name);
323 | #endif
324 | fprintf(stderr, "\n");
325 | opts_free(opts);
326 | return 0;
327 | break;
328 | }
329 |
330 | } while (c != -1);
331 |
332 | if (0 != opts->watch_pid) {
333 | if (opts->linemode || opts->null || opts->stop_at_size
334 | || (opts->skip_errors > 0) || (opts->buffer_size > 0)
335 | || (opts->rate_limit > 0)) {
336 | fprintf(stderr,
337 | _
338 | ("%s: cannot use line mode or transfer modifier options when watching file descriptors"),
339 | opts->program_name);
340 | fprintf(stderr, "\n");
341 | opts_free(opts);
342 | return 0;
343 | }
344 |
345 | if (opts->cursor) {
346 | fprintf(stderr,
347 | _
348 | ("%s: cannot use cursor positioning when watching file descriptors"),
349 | opts->program_name);
350 | fprintf(stderr, "\n");
351 | opts_free(opts);
352 | return 0;
353 | }
354 |
355 | if (0 != opts->remote) {
356 | fprintf(stderr,
357 | _
358 | ("%s: cannot use remote control when watching file descriptors"),
359 | opts->program_name);
360 | fprintf(stderr, "\n");
361 | opts_free(opts);
362 | return 0;
363 | }
364 |
365 | if (optind < argc) {
366 | fprintf(stderr,
367 | _
368 | ("%s: cannot transfer files when watching file descriptors"),
369 | opts->program_name);
370 | fprintf(stderr, "\n");
371 | opts_free(opts);
372 | return 0;
373 | }
374 |
375 | if (0 != access("/proc/self/fdinfo", X_OK)) {
376 | fprintf(stderr,
377 | _
378 | ("%s: -d: not available on systems without /proc/self/fdinfo"),
379 | opts->program_name);
380 | fprintf(stderr, "\n");
381 | opts_free(opts);
382 | return 0;
383 | }
384 | }
385 |
386 | /*
387 | * Default options: -pterb
388 | */
389 | if (0 == numopts) {
390 | opts->progress = 1;
391 | opts->timer = 1;
392 | opts->eta = 1;
393 | opts->rate = 1;
394 | opts->bytes = 1;
395 | }
396 |
397 | /*
398 | * Store remaining command-line arguments.
399 | */
400 | while (optind < argc) {
401 | opts->argv[opts->argc++] = argv[optind++];
402 | }
403 |
404 | return opts;
405 | }
406 |
407 | /* EOF */
408 |
--------------------------------------------------------------------------------
/src/main/remote.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Remote-control functions.
3 | */
4 |
5 | #ifdef HAVE_CONFIG_H
6 | #include "config.h"
7 | #endif
8 | #include "options.h"
9 | #include "pv.h"
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #ifdef HAVE_IPC
20 | #include
21 | #include
22 | #endif /* HAVE_IPC */
23 |
24 |
25 | #ifdef HAVE_IPC
26 | struct remote_msg {
27 | long mtype;
28 | unsigned char progress; /* progress bar flag */
29 | unsigned char timer; /* timer flag */
30 | unsigned char eta; /* ETA flag */
31 | unsigned char fineta; /* absolute ETA flag */
32 | unsigned char rate; /* rate counter flag */
33 | unsigned char average_rate; /* average rate counter flag */
34 | unsigned char bytes; /* bytes transferred flag */
35 | unsigned char bufpercent; /* transfer buffer percentage flag */
36 | unsigned int lastwritten; /* last-written bytes count */
37 | unsigned long long rate_limit; /* rate limit, in bytes per second */
38 | unsigned long long buffer_size; /* buffer size, in bytes (0=default) */
39 | unsigned long long size; /* total size of data */
40 | double interval; /* interval between updates */
41 | unsigned int width; /* screen width */
42 | unsigned int height; /* screen height */
43 | char name[256];
44 | char format[256];
45 | };
46 |
47 |
48 | static int remote__msgid = -1;
49 |
50 |
51 | /*
52 | * Return a key for use with msgget() which will be unique to the current
53 | * user.
54 | *
55 | * We can't just use ftok() because the queue needs to be user-specific
56 | * so that a user cannot send messages to another user's process, and we
57 | * can't easily find out the terminal a given process is connected to in a
58 | * cross-platform way.
59 | */
60 | static key_t remote__genkey(void)
61 | {
62 | int uid;
63 | key_t key;
64 |
65 | uid = geteuid();
66 | if (uid < 0)
67 | uid = 0;
68 |
69 | key = ftok("/tmp", 'P') | uid;
70 |
71 | return key;
72 | }
73 |
74 |
75 | /*
76 | * Return a message queue ID that is unique to the current user and the
77 | * given process ID, or -1 on error.
78 | */
79 | static int remote__msgget(void)
80 | {
81 | /* Catch SIGSYS in case msgget() raises it, so we get ENOSYS */
82 | signal(SIGSYS, SIG_IGN);
83 | return msgget(remote__genkey(), IPC_CREAT | 0600);
84 | }
85 |
86 |
87 | /*
88 | * Set the options of a remote process by setting up an IPC message queue,
89 | * sending a message containing the new options, and then waiting for the
90 | * message to be consumed by the remote process.
91 | *
92 | * Returns nonzero on error.
93 | */
94 | int pv_remote_set(opts_t opts)
95 | {
96 | struct remote_msg msgbuf;
97 | struct msqid_ds qbuf;
98 | long timeout;
99 | int msgid;
100 | long initial_qnum;
101 |
102 | /*
103 | * Check that the remote process exists.
104 | */
105 | if (kill(opts->remote, 0) != 0) {
106 | fprintf(stderr, "%s: %d: %s\n", opts->program_name,
107 | opts->remote, strerror(errno));
108 | return 1;
109 | }
110 |
111 | /*
112 | * Make sure parameters are within sensible bounds.
113 | */
114 | if (opts->width < 0)
115 | opts->width = 80;
116 | if (opts->height < 0)
117 | opts->height = 25;
118 | if (opts->width > 999999)
119 | opts->width = 999999;
120 | if (opts->height > 999999)
121 | opts->height = 999999;
122 | if ((opts->interval != 0) && (opts->interval < 0.1))
123 | opts->interval = 0.1;
124 | if (opts->interval > 600)
125 | opts->interval = 600;
126 |
127 | /*
128 | * Copy parameters into message buffer.
129 | */
130 | memset(&msgbuf, 0, sizeof(msgbuf));
131 | msgbuf.mtype = opts->remote;
132 | msgbuf.progress = opts->progress;
133 | msgbuf.timer = opts->timer;
134 | msgbuf.eta = opts->eta;
135 | msgbuf.fineta = opts->fineta;
136 | msgbuf.rate = opts->rate;
137 | msgbuf.average_rate = opts->average_rate;
138 | msgbuf.bytes = opts->bytes;
139 | msgbuf.bufpercent = opts->bufpercent;
140 | msgbuf.lastwritten = opts->lastwritten;
141 | msgbuf.rate_limit = opts->rate_limit;
142 | msgbuf.buffer_size = opts->buffer_size;
143 | msgbuf.size = opts->size;
144 | msgbuf.interval = opts->interval;
145 | msgbuf.width = opts->width;
146 | msgbuf.height = opts->height;
147 | if (opts->name != NULL) {
148 | strncpy(msgbuf.name, opts->name, sizeof(msgbuf.name) - 1);
149 | }
150 | if (opts->format != NULL) {
151 | strncpy(msgbuf.format, opts->format,
152 | sizeof(msgbuf.format) - 1);
153 | }
154 |
155 | msgid = remote__msgget();
156 | if (msgid < 0) {
157 | fprintf(stderr, "%s: %s\n", opts->program_name,
158 | strerror(errno));
159 | return 1;
160 | }
161 |
162 | if (msgctl(msgid, IPC_STAT, &qbuf) < 0) {
163 | fprintf(stderr, "%s: %s\n", opts->program_name,
164 | strerror(errno));
165 | return 1;
166 | }
167 |
168 | initial_qnum = qbuf.msg_qnum;
169 |
170 | if (msgsnd(msgid, &msgbuf, sizeof(msgbuf) - sizeof(long), 0) != 0) {
171 | fprintf(stderr, "%s: %s\n", opts->program_name,
172 | strerror(errno));
173 | return 1;
174 | }
175 |
176 | timeout = 1100000;
177 |
178 | while (timeout > 10000) {
179 | struct timeval tv;
180 |
181 | tv.tv_sec = 0;
182 | tv.tv_usec = 10000;
183 | select(0, NULL, NULL, NULL, &tv);
184 | timeout -= 10000;
185 |
186 | /*
187 | * If we can't stat the queue, it must have been deleted.
188 | */
189 | if (msgctl(msgid, IPC_STAT, &qbuf) < 0)
190 | break;
191 |
192 | /*
193 | * If the message count is at or below the message count
194 | * before we sent our message, assume it was received.
195 | */
196 | if (qbuf.msg_qnum <= initial_qnum) {
197 | return 0;
198 | }
199 | }
200 |
201 | /*
202 | * Message not received - delete it.
203 | */
204 | if (msgctl(msgid, IPC_STAT, &qbuf) >= 0) {
205 | msgrcv(msgid, &msgbuf, sizeof(msgbuf) - sizeof(long),
206 | opts->remote, IPC_NOWAIT);
207 | /*
208 | * If this leaves nothing on the queue, remove the
209 | * queue, in case we created one for no reason.
210 | */
211 | if (msgctl(msgid, IPC_STAT, &qbuf) >= 0) {
212 | if (qbuf.msg_qnum < 1)
213 | msgctl(msgid, IPC_RMID, &qbuf);
214 | }
215 | }
216 |
217 | fprintf(stderr, "%s: %d: %s\n", opts->program_name, opts->remote,
218 | _("message not received"));
219 | return 1;
220 | }
221 |
222 |
223 | /*
224 | * Check for an IPC remote handling message and, if there is one, replace
225 | * the current process's options with those being passed in.
226 | *
227 | * NB relies on pv_state_set_format() causing the output format to be
228 | * reparsed.
229 | */
230 | void pv_remote_check(pvstate_t state)
231 | {
232 | struct remote_msg msgbuf;
233 | int got;
234 |
235 | if (remote__msgid < 0)
236 | return;
237 |
238 | memset(&msgbuf, 0, sizeof(msgbuf));
239 |
240 | got =
241 | msgrcv(remote__msgid, &msgbuf, sizeof(msgbuf) - sizeof(long),
242 | getpid(), IPC_NOWAIT);
243 | if (got < 0) {
244 | /*
245 | * If our queue had been deleted, re-create it.
246 | */
247 | if (errno != EAGAIN && errno != ENOMSG) {
248 | remote__msgid = remote__msgget();
249 | }
250 | }
251 | if (got < 1)
252 | return;
253 |
254 | debug("%s", "received remote message");
255 |
256 | pv_state_format_string_set(state, NULL);
257 | pv_state_name_set(state, NULL);
258 |
259 | pv_state_set_format(state, msgbuf.progress, msgbuf.timer,
260 | msgbuf.eta, msgbuf.fineta, msgbuf.rate,
261 | msgbuf.average_rate,
262 | msgbuf.bytes, msgbuf.bufpercent,
263 | msgbuf.lastwritten,
264 | 0 ==
265 | msgbuf.name[0] ? NULL : strdup(msgbuf.name));
266 |
267 | if (msgbuf.rate_limit > 0)
268 | pv_state_rate_limit_set(state, msgbuf.rate_limit);
269 | if (msgbuf.buffer_size > 0) {
270 | pv_state_target_buffer_size_set(state, msgbuf.buffer_size);
271 | }
272 | if (msgbuf.size > 0)
273 | pv_state_size_set(state, msgbuf.size);
274 | if (msgbuf.interval > 0)
275 | pv_state_interval_set(state, msgbuf.interval);
276 | if (msgbuf.width > 0)
277 | pv_state_width_set(state, msgbuf.width);
278 | if (msgbuf.height > 0)
279 | pv_state_height_set(state, msgbuf.height);
280 | if (msgbuf.format[0] != 0)
281 | pv_state_format_string_set(state, strdup(msgbuf.format));
282 | }
283 |
284 |
285 | /*
286 | * Initialise remote message reception handling.
287 | */
288 | void pv_remote_init(void)
289 | {
290 | remote__msgid = remote__msgget();
291 | }
292 |
293 |
294 | /*
295 | * Clean up after remote message reception handling.
296 | */
297 | void pv_remote_fini(void)
298 | {
299 | if (remote__msgid >= 0) {
300 | struct msqid_ds qbuf;
301 | msgctl(remote__msgid, IPC_RMID, &qbuf);
302 | }
303 | }
304 |
305 | #else /* !HAVE_IPC */
306 |
307 | /*
308 | * Dummy stubs for remote control when we don't have IPC.
309 | */
310 | void pv_remote_init(void)
311 | {
312 | }
313 |
314 | void pv_remote_check(pvstate_t state)
315 | {
316 | }
317 |
318 | void pv_remote_fini(void)
319 | {
320 | }
321 |
322 | int pv_remote_set(pvstate_t state)
323 | {
324 | fprintf(stderr, "%s\n", _("IPC not supported on this system"));
325 | return 1;
326 | }
327 |
328 | #endif /* HAVE_IPC */
329 |
330 | /* EOF */
331 |
--------------------------------------------------------------------------------
/src/main/version.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Output version information to stdout.
3 | */
4 |
5 | #ifdef HAVE_CONFIG_H
6 | #include "config.h"
7 | #endif
8 |
9 | #include
10 |
11 |
12 | /*
13 | * Display current package version.
14 | */
15 | void display_version(void)
16 | {
17 | printf(_("%s %s - Copyright %s %s"),
18 | PROGRAM_NAME, VERSION, COPYRIGHT_YEAR, COPYRIGHT_HOLDER);
19 | printf("\n\n");
20 | printf(_("Web site: %s"), PROJECT_HOMEPAGE);
21 | printf("\n\n");
22 | printf("%s",
23 | _("This program is free software, and is being distributed "
24 | "under the\nterms of the Artistic License 2.0."));
25 | printf("\n\n");
26 | printf("%s",
27 | _
28 | ("This program is distributed in the hope that it will be useful,\n"
29 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
30 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."));
31 | printf("\n\n");
32 | }
33 |
34 | /* EOF */
35 |
--------------------------------------------------------------------------------
/src/nls/de.po:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/src/nls/de.po
--------------------------------------------------------------------------------
/src/nls/fr.po:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/src/nls/fr.po
--------------------------------------------------------------------------------
/src/nls/pl.po:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/src/nls/pl.po
--------------------------------------------------------------------------------
/src/nls/pt.po:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icetee/pv/fd138c0c96dd293206d082323665d3847b4ed1fd/src/nls/pt.po
--------------------------------------------------------------------------------
/src/nls/pv.pot:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the PACKAGE package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2017-06-30 22:21+0100\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=CHARSET\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 |
19 | #: src/pv/watchpid.c:51 src/pv/watchpid.c:66 src/pv/watchpid.c:76
20 | #: src/pv/watchpid.c:107 src/pv/loop.c:519 src/pv/loop.c:580 src/pv/loop.c:632
21 | msgid "pid"
22 | msgstr ""
23 |
24 | #: src/pv/watchpid.c:68 src/pv/watchpid.c:78 src/pv/watchpid.c:109
25 | msgid "fd"
26 | msgstr ""
27 |
28 | #: src/pv/watchpid.c:112
29 | msgid "not a regular file or block device"
30 | msgstr ""
31 |
32 | #: src/pv/cursor.c:53
33 | msgid "failed to get terminal name"
34 | msgstr ""
35 |
36 | #: src/pv/cursor.c:96
37 | msgid "failed to open lock file"
38 | msgstr ""
39 |
40 | #: src/pv/cursor.c:129
41 | msgid "lock attempt failed"
42 | msgstr ""
43 |
44 | #: src/pv/cursor.c:369
45 | msgid "failed to open terminal"
46 | msgstr ""
47 |
48 | #: src/pv/file.c:118
49 | msgid "failed to seek to start of output"
50 | msgstr ""
51 |
52 | #: src/pv/file.c:214
53 | msgid "failed to close file"
54 | msgstr ""
55 |
56 | #: src/pv/file.c:237
57 | msgid "failed to read file"
58 | msgstr ""
59 |
60 | #: src/pv/file.c:247
61 | msgid "failed to stat file"
62 | msgstr ""
63 |
64 | #: src/pv/file.c:256
65 | msgid "failed to stat output file"
66 | msgstr ""
67 |
68 | #: src/pv/file.c:279
69 | msgid "input file is output file"
70 | msgstr ""
71 |
72 | #: src/pv/display.c:117
73 | msgid "yzafpnum kMGTPEZY"
74 | msgstr ""
75 |
76 | #: src/pv/display.c:122
77 | msgid "yzafpnum KMGTPEZY"
78 | msgstr ""
79 |
80 | #: src/pv/display.c:532 src/pv/transfer.c:679
81 | msgid "buffer allocation failed"
82 | msgstr ""
83 |
84 | #: src/pv/display.c:592 src/pv/transfer.c:458
85 | msgid "B"
86 | msgstr ""
87 |
88 | #: src/pv/display.c:628 src/pv/display.c:636
89 | msgid "/s"
90 | msgstr ""
91 |
92 | #: src/pv/display.c:628 src/pv/display.c:636
93 | msgid "B/s"
94 | msgstr ""
95 |
96 | #: src/pv/display.c:671 src/pv/display.c:676 src/pv/display.c:738
97 | msgid "ETA"
98 | msgstr ""
99 |
100 | #: src/pv/transfer.c:341
101 | msgid "read failed"
102 | msgstr ""
103 |
104 | #: src/pv/transfer.c:359
105 | msgid "warning: read errors detected"
106 | msgstr ""
107 |
108 | #: src/pv/transfer.c:374
109 | msgid "file is not seekable"
110 | msgstr ""
111 |
112 | #: src/pv/transfer.c:437
113 | msgid "failed to seek past error"
114 | msgstr ""
115 |
116 | #: src/pv/transfer.c:456
117 | msgid "skipped past read error"
118 | msgstr ""
119 |
120 | #: src/pv/transfer.c:631
121 | msgid "write failed"
122 | msgstr ""
123 |
124 | #: src/pv/transfer.c:770
125 | msgid "select call failed"
126 | msgstr ""
127 |
128 | #: src/pv/state.c:33
129 | msgid "none"
130 | msgstr ""
131 |
132 | #: src/main/version.c:17
133 | #, c-format
134 | msgid "%s %s - Copyright %s %s"
135 | msgstr ""
136 |
137 | #: src/main/version.c:20
138 | #, c-format
139 | msgid "Web site: %s"
140 | msgstr ""
141 |
142 | #: src/main/version.c:23
143 | msgid ""
144 | "This program is free software, and is being distributed under the\n"
145 | "terms of the Artistic License 2.0."
146 | msgstr ""
147 |
148 | #: src/main/version.c:28
149 | msgid ""
150 | "This program is distributed in the hope that it will be useful,\n"
151 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
152 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
153 | msgstr ""
154 |
155 | #: src/main/main.c:73
156 | msgid "state allocation failed"
157 | msgstr ""
158 |
159 | #: src/main/options.c:98
160 | #, c-format
161 | msgid "%s: option structure allocation failed (%s)"
162 | msgstr ""
163 |
164 | #: src/main/options.c:114
165 | #, c-format
166 | msgid "%s: option structure argv allocation failed (%s)"
167 | msgstr ""
168 |
169 | #: src/main/options.c:154
170 | msgid "integer argument expected"
171 | msgstr ""
172 |
173 | #: src/main/options.c:165
174 | msgid "numeric argument expected"
175 | msgstr ""
176 |
177 | #: src/main/options.c:176
178 | msgid "process ID or pid:fd pair expected"
179 | msgstr ""
180 |
181 | #: src/main/options.c:183
182 | msgid "invalid process ID"
183 | msgstr ""
184 |
185 | #: src/main/options.c:317
186 | #, c-format
187 | msgid "Try `%s --help' for more information."
188 | msgstr ""
189 |
190 | #: src/main/options.c:321
191 | #, c-format
192 | msgid "Try `%s -h' for more information."
193 | msgstr ""
194 |
195 | #: src/main/options.c:338
196 | #, c-format
197 | msgid ""
198 | "%s: cannot use line mode or transfer modifier options when watching file "
199 | "descriptors"
200 | msgstr ""
201 |
202 | #: src/main/options.c:348
203 | #, c-format
204 | msgid "%s: cannot use cursor positioning when watching file descriptors"
205 | msgstr ""
206 |
207 | #: src/main/options.c:358
208 | #, c-format
209 | msgid "%s: cannot use remote control when watching file descriptors"
210 | msgstr ""
211 |
212 | #: src/main/options.c:368
213 | #, c-format
214 | msgid "%s: cannot transfer files when watching file descriptors"
215 | msgstr ""
216 |
217 | #: src/main/options.c:378
218 | #, c-format
219 | msgid "%s: -d: not available on systems without /proc/self/fdinfo"
220 | msgstr ""
221 |
222 | #: src/main/remote.c:218
223 | msgid "message not received"
224 | msgstr ""
225 |
226 | #: src/main/remote.c:324
227 | msgid "IPC not supported on this system"
228 | msgstr ""
229 |
230 | #: src/main/help.c:31
231 | msgid "show progress bar"
232 | msgstr ""
233 |
234 | #: src/main/help.c:33
235 | msgid "show elapsed time"
236 | msgstr ""
237 |
238 | #: src/main/help.c:35
239 | msgid "show estimated time of arrival (completion)"
240 | msgstr ""
241 |
242 | #: src/main/help.c:38
243 | msgid "show absolute estimated time of arrival (completion)"
244 | msgstr ""
245 |
246 | #: src/main/help.c:40
247 | msgid "show data transfer rate counter"
248 | msgstr ""
249 |
250 | #: src/main/help.c:42
251 | msgid "show data transfer average rate counter"
252 | msgstr ""
253 |
254 | #: src/main/help.c:44
255 | msgid "show number of bytes transferred"
256 | msgstr ""
257 |
258 | #: src/main/help.c:46
259 | msgid "show percentage of transfer buffer in use"
260 | msgstr ""
261 |
262 | #: src/main/help.c:47
263 | msgid "NUM"
264 | msgstr ""
265 |
266 | #: src/main/help.c:48
267 | msgid "show NUM bytes last written"
268 | msgstr ""
269 |
270 | #: src/main/help.c:49
271 | msgid "FORMAT"
272 | msgstr ""
273 |
274 | #: src/main/help.c:50
275 | msgid "set output format to FORMAT"
276 | msgstr ""
277 |
278 | #: src/main/help.c:52
279 | msgid "output percentages, not visual information"
280 | msgstr ""
281 |
282 | #: src/main/help.c:54
283 | msgid "do not output any transfer information at all"
284 | msgstr ""
285 |
286 | #: src/main/help.c:57
287 | msgid "display nothing until first byte transferred"
288 | msgstr ""
289 |
290 | #: src/main/help.c:58 src/main/help.c:66
291 | msgid "SEC"
292 | msgstr ""
293 |
294 | #: src/main/help.c:59
295 | msgid "display nothing until SEC seconds have passed"
296 | msgstr ""
297 |
298 | #: src/main/help.c:60
299 | msgid "SIZE"
300 | msgstr ""
301 |
302 | #: src/main/help.c:61
303 | msgid "set estimated data size to SIZE bytes"
304 | msgstr ""
305 |
306 | #: src/main/help.c:63
307 | msgid "count lines instead of bytes"
308 | msgstr ""
309 |
310 | #: src/main/help.c:65
311 | msgid "lines are null-terminated"
312 | msgstr ""
313 |
314 | #: src/main/help.c:67
315 | msgid "update every SEC seconds"
316 | msgstr ""
317 |
318 | #: src/main/help.c:68
319 | msgid "WIDTH"
320 | msgstr ""
321 |
322 | #: src/main/help.c:69
323 | msgid "assume terminal is WIDTH characters wide"
324 | msgstr ""
325 |
326 | #: src/main/help.c:70
327 | msgid "HEIGHT"
328 | msgstr ""
329 |
330 | #: src/main/help.c:71
331 | msgid "assume terminal is HEIGHT rows high"
332 | msgstr ""
333 |
334 | #: src/main/help.c:72
335 | msgid "NAME"
336 | msgstr ""
337 |
338 | #: src/main/help.c:73
339 | msgid "prefix visual information with NAME"
340 | msgstr ""
341 |
342 | #: src/main/help.c:75
343 | msgid "output even if standard error is not a terminal"
344 | msgstr ""
345 |
346 | #: src/main/help.c:77
347 | msgid "use cursor positioning escape sequences"
348 | msgstr ""
349 |
350 | #: src/main/help.c:79
351 | msgid "RATE"
352 | msgstr ""
353 |
354 | #: src/main/help.c:80
355 | msgid "limit transfer to RATE bytes per second"
356 | msgstr ""
357 |
358 | #: src/main/help.c:81
359 | msgid "BYTES"
360 | msgstr ""
361 |
362 | #: src/main/help.c:82
363 | msgid "use a buffer size of BYTES"
364 | msgstr ""
365 |
366 | #: src/main/help.c:84
367 | msgid "never use splice(), always use read/write"
368 | msgstr ""
369 |
370 | #: src/main/help.c:86
371 | msgid "skip read errors in input"
372 | msgstr ""
373 |
374 | #: src/main/help.c:88
375 | msgid "stop after --size bytes have been transferred"
376 | msgstr ""
377 |
378 | #: src/main/help.c:90
379 | msgid "PID"
380 | msgstr ""
381 |
382 | #: src/main/help.c:91
383 | msgid "update settings of process PID"
384 | msgstr ""
385 |
386 | #: src/main/help.c:94
387 | msgid "FILE"
388 | msgstr ""
389 |
390 | #: src/main/help.c:95
391 | msgid "save process ID in FILE"
392 | msgstr ""
393 |
394 | #: src/main/help.c:97
395 | msgid "PID[:FD]"
396 | msgstr ""
397 |
398 | #: src/main/help.c:98
399 | msgid "watch file FD opened by process PID"
400 | msgstr ""
401 |
402 | #: src/main/help.c:101
403 | msgid "show this help and exit"
404 | msgstr ""
405 |
406 | #: src/main/help.c:103
407 | msgid "show version information and exit"
408 | msgstr ""
409 |
410 | #: src/main/help.c:109
411 | #, c-format
412 | msgid "Usage: %s [OPTION] [FILE]..."
413 | msgstr ""
414 |
415 | #: src/main/help.c:112
416 | msgid ""
417 | "Concatenate FILE(s), or standard input, to standard output,\n"
418 | "with monitoring."
419 | msgstr ""
420 |
421 | #: src/main/help.c:201
422 | msgid ""
423 | "Debugging is enabled; export the DEBUG environment variable to define the\n"
424 | "output filename.\n"
425 | msgstr ""
426 |
427 | #: src/main/help.c:205
428 | #, c-format
429 | msgid "Please report any bugs to %s."
430 | msgstr ""
431 |
--------------------------------------------------------------------------------
/src/pv/file.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Functions for opening and closing files.
3 | */
4 |
5 | #include "pv-internal.h"
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 |
17 | /*
18 | * Try to work out the total size of all data by adding up the sizes of all
19 | * input files. If any of the input files are of indeterminate size (i.e.
20 | * they are a pipe), the total size is set to zero.
21 | *
22 | * Any files that cannot be stat()ed or that access() says we can't read
23 | * will cause a warning to be output and will be removed from the list.
24 | *
25 | * In line mode, any files that pass the above checks will then be read to
26 | * determine how many lines they contain, and the total size will be set to
27 | * the total line count. Only regular files will be read.
28 | *
29 | * Returns the total size, or 0 if it is unknown.
30 | */
31 | unsigned long long pv_calc_total_size(pvstate_t state)
32 | {
33 | unsigned long long total;
34 | struct stat64 sb;
35 | int rc, i, j, fd;
36 |
37 | total = 0;
38 | rc = 0;
39 |
40 | /*
41 | * No files specified - check stdin.
42 | */
43 | if (state->input_file_count < 1) {
44 | if (0 == fstat64(STDIN_FILENO, &sb))
45 | total = sb.st_size;
46 | return total;
47 | }
48 |
49 | for (i = 0; i < state->input_file_count; i++) {
50 | if (0 == strcmp(state->input_files[i], "-")) {
51 | rc = fstat64(STDIN_FILENO, &sb);
52 | if (rc != 0) {
53 | total = 0;
54 | return total;
55 | }
56 | } else {
57 | rc = stat64(state->input_files[i], &sb);
58 | if (0 == rc)
59 | rc = access(state->input_files[i], R_OK);
60 | }
61 |
62 | if (rc != 0) {
63 | pv_error(state, "%s: %s",
64 | state->input_files[i], strerror(errno));
65 | for (j = i; j < state->input_file_count - 1; j++) {
66 | state->input_files[j] =
67 | state->input_files[j + 1];
68 | }
69 | state->input_file_count--;
70 | i--;
71 | state->exit_status |= 2;
72 | continue;
73 | }
74 |
75 | if (S_ISBLK(sb.st_mode)) {
76 | /*
77 | * Get the size of block devices by opening
78 | * them and seeking to the end.
79 | */
80 | if (0 == strcmp(state->input_files[i], "-")) {
81 | fd = open64("/dev/stdin", O_RDONLY);
82 | } else {
83 | fd = open64(state->input_files[i],
84 | O_RDONLY);
85 | }
86 | if (fd >= 0) {
87 | total += lseek64(fd, 0, SEEK_END);
88 | close(fd);
89 | } else {
90 | pv_error(state, "%s: %s",
91 | state->input_files[i],
92 | strerror(errno));
93 | state->exit_status |= 2;
94 | }
95 | } else if (S_ISREG(sb.st_mode)) {
96 | total += sb.st_size;
97 | } else {
98 | total = 0;
99 | }
100 | }
101 |
102 | /*
103 | * Patch from Peter Samuelson: if we cannot work out the size of the
104 | * input, but we are writing to a block device, then use the size of
105 | * the output block device.
106 | *
107 | * Further modified to check that stdout is not in append-only mode
108 | * and that we can seek back to the start after getting the size.
109 | */
110 | if (total <= 0) {
111 | rc = fstat64(STDOUT_FILENO, &sb);
112 | if ((0 == rc) && S_ISBLK(sb.st_mode)
113 | && (0 == (fcntl(STDOUT_FILENO, F_GETFL) & O_APPEND))) {
114 | total = lseek64(STDOUT_FILENO, 0, SEEK_END);
115 | if (lseek64(STDOUT_FILENO, 0, SEEK_SET) != 0) {
116 | pv_error(state, "%s: %s: %s", "(stdout)",
117 | _
118 | ("failed to seek to start of output"),
119 | strerror(errno));
120 | state->exit_status |= 2;
121 | }
122 | /*
123 | * If we worked out a size, then set the
124 | * stop-at-size flag to prevent a "no space left on
125 | * device" error when we reach the end of the output
126 | * device.
127 | */
128 | if (total > 0) {
129 | state->stop_at_size = 1;
130 | }
131 | }
132 | }
133 |
134 | if (!state->linemode)
135 | return total;
136 |
137 | /*
138 | * In line mode, we count input lines to work out the total size.
139 | */
140 | total = 0;
141 |
142 | for (i = 0; i < state->input_file_count; i++) {
143 | fd = -1;
144 |
145 | if (0 == strcmp(state->input_files[i], "-")) {
146 | rc = fstat64(STDIN_FILENO, &sb);
147 | if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
148 | total = 0;
149 | return total;
150 | }
151 | fd = dup(STDIN_FILENO);
152 | } else {
153 | rc = stat64(state->input_files[i], &sb);
154 | if ((rc != 0) || (!S_ISREG(sb.st_mode))) {
155 | total = 0;
156 | return total;
157 | }
158 | fd = open64(state->input_files[i], O_RDONLY);
159 | }
160 |
161 | if (fd < 0) {
162 | pv_error(state, "%s: %s", state->input_files[i],
163 | strerror(errno));
164 | total = 0;
165 | state->exit_status |= 2;
166 | return total;
167 | }
168 |
169 | while (1) {
170 | unsigned char scanbuf[1024];
171 | int numread, j;
172 |
173 | numread = read(fd, scanbuf, sizeof(scanbuf));
174 | if (numread < 0) {
175 | pv_error(state, "%s: %s",
176 | state->input_files[i],
177 | strerror(errno));
178 | state->exit_status |= 2;
179 | break;
180 | } else if (0 == numread) {
181 | break;
182 | }
183 | for (j = 0; j < numread; j++) {
184 | if ('\n' == scanbuf[j])
185 | total++;
186 | }
187 | }
188 |
189 | lseek64(fd, 0, SEEK_SET);
190 | close(fd);
191 | }
192 |
193 | return total;
194 | }
195 |
196 |
197 | /*
198 | * Close the given file descriptor and open the next one, whose number in
199 | * the list is "filenum", returning the new file descriptor (or negative on
200 | * error). It is an error if the next input file is the same as the file
201 | * stdout is pointing to.
202 | *
203 | * Updates state->current_file in the process.
204 | */
205 | int pv_next_file(pvstate_t state, int filenum, int oldfd)
206 | {
207 | struct stat64 isb;
208 | struct stat64 osb;
209 | int fd, input_file_is_stdout;
210 |
211 | if (oldfd > 0) {
212 | if (close(oldfd)) {
213 | pv_error(state, "%s: %s",
214 | _("failed to close file"),
215 | strerror(errno));
216 | state->exit_status |= 8;
217 | return -1;
218 | }
219 | }
220 |
221 | if (filenum >= state->input_file_count) {
222 | state->exit_status |= 8;
223 | return -1;
224 | }
225 |
226 | if (filenum < 0) {
227 | state->exit_status |= 8;
228 | return -1;
229 | }
230 |
231 | if (0 == strcmp(state->input_files[filenum], "-")) {
232 | fd = STDIN_FILENO;
233 | } else {
234 | fd = open64(state->input_files[filenum], O_RDONLY);
235 | if (fd < 0) {
236 | pv_error(state, "%s: %s: %s",
237 | _("failed to read file"),
238 | state->input_files[filenum],
239 | strerror(errno));
240 | state->exit_status |= 2;
241 | return -1;
242 | }
243 | }
244 |
245 | if (fstat64(fd, &isb)) {
246 | pv_error(state, "%s: %s: %s",
247 | _("failed to stat file"),
248 | state->input_files[filenum], strerror(errno));
249 | close(fd);
250 | state->exit_status |= 2;
251 | return -1;
252 | }
253 |
254 | if (fstat64(STDOUT_FILENO, &osb)) {
255 | pv_error(state, "%s: %s",
256 | _("failed to stat output file"), strerror(errno));
257 | close(fd);
258 | state->exit_status |= 2;
259 | return -1;
260 | }
261 |
262 | /*
263 | * Check that this new input file is not the same as stdout's
264 | * destination. This restriction is ignored for anything other
265 | * than a regular file or block device.
266 | */
267 | input_file_is_stdout = 1;
268 | if (isb.st_dev != osb.st_dev)
269 | input_file_is_stdout = 0;
270 | if (isb.st_ino != osb.st_ino)
271 | input_file_is_stdout = 0;
272 | if (isatty(fd))
273 | input_file_is_stdout = 0;
274 | if ((!S_ISREG(isb.st_mode)) && (!S_ISBLK(isb.st_mode)))
275 | input_file_is_stdout = 0;
276 |
277 | if (input_file_is_stdout) {
278 | pv_error(state, "%s: %s",
279 | _("input file is output file"),
280 | state->input_files[filenum]);
281 | close(fd);
282 | state->exit_status |= 4;
283 | return -1;
284 | }
285 |
286 | state->current_file = state->input_files[filenum];
287 | if (0 == strcmp(state->input_files[filenum], "-")) {
288 | state->current_file = "(stdin)";
289 | }
290 | return fd;
291 | }
292 |
293 | /* EOF */
294 |
--------------------------------------------------------------------------------
/src/pv/number.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Functions for converting strings to numbers.
3 | */
4 |
5 | #ifdef HAVE_CONFIG_H
6 | #include "config.h"
7 | #endif
8 | #include "pv.h"
9 |
10 |
11 | /*
12 | * This function is used instead of the macro from because
13 | * including causes weird versioned glibc dependencies on certain
14 | * Red Hat systems, complicating package management.
15 | */
16 | static int pv__isdigit(char c)
17 | {
18 | return ((c >= '0') && (c <= '9'));
19 | }
20 |
21 |
22 | /*
23 | * Return the numeric value of "str", as a long long.
24 | */
25 | long long pv_getnum_ll(const char *str)
26 | {
27 | long long n = 0;
28 | long long decimal = 0;
29 | int decdivisor = 1;
30 | int shift = 0;
31 |
32 | if (0 == str)
33 | return n;
34 |
35 | while (str[0] != 0 && (!pv__isdigit(str[0])))
36 | str++;
37 |
38 | for (; pv__isdigit(str[0]); str++) {
39 | n = n * 10;
40 | n += (str[0] - '0');
41 | }
42 |
43 | /*
44 | * If a decimal value was given, skip the decimal part.
45 | */
46 | if (('.' == str[0]) || (',' == str[0])) {
47 | str++;
48 | for (; pv__isdigit(str[0]); str++) {
49 | if (decdivisor < 10000) {
50 | decimal = decimal * 10;
51 | decimal += (str[0] - '0');
52 | decdivisor = decdivisor * 10;
53 | }
54 | }
55 | }
56 |
57 | /*
58 | * Parse any units given (K=KiB=*1024, M=MiB=1024KiB, G=GiB=1024MiB,
59 | * T=TiB=1024GiB).
60 | */
61 | if (str[0]) {
62 | while ((' ' == str[0]) || ('\t' == str[0]))
63 | str++;
64 | switch (str[0]) {
65 | case 'k':
66 | case 'K':
67 | shift = 10;
68 | break;
69 | case 'm':
70 | case 'M':
71 | shift = 20;
72 | break;
73 | case 'g':
74 | case 'G':
75 | shift = 30;
76 | break;
77 | case 't':
78 | case 'T':
79 | shift = 40;
80 | break;
81 | default:
82 | break;
83 | }
84 | }
85 |
86 | /*
87 | * Binary left-shift the supplied number by "shift" times, i.e.
88 | * apply the given units (KiB, MiB, etc) to it, but never shift left
89 | * more than 30 at a time to avoid overflows.
90 | */
91 | while (shift > 0) {
92 | int shiftby;
93 |
94 | shiftby = shift;
95 | if (shiftby > 30)
96 | shiftby = 30;
97 |
98 | n = n << shiftby;
99 | decimal = decimal << shiftby;
100 | shift -= shiftby;
101 | }
102 |
103 | /*
104 | * Add any decimal component.
105 | */
106 | decimal = decimal / decdivisor;
107 | n += decimal;
108 |
109 | return n;
110 | }
111 |
112 |
113 | /*
114 | * Return the numeric value of "str", as a double.
115 | */
116 | double pv_getnum_d(const char *str)
117 | {
118 | double n = 0.0;
119 | double step = 1;
120 |
121 | if (0 == str)
122 | return n;
123 |
124 | while (str[0] != 0 && (!pv__isdigit(str[0])))
125 | str++;
126 |
127 | for (; pv__isdigit(str[0]); str++) {
128 | n = n * 10;
129 | n += (str[0] - '0');
130 | }
131 |
132 | if ((str[0] != '.') && (str[0] != ','))
133 | return n;
134 |
135 | str++;
136 |
137 | for (; pv__isdigit(str[0]) && step < 1000000; str++) {
138 | step = step * 10;
139 | n += (str[0] - '0') / step;
140 | }
141 |
142 | return n;
143 | }
144 |
145 |
146 | /*
147 | * Return the numeric value of "str", as an int.
148 | */
149 | int pv_getnum_i(const char *str)
150 | {
151 | return (int) pv_getnum_ll(str);
152 | }
153 |
154 |
155 | /*
156 | * Return nonzero if the given string is not a valid number of the given
157 | * type.
158 | */
159 | int pv_getnum_check(const char *str, pv_numtype_t type)
160 | {
161 | if (0 == str)
162 | return 1;
163 |
164 | while ((' ' == str[0]) || ('\t' == str[0]))
165 | str++;
166 |
167 | if (!pv__isdigit(str[0]))
168 | return 1;
169 |
170 | for (; pv__isdigit(str[0]); str++);
171 |
172 | if (('.' == str[0]) || (',' == str[0])) {
173 | if (type == PV_NUMTYPE_INTEGER)
174 | return 1;
175 | str++;
176 | for (; pv__isdigit(str[0]); str++);
177 | }
178 |
179 | if (0 == str[0])
180 | return 0;
181 |
182 | /*
183 | * Suffixes are not allowed for doubles, only for integers.
184 | */
185 | if (type == PV_NUMTYPE_DOUBLE)
186 | return 1;
187 |
188 | while ((' ' == str[0]) || ('\t' == str[0]))
189 | str++;
190 | switch (str[0]) {
191 | case 'k':
192 | case 'K':
193 | case 'm':
194 | case 'M':
195 | case 'g':
196 | case 'G':
197 | case 't':
198 | case 'T':
199 | str++;
200 | break;
201 | default:
202 | return 1;
203 | }
204 |
205 | if (str[0] != 0)
206 | return 1;
207 |
208 | return 0;
209 | }
210 |
211 | /* EOF */
212 |
--------------------------------------------------------------------------------
/src/pv/signal.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Signal handling functions.
3 | */
4 |
5 | #include "pv-internal.h"
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #ifdef HAVE_IPC
15 | void pv_crs_needreinit(pvstate_t);
16 | #endif
17 |
18 | static pvstate_t pv_sig_state = NULL;
19 |
20 |
21 | /*
22 | * Handle SIGTTOU (tty output for background process) by redirecting stderr
23 | * to /dev/null, so that we can be stopped and backgrounded without messing
24 | * up the terminal. We store the old stderr file descriptor so that on a
25 | * subsequent SIGCONT we can try writing to the terminal again, in case we
26 | * get backgrounded and later get foregrounded again.
27 | */
28 | static void pv_sig_ttou(int s)
29 | {
30 | int fd;
31 |
32 | fd = open("/dev/null", O_RDWR);
33 | if (fd < 0)
34 | return;
35 |
36 | if (-1 == pv_sig_state->pv_sig_old_stderr)
37 | pv_sig_state->pv_sig_old_stderr = dup(STDERR_FILENO);
38 |
39 | dup2(fd, STDERR_FILENO);
40 | close(fd);
41 | }
42 |
43 |
44 | /*
45 | * Handle SIGTSTP (stop typed at tty) by storing the time the signal
46 | * happened for later use by pv_sig_cont(), and then stopping the process.
47 | */
48 | static void pv_sig_tstp(int s)
49 | {
50 | gettimeofday(&(pv_sig_state->pv_sig_tstp_time), NULL);
51 | raise(SIGSTOP);
52 | }
53 |
54 |
55 | /*
56 | * Handle SIGCONT (continue if stopped) by adding the elapsed time since the
57 | * last SIGTSTP to the elapsed time offset, and by trying to write to the
58 | * terminal again (by replacing the /dev/null stderr with the old stderr).
59 | */
60 | static void pv_sig_cont(int s)
61 | {
62 | struct timeval tv;
63 | struct termios t;
64 |
65 | pv_sig_state->pv_sig_newsize = 1;
66 |
67 | if (0 == pv_sig_state->pv_sig_tstp_time.tv_sec) {
68 | tcgetattr(STDERR_FILENO, &t);
69 | t.c_lflag |= TOSTOP;
70 | tcsetattr(STDERR_FILENO, TCSANOW, &t);
71 | #ifdef HAVE_IPC
72 | pv_crs_needreinit(pv_sig_state);
73 | #endif
74 | return;
75 | }
76 |
77 | gettimeofday(&tv, NULL);
78 |
79 | pv_sig_state->pv_sig_toffset.tv_sec +=
80 | (tv.tv_sec - pv_sig_state->pv_sig_tstp_time.tv_sec);
81 | pv_sig_state->pv_sig_toffset.tv_usec +=
82 | (tv.tv_usec - pv_sig_state->pv_sig_tstp_time.tv_usec);
83 | if (pv_sig_state->pv_sig_toffset.tv_usec >= 1000000) {
84 | pv_sig_state->pv_sig_toffset.tv_sec++;
85 | pv_sig_state->pv_sig_toffset.tv_usec -= 1000000;
86 | }
87 | if (pv_sig_state->pv_sig_toffset.tv_usec < 0) {
88 | pv_sig_state->pv_sig_toffset.tv_sec--;
89 | pv_sig_state->pv_sig_toffset.tv_usec += 1000000;
90 | }
91 |
92 | pv_sig_state->pv_sig_tstp_time.tv_sec = 0;
93 | pv_sig_state->pv_sig_tstp_time.tv_usec = 0;
94 |
95 | if (pv_sig_state->pv_sig_old_stderr != -1) {
96 | dup2(pv_sig_state->pv_sig_old_stderr, STDERR_FILENO);
97 | close(pv_sig_state->pv_sig_old_stderr);
98 | pv_sig_state->pv_sig_old_stderr = -1;
99 | }
100 |
101 | tcgetattr(STDERR_FILENO, &t);
102 | t.c_lflag |= TOSTOP;
103 | tcsetattr(STDERR_FILENO, TCSANOW, &t);
104 |
105 | #ifdef HAVE_IPC
106 | pv_crs_needreinit(pv_sig_state);
107 | #endif
108 | }
109 |
110 |
111 | /*
112 | * Handle SIGWINCH (window size changed) by setting a flag.
113 | */
114 | static void pv_sig_winch(int s)
115 | {
116 | pv_sig_state->pv_sig_newsize = 1;
117 | }
118 |
119 |
120 | /*
121 | * Handle termination signals by setting the abort flag.
122 | */
123 | static void pv_sig_term(int s)
124 | {
125 | pv_sig_state->pv_sig_abort = 1;
126 | }
127 |
128 |
129 | /*
130 | * Initialise signal handling.
131 | */
132 | void pv_sig_init(pvstate_t state)
133 | {
134 | struct sigaction sa;
135 |
136 | pv_sig_state = state;
137 |
138 | pv_sig_state->pv_sig_old_stderr = -1;
139 | pv_sig_state->pv_sig_tstp_time.tv_sec = 0;
140 | pv_sig_state->pv_sig_tstp_time.tv_usec = 0;
141 | pv_sig_state->pv_sig_toffset.tv_sec = 0;
142 | pv_sig_state->pv_sig_toffset.tv_usec = 0;
143 |
144 | /*
145 | * Ignore SIGPIPE, so we don't die if stdout is a pipe and the other
146 | * end closes unexpectedly.
147 | */
148 | sa.sa_handler = SIG_IGN;
149 | sigemptyset(&(sa.sa_mask));
150 | sa.sa_flags = 0;
151 | sigaction(SIGPIPE, &sa, &(pv_sig_state->pv_sig_old_sigpipe));
152 |
153 | /*
154 | * Handle SIGTTOU by continuing with output switched off, so that we
155 | * can be stopped and backgrounded without messing up the terminal.
156 | */
157 | sa.sa_handler = pv_sig_ttou;
158 | sigemptyset(&(sa.sa_mask));
159 | sa.sa_flags = 0;
160 | sigaction(SIGTTOU, &sa, &(pv_sig_state->pv_sig_old_sigttou));
161 |
162 | /*
163 | * Handle SIGTSTP by storing the time the signal happened for later
164 | * use by pv_sig_cont(), and then stopping the process.
165 | */
166 | sa.sa_handler = pv_sig_tstp;
167 | sigemptyset(&(sa.sa_mask));
168 | sa.sa_flags = 0;
169 | sigaction(SIGTSTP, &sa, &(pv_sig_state->pv_sig_old_sigtstp));
170 |
171 | /*
172 | * Handle SIGCONT by adding the elapsed time since the last SIGTSTP
173 | * to the elapsed time offset, and by trying to write to the
174 | * terminal again.
175 | */
176 | sa.sa_handler = pv_sig_cont;
177 | sigemptyset(&(sa.sa_mask));
178 | sa.sa_flags = 0;
179 | sigaction(SIGCONT, &sa, &(pv_sig_state->pv_sig_old_sigcont));
180 |
181 | /*
182 | * Handle SIGWINCH by setting a flag to let the main loop know it
183 | * has to reread the terminal size.
184 | */
185 | sa.sa_handler = pv_sig_winch;
186 | sigemptyset(&(sa.sa_mask));
187 | sa.sa_flags = 0;
188 | sigaction(SIGWINCH, &sa, &(pv_sig_state->pv_sig_old_sigwinch));
189 |
190 | /*
191 | * Handle SIGINT, SIGHUP, SIGTERM by setting a flag to let the
192 | * main loop know it should quit now.
193 | */
194 | sa.sa_handler = pv_sig_term;
195 | sigemptyset(&(sa.sa_mask));
196 | sa.sa_flags = 0;
197 | sigaction(SIGINT, &sa, &(pv_sig_state->pv_sig_old_sigint));
198 |
199 | sa.sa_handler = pv_sig_term;
200 | sigemptyset(&(sa.sa_mask));
201 | sa.sa_flags = 0;
202 | sigaction(SIGHUP, &sa, &(pv_sig_state->pv_sig_old_sighup));
203 |
204 | sa.sa_handler = pv_sig_term;
205 | sigemptyset(&(sa.sa_mask));
206 | sa.sa_flags = 0;
207 | sigaction(SIGTERM, &sa, &(pv_sig_state->pv_sig_old_sigterm));
208 | }
209 |
210 |
211 | /*
212 | * Shut down signal handling.
213 | */
214 | void pv_sig_fini(pvstate_t state)
215 | {
216 | sigaction(SIGPIPE, &(pv_sig_state->pv_sig_old_sigpipe), NULL);
217 | sigaction(SIGTTOU, &(pv_sig_state->pv_sig_old_sigttou), NULL);
218 | sigaction(SIGTSTP, &(pv_sig_state->pv_sig_old_sigtstp), NULL);
219 | sigaction(SIGCONT, &(pv_sig_state->pv_sig_old_sigcont), NULL);
220 | sigaction(SIGWINCH, &(pv_sig_state->pv_sig_old_sigwinch), NULL);
221 | sigaction(SIGINT, &(pv_sig_state->pv_sig_old_sigint), NULL);
222 | sigaction(SIGHUP, &(pv_sig_state->pv_sig_old_sighup), NULL);
223 | sigaction(SIGTERM, &(pv_sig_state->pv_sig_old_sigterm), NULL);
224 | }
225 |
226 |
227 | /*
228 | * Stop reacting to SIGTSTP and SIGCONT.
229 | */
230 | void pv_sig_nopause(void)
231 | {
232 | struct sigaction sa;
233 |
234 | sa.sa_handler = SIG_IGN;
235 | sigemptyset(&(sa.sa_mask));
236 | sa.sa_flags = 0;
237 | sigaction(SIGTSTP, &sa, NULL);
238 |
239 | sa.sa_handler = SIG_DFL;
240 | sigemptyset(&(sa.sa_mask));
241 | sa.sa_flags = 0;
242 | sigaction(SIGCONT, &sa, NULL);
243 | }
244 |
245 |
246 | /*
247 | * Start catching SIGTSTP and SIGCONT again.
248 | */
249 | void pv_sig_allowpause(void)
250 | {
251 | struct sigaction sa;
252 |
253 | sa.sa_handler = pv_sig_tstp;
254 | sigemptyset(&(sa.sa_mask));
255 | sa.sa_flags = 0;
256 | sigaction(SIGTSTP, &sa, NULL);
257 |
258 | sa.sa_handler = pv_sig_cont;
259 | sigemptyset(&(sa.sa_mask));
260 | sa.sa_flags = 0;
261 | sigaction(SIGCONT, &sa, NULL);
262 | }
263 |
264 |
265 | /*
266 | * If we have redirected stderr to /dev/null, check every second or so to
267 | * see whether we can write to the terminal again - this is so that if we
268 | * get backgrounded, then foregrounded again, we start writing to the
269 | * terminal again.
270 | */
271 | void pv_sig_checkbg(void)
272 | {
273 | static time_t next_check = 0;
274 | struct termios t;
275 |
276 | if (time(NULL) < next_check)
277 | return;
278 |
279 | next_check = time(NULL) + 1;
280 |
281 | if (-1 == pv_sig_state->pv_sig_old_stderr)
282 | return;
283 |
284 | dup2(pv_sig_state->pv_sig_old_stderr, STDERR_FILENO);
285 | close(pv_sig_state->pv_sig_old_stderr);
286 | pv_sig_state->pv_sig_old_stderr = -1;
287 |
288 | tcgetattr(STDERR_FILENO, &t);
289 | t.c_lflag |= TOSTOP;
290 | tcsetattr(STDERR_FILENO, TCSANOW, &t);
291 |
292 | #ifdef HAVE_IPC
293 | pv_crs_needreinit(pv_sig_state);
294 | #endif
295 | }
296 |
297 | /* EOF */
298 |
--------------------------------------------------------------------------------
/src/pv/state.c:
--------------------------------------------------------------------------------
1 | /*
2 | * State management functions.
3 | */
4 |
5 | #include "pv-internal.h"
6 |
7 | #include
8 | #include
9 | #include
10 |
11 |
12 | /*
13 | * Create a new state structure, and return it, or 0 (NULL) on error.
14 | */
15 | pvstate_t pv_state_alloc(const char *program_name)
16 | {
17 | pvstate_t state;
18 |
19 | state = calloc(1, sizeof(*state));
20 | if (0 == state)
21 | return 0;
22 |
23 | state->program_name = program_name;
24 | state->watch_pid = 0;
25 | state->watch_fd = -1;
26 | #ifdef HAVE_IPC
27 | state->crs_shmid = -1;
28 | state->crs_pvcount = 1;
29 | #endif /* HAVE_IPC */
30 | state->crs_lock_fd = -1;
31 |
32 | state->reparse_display = 1;
33 | state->current_file = _("none");
34 | #ifdef HAVE_SPLICE
35 | state->splice_failed_fd = -1;
36 | #endif /* HAVE_SPLICE */
37 | state->display_visible = 0;
38 |
39 | return state;
40 | }
41 |
42 |
43 | /*
44 | * Free a state structure, after which it can no longer be used.
45 | */
46 | void pv_state_free(pvstate_t state)
47 | {
48 | if (0 == state)
49 | return;
50 |
51 | if (state->display_buffer)
52 | free(state->display_buffer);
53 | state->display_buffer = NULL;
54 |
55 | if (state->transfer_buffer)
56 | free(state->transfer_buffer);
57 | state->transfer_buffer = NULL;
58 |
59 | free(state);
60 |
61 | return;
62 | }
63 |
64 |
65 | /*
66 | * Set the formatting string, given a set of old-style formatting options.
67 | */
68 | void pv_state_set_format(pvstate_t state, unsigned char progress,
69 | unsigned char timer, unsigned char eta,
70 | unsigned char fineta, unsigned char rate,
71 | unsigned char average_rate, unsigned char bytes,
72 | unsigned char bufpercent,
73 | unsigned int lastwritten, const char *name)
74 | {
75 | #define PV_ADDFORMAT(x,y) if (x) { \
76 | if (state->default_format[0] != 0) \
77 | strcat(state->default_format, " "); \
78 | strcat(state->default_format, y); \
79 | }
80 |
81 | state->default_format[0] = 0;
82 | PV_ADDFORMAT(name, "%N");
83 | PV_ADDFORMAT(bytes, "%b");
84 | PV_ADDFORMAT(bufpercent, "%T");
85 | PV_ADDFORMAT(timer, "%t");
86 | PV_ADDFORMAT(rate, "%r");
87 | PV_ADDFORMAT(average_rate, "%a");
88 | PV_ADDFORMAT(progress, "%p");
89 | PV_ADDFORMAT(eta, "%e");
90 | PV_ADDFORMAT(fineta, "%I");
91 | if (lastwritten > 0) {
92 | char buf[16];
93 | sprintf(buf, "%%%uA", lastwritten);
94 | PV_ADDFORMAT(lastwritten, buf);
95 | }
96 |
97 | state->name = name;
98 | state->reparse_display = 1;
99 | }
100 |
101 |
102 | void pv_state_force_set(pvstate_t state, unsigned char val)
103 | {
104 | state->force = val;
105 | }
106 |
107 | void pv_state_cursor_set(pvstate_t state, unsigned char val)
108 | {
109 | state->cursor = val;
110 | };
111 |
112 | void pv_state_numeric_set(pvstate_t state, unsigned char val)
113 | {
114 | state->numeric = val;
115 | };
116 |
117 | void pv_state_wait_set(pvstate_t state, unsigned char val)
118 | {
119 | state->wait = val;
120 | };
121 |
122 | void pv_state_delay_start_set(pvstate_t state, double val)
123 | {
124 | state->delay_start = val;
125 | };
126 |
127 | void pv_state_linemode_set(pvstate_t state, unsigned char val)
128 | {
129 | state->linemode = val;
130 | };
131 |
132 | void pv_state_null_set(pvstate_t state, unsigned char val)
133 | {
134 | state->null = val;
135 | };
136 |
137 | void pv_state_no_op_set(pvstate_t state, unsigned char val)
138 | {
139 | state->no_op = val;
140 | };
141 |
142 | void pv_state_skip_errors_set(pvstate_t state, unsigned char val)
143 | {
144 | state->skip_errors = val;
145 | };
146 |
147 | void pv_state_stop_at_size_set(pvstate_t state, unsigned char val)
148 | {
149 | state->stop_at_size = val;
150 | };
151 |
152 | void pv_state_rate_limit_set(pvstate_t state, unsigned long long val)
153 | {
154 | state->rate_limit = val;
155 | };
156 |
157 | void pv_state_target_buffer_size_set(pvstate_t state,
158 | unsigned long long val)
159 | {
160 | state->target_buffer_size = val;
161 | };
162 |
163 | void pv_state_no_splice_set(pvstate_t state, unsigned char val)
164 | {
165 | state->no_splice = val;
166 | };
167 |
168 | void pv_state_size_set(pvstate_t state, unsigned long long val)
169 | {
170 | state->size = val;
171 | };
172 |
173 | void pv_state_interval_set(pvstate_t state, double val)
174 | {
175 | state->interval = val;
176 | };
177 |
178 | void pv_state_width_set(pvstate_t state, unsigned int val)
179 | {
180 | state->width = val;
181 | };
182 |
183 | void pv_state_height_set(pvstate_t state, unsigned int val)
184 | {
185 | state->height = val;
186 | };
187 |
188 | void pv_state_name_set(pvstate_t state, const char *val)
189 | {
190 | state->name = val;
191 | };
192 |
193 | void pv_state_format_string_set(pvstate_t state, const char *val)
194 | {
195 | state->format_string = val;
196 | };
197 |
198 | void pv_state_watch_pid_set(pvstate_t state, unsigned int val)
199 | {
200 | state->watch_pid = val;
201 | };
202 |
203 | void pv_state_watch_fd_set(pvstate_t state, int val)
204 | {
205 | state->watch_fd = val;
206 | };
207 |
208 |
209 | /*
210 | * Set the array of input files.
211 | */
212 | void pv_state_inputfiles(pvstate_t state, int input_file_count,
213 | const char **input_files)
214 | {
215 | state->input_file_count = input_file_count;
216 | state->input_files = input_files;
217 | }
218 |
219 | /* EOF */
220 |
--------------------------------------------------------------------------------
/src/pv/watchpid.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Functions for watching file descriptors in other processes.
3 | */
4 |
5 | #include "pv-internal.h"
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define _GNU_SOURCE 1
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 |
24 | /*
25 | * Fill in the given information structure with the file paths and stat
26 | * details of the given file descriptor within the given process (given
27 | * within the info structure).
28 | *
29 | * Returns nonzero on error - error codes are:
30 | *
31 | * -1 - info or state were NULL
32 | * 1 - process does not exist
33 | * 2 - readlink on /proc/pid/fd/N failed
34 | * 3 - stat or lstat on /proc/pid/fd/N failed
35 | * 4 - file descriptor is not opened on a regular file
36 | *
37 | * If "automatic" is nonzero, then this fd was picked automatically, and so
38 | * if it's not readable or not a regular file, no error is displayed and the
39 | * function just returns an error code.
40 | */
41 | int pv_watchfd_info(pvstate_t state, pvwatchfd_t info, int automatic)
42 | {
43 | if (NULL == state)
44 | return -1;
45 | if (NULL == info)
46 | return -1;
47 |
48 | if (kill(info->watch_pid, 0) != 0) {
49 | if (!automatic)
50 | pv_error(state, "%s %u: %s",
51 | _("pid"),
52 | info->watch_pid, strerror(errno));
53 | return 1;
54 | }
55 |
56 | snprintf(info->file_fdinfo, sizeof(info->file_fdinfo) - 1,
57 | "/proc/%u/fdinfo/%d", info->watch_pid, info->watch_fd);
58 | snprintf(info->file_fd, sizeof(info->file_fd) - 1,
59 | "/proc/%u/fd/%d", info->watch_pid, info->watch_fd);
60 |
61 | if (readlink
62 | (info->file_fd, info->file_fdpath,
63 | sizeof(info->file_fdpath) - 1) < 0) {
64 | if (!automatic)
65 | pv_error(state, "%s %u: %s %d: %s",
66 | _("pid"),
67 | info->watch_pid,
68 | _("fd"), info->watch_fd, strerror(errno));
69 | return 2;
70 | }
71 |
72 | if (!((0 == stat64(info->file_fd, &(info->sb_fd)))
73 | && (0 == lstat64(info->file_fd, &(info->sb_fd_link))))) {
74 | if (!automatic)
75 | pv_error(state, "%s %u: %s %d: %s: %s",
76 | _("pid"),
77 | info->watch_pid,
78 | _("fd"),
79 | info->watch_fd, info->file_fdpath,
80 | strerror(errno));
81 | return 3;
82 | }
83 |
84 | info->size = 0;
85 |
86 | if (S_ISBLK(info->sb_fd.st_mode)) {
87 | int fd;
88 |
89 | /*
90 | * Get the size of block devices by opening
91 | * them and seeking to the end.
92 | */
93 | fd = open64(info->file_fdpath, O_RDONLY);
94 | if (fd >= 0) {
95 | info->size = lseek64(fd, 0, SEEK_END);
96 | close(fd);
97 | } else {
98 | info->size = 0;
99 | }
100 | } else if (S_ISREG(info->sb_fd.st_mode)) {
101 | if ((info->sb_fd_link.st_mode & S_IWUSR) == 0) {
102 | info->size = info->sb_fd.st_size;
103 | }
104 | } else {
105 | if (!automatic)
106 | pv_error(state, "%s %u: %s %d: %s: %s",
107 | _("pid"),
108 | info->watch_pid,
109 | _("fd"),
110 | info->watch_fd,
111 | info->file_fdpath,
112 | _("not a regular file or block device"));
113 | return 4;
114 | }
115 |
116 | return 0;
117 | }
118 |
119 |
120 | /*
121 | * Return nonzero if the given file descriptor has changed in some way since
122 | * we started looking at it (i.e. changed destination or permissions).
123 | */
124 | int pv_watchfd_changed(pvwatchfd_t info)
125 | {
126 | struct stat64 sb_fd, sb_fd_link;
127 |
128 | if ((0 == stat64(info->file_fd, &sb_fd))
129 | && (0 == lstat64(info->file_fd, &sb_fd_link))) {
130 | if ((sb_fd.st_dev != info->sb_fd.st_dev)
131 | || (sb_fd.st_ino != info->sb_fd.st_ino)
132 | || (sb_fd_link.st_mode != info->sb_fd_link.st_mode)
133 | ) {
134 | return 1;
135 | }
136 | } else {
137 | return 1;
138 | }
139 |
140 | return 0;
141 | }
142 |
143 |
144 | /*
145 | * Return the current file position of the given file descriptor, or -1 if
146 | * the fd has closed or has changed in some way.
147 | */
148 | long long pv_watchfd_position(pvwatchfd_t info)
149 | {
150 | long long position;
151 | FILE *fptr;
152 |
153 | if (pv_watchfd_changed(info))
154 | return -1;
155 |
156 | fptr = fopen(info->file_fdinfo, "r");
157 | if (NULL == fptr)
158 | return -1;
159 | position = -1;
160 | fscanf(fptr, "pos: %llu", &position);
161 | fclose(fptr);
162 |
163 | return position;
164 | }
165 |
166 |
167 | /*
168 | * Scan the given process and update the arrays with any new file
169 | * descriptors.
170 | *
171 | * Returns 0 on success, 1 if the process no longer exists or could not be
172 | * read, or 2 for a memory allocation error.
173 | */
174 | int pv_watchpid_scanfds(pvstate_t state, pvstate_t pristine,
175 | unsigned int watch_pid, int *array_length_ptr,
176 | pvwatchfd_t * info_array_ptr,
177 | pvstate_t * state_array_ptr, int *fd_to_idx)
178 | {
179 | char fd_dir[512] = { 0, };
180 | DIR *dptr;
181 | struct dirent *d;
182 | int array_length = 0;
183 | struct pvwatchfd_s *info_array = NULL;
184 | struct pvstate_s *state_array = NULL;
185 |
186 | snprintf(fd_dir, sizeof(fd_dir) - 1, "/proc/%u/fd", watch_pid);
187 | dptr = opendir(fd_dir);
188 | if (NULL == dptr)
189 | return 1;
190 |
191 | array_length = *array_length_ptr;
192 | info_array = *info_array_ptr;
193 | state_array = *state_array_ptr;
194 |
195 | while ((d = readdir(dptr)) != NULL) {
196 | int fd, check_idx, use_idx, rc;
197 | long long position_now;
198 |
199 | fd = -1;
200 | if (sscanf(d->d_name, "%d", &fd) != 1)
201 | continue;
202 | if ((fd < 0) || (fd >= FD_SETSIZE))
203 | continue;
204 |
205 | /*
206 | * Skip if this fd is already known to us.
207 | */
208 | if (fd_to_idx[fd] != -1) {
209 | continue;
210 | }
211 |
212 | /*
213 | * See if there's an empty slot we can re-use. An empty slot
214 | * has a watch_pid of 0.
215 | */
216 | use_idx = -1;
217 | for (check_idx = 0; check_idx < array_length; check_idx++) {
218 | if (info_array[check_idx].watch_pid == 0) {
219 | use_idx = check_idx;
220 | break;
221 | }
222 | }
223 |
224 | /*
225 | * If there's no empty slot, extend the arrays.
226 | */
227 | if (use_idx < 0) {
228 | struct pvwatchfd_s *new_info_array;
229 | struct pvstate_s *new_state_array;
230 |
231 | array_length++;
232 | use_idx = array_length - 1;
233 |
234 | if (NULL == info_array) {
235 | new_info_array =
236 | malloc(array_length *
237 | sizeof(*info_array));
238 | } else {
239 | new_info_array =
240 | realloc(info_array,
241 | array_length *
242 | sizeof(*info_array));
243 | }
244 | if (NULL == new_info_array)
245 | return 2;
246 | info_array = new_info_array;
247 | *info_array_ptr = info_array;
248 | info_array[use_idx].watch_pid = 0;
249 |
250 | if (NULL == state_array) {
251 | new_state_array =
252 | malloc(array_length *
253 | sizeof(*state_array));
254 | } else {
255 | new_state_array =
256 | realloc(state_array,
257 | array_length *
258 | sizeof(*state_array));
259 | }
260 | if (NULL == new_state_array)
261 | return 2;
262 | state_array = new_state_array;
263 | *state_array_ptr = state_array;
264 |
265 | *array_length_ptr = array_length;
266 |
267 | for (check_idx = 0; check_idx < array_length;
268 | check_idx++) {
269 | state_array[check_idx].name =
270 | info_array[check_idx].display_name;
271 | state_array[check_idx].reparse_display = 1;
272 | }
273 | }
274 |
275 | debug("%s: %d => index %d", "found new fd", fd, use_idx);
276 |
277 | /*
278 | * Initialise the details of this new entry.
279 | */
280 | memcpy(&(state_array[use_idx]), pristine,
281 | sizeof(*pristine));
282 | memset(&(info_array[use_idx]), 0,
283 | sizeof(info_array[use_idx]));
284 |
285 | info_array[use_idx].watch_pid = watch_pid;
286 | info_array[use_idx].watch_fd = fd;
287 | rc = pv_watchfd_info(state, &(info_array[use_idx]), 1);
288 |
289 | /*
290 | * Lookup failed - mark this slot as being free for re-use.
291 | */
292 | if ((rc != 0) && (rc != 4)) {
293 | info_array[use_idx].watch_pid = 0;
294 | debug("%s %d: %s: %d", "fd", fd,
295 | "lookup failed - marking slot for re-use",
296 | use_idx);
297 | continue;
298 | }
299 |
300 | fd_to_idx[fd] = use_idx;
301 |
302 | /*
303 | * Not displayable - set fd to -1 so the main loop doesn't
304 | * show it.
305 | */
306 | if (rc != 0) {
307 | debug("%s %d: %s", "fd", fd,
308 | "marking as not displayable");
309 | info_array[use_idx].watch_fd = -1;
310 | }
311 |
312 | state_array[use_idx].size = info_array[use_idx].size;
313 | if (state_array[use_idx].size < 1) {
314 | char *fmt;
315 | while (NULL !=
316 | (fmt =
317 | strstr(state_array[use_idx].default_format,
318 | "%e"))) {
319 | debug("%s", "zero size - removing ETA");
320 | /* strlen-1 here to include trailing NUL */
321 | memmove(fmt, fmt + 2, strlen(fmt) - 1);
322 | state_array[use_idx].reparse_display = 1;
323 | }
324 | }
325 |
326 | state_array[use_idx].name =
327 | info_array[use_idx].display_name;
328 |
329 | pv_watchpid_setname(state, &(info_array[use_idx]));
330 |
331 | state_array[use_idx].reparse_display = 1;
332 |
333 | gettimeofday(&(info_array[use_idx].start_time), NULL);
334 |
335 | state_array[use_idx].initial_offset = 0;
336 | info_array[use_idx].position = 0;
337 |
338 | position_now = pv_watchfd_position(&(info_array[use_idx]));
339 | if (position_now >= 0) {
340 | state_array[use_idx].initial_offset = position_now;
341 | info_array[use_idx].position = position_now;
342 | }
343 | }
344 |
345 | closedir(dptr);
346 |
347 | return 0;
348 | }
349 |
350 |
351 | /*
352 | * Set the display name for the given watched file descriptor, truncating at
353 | * the relevant places according to the current screen width.
354 | */
355 | void pv_watchpid_setname(pvstate_t state, pvwatchfd_t info)
356 | {
357 | int path_length, max_display_length;
358 |
359 | memset(info->display_name, 0, sizeof(info->display_name));
360 |
361 | path_length = strlen(info->file_fdpath);
362 |
363 | max_display_length = (state->width / 2) - 6;
364 | if (max_display_length >= path_length) {
365 | snprintf(info->display_name,
366 | sizeof(info->display_name) - 1, "%4d:%s",
367 | info->watch_fd, info->file_fdpath);
368 | } else {
369 | int prefix_length, suffix_length;
370 |
371 | prefix_length = max_display_length / 4;
372 | suffix_length = max_display_length - prefix_length - 3;
373 |
374 | snprintf(info->display_name,
375 | sizeof(info->display_name) - 1, "%4d:%.*s...%.*s",
376 | info->watch_fd, prefix_length, info->file_fdpath,
377 | suffix_length,
378 | info->file_fdpath + path_length - suffix_length);
379 | }
380 |
381 | debug("%s: %d: [%s]", "set name for fd", info->watch_fd,
382 | info->display_name);
383 | }
384 |
385 | /* EOF */
386 |
--------------------------------------------------------------------------------
/tests/000-cat:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that data can be just passed straight through.
4 |
5 | VALUE=`echo TESTING | $PROG 2>/dev/null` || exit 1
6 | test "$VALUE" = "TESTING"
7 |
8 | # EOF
9 |
--------------------------------------------------------------------------------
/tests/001-interval:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the update interval can be set.
4 |
5 | sleep 1 | $PROG -f -i 0.1 >/dev/null 2>$TMP1
6 |
7 | # There should be more than 6 lines of output.
8 | #
9 | NUM=`tr '\r' '\n' < $TMP1 | wc -l | tr -d ' '`
10 | test $NUM -gt 6
11 |
12 | # EOF
13 |
--------------------------------------------------------------------------------
/tests/002-rate:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # A simple test of rate limiting.
4 |
5 | # Transfer 102 bytes at 100 bytes/sec. It should take at least 1 second.
6 | #
7 | START=`date +%S`
8 | dd if=/dev/zero bs=102 count=1 2>/dev/null | $PROG -L 100 2>/dev/null | cat >/dev/null
9 | END=`date +%S`
10 |
11 | test $START -ne $END
12 |
13 | # EOF
14 |
--------------------------------------------------------------------------------
/tests/003-progress:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the progress bar moves when data is coming in.
4 |
5 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
6 | | $PROG -f -p -i 0.1 -L 500 >/dev/null 2>$TMP1
7 |
8 | # There should be more than 2 different lines of output.
9 | #
10 | NUM=`tr '\r' '\n' < $TMP1 | sort | uniq -u | wc -l | tr -d ' '`
11 | test $NUM -gt 2
12 |
13 | # EOF
14 |
--------------------------------------------------------------------------------
/tests/004-timer:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the elapsed time counter does count up.
4 |
5 | # Transfer a zero amount of data, but take 3 seconds to do it.
6 | #
7 | (sleep 3 | $PROG -f -t >/dev/null) 2>&1 | tr '\r' '\n' > $TMP1
8 |
9 | # Count the number of different timer values; it should be >1.
10 | #
11 | NUM=`sort < $TMP1 | uniq -u | wc -l | tr -d ' '`
12 | test $NUM -gt 1
13 |
14 | # EOF
15 |
--------------------------------------------------------------------------------
/tests/005-eta:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the estimated time counter counts.
4 |
5 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
6 | | $PROG -f -e -s 100 -i 0.1 -L 25 >/dev/null 2>$TMP1
7 |
8 | # Count the number of different ETA values there have been.
9 | #
10 | NUM=`tr '\r' '\n' < $TMP1 | tr -d ' ' | sed '/^$/d' | sort | uniq | wc -l | tr -d ' '`
11 |
12 | # 3 or less - not OK, since it should have taken 4 seconds.
13 | #
14 | test $NUM -gt 3 || exit 1
15 |
16 | # 8 or more - not OK, since even on a heavily loaded system that's too long.
17 | #
18 | test $NUM -lt 8
19 |
20 | # EOF
21 |
--------------------------------------------------------------------------------
/tests/005a-eta:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the estimated time counter counts.
4 |
5 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
6 | | $PROG -f -e -s 100 -i 0.1 -L 25 >/dev/null 2>$TMP1
7 |
8 | # Count the number of different ETA values there have been.
9 | #
10 | NUM=`tr '\r' '\n' < $TMP1 | tr -d ' ' | sed '/^$/d' | sort | uniq | wc -l | tr -d ' '`
11 |
12 | # 3 or less - not OK, since it should have taken 4 seconds.
13 | #
14 | test $NUM -gt 3 || exit 1
15 |
16 | # 8 or more - not OK, since even on a heavily loaded system that's too long.
17 | #
18 | test $NUM -lt 8
19 |
20 | # EOF
21 |
--------------------------------------------------------------------------------
/tests/005b-fineta:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the estimated time counter can show the end time of day.
4 |
5 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
6 | | $PROG -f -I -s 100 -i 0.1 -L 25 >/dev/null 2>$TMP1
7 |
8 | # Count the number of different ETA values there have been.
9 | #
10 | NUM=`tr '\r' '\n' < $TMP1 | tr -d ' ' | sed '/^$/d' | sort | uniq | wc -l | tr -d ' '`
11 |
12 | # There should be at least 1 line of output.
13 | #
14 | test $NUM -gt 0 || exit 1
15 |
16 | # 8 or more different values - not OK.
17 | #
18 | test $NUM -lt 8
19 |
20 | # EOF
21 |
--------------------------------------------------------------------------------
/tests/006-ratecount:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the transfer rate counter changes.
4 |
5 | # Transfer 200 bytes as two 100-byte blocks with a 2-second gap between.
6 | #
7 | (dd if=/dev/zero bs=100 count=1 2>/dev/null;
8 | sleep 2;
9 | dd if=/dev/zero bs=100 count=1 2>/dev/null;
10 | ) | $PROG -f -i 0.5 -r >/dev/null 2>$TMP1
11 |
12 | # Count the number of different rates output.
13 | #
14 | NUM=`tr '\r' '\n' < $TMP1 | sort | uniq -u | wc -l | tr -d ' '`
15 |
16 | # There should be more than 2 different rates counted (around 100 bytes/sec
17 | # for the each block, 0 bytes/sec for the gap in the middle, and around 50
18 | # bytes/sec for the average time reported at the end).
19 | #
20 | test $NUM -gt 2
21 |
22 | # EOF
23 |
--------------------------------------------------------------------------------
/tests/007-bytes:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the byte counter counts.
4 |
5 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
6 | | LANG=C $PROG -f -b >/dev/null 2>$TMP1
7 | NUM=`tr '\r' '\n' < $TMP1 | tr -d ' '`
8 | test "$NUM" = "100B"
9 |
10 | # EOF
11 |
--------------------------------------------------------------------------------
/tests/008-numeric:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that numeric output outputs some percentages.
4 |
5 | # Process 100 bytes at 100 bytes per second, updating every 0.1 seconds for
6 | # around 10 output lines.
7 | #
8 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
9 | | $PROG -s 100 -n -i 0.1 -L 100 >/dev/null 2>$TMP1
10 |
11 | # The number of output lines should be >8 and <13, and the final percentage
12 | # should be 100.
13 | #
14 | test `wc -l < $TMP1` -gt 8
15 | test `wc -l < $TMP1` -lt 13
16 | test `sed -n '$p' < $TMP1` -eq 100
17 |
18 | # EOF
19 |
--------------------------------------------------------------------------------
/tests/009-quiet:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the -q option shuts everything up.
4 |
5 | dd if=/dev/zero bs=1000 count=5 2>/dev/null \
6 | | $PROG -f -q -i 0.1 -L 5000 >/dev/null 2>$TMP1
7 | test ! -s $TMP1
8 |
9 | # EOF
10 |
--------------------------------------------------------------------------------
/tests/010-pipe:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that there is no SIGPIPE or dropped data on bigger data transfers.
4 |
5 | # We nead GNU head. On some platforms it is named ghead instead of head.
6 | HEAD=head
7 | for p in `echo $PATH | tr ':' '\n'`
8 | do
9 | if test -x $p/ghead
10 | then
11 | HEAD=$p/ghead
12 | break
13 | fi
14 | done
15 |
16 | # Don't use dd. See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=324308
17 | COUNT1=100000000
18 | #COUNT2=`$PROG -B 100000 -q /dev/zero | $HEAD -c $COUNT1 | wc -c | tr -d ' '`
19 | # Remove \n to fix the test on AIX
20 | COUNT2=`$PROG -B 100000 -q /dev/zero | $HEAD -c $COUNT1 | tr -d '\n' | wc -c | tr -d ' '`
21 |
22 | #echo "[$COUNT1] [$COUNT2]"
23 |
24 | test "x$COUNT1" = "x$COUNT2"
25 |
26 | # EOF
27 |
--------------------------------------------------------------------------------
/tests/011-cksum:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Transfer a large chunk of data through pv and check data correctness
4 | # afterwards.
5 |
6 | rm -f $TMP1 $TMP2 2>/dev/null
7 |
8 | # exit on non-zero return codes
9 | set -e
10 |
11 | # generate some data
12 | dd if=/dev/urandom of=$TMP1 bs=1024 count=10240 2>/dev/null
13 |
14 | CKSUM1=`cksum $TMP1 | awk '{print $1}'`
15 |
16 | # read through pv and test afterwards
17 | $PROG -B 100000 -q $TMP1 > $TMP2
18 |
19 | CKSUM2=`cksum $TMP2 | awk '{print $1}'`
20 |
21 | test "x$CKSUM1" = "x$CKSUM2"
22 |
23 | # clean up
24 | rm -f $TMP1 $TMP2 2>/dev/null
25 |
26 | # EOF
27 |
--------------------------------------------------------------------------------
/tests/012-averagerate:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the average transfer rate counter changes, but not more than it
4 | # should.
5 |
6 | # Transfer 210 bytes as 100 bytes, a 1 second gap, 110 bytes, and another 1
7 | # second gap.
8 | #
9 | (dd if=/dev/zero bs=100 count=1 2>/dev/null;
10 | sleep 1;
11 | dd if=/dev/zero bs=110 count=1 2>/dev/null;
12 | sleep 1;
13 | ) | $PROG -f -i 0.5 -a >/dev/null 2>$TMP1
14 |
15 | # Count the number of rates output that are below 80.
16 | #
17 | NUM=`tr '\r' '\n' < $TMP1 | tr -dc '0-9.\n' | sed '/^$/d' | awk '$1<80{print}' | wc -l | tr -d ' '`
18 |
19 | # Nearly all of the output rates should be above 80 since the average rate
20 | # will always be around 100 bytes per second, except for pauses.
21 | #
22 | test $NUM -lt 2
23 |
24 | # EOF
25 |
--------------------------------------------------------------------------------
/tests/013-1mboundary:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that the bytes count doesn't increase the line length as it passes
4 | # 1MiB, described here:
5 | # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=586763
6 |
7 | # Transfer 1500kB of data in a bursty fashion.
8 | #
9 | (dd if=/dev/zero bs=1k count=999;
10 | sleep 1;
11 | dd if=/dev/zero bs=1k count=1;
12 | sleep 1;
13 | dd if=/dev/zero bs=1k count=500;
14 | sleep 1;
15 | ) 2>/dev/null | ($PROG -btef -s 1500k >/dev/null) 2>$TMP1
16 |
17 | # Count how many different line lengths we've seen.
18 | #
19 | NUM=`tr '\r' '\n' < $TMP1 | awk '{x=length($0);if(x>0)print length($0)}' | sort | uniq | wc -l`
20 |
21 | # There should only be one length (not counting 0).
22 | #
23 | test $NUM -eq 1 || { echo; tr '\r' '\n' < $TMP1; exit 1; }
24 |
25 | # EOF
26 |
--------------------------------------------------------------------------------
/tests/014-1mboundary2:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Same as test 13 (1mboundary) but for rate, not bytes transferred.
4 |
5 | # Transfer 1500kB of data in a bursty fashion.
6 | #
7 | (dd if=/dev/zero bs=1k count=999;
8 | sleep 1;
9 | dd if=/dev/zero bs=1k count=1;
10 | sleep 1;
11 | dd if=/dev/zero bs=3 count=1;
12 | sleep 1;
13 | dd if=/dev/zero bs=1k count=500;
14 | sleep 1;
15 | ) 2>/dev/null | ($PROG -rtef -s 1500k >/dev/null) 2>$TMP1
16 |
17 | # Count how many different line lengths we've seen.
18 | #
19 | NUM=`tr '\r' '\n' < $TMP1 | awk '{x=length($0);if(x>0)print length($0)}' | sort | uniq | wc -l`
20 |
21 | # There should only be one length (not counting 0).
22 | #
23 | test $NUM -eq 1 || { echo; tr '\r' '\n' < $TMP1; exit 1; }
24 |
25 | # EOF
26 |
--------------------------------------------------------------------------------
/tests/015-cksumpipe:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Transfer a large chunk of data through pv using pipes, sending it in a
4 | # bursty fashion, and check data correctness afterwards.
5 |
6 | rm -f $TMP1 $TMP2 2>/dev/null
7 |
8 | # exit on non-zero return codes
9 | set -e
10 |
11 | # generate some data
12 | dd if=/dev/urandom of=$TMP1 bs=1024 count=10240 2>/dev/null
13 |
14 | CKSUM1=`cksum $TMP1 | awk '{print $1}'`
15 |
16 | # read through pv and test afterwards
17 | (
18 | dd if=$TMP1 bs=1 count=9000
19 | sleep 1
20 | dd if=$TMP1 bs=1 skip=9000 count=1240
21 | sleep 1
22 | dd if=$TMP1 bs=1024 skip=10 count=1014
23 | sleep 1
24 | dd if=$TMP1 bs=1024 skip=1024 count=1024
25 | sleep 1
26 | dd if=$TMP1 bs=1024 skip=2048
27 | ) 2>/dev/null | $PROG -q -L 2M | cat > $TMP2
28 |
29 | CKSUM2=`cksum $TMP2 | awk '{print $1}'`
30 |
31 | test "x$CKSUM1" = "x$CKSUM2"
32 |
33 | # same again but with one less pipe
34 | (
35 | dd if=$TMP1 bs=1 count=9000
36 | sleep 1
37 | dd if=$TMP1 bs=1 skip=9000 count=1240
38 | sleep 1
39 | dd if=$TMP1 bs=1024 skip=10 count=1014
40 | sleep 1
41 | dd if=$TMP1 bs=1024 skip=1024 count=1024
42 | sleep 1
43 | dd if=$TMP1 bs=1024 skip=2048
44 | ) 2>/dev/null | $PROG -q -L 2M > $TMP2
45 |
46 | CKSUM2=`cksum $TMP2 | awk '{print $1}'`
47 |
48 | test "x$CKSUM1" = "x$CKSUM2"
49 |
50 | # clean up
51 | rm -f $TMP1 $TMP2 2>/dev/null
52 |
53 | # EOF
54 |
--------------------------------------------------------------------------------
/tests/016-numeric-timer:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that numeric output gives a timer when used with -t.
4 |
5 | # Process 100 bytes at 100 bytes per second, updating every 0.1 seconds for
6 | # around 10 output lines.
7 | #
8 | dd if=/dev/zero bs=100 count=1 2>/dev/null \
9 | | $PROG -s 100 -n -t -i 0.1 -L 100 >/dev/null 2>$TMP1
10 |
11 | # The number of output lines should be >8 and <13, and the number of
12 | # different elapsed times should be at least 7. The last percentage should
13 | # be 100.
14 | #
15 | test `wc -l < $TMP1` -gt 8
16 | test `wc -l < $TMP1` -lt 13
17 | test `tr , . < "$TMP1" | awk '{print int(10*$1)}' | sort -n | uniq | wc -l` -gt 7
18 | test `sed -n '$p' < $TMP1 | awk '{print $2}'` -eq 100
19 |
20 | # EOF
21 |
--------------------------------------------------------------------------------
/tests/017-numeric-bytes:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Check that numeric output gives a byte count instead of a percentage when
4 | # used with -b.
5 |
6 | # Process 500 bytes at 500 bytes per second, updating every 0.1 seconds for
7 | # around 10 output lines.
8 | #
9 | dd if=/dev/zero bs=500 count=1 2>/dev/null \
10 | | $PROG -s 500 -n -b -i 0.1 -L 500 >/dev/null 2>$TMP1
11 |
12 | # The number of output lines should be >8 and <13, and the final byte count
13 | # should be 500.
14 | #
15 | test `wc -l < $TMP1` -gt 8
16 | test `wc -l < $TMP1` -lt 13
17 | test `sed -n '$p' < $TMP1` -eq 500
18 |
19 | # EOF
20 |
--------------------------------------------------------------------------------
/tests/018-remote-format:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Try changing the format of a transfer remotely.
4 |
5 | # Do nothing if IPC is not supported.
6 | if ! $PROG -h | grep -Eq "^ -R,"; then
7 | echo "SKIPPED" | tr "\n" ' '
8 | exit 0
9 | fi
10 |
11 | rm -f $TMP1 $TMP2 $TMP3 $TMP4 2>/dev/null
12 |
13 | # Exit on non-zero return codes.
14 | set -e
15 |
16 | # Generate an empty test file.
17 | dd if=/dev/zero of=$TMP1 bs=1024 count=10240 2>/dev/null
18 |
19 | (
20 | sleep 1
21 | $PROG -R `cat $TMP4` -a
22 | sleep 2
23 | $PROG -R `cat $TMP4` -L 10M
24 | ) &
25 |
26 | $PROG -L 2M -f -P $TMP4 $TMP1 > $TMP2 2>$TMP3
27 |
28 | # Make sure there is more than one length of line (excluding blank lines).
29 | line_lengths=`tr '\r' '\n' < "$TMP3" | awk '{print length($0)}' | grep -Fvx 0 | sort -n | uniq | wc -l`
30 | test $line_lengths -gt 1
31 |
32 | # EOF
33 |
--------------------------------------------------------------------------------
/tests/019-remote-cksum:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Try repeatedly messaging a transfer process, and make sure the data stays
4 | # intact.
5 |
6 | # Do nothing if IPC is not supported.
7 | if ! $PROG -h | grep -Eq "^ -R,"; then
8 | echo "SKIPPED" | tr "\n" ' '
9 | exit 0
10 | fi
11 |
12 | rm -f $TMP1 $TMP2 $TMP3 $TMP4 2>/dev/null
13 |
14 | # Exit on non-zero return codes.
15 | set -e
16 |
17 | # Generate some data.
18 | dd if=/dev/urandom of=$TMP1 bs=1024 count=10240 2>/dev/null
19 |
20 | # Run a few remote control commands in the background.
21 | #
22 | echo FAIL > $TMP3
23 | (
24 | set +e
25 | sleep 2
26 | for x in 1 2 3; do
27 | $PROG -R `cat $TMP4` -apterb || exit 1
28 | (usleep 200000 || sleep 1) 2>/dev/null
29 | $PROG -R `cat $TMP4` -p || exit 1
30 | (usleep 200000 || sleep 1) 2>/dev/null
31 | $PROG -R `cat $TMP4` -N "test" || exit 1
32 | (usleep 200000 || sleep 1) 2>/dev/null
33 | $PROG -R `cat $TMP4` -F "%e" || exit 1
34 | (usleep 200000 || sleep 1) 2>/dev/null
35 | $PROG -R `cat $TMP4` -N "." || exit 1
36 | (usleep 200000 || sleep 1) 2>/dev/null
37 | done
38 | $PROG -R `cat $TMP4` -L 10M
39 | echo OK > $TMP3
40 | ) &
41 |
42 | # Run our data transfer.
43 | $PROG -L 100k -i 0.1 -f -P $TMP4 $TMP1 > $TMP2 2>/dev/null
44 |
45 | # Check our remote control calls ran OK.
46 | BGSTATUS=`cat $TMP3`
47 | test "x$BGSTATUS" = "xOK"
48 |
49 | # Check data integrity.
50 | CKSUM1=`cksum $TMP1 | awk '{print $1}'`
51 | CKSUM2=`cksum $TMP2 | awk '{print $1}'`
52 | test "x$CKSUM1" = "x$CKSUM2"
53 |
54 | # EOF
55 |
--------------------------------------------------------------------------------
/tests/020-stop-at-size:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Make sure -S stops at the given size.
4 |
5 | rm -f $TMP1 $TMP2 2>/dev/null
6 |
7 | # exit on non-zero return codes
8 | set -e
9 |
10 | # generate some data
11 | dd if=/dev/urandom of=$TMP1 bs=1024 count=10 2>/dev/null
12 |
13 | # read through pv and test afterwards
14 | $PROG -S -s 5120 -q $TMP1 > $TMP2
15 |
16 | CKSUM2=`cksum $TMP2 | awk '{print $1}'`
17 |
18 | # take the first 5120 bytes of TMP1 and cksum them
19 | rm -f $TMP2
20 | dd if=$TMP1 of=$TMP2 bs=1024 count=5 2>/dev/null
21 | CKSUM1=`cksum $TMP2 | awk '{print $1}'`
22 |
23 | test "x$CKSUM1" = "x$CKSUM2"
24 |
25 | # clean up
26 | rm -f $TMP1 $TMP2 2>/dev/null
27 |
28 | # EOF
29 |
--------------------------------------------------------------------------------