Questions
and Answers
Amy Rich
In the December issue, one of the questions covered modifying
root's crontab using scp and ssh. In order for the supplied script
to work correctly, each command after the ssh needs to be
quoted so that it is not executed on the local machine instead of
the intended target machine. Thanks to Josh Simon for catching this
error. The corrected script should be:
#!/bin/sh
for i in host1 host2 host2 host4; do
scp master.cron root@${i}:/location/to/crontab/file
ssh root@${i} "chmod 0400 /location/to/crontab/file;" \
"chown root /location/to/crontab/file;" \
"crontab /location/to/crontab/file;" \
"crontab -l"
Q I'm running Solaris
9 on a V880, and I'm having an issue with a script running from cron.
The script is a slightly modified version of the updatedb script
that comes with locate. Here's my version of the script (available
at http://www.gnu.org/licenses/licenses.html#GPL) with all
of the comments and copyright information edited out for simplicity's
sake:
#!/bin/sh
usage="\
Usage: updatedb [--localpaths='dir1 dir2...'] [--netpaths='dir1 dir2...']
[--prunepaths='dir1 dir2...'] [--output=dbfile] [--netuser=user]
[--old-format] [--version] [--help]"
old=no
for arg
do
opt='echo $arg|sed 's/^\([^=]*\).*/\1/''
val='echo $arg|sed 's/^[^=]*=\(.*\)/\1/''
case "$opt" in
--localpaths) SEARCHPATHS="$val" ;;
--netpaths) NETPATHS="$val" ;;
--prunepaths) PRUNEPATHS="$val" ;;
--output) LOCATE_DB="$val" ;;
--netuser) NETUSER="$val" ;;
--old-format) old=yes ;;
--version) echo "GNU updatedb version 4.1"; exit 0 ;;
--help) echo "$usage"; exit 0 ;;
*) echo "updatedb: invalid option $opt
$usage" >&2
exit 1 ;;
esac
done
: ${SEARCHPATHS="/"}
: ${NETPATHS=}
: ${PRUNEPATHS="/tmp /usr/tmp /var /users /usr/local/src \
/root /proc /dev /devices /data/amanda"}
test -z "$PRUNEREGEX" &&
PRUNEREGEX='echo $PRUNEPATHS|sed -e 's,^,\\\(^,' -e 's, \
,$\\\)\\\|\\\(^,g' -e 's,$,$\\\),''
: ${LOCATE_DB=/usr/local/var/locatedb}
if test -d /root/tmp; then
: ${TMPDIR=/root/tmp}
else
: ${TMPDIR=/tmp}
fi
: ${NETUSER=daemon}
: ${LIBEXECDIR=/usr/local/libexec}
: ${BINDIR=/usr/local/bin}
: ${find=find}
: ${frcode=frcode}
: ${bigram=bigram}
: ${code=code}
PATH=$LIBEXECDIR:$BINDIR:/usr/ucb:/bin:/usr/bin:$PATH export PATH
if test $old = no; then
{
if test -n "$SEARCHPATHS"; then
$find $SEARCHPATHS \
\( -fstype nfs -o -fstype NFS -o -type d -regex "$PRUNEREGEX" \) \
-prune -o -print
fi
if test -n "$NETPATHS"; then
su $NETUSER -c \
"$find $NETPATHS \\( -type d -regex \"$PRUNEREGEX\" -prune \\) \
-o -print"
fi
} | sort -f | $frcode > $LOCATE_DB.n
if test -s $LOCATE_DB.n; then
rm -f $LOCATE_DB
mv $LOCATE_DB.n $LOCATE_DB
chmod 644 $LOCATE_DB
else
echo "updatedb: new database would be empty" >&2
rm -f $LOCATE_DB.n
fi
else
bigrams=$TMPDIR/f.bigrams$$
filelist=$TMPDIR/f.list$$
trap 'rm -f $bigrams $filelist; exit' 1 15
{
if test -n "$SEARCHPATHS"; then
$find $SEARCHPATHS \
\( -fstype nfs -o -fstype NFS -o -type d -regex "$PRUNEREGEX" \) \
-prune -o -print
fi
if test -n "$NETPATHS"; then
su $NETUSER -c \
"$find $NETPATHS \\( -type d -regex \"$PRUNEREGEX\" -prune \\) \
-o -print"
fi
} | tr / '\001' | sort -f | tr '\001' / > $filelist
$bigram < $filelist | sort | uniq -c | sort -nr |
awk '{ if (NR <= 128) print $2 }' | tr -d '\012' > $bigrams
$code $bigrams < $filelist > $LOCATE_DB
chmod 644 $LOCATE_DB
rm -f $bigrams $filelist $errs
fi
If I run this script by hand, everything works fine, but when I invoke
it from cron:
0 0,4,8,12,16,20 * * * * /usr/local/bin/updatedb.local > /dev/null 2>&1
I get this error in email:
Your "cron" job on db
* /usr/local/bin/updatedb.local > /dev/null 2>&1
produced the following output:
sh: TT_DB: not found
According to what I've been able to find, TT_DB is related
to ToolTalk's rpc.ttdbserverd. I have no idea why that would
ever be called with the updatedb.local script, so I was hoping you
could enlighten me and help me debug this issue.
A There's actually nothing wrong
with your script, and if you look closely at the error you'll see
what the real problem is. The output lists your script as * /usr/local/bin/updatedb.local
> /dev/null 2>&1. Note that there's an extra asterisk
in there. You've put too many fields into the cron entry, and the
first asterisk is being interpreted by the shell. The first (non-dotfile)
entry in your root directory must be the directory TT_DB. Cron is
trying to execute this directory and so gives you the somewhat misleading
error message.
Q We're migrating services from
a FreeBSD 4.2 machine to a new FreeBSD 5.3 machine and have been
experiencing problems with LPRng and printing out banner pages.
We have a custom banner page that we're printing using the pclbanner
Bourne shell script. I've copied this over from the old machine
and set up the printcap file in the same way. When I try
to print a page, though, I see the following errors in the logs:
Status: BANNER: expr: illegal option -- A at 09:38:13.218
Status: BANNER: usage: expr [-e] expression at 09:38:13.219
My printcap file contains the following:
hp5100dtn
:af=acct
:bp=/usr/libexec/filters/pclbanner
:filter=/usr/libexec/filters/ifhp
:ifhp=model=hp5,status,sync,pagecount,waitend
:lf=log
:db=2,print+4
:mx=0
:prefix_z=1200,letter,portrait
:sd=/var/spool/lpd/%P
:sh@
:lp=<ip address>%9100
I haven't changed the pclbanner script or the printcap
at all, and I even tried compiling LPRng from scratch to see if that
was the problem. Any suggestions on how I can get this to work again?
A You're running into an issue
with the change in the way expr behaves on FreeBSD 5.x. From
the FreeBSD 5.x release notes:
expr(1) is now compliant with POSIX.2-1992 (and thus also
with POSIX.1-2001). Some programs depend on the old, historic behavior
and do not properly protect their arguments to keep them from being
misinterpreted as command-line options. (the devel/libtool port/package,
used by many GNU programs, is a notable example). The old behavior
can be requested by enabling compatibility mode for expr(1)
as described in check_utility_compat(3).
You can try to rewrite your pclbanner script to use the
POSIX-compliant invocation of expr, or you can turn on compatibility
mode so that expr uses the pre-POSIX syntax. The latter may
be your best bet if you don't understand Bourne shell scripting
very well or can't decipher what's being incorrectly passed to the
pclbanner program. From the check_utility_compat(3)
man page:
The check_utility_compat() function checks whether utility should
behave in a traditional (FreeBSD 4.7-compatible) manner, or in accordance
with IEEE Std 1003.1-2001 ('POSIX.1''). The configuration is given
as a comma-separated list of utility names; if the list is present
but empty, all supported utilities assume their most compatible
mode. The check_utility_compat() function first checks for an environment
variable named _COMPAT_FreeBSD_4. If that environment variable does
not exist, then check_utility_compat() will attempt to read the
contents of a symbolic link named /etc/compat-FreeBSD-4-util.
If no configuration is found, compatibility mode is disabled.
Because there will be issues with any programs that require the
POSIX syntax, I would suggest setting the environment variable in
the pclbanner script instead of making a global modification
in the profiles of all users or in the /etc/compat-FreeBSD-4-util
file. Near the top of your pclbanner script, add the following
line:
export _COMPAT_FreeBSD_4=expr
This runs expr in compatibility mode just for this specific
application and does not affect any other programs that call expr.
Q I have an HP-UX 11i running a
mail server using an in-house compiled sendmail 8.13.2. I've created
the cf file with an absolute basic mc file that only contains the
following:
divert(0)dnl
OSTYPE(hpux11)dnl
MASQUERADE_AS('my.domain')dnl
FEATURE('masquerade_entire_domain')dnl
FEATURE('allmasquerade')dnl
FEATURE('masquerade_envelope')dnl
FEATURE('always_add_domain')dnl
FEATURE('nouucp','reject')dnl
FEATURE('use_cw_file')dnl
LOCAL_USER('root')dnl
EXPOSED_USER('root')dnl
MAILER(local)dnl
MAILER(smtp)dnl
The compile and the installation work without any errors, and the
daemon starts up just like it's supposed to. I wrote a few scripts
that use telnet and expect to connect to port 25 to
do some automated testing, and I turned up something strange when
sending test messages using this method. The following gets sent to
the SMTP port after connection:
ehlo host.my.domain
mail from: myaddress@my.domain
rcpt to: myaddress@my.domain
data
From: myaddress@my.domain
To: myaddress@my.domain
Subject: test
... Testing, 1, 2, 3 ...
.
I receive the mail on the local machine, as expected, but the contents
of the message have been modified so that the leading dot is missing
from the body:
.. Testing, 1, 2, 3 ...
At first I thought this might be an issue with my script, so I manually
telnet'ed to port 25 and entered the above text. The body was
once again modified, but I'm not sure what's eating that first dot.
Did I mis-configure the cf file somehow, or did something go wrong
in the compile? Any insight would go a long way toward helping me
track down this issue.
A The behavior you're seeing from
sendmail, known as dot-stuffing, is actually documented in RFC 821
and the superseding RFC, 2821. These RFCs are available from http://www.faqs.org/,
among other places. From looking at your script, you already know
that a line consisting of a dot followed by a CRLF terminates the
current message. Dot-stuffing is designed to prevent message termination
due to the contents of the message body as submitted by an end user.
From RFC 2821, section 4.1.1.4:
The mail data is terminated by a line containing only a period,
that is, the character sequence "<CRLF>.<CRLF>" (see
section 4.5.2). This is the end of mail data indication.
And from section 4.5.2 of the same document:
Without some provision for data transparency, the character sequence
"<CRLF>.<CRLF>" ends the mail text and cannot be sent
by the user. In general, users are not aware of such "forbidden"
sequences. To allow all user composed text to be transmitted transparently,
the following procedures are used:
- Before sending a line of mail text, the SMTP client checks the
first character of the line. If it is a period, one additional period
is inserted at the beginning of the line.
- When a line of mail text is received by the SMTP server, it
checks the line. If the line is composed of a single period, it
is treated as the end of mail indicator. If the first character
is a period, and there are other characters on the line, the first
character is deleted.
This means is that the initiating SMTP server will add a dot to
the beginning of any line of text in the DATA portion of the connection
that starts with a dot. This prevents the receiving SMTP server
from seeing a lone dot in a message body line and inadvertently
terminating the message in the middle of the body.
Because you're connecting to the SMTP port directly, there is
no "sending" SMTP server to add the additional dot into the DATA
portion of the message. As a result, the SMTP daemon to which you're
connecting (which happens to be sendmail, but this is not a sendmail-specific
issue) strips off the first dot and leaves you with only three.
If you want your message body to remain unchanged, you'll need to
manually dot-stuff the message in your script or when you connect
interactively.
As a side note, technically your MAIL FROM and RCPT TO SMTP commands
should have no space between the colon and the address. From the
same RFC, section 3.3:
MAIL FROM:<reverse-path> [SP <mail-parameters> ] <CRLF>
RCPT TO:<forward-path> [ SP <rcpt-parameters> ] <CRLF>
If service extensions were negotiated, then these become as follows
(section 4.1.1.2 and 4.1.1.3):
"MAIL FROM:" ("<>" / Reverse-Path)
[SP Mail-parameters] CRLF
"RCPT TO:" ("<Postmaster@" domain ">" / "<Postmaster>" / Forward-Path)
[SP Rcpt-parameters] CRLF
Amy Rich has more
than a decade of Unix systems administration experience in various
types of environments. Her current roles include that of Senior Systems
Administrator for the University Systems Group at Tufts University,
Unix systems administration consultant, and author. She can be reached
at: qna@oceanwave.com. |