├── 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 '

Source Code Index

' 51 | echo '

' 56 | 57 | echo '

File Listing

' 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 '' 79 | echo '' 80 | echo '' 81 | echo '
' 78 | echo ''"$FILE"' - '`html_safe "$FILESHORTDESC"`'

' 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 '

Function Listing

' 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 '

To Do Listing

' 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 | --------------------------------------------------------------------------------