Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Mar 2013 15:26:33 +0100
From:      Jilles Tjoelker <jilles@stack.nl>
To:        Peter Jeremy <peter@rulingia.com>
Cc:        grog@FreeBSD.org, svn-src-head@FreeBSD.org, svn-src-all@FreeBSD.org, src-committers@FreeBSD.org
Subject:   Re: svn commit: r247274 - in head: bin/test tools/regression/bin/test
Message-ID:  <20130301142633.GA49921@stack.nl>
In-Reply-To: <20130227082548.GF99210@server.rulingia.com>
References:  <201302251905.r1PJ5fKF085179@svn.freebsd.org> <20130226000227.GA80718@stack.nl> <20130227082548.GF99210@server.rulingia.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, Feb 27, 2013 at 07:25:48PM +1100, Peter Jeremy wrote:
> On 2013-Feb-26 01:02:27 +0100, Jilles Tjoelker <jilles@stack.nl> wrote:
> >>   Enhance test(1) by adding provision to compare any combination of the
> >>   access, birth, change and modify times of two files, instead of only
> >>   being able to compare modify times.  The builtin test in sh(1) will
> >>   automagically acquire the same expansion.

> >What do you need this for? If it is not needed very often, this test can
> >be done more portably (older FreeBSD and GNU) as
> >  [ -n "$(find -L FILE1 -prune -newerXY FILE2 2>/dev/null)" ]

> In my case I needed to compare the ctime on one set of files with the
> mtime in another set.  I had a think about using find(1) and gave it
> away as too ugly.  That expression needs serious thought to understand
> and about ½ the tokens in the find(1) are to handle special cases -
> which is a further indication that it isn't ideal.

Making everything ideal out of the box is not possible; it would bloat
up things too much and make scripts harder to read. There are many
possible extensions to avoid problems with special cases that would be
useful more frequently, such as arrays, ${PARAM/WORD/REPLACEMENT},
${PARAM:START:LENGTH} and optional more useful signal handling.

And I don't think this case is particularly bad. By defining the below
function

file_newer() {
	test -n "$(find -L -- "$2" -prune -newer$1$3 "$4" 2>/dev/null)"
}

you can do things like  file_newer m file1 c file2  to compare file1's
mtime to file2's ctime. The ugliness is isolated to the function
definition.

The birth time is designated by B instead of b. This is because find(1)
wants B, and so does stat(1).

Furthermore, it also allows  file_newer m file1 t '2 days ago'  to
compare to a specified time; however, only the second time can be 't'.

It is also possible to query file times using stat(1). This allows
intuitive constructions like
  [ $(stat -f %m FILE1) -gt $(stat -f %c FILE2) ]
lets you compare to things like  $(($(date +%s) - 86400))  and allows
control whether symlinks should be followed. However, this may fork more
often than the find(1)-based approach and hard-codes the limitation to
seconds into the script unless you do something more complicated like
  [ $(stat -f %040.9Fm FILE1) \> $(stat -f %040.9Fc FILE2) ]
The test(1) syntax will also be incorrect if the files do not exist.

The find(1) and stat(1) approaches also work in other shells such as
bash, ksh and zsh. An extension to test(1) can only be used by writing
ugly things like /bin/test. Whatever you may think of it, people write
scripts for those other shells and it is somewhat unfortunate that they
cannot use all FreeBSD-specific features.

> >I have generally been rather reluctant in adding things to sh(1) and
> >even more so if they are completely new. Someone proposed something
> >rather similar (except that it added a time string parser -- even more
> >code) in PR bin/57054 and I rejected it in 2009.

> Time parsing is a large can of worms - getting it right is messy (that
> patch includes 1KLOC of new code and still isn't locale aware).  And
> the work-around of touching a dummy file to the wanted age isn't too
> horrrible.  This is a much smaller patch and there's no equally clean
> work-around.

I think my function definition is a clean enough workaround.

I wouldn't mind having more such functions somewhere part of the base
system, perhaps somewhat like rc.subr and dteske's bsdconfig scripts.
There are some such functions in src/bin/sh/funcs/ but they are not
installed.

When I add things to sh, I usually include the new feature in a message
to a mailing list like
http://lists.freebsd.org/pipermail/freebsd-arch/2010-June/010353.html
and
http://lists.freebsd.org/pipermail/freebsd-arch/2011-December/011976.html
first. Randomly adding features interferes with the design and the
process.

> >> +a=/tmp/test$$.1
> >> +b=/tmp/test$$.2

> >Please use mktemp(1). Using $$ for temporary files is insecure on
> >multiuser systems.

> In this case, I want filenames that don't exist.  I will look at using
> mktemp(1) to create a temporary directory.

That's what I usually do in sh testcases. The directory usually serves
to contain temporary fifos. Fifos are both faster and more reliable to
enforce ordering than sleeps.

> >> +sleep 2    # Ensure $b is newer than $a
> >> +touch $b

> >Please use touch -t instead of sleeping. I'm impatient while running
> >tests :)

> In this case, I want all the timestamps on $b to be later than $a.  I
> initially tried without the sleep but that failed with the builtin
> test(1) because the FS timestamps weren't sufficiently granular to
> report the difference.  I could create one of the files much earlier
> during the test and then use a conditional test to only sleep if the
> timestamps were indistinguishable (this probably needs to use the
> above find(1) horror to avoid using test(1) to test itself).

You can compare to a file somewhere else on the system.

> I agree the other sleep(1)s should be able to be replaced with
> touch(1) but I ran into problems with my initial efforts to do
> everything using touch(1).  I will revisit it.

The tests can still be used to test the above find(1)-based
implementation. I have done this locally and it works.

-- 
Jilles Tjoelker



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130301142633.GA49921>