October 2005

Bits of Scripts & Source

Working as a multi-customer facing administrator and programmer, there come times when something needed - isn't there. Earlier texts here have mentioned some shell script bits, the text will revisit those and discuss C and Perl bits that have proven to come in handy time and again. The bits discussed are not exclusive, just some examples. The usual simple constructs like if/else ladders, for, while, unless loops as well as referencing are generally easy to remember.

Shell Bits

Examples of fast and easy to use shell bits can be surprisingly hard to find, especially when a script needs to be finished yesterday. In the following, some simple constructs are shown as well as a generic bomb() routine.

A Simple bomb() Routine

The syntax for it while simple is quite forgettable. The following shows the routine itself with an example that calls it:

bomb()
{
    cat >&2 <<ERRORMESSAGE
ERROR: $@
*** ${progname} aborted ***
ERRORMESSAGE
    kill ${toppid}
    exit 1
}

# Shell test
if ! type getopts >/dev/null 2>&1; then
    bomb "/bin/sh shell is too old; try ksh or bash"
fi

Additionally, keeping a copy of switch case and redirect based usage() examples have also come in handy:

progname=${0##*/}
...
usage()
{
cat << _usage_
${progname} opt arg
${progname} help
_usage_
    exit 0
}

while getopts e:g:u: ch; do
    case ${ch} in
        e)
            example=${OPTARG}
            ;;
        g)
            good=${OPTARG}
            ;;
        u)
            usage
                        return 0
            ;;
    esac
done
shift $((${OPTIND} - 1))

Perl Bits

Going between different systems has proven one thing to most administrators and programmers - the only guarantee about perl is the core might be installed. Not unlike the shell examples, a good starting point is interrupt handling:

$SIG{'INT' } = 'interrupt';
$SIG{'HUP' } = 'interrupt';
$SIG{'ABRT'} = 'interrupt';
$SIG{'QUIT'} = 'interrupt';
$SIG{'TRAP'} = 'interrupt';
$SIG{'STOP'} = 'interrupt';
$SIG{'TERM'} = 'interrupt';

...

sub interrupt
{
        print "Caught @_ exiting\n";
        die;
}

Very generic - but enough to start with. The next few are a set of bare bones generic routines:

$LOG="/tmp/foo";
...
sub logit
{
        my ($msg) = shift;
        my $date = longfmt();

        appendfile($LOG, "$PROGRAM: $date $msg");
}

sub insert0
{
        my ($date) = shift;

        if ($date < 10) {
                return "0$date";
        }

        return $date;
}

sub longfmt
{
        my ($sec,$min,$hour,$mday,$mon,$year,
                $wday,$yday,$iddst) = localtime(time);
        my $datestring;

        $year += 1900;
        $mon++;
        $mon  = insert0($mon);
        $mday = insert0($mday);
        $min  = insert0($min);
        $datestring = "$year-$mon-$mday $hour:$min";

        return($datestring);
}

Finally, an anonymous hash which is always handy to have around:

my @items;

for (my $j = 0; $j < @init_list; $j++) {
    push @items, { name => $init_list[$j], tics => 0, alarm => none };
}

Other things that might be good to keep around in perl might be:

  • Implementations of reading and working with directories.
  • Any file manipulation bits - especially text mangling and changing.
  • Stuff that successfully uses regex.

Some C-bits

Last and not least, some ideas about C bits that are handy to have within reach. To start, a copy of the strl* functions which are often not on a variety of UNIX systems and Linux distributions:

/* strlcat based on OpenBSDs strlcat */
#include <sys/types.h>

size_t  strlcat(char *, const char *, size_t);

size_t
strlcat (char *dst, const char *src, size_t dst_sz)
{
    size_t len = strlen(dst);

    if (dst_sz < len)
        return len + strlen(src);

    return len + strlcpy (dst + len, src, dst_sz - len);
}

The same can be done for strlcpy():

/* strlcpy based on OpenBSDs strlcpy */
#include <stdio.h>
#include <sys/types.h>

size_t strlcpy(char *, const char *, size_t);

strlcpy(char *dst, const char *src, size_t siz)
{
  char *d = dst;
  const char *s = src;
  size_t n = siz;


  /* Copy as many bytes as will fit */
  if (n != 0 && --n != 0) {
    do {
      if ((*d++ = *s++) == 0)
        break;
    } while (--n != 0);
  }

  /* Not enough room in dst, add NUL and traverse rest of src */
  if (n == 0) {
    if (siz != 0)
      *d = '\0';                /* NUL-terminate dst */
    while (*s++)
      ;
  }

  return(s - src - 1);  /* count does not include NUL */
}

Other C-bits

Some other useful C-bits to keep handy might be:

  • Examples of structs and pointer usage.
  • Path handling routines.
  • The same ones as the perl list above :-)

Where to Keep?

In some cases - a laptop. Or - in a place where the bits can be easily retrieved. Some people even setup their own CVS or subversion repositories that they can access from anyplace they can run their laptop or have access to the commands. Last and not least - a copy on a USB stick never hurts.

Just Food for Thought

The article was not meant to be a tutorial as much as to make readers think about how it can be when moving from system to system, company to company, or even customer to customer. Keeping a working copy of what one knows - even if they are just templates - is a very good idea.