1
0
Fork 0

Merging upstream version 1.2~pre2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 05:45:19 +01:00
parent f9513766bb
commit efa0d5eefe
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
22 changed files with 804 additions and 87 deletions

View file

@ -1,3 +1,8 @@
2013-09-04 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.2-pre2 released.
* Added new utility; zupdate.
2013-08-02 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.1 released.

View file

@ -1,6 +1,7 @@
Requirements
------------
You will need a C++ compiler.
You will need a C++ compiler, (de)compressors for bzip2 and gzip
formats, and a compressor for the lzip format.
I use gcc 4.8.1 and 3.3.6, but the code should compile with any
standards compliant compiler.
Gcc is available at http://gcc.gnu.org.

View file

@ -10,6 +10,7 @@ SHELL = /bin/sh
objs = arg_parser.o rc.o zutils.o main.o
zcmp_objs = arg_parser.o rc.o zutils.o zcmp.o
zdiff_objs = arg_parser.o rc.o zutils.o zdiff.o
zupdate_objs = arg_parser.o rc.o zutils.o zupdate.o
scripts = zcat zegrep zfgrep zgrep ztest
@ -17,7 +18,7 @@ scripts = zcat zegrep zfgrep zgrep ztest
uninstall uninstall-bin uninstall-info uninstall-man \
doc info man check dist clean distclean
all : $(progname) zcmp zdiff $(scripts)
all : $(progname) zcmp zdiff zupdate $(scripts)
$(progname) : $(objs)
$(CXX) $(LDFLAGS) -o $@ $(objs)
@ -51,6 +52,9 @@ ztest : ztest.in
cat $(VPATH)/ztest.in > $@
chmod a+x ztest
zupdate : $(zupdate_objs)
$(CXX) $(LDFLAGS) -o $@ $(zupdate_objs)
main.o : main.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DGREP=\"$(GREP)\" -c -o $@ $<
@ -73,6 +77,7 @@ main.o : arg_parser.h zutils.h rc.h zcat.cc zgrep.cc ztest.cc
rc.o : arg_parser.h zutils.h rc.h
zcmp.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile
zdiff.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile
zupdate.o : arg_parser.h zutils.h rc.h Makefile
zutils.o : zutils.h rc.h
@ -84,7 +89,7 @@ $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zcmp.1 $(VPATH)/doc/zdiff.1 \
$(VPATH)/doc/zgrep.1 $(VPATH)/doc/ztest.1
$(VPATH)/doc/zgrep.1 $(VPATH)/doc/ztest.1 $(VPATH)/doc/zupdate.1
$(VPATH)/doc/zcat.1 : $(progname) zcat
help2man -n 'decompress and concatenate files to standard output' \
@ -106,6 +111,10 @@ $(VPATH)/doc/ztest.1 : $(progname) ztest
help2man -n 'verify integrity of compressed files' \
-o $@ --no-info ./ztest
$(VPATH)/doc/zupdate.1 : zupdate
help2man -n 'recompress bzip2, gzip, xz files to lzip files' \
-o $@ --no-info ./zupdate
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
./config.status
@ -124,6 +133,7 @@ install-bin : all
$(INSTALL_SCRIPT) ./zfgrep "$(DESTDIR)$(bindir)/zfgrep"
$(INSTALL_SCRIPT) ./zgrep "$(DESTDIR)$(bindir)/zgrep"
$(INSTALL_SCRIPT) ./ztest "$(DESTDIR)$(bindir)/ztest"
$(INSTALL_PROGRAM) ./zupdate "$(DESTDIR)$(bindir)/zupdate"
if [ ! -e "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ] ; then \
if [ ! -d "$(DESTDIR)$(sysconfdir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)" ; fi ; \
$(INSTALL_DATA) $(VPATH)/$(pkgname)rc "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ; \
@ -141,6 +151,7 @@ install-man :
$(INSTALL_DATA) $(VPATH)/doc/zdiff.1 "$(DESTDIR)$(mandir)/man1/zdiff.1"
$(INSTALL_DATA) $(VPATH)/doc/zgrep.1 "$(DESTDIR)$(mandir)/man1/zgrep.1"
$(INSTALL_DATA) $(VPATH)/doc/ztest.1 "$(DESTDIR)$(mandir)/man1/ztest.1"
$(INSTALL_DATA) $(VPATH)/doc/zupdate.1 "$(DESTDIR)$(mandir)/man1/zupdate.1"
install-strip : all
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
@ -156,6 +167,7 @@ uninstall-bin :
-rm -f "$(DESTDIR)$(bindir)/zfgrep"
-rm -f "$(DESTDIR)$(bindir)/zgrep"
-rm -f "$(DESTDIR)$(bindir)/ztest"
-rm -f "$(DESTDIR)$(bindir)/zupdate"
-rm -f "$(DESTDIR)$(sysconfdir)/$(pkgname)rc"
uninstall-info :
@ -168,6 +180,7 @@ uninstall-man :
-rm -f "$(DESTDIR)$(mandir)/man1/zdiff.1"
-rm -f "$(DESTDIR)$(mandir)/man1/zgrep.1"
-rm -f "$(DESTDIR)$(mandir)/man1/ztest.1"
-rm -f "$(DESTDIR)$(mandir)/man1/zupdate.1"
dist : doc
ln -sf $(VPATH) $(DISTNAME)
@ -195,7 +208,7 @@ dist : doc
clean :
-rm -f $(progname) $(progname)_profiled $(objs)
-rm -f zcmp zcmp.o zdiff zdiff.o $(scripts)
-rm -f zcmp zcmp.o zdiff zdiff.o zupdate zupdate.o $(scripts)
distclean : clean
-rm -f Makefile config.status *.tar *.tar.lz

14
NEWS
View file

@ -1,12 +1,4 @@
Changes in version 1.1:
Changes in version 1.2:
The new options "--bz2", "--gz", "--lz" and "--xz" have been added to
all utilities.
Zutils now provides the runtime configuration file "zutilsrc", which
allows the user change the compressor to be used for each format.
The checking of the exit status of compressors has been improved.
The use of "decompressed" and "uncompressed" in the documentation has
been revised.
The new utility zupdate, which recompresses bzip2, gzip and xz files to
lzip format, has been added.

View file

@ -156,12 +156,12 @@ Arg_parser::Arg_parser( const int argc, const char * const argv[],
while( argind < argc )
{
const unsigned char ch1 = argv[argind][0];
const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 );
const unsigned char ch2 = ch1 ? argv[argind][1] : 0;
if( ch1 == '-' && ch2 ) // we found an option
{
const char * const opt = argv[argind];
const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0;
const char * const arg = ( argind + 1 < argc ) ? argv[argind+1] : 0;
if( ch2 == '-' )
{
if( !argv[argind][2] ) { ++argind; break; } // we found "--"

2
configure vendored
View file

@ -6,7 +6,7 @@
# to copy, distribute and modify it.
pkgname=zutils
pkgversion=1.1
pkgversion=1.2-pre2
progname=zutils
srctrigger=doc/${pkgname}.texinfo

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCAT "1" "August 2013" "Zcat (zutils) 1.1" "User Commands"
.TH ZCAT "1" "September 2013" "Zcat (zutils) 1.2-pre2" "User Commands"
.SH NAME
Zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCMP "1" "August 2013" "Zcmp (zutils) 1.1" "User Commands"
.TH ZCMP "1" "September 2013" "Zcmp (zutils) 1.2-pre2" "User Commands"
.SH NAME
Zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZDIFF "1" "August 2013" "Zdiff (zutils) 1.1" "User Commands"
.TH ZDIFF "1" "September 2013" "Zdiff (zutils) 1.2-pre2" "User Commands"
.SH NAME
Zdiff \- decompress and compare two files line by line
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZGREP "1" "August 2013" "Zgrep (zutils) 1.1" "User Commands"
.TH ZGREP "1" "September 2013" "Zgrep (zutils) 1.2-pre2" "User Commands"
.SH NAME
Zgrep \- search compressed files for a regular expression
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZTEST "1" "August 2013" "Ztest (zutils) 1.1" "User Commands"
.TH ZTEST "1" "September 2013" "Ztest (zutils) 1.2-pre2" "User Commands"
.SH NAME
Ztest \- verify integrity of compressed files
.SH SYNOPSIS

76
doc/zupdate.1 Normal file
View file

@ -0,0 +1,76 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZUPDATE "1" "September 2013" "Zupdate (zutils) 1.2-pre2" "User Commands"
.SH NAME
Zupdate \- recompress bzip2, gzip, xz files to lzip files
.SH SYNOPSIS
.B zupdate
[\fIoptions\fR] [\fIfiles\fR]
.SH DESCRIPTION
Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.
The originals are compared with the new files and then deleted.
Only regular files with standard file name extensions are recompressed,
other files are ignored.
Compressed files are decompressed and then recompressed on the fly; no
temporary files are created.
The lzip format is chosen as destination because it is by far the most
appropriate for long\-term data archiving.
.PP
If the lzip compressed version of a file already exists, the file is
skipped unless the '\-\-force' option is given. In this case, if the
comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted.
.PP
Exit status is 0 if all the compressed files were successfully
recompressed (if needed), compared and deleted. Non\-zero otherwise.
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
display this help and exit
.TP
\fB\-V\fR, \fB\-\-version\fR
output version information and exit
.TP
\fB\-f\fR, \fB\-\-force\fR
do not skip a file even if the .lz exists
.TP
\fB\-l\fR, \fB\-\-lzip\-verbose\fR
pass a \fB\-v\fR option to the lzip compressor
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
\fB\-r\fR, \fB\-\-recursive\fR
operate recursively on directories
.TP
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-0\fR .. \fB\-9\fR
set compression level [default 9]
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org
.br
Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT
Copyright \(co 2013 Antonio Diaz Diaz.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
.br
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

View file

@ -12,7 +12,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual
*************
This manual is for Zutils (version 1.1, 2 August 2013).
This manual is for Zutils (version 1.2-pre2, 4 September 2013).
* Menu:
@ -24,11 +24,12 @@ This manual is for Zutils (version 1.1, 2 August 2013).
* Zdiff:: Comparing compressed files line by line
* Zgrep:: Searching inside compressed files
* Ztest:: Testing integrity of compressed files
* Zupdate:: Recompressing files to lzip format
* Problems:: Reporting bugs
* Concept index:: Index of concepts
Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
Copyright (C) 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to
copy, distribute and modify it.
@ -49,12 +50,13 @@ are created.
C++ programs. In particular the `--recursive' option is very efficient
in those utilities supporting it.
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest.
The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate.
The supported formats are bzip2, gzip, lzip and xz.
The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils.
scripts provided with GNU gzip. Ztest is unique to zutils. Zupdate is
similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status,
which makes them safe to use with zutils. Gzip and xz may return
@ -545,7 +547,7 @@ matches were found, and 2 means trouble.

File: zutils.info, Node: Ztest, Next: Problems, Prev: Zgrep, Up: Top
File: zutils.info, Node: Ztest, Next: Zupdate, Prev: Zgrep, Up: Top
8 Ztest
*******
@ -588,10 +590,76 @@ environmental problems (file not found, invalid flags, I/O errors, etc),

File: zutils.info, Node: Problems, Next: Concept index, Prev: Ztest, Up: Top
File: zutils.info, Node: Zupdate, Next: Problems, Prev: Ztest, Up: Top
9 Reporting Bugs
****************
9 Zupdate
*********
Zupdate recompresses files from bzip2, gzip, and xz formats to lzip
format. The originals are compared with the new files and then deleted.
Only regular files with standard file name extensions are recompressed,
other files are ignored. Compressed files are decompressed and then
recompressed on the fly; no temporary files are created. The lzip format
is chosen as destination because it is by far the most appropriate for
long-term data archiving.
If the lzip compressed version of a file already exists, the file is
skipped unless the `--force' option is given. In this case, if the
comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted.
The names of the original files must have one of the following
extensions: `.bz2', `.tbz', `.tbz2', `.gz', `.tgz', `.xz', `.txz'. The
files produced have the extensions `.lz' or `.tar.lz'.
The format for running zupdate is:
zupdate [OPTIONS] [FILES]
Exit status is 0 if all the compressed files were successfully
recompressed (if needed), compared and deleted. Non-zero otherwise.
Zupdate supports the following options:
`-f'
`--force'
Do not skip a file for which a lzip compressed version already
exists. `--force' compares the content of the input file with the
content of the lzip file and deletes the input file if both
contents are identical.
`-l'
`--lzip-verbose'
Pass a `-v' option to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and
newer, a second `-l' shows the progress of compression. Use it
together with `-v' to see the name of the file.
`-q'
`--quiet'
Quiet operation. Suppress all messages.
`-r'
`--recursive'
Operate recursively on directories.
`-v'
`--verbose'
Verbose mode. Show the files being processed. A second `-v' also
shows the files being ignored.
`-0 .. -9'
Set the compression level of lzip. By default zupdate passes `-9'
to lzip.

File: zutils.info, Node: Problems, Next: Concept index, Prev: Zupdate, Up: Top
10 Reporting bugs
*****************
There are probably bugs in zutils. There are certainly errors and
omissions in this manual. If you report them, they will get fixed. If
@ -621,21 +689,23 @@ Concept index
* zdiff: Zdiff. (line 6)
* zgrep: Zgrep. (line 6)
* ztest: Ztest. (line 6)
* zupdate: Zupdate. (line 6)

Tag Table:
Node: Top224
Node: Introduction1095
Node: Common options3153
Node: The zutilsrc file4402
Node: Zcat5328
Node: Zcmp7250
Node: Zdiff9574
Node: Zgrep12077
Node: Ztest14914
Node: Problems16139
Node: Concept index16668
Node: Introduction1156
Node: Common options3258
Node: The zutilsrc file4507
Node: Zcat5433
Node: Zcmp7355
Node: Zdiff9679
Node: Zgrep12182
Node: Ztest15019
Node: Zupdate16243
Node: Problems18477
Node: Concept index19010

End Tag Table

View file

@ -6,8 +6,8 @@
@finalout
@c %**end of header
@set UPDATED 2 August 2013
@set VERSION 1.1
@set UPDATED 4 September 2013
@set VERSION 1.2-pre2
@dircategory Data Compression
@direntry
@ -43,13 +43,13 @@ This manual is for Zutils (version @value{VERSION}, @value{UPDATED}).
* Zdiff:: Comparing compressed files line by line
* Zgrep:: Searching inside compressed files
* Ztest:: Testing integrity of compressed files
* Zupdate:: Recompressing files to lzip format
* Problems:: Reporting bugs
* Concept index:: Index of concepts
@end menu
@sp 1
Copyright @copyright{} 2008, 2009, 2010, 2011, 2012, 2013
Antonio Diaz Diaz.
Copyright @copyright{} 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission
to copy, distribute and modify it.
@ -70,12 +70,13 @@ programs. In particular the @samp{--recursive} option is very efficient
in those utilities supporting it.
@noindent
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest.@*
The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate.@*
The supported formats are bzip2, gzip, lzip and xz.@*
The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils.
scripts provided with GNU gzip. Ztest is unique to zutils. Zupdate is
similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which
makes them safe to use with zutils. Gzip and xz may return ambiguous
@ -638,14 +639,85 @@ Operate recursively on directories.
@item -v
@itemx --verbose
Verbose mode. Show the verify status for each file processed.
Verbose mode. Show the verify status for each file processed.@*
Further -v's increase the verbosity level.
@end table
@node Zupdate
@chapter Zupdate
@cindex zupdate
Zupdate recompresses files from bzip2, gzip, and xz formats to lzip
format. The originals are compared with the new files and then deleted.
Only regular files with standard file name extensions are recompressed,
other files are ignored. Compressed files are decompressed and then
recompressed on the fly; no temporary files are created. The lzip format
is chosen as destination because it is by far the most appropriate for
long-term data archiving.
If the lzip compressed version of a file already exists, the file is
skipped unless the @samp{--force} option is given. In this case, if the
comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted.
The names of the original files must have one of the following
extensions: @samp{.bz2}, @samp{.tbz}, @samp{.tbz2}, @samp{.gz},
@samp{.tgz}, @samp{.xz}, @samp{.txz}. The files produced have the
extensions @samp{.lz} or @samp{.tar.lz}.
The format for running zupdate is:
@example
zupdate [@var{options}] [@var{files}]
@end example
@noindent
Exit status is 0 if all the compressed files were successfully
recompressed (if needed), compared and deleted. Non-zero otherwise.
Zupdate supports the following options:
@table @samp
@item -f
@itemx --force
Do not skip a file for which a lzip compressed version already exists.
@samp{--force} compares the content of the input file with the content
of the lzip file and deletes the input file if both contents are
identical.
@item -l
@itemx --lzip-verbose
Pass a @samp{-v} option to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and newer, a
second @samp{-l} shows the progress of compression. Use it together with
@samp{-v} to see the name of the file.
@item -q
@itemx --quiet
Quiet operation. Suppress all messages.
@item -r
@itemx --recursive
Operate recursively on directories.
@item -v
@itemx --verbose
Verbose mode. Show the files being processed. A second @samp{-v} also
shows the files being ignored.
@item -0 .. -9
Set the compression level of lzip. By default zupdate passes @samp{-9}
to lzip.
@end table
@node Problems
@chapter Reporting Bugs
@chapter Reporting bugs
@cindex bugs
@cindex getting help

View file

@ -275,7 +275,7 @@ int main( const int argc, const char * const argv[] )
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
const char * arg = parser.argument( argind ).c_str();
const char * const arg = parser.argument( argind ).c_str();
if( !code )
{
if( program_mode == m_zgrep && !grep_pattern_found )
@ -399,7 +399,7 @@ int main( const int argc, const char * const argv[] )
if( recursive )
{
struct stat st;
if( !stat( input_filename.c_str(), &st ) && S_ISDIR( st.st_mode ) )
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{
DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp )

View file

@ -16,6 +16,7 @@ ZGREP="${objdir}"/zgrep
ZEGREP="${objdir}"/zegrep
ZFGREP="${objdir}"/zfgrep
ZTEST="${objdir}"/ztest
ZUPDATE="${objdir}"/zupdate
compressors="bzip2 gzip lzip"
extensions="bz2 gz lz"
compressor_needed() { echo "${compressors} are needed to run tests" ; exit 1 ; }
@ -45,9 +46,9 @@ cat in.lz > lz_only.lz || framework_failure
cat in in in in in in > in6 || framework_failure
fail=0
printf "testing zutils-%s..." "$2"
printf "testing zutils-%s..." "$2"
printf "\ntesting zcat-%s..." "$2"
printf "\ntesting zcat-%s..." "$2"
for i in ${extensions}; do
"${ZCAT}" -N in.$i > copy || fail=1
@ -95,7 +96,7 @@ if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zcmp-%s..." "$2"
printf "\ntesting zcmp-%s..." "$2"
for i in ${extensions}; do
"${ZCMP}" -N in.$i || fail=1
@ -176,7 +177,7 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zdiff-%s..." "$2"
printf "\ntesting zdiff-%s..." "$2"
for i in ${extensions}; do
"${ZDIFF}" -N in.$i > /dev/null || fail=1
@ -239,7 +240,7 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zgrep-%s..." "$2"
printf "\ntesting zgrep-%s..." "$2"
for i in ${extensions}; do
"${ZGREP}" -N "GNU" in.$i > /dev/null || fail=1
@ -305,7 +306,7 @@ printf .
printf .
printf "\ntesting ztest-%s..." "$2"
printf "\ntesting ztest-%s..." "$2"
for i in ${extensions}; do
"${ZTEST}" -N --format=$i < in.$i || fail=1
@ -335,10 +336,80 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --format=lz in.bz2 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --lz='lzip --bad-option' in.lz 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --bad-option 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zupdate-%s..." "$2"
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N --bz2=bad_command x.bz2 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --bz2='bzip2 --bad-option' x.bz2 > /dev/null 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --gz=bad_command x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --gz='gzip --bad-option' x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --lz=bad_command x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --lz='lzip --bad-option' x.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZUPDATE}" -N --bad-option 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
cat in.lz in.lz > x.lz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null
if [ $? = 1 ] && [ -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
"${ZUPDATE}" -N x.bz2 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
"${ZUPDATE}" -N x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N x.bz2 x.gz 2> /dev/null
if [ $? = 1 ] && [ ! -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] &&
[ ! -e x ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure
"${ZUPDATE}" -N -6 -q x.bz2
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1
fi
rm -f x.lz || framework_failure
echo
if [ ${fail} = 0 ] ; then
echo "tests completed successfully."

View file

@ -246,12 +246,12 @@ int cmp( const long long max_size, const int infd[2],
}
}
buffer0[rd[0]] = ~buffer1[rd[0]]; // sentinels for the block compare
buffer1[rd[1]] = ~buffer0[rd[1]];
const int min_rd = std::min( rd[0], rd[1] );
buffer0[min_rd] = 0; // sentinels for the block compare
buffer1[min_rd] = 1;
int first_diff = block_compare( buffer0, buffer1, &line_number );
byte_number += first_diff;
const int min_rd = std::min( rd[0], rd[1] );
if( first_diff < min_rd )
{

View file

@ -389,6 +389,11 @@ int main( const int argc, const char * const argv[] )
set_signals();
if( !set_fifonames( filenames ) ) return 2;
Children children[2];
if( !set_data_feeder( fifonames[0], infd[0], children[0], format_types[0] ) ||
!set_data_feeder( fifonames[1], infd[1], children[1], format_types[1] ) )
return 2;
const pid_t diff_pid = fork();
if( diff_pid == 0 ) // child (diff)
{
@ -407,11 +412,6 @@ int main( const int argc, const char * const argv[] )
if( diff_pid < 0 ) // parent
{ show_fork_error( DIFF ); return 2; }
Children children[2];
if( !set_data_feeder( fifonames[0], infd[0], children[0], format_types[0] ) ||
!set_data_feeder( fifonames[1], infd[1], children[1], format_types[1] ) )
return 2;
int retval = wait_for_child( diff_pid, DIFF );
for( int i = 0; i < 2; ++i )

View file

@ -59,7 +59,20 @@ int ztest_stdin( const int infd, int format_index,
{ show_error( "Can't create pipe", errno ); return 1; }
const pid_t pid = fork();
if( pid == 0 ) // child1 (compressor)
if( pid == 0 ) // child1 (compressor feeder)
{
if( close( fda[0] ) != 0 ||
!feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 1 );
if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 1 ); }
_exit( 0 );
}
if( pid < 0 ) // parent
{ show_fork_error( "data feeder" ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (compressor)
{
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 )
@ -81,25 +94,13 @@ int ztest_stdin( const int infd, int format_index,
show_exec_error( compressor_name );
_exit( 1 );
}
if( pid < 0 ) // parent
if( pid2 < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (compressor feeder)
{
if( close( fda[0] ) != 0 ||
!feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 1 );
if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 1 ); }
_exit( 0 );
}
if( pid2 < 0 ) // parent
{ show_fork_error( "data feeder" ); return 1; }
close( fda[0] ); close( fda[1] );
int retval = wait_for_child( pid, compressor_name, 1 );
if( retval == 0 && wait_for_child( pid2, "data feeder" ) != 0 )
const bool isgzxz = ( format_index == fmt_gz || format_index == fmt_xz );
int retval = wait_for_child( pid2, compressor_name, 1, isgzxz );
if( retval == 0 && wait_for_child( pid, "data feeder" ) != 0 )
retval = 1;
return retval;
}
@ -141,5 +142,6 @@ int ztest_file( const int infd, int format_index,
if( pid < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; }
return wait_for_child( pid, compressor_name, 1 );
const bool isgzxz = ( format_index == fmt_gz || format_index == fmt_xz );
return wait_for_child( pid, compressor_name, 1, isgzxz );
}

415
zupdate.cc Normal file
View file

@ -0,0 +1,415 @@
/* Zupdate - recompress bzip2, gzip, xz files to lzip files
Copyright (C) 2013 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#include <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include <vector>
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <utime.h>
#include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__)
#include <io.h>
#endif
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
#endif
namespace {
#ifdef O_BINARY
const int o_binary = O_BINARY;
#else
const int o_binary = 0;
#endif
void show_zupdate_help()
{
std::printf( "Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.\n"
"The originals are compared with the new files and then deleted.\n"
"Only regular files with standard file name extensions are recompressed,\n"
"other files are ignored.\n"
"Compressed files are decompressed and then recompressed on the fly; no\n"
"temporary files are created.\n"
"The lzip format is chosen as destination because it is by far the most\n"
"appropriate for long-term data archiving.\n"
"\nIf the lzip compressed version of a file already exists, the file is\n"
"skipped unless the '--force' option is given. In this case, if the\n"
"comparison fails, an error is returned and the original file is not\n"
"deleted. The operation of zupdate is meant to be safe and not produce\n"
"any data loss. Therefore, existing lzip compressed files are never\n"
"overwritten nor deleted.\n"
"\nUsage: zupdate [options] [files]\n"
"\nExit status is 0 if all the compressed files were successfully\n"
"recompressed (if needed), compared and deleted. Non-zero otherwise.\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" -f, --force do not skip a file even if the .lz exists\n"
" -l, --lzip-verbose pass a -v option to the lzip compressor\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" -0 .. -9 set compression level [default 9]\n"
" --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" );
show_help_addr();
}
int cant_execute( const std::string & command, const int status )
{
if( verbosity >= 0 )
{
if( WIFEXITED( status ) )
std::fprintf( stderr, "%s: Error executing '%s'. Exit status = %d.\n",
util_name, command.c_str(), WEXITSTATUS( status ) );
else
std::fprintf( stderr, "%s: Can't execute '%s'.\n",
util_name, command.c_str() );
}
return 1;
}
// Set permissions, owner and times.
void set_permissions( const char * const rname, const struct stat & in_stats )
{
bool warning = false;
// fchown will in many cases return with EPERM, which can be safely ignored.
if( ( chown( rname, in_stats.st_uid, in_stats.st_gid ) != 0 &&
errno != EPERM ) ||
chmod( rname, in_stats.st_mode ) != 0 ) warning = true;
struct utimbuf t;
t.actime = in_stats.st_atime;
t.modtime = in_stats.st_mtime;
if( utime( rname, &t ) != 0 ) warning = true;
if( warning && verbosity >= 2 )
show_error( "Can't change output file attributes." );
}
struct { const char * from; const char * to; int format_index; } const
known_extensions[] = {
{ ".bz2", "", fmt_bz2 },
{ ".tbz", ".tar", fmt_bz2 },
{ ".tbz2", ".tar", fmt_bz2 },
{ ".gz", "", fmt_gz },
{ ".tgz", ".tar", fmt_gz },
{ ".lz", "", fmt_lz },
{ ".tlz", ".tar", fmt_lz },
{ ".xz", "", fmt_xz },
{ ".txz", ".tar", fmt_xz },
{ 0, 0, -1 } };
// Returns 0 for success, -1 for file skipped, 1 for error.
int zupdate_file( const std::string & name, const char * const lzip_name,
const std::vector< std::string > & lzip_args2,
const bool force )
{
int format_index = -1;
std::string dname; // decompressed_name
for( int i = 0; known_extensions[i].from; ++i ) // search extension
{
const std::string from( known_extensions[i].from );
if( name.size() > from.size() &&
name.compare( name.size() - from.size(), from.size(), from ) == 0 )
{
dname.assign( name, 0, name.size() - from.size() );
dname += known_extensions[i].to;
format_index = known_extensions[i].format_index;
if( format_index == fmt_lz )
{
if( verbosity >= 2 )
std::fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
util_name, name.c_str(), known_extensions[i].from );
return 0; // ignore this file
}
break;
}
}
const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name || !compressor_name[0] )
{
if( verbosity >= 2 )
std::fprintf( stderr, "%s: Unknown extension in file name '%s' -- ignored.\n",
util_name, name.c_str() );
return 0; // ignore this file
}
struct stat in_stats;
if( stat( name.c_str(), &in_stats ) != 0 ) // check input file
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't stat input file '%s': %s.\n",
util_name, name.c_str(), std::strerror( errno ) );
return 1;
}
if( !S_ISREG( in_stats.st_mode ) )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Input file '%s' is not a regular file.\n",
util_name, name.c_str() );
return 1;
}
struct stat st;
std::string rname( dname ); rname += ".lz"; // recompressed_name
const bool lz_exists = ( stat( rname.c_str(), &st ) == 0 );
if( lz_exists && !force )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
util_name, rname.c_str() );
return -1;
}
if( !lz_exists ) // recompress
{
if( verbosity >= 1 )
std::fprintf( stderr, "Recompressing file '%s'.\n", name.c_str() );
int fda[2]; // pipe between decompressor and compressor
if( pipe( fda ) < 0 )
{ show_error( "Can't create pipe", errno ); return 1; }
const pid_t pid = fork();
if( pid == 0 ) // child1 (decompressor)
{
if( dup2( fda[1], STDOUT_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 )
{
const std::vector< std::string > & compressor_args =
get_compressor_args( format_index );
const int size = compressor_args.size();
const char ** const argv = new const char *[size+5];
argv[0] = compressor_name;
for( int i = 0; i < size; ++i ) argv[i+1] = compressor_args[i].c_str();
argv[size+1] = "-cd";
argv[size+2] = "--";
argv[size+3] = name.c_str();
argv[size+4] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( compressor_name );
_exit( 1 );
}
if( pid < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (lzip compressor)
{
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 )
{
const std::vector< std::string > & lzip_args =
get_compressor_args( fmt_lz );
const int size = lzip_args.size();
const int size2 = lzip_args2.size();
const char ** const argv = new const char *[size+size2+5];
argv[0] = lzip_name;
argv[1] = "-9";
for( int i = 0; i < size; ++i ) argv[i+2] = lzip_args[i].c_str();
for( int i = 0; i < size2; ++i ) argv[i+size+2] = lzip_args2[i].c_str();
argv[size+size2+2] = "-o";
argv[size+size2+3] = dname.c_str();
argv[size+size2+4] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( lzip_name );
_exit( 1 );
}
if( pid2 < 0 ) // parent
{ show_fork_error( lzip_name ); return 1; }
close( fda[0] ); close( fda[1] );
int retval = wait_for_child( pid, compressor_name );
int retval2 = wait_for_child( pid2, lzip_name );
if( retval || retval2 ) { std::remove( rname.c_str() ); return 1; }
set_permissions( rname.c_str(), in_stats );
}
{
if( lz_exists && verbosity >= 1 )
std::fprintf( stderr, "Comparing file '%s'.\n", name.c_str() );
std::string zcmp_command( invocation_name );
unsigned i = zcmp_command.size();
while( i > 0 && zcmp_command[i-1] != '/' ) --i;
zcmp_command.resize( i );
zcmp_command += "zcmp "; // ${bindir}zcmp
zcmp_command += name; zcmp_command += ' '; zcmp_command += rname;
int status = std::system( zcmp_command.c_str() );
if( status != 0 )
{ if( !lz_exists ) std::remove( rname.c_str() );
return cant_execute( zcmp_command, status ); }
}
if( std::remove( name.c_str() ) != 0 && errno != ENOENT )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't delete input file '%s': %s.\n",
util_name, name.c_str(), std::strerror( errno ) );
return 1;
}
return 0;
}
} // end namespace
int main( const int argc, const char * const argv[] )
{
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt };
std::string input_filename;
std::list< std::string > filenames;
std::vector< std::string > lzip_args2; // args to lzip, maybe empty
bool force = false;
bool recursive = false;
invocation_name = argv[0];
util_name = "zupdate";
const Arg_parser::Option options[] =
{
{ '0', 0, Arg_parser::no },
{ '1', 0, Arg_parser::no },
{ '2', 0, Arg_parser::no },
{ '3', 0, Arg_parser::no },
{ '4', 0, Arg_parser::no },
{ '5', 0, Arg_parser::no },
{ '6', 0, Arg_parser::no },
{ '7', 0, Arg_parser::no },
{ '8', 0, Arg_parser::no },
{ '9', 0, Arg_parser::no },
{ 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
{ 'l', "lzip-verbose", Arg_parser::no },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 'r', "recursive", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 1; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
switch( code ) // common options
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
lzip_args2.push_back( "-" ); lzip_args2.back() += code; break;
case 'f': force = true; break;
case 'h': show_zupdate_help(); return 0;
case 'l': lzip_args2.push_back( "-v" ); break;
case 'N': continue;
case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break;
case 'r': recursive = true; break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version( "Zupdate" ); return 0;
case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); continue;
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); continue;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); continue;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); continue;
default : internal_error( "uncaught option" );
}
} // end process options
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY );
#endif
const char * const lzip_name = get_compressor_name( fmt_lz );
if( !lzip_name || !lzip_name[0] )
{ show_error( "Missing name of compressor for lzip format." ); return 1; }
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
int retval = 0;
while( !filenames.empty() )
{
input_filename = filenames.front();
filenames.pop_front();
if( !input_filename.size() || input_filename == "-" ) continue;
if( recursive )
{
struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{
DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp )
{
show_error2( "Can't open directory", input_filename.c_str() );
if( retval < 1 ) retval = 1; continue;
}
std::list< std::string > tmp_list;
while( true )
{
const struct dirent * const entryp = readdir( dirp );
if( !entryp ) { closedir( dirp ); break; }
std::string tmp_name( entryp->d_name );
if( tmp_name != "." && tmp_name != ".." )
tmp_list.push_back( input_filename + "/" + tmp_name );
}
filenames.splice( filenames.begin(), tmp_list );
continue;
}
}
int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force );
if( tmp < 0 && retval < 1 ) retval = 1;
if( tmp > retval ) retval = tmp;
if( tmp > 0 ) break;
}
return retval;
}

View file

@ -338,7 +338,7 @@ int test_format( const int infd, const uint8_t ** const magic_datap,
int wait_for_child( const pid_t pid, const char * const name,
const int eretval )
const int eretval, const bool isgzxz )
{
int status;
while( waitpid( pid, &status, 0 ) == -1 )
@ -355,7 +355,7 @@ int wait_for_child( const pid_t pid, const char * const name,
if( WIFEXITED( status ) )
{
const int tmp = WEXITSTATUS( status );
if( eretval == 1 && tmp == 1 ) return 2; // for ztest
if( isgzxz && eretval == 1 && tmp == 1 ) return 2; // for ztest
return tmp;
}
return eretval;

View file

@ -79,7 +79,7 @@ int test_format( const int infd, const uint8_t ** const magic_datap,
// Returns exit status of child process 'pid', or 'eretval' in case of error.
//
int wait_for_child( const pid_t pid, const char * const name,
const int eretval = 2 );
const int eretval = 2, const bool isgzxz = false );
// Returns -1 if child not terminated, 'eretval' in case of error, or
// exit status of child process 'pid'.