1

I've got an installer/updater script that's meant for IRIX/Linux/macOS/FreeBSD and I would like to extend its compatibility to Solaris.

I've already fixed a few parts that weren't POSIX compliant, except for the crontab which is generated like this:

printf '%s\n' MAILTO=me@xyz.org '*/15 * * * * /path/cmd' | crontab -
# crontab -l # (on Linux/macOS/FreeBSD)
MAILTO=me@xyz.org
*/15 * * * * /path/cmd

note: /path/cmd is quiet unless it detects a problem

The code fails on Solaris for three reasons:

  1. MAILTO= throws a syntax error
  2. */15 throws a syntax error
  3. crontab - tries to open the file named -

I fixed #2 and #3 with:

printf '%s\n' '0,15,30,45 * * * * /path/cmd' | crontab
# crontab -l
0,15,30,45 * * * * /path/cmd

Now I don't know how to convert the MAILTO= part. What would be a POSIX way to forward emails from a crontab?


Selected workaround:

Thanks to @ilkkachu and @Gilles'SO-stopbeingevil' pointers, here's how I decided to emulate crontab's MAILTO behavior in a POSIX compliant way:

# crontab -l
0,15,30,45 * * * * out=$(/path/cmd 2>&1); [ -n "$out" ] && printf \%s\\n "$out" | mailx -s "Cron <$LOGNAME@$(uname -n)>" me@xyz.org

But, there's a potential problem with this solution: if printf is not a shell builtin and the output is too big then it will fail with an Argument list too long or the likes.

Fravadona
  • 561

1 Answers1

3

Note that MAILTO is no good for a software installer even where it's supported, because it's a global setting: it would apply to all the entries in the crontab, not just to the one added by your software.

If you want your software to send emails to a different address, you need to handle that in your own code. And that means you need to handle the logic of exit status and empty output yourself.

Here's some untested code that implements this logic. Replace newlines by spaces (or just remove them) to put them on a single line in the crontab file.

out=$(mktemp) &&
/path/cmd >"$out" 2>&1;
status=$?;
if [ "$status" -ne 0 ] || [ -s "$out" ]; then
  mailx -s "/path/cmd exited with status $status" me@example.org <"$out";
fi;
rm -- "$out";

This code uses only POSIX features plus the widely available mktemp. Unfortunately, it's not available on IRIX. If IRIX has a POSIX-compliant m4, you can use it to implement mktemp. As a fallback, you can store a temporary file somewhere under the user's home directory, or in some other directory where only the other may write. Do not create a temporary file with a predictable name in a shared directory like /tmp: that's insecure.

  • 1
    @ilkkachu I wanted to avoid running the command if the temporary file couldn't be created. But I hadn't paid attention to the fact that it would also result in not sending an email or removing the temporary file if the command fails. – Gilles 'SO- stop being evil' Mar 31 '22 at 15:34