Translate

Image of RHCE Red Hat Certified Engineer Linux Study Guide (Exam RH302) (Certification Press)
Image of Advanced Programming in the UNIX Environment, Second Edition (Addison-Wesley Professional Computing Series)
Image of Android Wireless Application Development
Image of Beginning Google Maps API 3

Korn Shell 93 Hash Builtins

Here is a simple Korn shell plugin which enables you to use the hash functions built into the AT&T Advanced Software Technologies (AST) (libsum) library in your ksh93 shell scripts. There are more hash functions in this library than those that I have included here but these are the most useful hash functions in my opinion.

Here is the source code for the plugin:

#include <shell.h>
#include <shcmd.h>
#include <ctype.h>
#include <error.h>
#include <sum.h>

#define SH_DICT "libhash"

static const char md5_usage[] =
   "[-?\n@(#)$Id: md5sum 2010-07-16 $\n]"
   "[-author?Finnbarr P. Murphy <fpmATun-ixDOTcom>]"
   "[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
   "[+NAME?md5sum - generate an MD5 hash.]"
   "/n"
   "[+EXIT STATUS?] {"
      "[+0?Success.]"
      "[+>0?An error occurred.]"
   "}"
;

static const char sha1_usage[] =
   "[-?\n@(#)$Id: sha1sum 2010-07-16 $\n]"
   "[-author?Finnbarr P. Murphy <fpmATun-ixDOTcom>]"
   "[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
   "[+NAME?sha1sum - generate an SHA1 hash.]"
   "/n"
   "[+EXIT STATUS?] {"
      "[+0?Success.]"
      "[+>0?An error occurred.]"
   "}"
;

static const char sha256_usage[] =
   "[-?\n@(#)$Id: sha256sum 2010-07-16 $\n]"
   "[-author?Finnbarr P. Murphy <fpmATun-ixDOTcom>]"
   "[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
   "[+NAME?sha256sum - generate an SHA256 hash.]"
   "/n"
   "[+EXIT STATUS?] {"
      "[+0?Success.]"
      "[+>0?An error occurred.]"
   "}"
;

static const char sha384_usage[] =
   "[-?\n@(#)$Id: sha384sum 2010-07-16 $\n]"
   "[-author?Finnbarr P. Murphy <fpmATun-ixDOTcom>]"
   "[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
   "[+NAME?sha384sum - generate an SHA384 hash.]"
   "/n"
   "[+EXIT STATUS?] {"
      "[+0?Success.]"
      "[+>0?An error occurred.]"
   "}"
;

static const char sha512_usage[] =
   "[-?\n@(#)$Id: sha512sum 2010-07-16 $\n]"
   "[-author?Finnbarr P. Murphy <fpmATun-ixDOTcom>]"
   "[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
   "[+NAME?sha512sum - generate an SHA512 hash.]"
   "/n"
   "[+EXIT STATUS?] {"
      "[+0?Success.]"
      "[+>0?An error occurred.]"
   "}"
;

SHLIB(ksh)

static int
makehash( int mode,
          const char* path)
{
    Sfio_t* sp;
    char*   s;
    int     r;

    static Sum_t* sum = (Sum_t *)NULL;

    switch (mode) {
        case 1:
             if ((sum = sumopen("sha1")) == NULL)
                error(3, "SHA1 initialization error");
             break;
        case 5:
             if ((sum = sumopen("md5")) == NULL)
                error(3, "MD5 initialization error");
             break;
        case 256:
             if ((sum = sumopen("sha256")) == NULL)
                error(3, "SHA256 initialization error");
             break;
        case 384:
             if ((sum = sumopen("sha384")) == NULL)
                error(3, "SHA384 initialization error");
             break;
        case 512:
             if ((sum = sumopen("sha512")) == NULL)
                error(3, "SHA512 initialization error");
             break;
        default:
             return 1;
    }

    suminit(sum);
    if (!(sp = sfopen(NiL, path, "r")))
        return 1;

    while (s = (char*)sfreserve(sp, SF_UNBOUND, 0))
         sumblock(sum, s, sfvalue(sp));
    r = !!sfvalue(sp);
    if (sfclose(sp) || r)
        return 1;

    sumdone(sum);
    sumprint(sum, sfstdout, 0, 0);
    sumclose(sum);

    return 0;
}


int
b_md5sum(int argc, char *argv[], void *extra)
{
    char* infile;

    NoP(argc);
    error_info.id = "md5sum";

    for (;;)
    {
        switch (optget(argv, md5_usage))
        {
        case '?':
            error(ERROR_USAGE|4, "%s", opt_info.arg);
            continue;
        case ':':
            error(2, "%s", opt_info.arg);
            continue;
        }
        break;
    }

    argv += opt_info.index;

    if (error_info.errors || !(infile = *argv++))
        error(ERROR_USAGE|4, "%s", optusage(NiL));

    return makehash(5, infile);
}


