Hi Ola, Marc,

Ola Lundqvist wrote:
> I'm also adding Bob into this mail chain as he was the one that wrote the
> code for RANDOM in 2004.

Actually I had suggested the randomization using $RANDOM in email in
May 2003 and after discussion with Ola it settled on using #!/bin/bash
to support it.  I think it was released for use after Bug#191981 was
coincidentally reported soon afterward for the same reason.  Giving
credit where credit is due David Weinehall suggested in Bug#260071 the
RANDOM fallback code currently in use with /dev/urandom & cut which as
I recall allowed the script to return to #!/bin/sh.  :-)

> Marc Haber wrote:

> > Please consider the following patch:
> > -           RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut 
> > -c"1-5")
> > +           RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut 
> > -d' ' -f1)
> > which will help cron-apt to gracefully handle the case where the
> > checksum returned by cksum is shorter than four digits.

Ah...  cksum prints the cksum with %u.  If the cksum ever results in a
small integer then the width of the field may be shorter than four
characters.  In that case the second field would be pulled into the
output since it is cutting strictly by fields.  Here is a simulation.

  $ echo 123 512 | cut -c1-5
  123 5

I assume you discovered this case by inspection of the code rather
than in actual practice.  This would be a very unlikely case to ever
hit in real life.  If it did then it would produce one spurious cron
email out of years of runs.  I have a test program running right now
looking for a random hit on this case and while it has been running
for some time now and generated many zillions of test cases I have yet
to produce a cksum shorter than four digits.  Not impossible but
statistically extremely unlikely.  Out of curiosity I will leave my
test case running for some more hours to see if I can produce an
example.  I don't know if it will obtain one before the heat death of
the universe though.

> > -           RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut 
> > -c"1-5")
> > +           RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut 
> > -d' ' -f1)

If I had my preference I would use awk instead of cut for splitting
fields.  Using awk is as standard as cut and so no difference in
dependencies.  But for splitting fields on whitespace awk is a better
fit to the task than cut.

  RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | awk '{print$1}')

Splitting on whitespace is more resilient to input differences than
splitting on each space character.  IMNHO using awk for field
selection is almost always better than using cut.  The variations in
'wc' output is a good example of where awk works as desired but cut
would not.

> When testing this out I noticed the following:
> ...
> As you can see it gives different output. I do not really think that is
> a real problem, but I think you two should have the possibility to comment
> it before I apply the patch.

This is okay.  It is changing one random number for a different random
number.  The generation of the arithmetic remainder of ARG1 divided by
ARG2 in the TIME=$(($RANDOM % $RUNSLEEP)) part washes the difference
away.  The result will be a different random value between 0-$RUNSLEEP.

(And noting for the casual reader that RUNSLEEP defaults to 3600 and
so this gives a random delay across an hour interval.  The cron job
runs in local time.  As machines worldwide are located in different
timezones the load on the upstream repositories will be distributed
across the different timezones.  Although some timezones will be more
populous than others.)

Since this has come up for discussion here it gives me an opportunity
to cringe once again at using /dev/*random and the unportability of
it and perhaps suggest using awk instead.  In my own scripts I have
been using portable awk for generating random numbers.  Therefore I
would suggest this instead and eliminate the use of /dev/*random.
Noting that in Debian this works with either mawk or gawk.

  RANDOM=$(awk -v rs=$RUNSLEEP -v s=$$$(date +%M%S) 
'BEGIN{srand(s);print(int(rs*rand()));}')

Command line test case:

  $ awk -v rs=3600 -v s=$$$(date +%M%S) 'BEGIN{srand(s);print(int(rs*rand()));}'
  1194

But I am unaware of any Debian kernel that doesn't support
/dev/*random and therefore do not feel strongly about it.  Any
solution that works is okay with me.

Thanks Ola for maintaining cron-apt!

Bob

Attachment: signature.asc
Description: Digital signature

Reply via email to