int
b_sha1sum(int argc, char *argv[], void *extra)
{
    char* infile;

    NoP(argc);
    error_info.id = "sha1sum";

    for (;;)
    {
        switch (optget(argv, sha1_usage))
        {
        case '?':
            error(ERROR_USAGE|4, "%s", opt_info.arg);
            continue;
        case ':':
            error(2, "%s", opt_info.arg);
            continue;
        }
        break;
    }

    argv += opt_info.index;

    if (error_info.errors || !(infile = *argv++))
        error(ERROR_USAGE|4, "%s", optusage(NiL));

    return makehash(1, infile);
}


int
b_sha256sum(int argc, char *argv[], void *extra)
{
    char* infile;

    NoP(argc);
    error_info.id = "sha256sum";

    for (;;)
    {
        switch (optget(argv, sha256_usage))
        {
        case '?':
            error(ERROR_USAGE|4, "%s", opt_info.arg);
            continue;
        case ':':
            error(2, "%s", opt_info.arg);
            continue;
        }
        break;
    }

    argv += opt_info.index;

    if (error_info.errors || !(infile = *argv++))
        error(ERROR_USAGE|4, "%s", optusage(NiL));

    return makehash(256, infile);
}


int
b_sha384sum(int argc, char *argv[], void *extra)
{
    char* infile;

    NoP(argc);
    error_info.id = "sha384sum";

    for (;;)
    {
        switch (optget(argv, sha384_usage))
        {
        case '?':
            error(ERROR_USAGE|4, "%s", opt_info.arg);
            continue;
        case ':':
            error(2, "%s", opt_info.arg);
            continue;
        }
        break;
    }

    argv += opt_info.index;

    if (error_info.errors || !(infile = *argv++))
        error(ERROR_USAGE|4, "%s", optusage(NiL));

    return makehash(384, infile);
}


int
b_sha512sum(int argc, char *argv[], void *extra)
{
    char* infile;

    NoP(argc);
    error_info.id = "sha512sum";

    for (;;)
    {
        switch (optget(argv, sha512_usage))
        {
        case '?':
            error(ERROR_USAGE|4, "%s", opt_info.arg);
            continue;
        case ':':
            error(2, "%s", opt_info.arg);
            continue;
        }
        break;
    }

    argv += opt_info.index;

    if (error_info.errors || !(infile = *argv++))
        error(ERROR_USAGE|4, "%s", optusage(NiL));

    return makehash(512, infile);
}


void
lib_init(int c, void *context)
{
    /* automatically load following functions when libhash is loaded */
    sh_addbuiltin("md5sum", b_md5sum, 0);
    sh_addbuiltin("sha1sum", b_sha1sum, 0);
}


It is all fairly standard ksh93 plugin code so I will not go into too many details. The makehash function is where all the interesting work occurs. It calls libsum’s sumopen. function with an appropriate string argument to set up pointers to the required hash functions. See ../src/lib/libsum/sumlib.c for full details.

Note the inclusion of the shcmd.h header and the SHLIB(ksh) macro. This is a new requirement for Korn Shell plugins in versions 93u- 2010-06-29 and newer. AST (of which ksh93 is a component of) plugins are divided into domains whose name is based on the main executable or library for the domain.

At present, AST has the following plugin domains:

  • codex – data transform methods.
  • dss – data stream scan (types, schemas, queries).
  • ksh – ksh93 builtins.
  • pax – archive formats.
  • pz – pzip methods.
  • sort – sort methods.
  • vcodex – buffer data transform methods.

Each domain has one or more dynamic loadable files (.dll or .so) that contain the actual plugins. Each domain has a current YYYYMMDD version stamp defined as a macro in the domain plugin header, e.g. shcmd.h for ksh93. The plugin version stamp is compiled into both the executable and plugins. Only dynamically loadable files with a version stamp equal to or greater than that of the calling executable’s domain version stamp are loadable.

Each dynamic loadable file must now contain a function whose prototype is:

unsigned long plugin_version(void)


and which returns the version stamp for all of the plugins it contains.

Each domain plugin header has a macro that encodes this function. For ksh93, the macro is:

SHLIB(ksh)


which expands to:

unsigned long plugin_version(void) { return SH_PLUGIN_VERSION; }


That is about all that you need to know about ksh93 plugin versioning.

Assuming that you are on 64-bit GNU/Linux and your plugin source file is named hash.c and the AST sources and binaries are located under /work/ast, the following commands will build a dynamically loadable file called libhash.so:

gcc -fPIC -g -I /work/ast/arch/linux.i386-64/include/ast -c hash.c
gcc -shared -W1,-soname,libhash.so -o libhash.so hash.o /work/ast/arch/linux.i386-64/lib/libsum.a


Here is an example of using the libhash plugin to hash a binary:

$ builtin -f ./libhash.so
$ sha512sum libhash.so
eb1e1e73c04c1eaea826b869d1e6c7872e358410bad1806e699afd3dbd17434f95b4e731c1d11fc13302de3a92e71b8a9be2e4d58db36f6ed94e80a73c501564
$ md5sum libhash.so
a1cb80f3332162ae2eab5048c5ea84d5


As always, enjoy!
 

Comments are closed.