openpkg/mutex.c

Thu, 04 Oct 2012 20:30:05 +0200

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 04 Oct 2012 20:30:05 +0200
changeset 715
c10fb90893b9
permissions
-rw-r--r--

Correct out of date build configuration, porting to Solaris 11 network
link infrastructure and new libpcap logic. This additionally allows for
device drivers in subdirectories of /dev. Correct packaged nmap
personalities and signatures to work out of the box. Finally, hack
arpd logic to properly close sockets and quit on TERM by repeating
signaling in the run command script. Sadly, all this fails to correct
the run time behaviour of honeyd which fails to bind to the IP layer.

     1 /*
     2 **  mutex.c -- OpenPKG Mutex Utility
     3 **  Copyright (c) 2008-2012 OpenPKG GmbH <http://openpkg.com/>
     4 **
     5 **  This software is property of the OpenPKG GmbH, DE MUC HRB 160208.
     6 **  All rights reserved. Licenses which grant limited permission to use,
     7 **  copy, modify and distribute this software are available from the
     8 **  OpenPKG GmbH.
     9 **
    10 **  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
    11 **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    12 **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    13 **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
    14 **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    15 **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    16 **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    17 **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    18 **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    19 **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    20 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    21 **  SUCH DAMAGE.
    22 */
    24 /*  standard system headers  */
    25 #include <stdio.h>
    26 #include <stdlib.h>
    27 #include <stdarg.h>
    28 #include <string.h>
    29 #include <unistd.h>
    30 #include <errno.h>
    31 #include <fcntl.h>
    32 #include <signal.h>
    33 #include <sys/types.h>
    34 #include <sys/wait.h>
    36 /*  non-standard add-on headers */
    37 #include "popt.h"
    39 /*  program information  */
    40 #define PROGRAM_NAME         "mutex"
    42 /*  error handling constants  */
    43 #define EXITCODE_NONE        00
    44 #define EXITCODE_USAGE       64
    45 #define EXITCODE_OSERR       71
    46 #define EXITCODE_CANTCREAT   73
    47 #define EXITCODE_TEMPFAIL    75
    48 #define ERRORCODE_NONE       0
    49 #define ERRORCODE_SYSTEM     1
    51 /*  global variables  */
    52 static const char           *mutex_filename  = NULL;
    53 static int                   mutex_fd        = -1;
    54 static int                   mutex_keep      = 0;
    55 static int                   mutex_timeout   = -1;
    56 static volatile int          mutex_timed_out = 0;
    58 /*  display warning and continue or display error and exit  */
    59 static void
    60 error(
    61     int exitcode,
    62     int errorcode,
    63     const char *fmt, ...)
    64 {
    65     va_list ap;
    66     int errno_safed = errno;
    68     va_start(ap, fmt);
    69     if (exitcode != 0)
    70         fprintf(stderr, PROGRAM_NAME ":ERROR: ");
    71     else
    72         fprintf(stderr, PROGRAM_NAME ":WARNING: ");
    73     vfprintf(stderr, fmt, ap);
    74     if (errorcode)
    75        fprintf(stderr, ": %s", strerror(errno_safed));
    76     fprintf(stderr, "\n");
    77     va_end(ap);
    78     if (exitcode != 0)
    79         exit(exitcode);
    80     return;
    81 }
    83 /*  acquire mutex */
    84 static int
    85 mutex_acquire(int nonblock)
    86 {
    87     static struct flock lock;
    88     int flags;
    90     /* open mutex file (and optionally create it) */
    91     flags = O_RDWR|O_CREAT;
    92     if (nonblock)
    93         flags |= O_NONBLOCK;
    94     if ((mutex_fd = open(mutex_filename, flags, 0600)) == -1) {
    95         if (errno == EAGAIN || errno == EINTR)
    96             return 0;
    97         error(EXITCODE_CANTCREAT, ERRORCODE_SYSTEM, "cannot open mutex file \"%s\"",
    98             mutex_filename);
    99     }
   101     /* acquire exclusive lock on the mutex file */
   102     lock.l_whence = SEEK_SET; /* from current point */
   103     lock.l_start  = 0;        /* -"- */
   104     lock.l_len    = 0;        /* until end of file */
   105     lock.l_type   = F_WRLCK;  /* set exclusive/read-write lock */
   106     lock.l_pid    = 0;        /* pid not actually interesting */
   107     if (fcntl(mutex_fd, nonblock ? F_SETLK : F_SETLKW, &lock) == -1) {
   108         close(mutex_fd);
   109         mutex_fd = -1;
   110         return 0;
   111     }
   113     return 1;
   114 }
   116 /*  release mutex  */
   117 static void
   118 mutex_release(void)
   119 {
   120     static struct flock unlock;
   122     if (mutex_fd != -1) {
   123         /* release lock on the mutex file */
   124         unlock.l_whence  = SEEK_SET; /* from current point */
   125         unlock.l_start   = 0;        /* -"- */
   126         unlock.l_len     = 0;        /* until end of file */
   127         unlock.l_type    = F_UNLCK;  /* unlock */
   128         unlock.l_pid     = 0;        /* pid not actually interesting */
   129         fcntl(mutex_fd, F_SETLK, &unlock);
   131         /* close mutex file */
   132         close(mutex_fd);
   133         mutex_fd = -1;
   134     }
   135     return;
   136 }
   138 /*  destroy the mutex  */
   139 static void
   140 mutex_destroy(
   141     void)
   142 {
   143     /* release lock on mutex file */
   144     mutex_release();
   146     /* optionally remove mutex file */
   147     if (!mutex_keep)
   148         unlink(mutex_filename);
   150     return;
   151 }
   153 /*  signal handler for SIGTERM  */
   154 static void
   155 handler_killed(
   156     int sig)
   157 {
   158     /* destroy mutex */
   159     mutex_destroy();
   161     /* re-raise the signal */
   162     signal(sig, SIG_DFL);
   163     if (kill(getpid(), sig) == -1)
   164         error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "kill(2) failed");
   166     return;
   167 }
   169 /*  signal handler for SIGALRM  */
   170 static void
   171 handler_timeout(
   172     int sig)
   173 {
   174     mutex_timed_out = 1;
   175     return;
   176 }
   178 /*  command line options  */
   179 static struct poptOption options_tab[] = {
   180     { "keep",    'k', POPT_ARG_NONE, &mutex_keep,    0, NULL, NULL },
   181     { "timeout", 't', POPT_ARG_INT,  &mutex_timeout, 0, NULL, NULL },
   182     POPT_TABLEEND
   183 };
   185 /*  main program procedure  */
   186 int
   187 main(
   188     int argc,
   189     char *argv[])
   190 {
   191     int status;
   192     pid_t child;
   193     int locked;
   194     char c;
   195     const char **args;
   196     poptContext options_ctx;
   198     /* process command line arguments */
   199     options_ctx = poptGetContext(argv[0], argc, (const char **)argv,
   200         options_tab, POPT_CONTEXT_NO_EXEC|POPT_CONTEXT_POSIXMEHARDER);
   201     while ((c = poptGetNextOpt(options_ctx)) > 0)
   202         ;
   203     if (c < -1)
   204         error(EXITCODE_USAGE, ERRORCODE_NONE, "command line option \"%s\": %s",
   205             poptBadOption(options_ctx, POPT_BADOPTION_NOALIAS), poptStrerror(c));
   206     mutex_filename = poptGetArg(options_ctx);
   207     if (mutex_filename == NULL) {
   208         fprintf(stderr,
   209             "usage: %s [--keep|-k] [--timeout|-t <seconds>] <mutex-file> <command> [<arguments>]\n",
   210             PROGRAM_NAME);
   211         exit(EXITCODE_USAGE);
   212     }
   213     args = poptGetArgs(options_ctx);
   215     /* optionally set up a timeout */
   216     if (mutex_timeout > 0) {
   217         struct sigaction act;
   218         act.sa_handler = handler_timeout;
   219         act.sa_flags = 0;
   220         sigemptyset(&act.sa_mask);
   221         sigaction(SIGALRM, &act, NULL);
   222         alarm(mutex_timeout);
   223     }
   225     /* try to acquire the mutex lock */
   226     locked = mutex_acquire(1 /* non-blocking */);
   227     while (!locked && !mutex_timed_out && mutex_timeout != 0)
   228         locked = mutex_acquire(0 /* blocking */);
   230     /* optionally destroy timeout */
   231     if (mutex_timeout > 0)
   232         alarm(0);
   234     /* exit in case we failed to acquire the mutex lock */
   235     if (!locked)
   236         error(EXITCODE_TEMPFAIL, ERRORCODE_NONE, "%s: already locked", mutex_filename);
   238     /* execute the command */
   239     if (atexit(mutex_destroy) == -1)
   240         error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "atexit(3) failed");
   241     if ((child = fork()) == -1)
   242         error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "fork(2) failed");
   243     if (child == 0) {
   244         /* the child process */
   245         mutex_release();
   246         execvp((char *)args[0], (char **)args);
   247         error(EXITCODE_NONE, ERRORCODE_SYSTEM, "execvp(2) failed: %s", args[0]);
   248         exit(1);
   249     }
   250     poptFreeContext(options_ctx);
   252     /* wait for child process and return its exit status */
   253     signal(SIGINT,  SIG_IGN);
   254     signal(SIGQUIT, SIG_IGN);
   255     signal(SIGTERM, handler_killed);
   256     if (waitpid(child, &status, 0) == -1)
   257         error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "waitpid(2) failed");
   258     return (WIFEXITED(status) ? WEXITSTATUS(status) : 1);
   259 }

mercurial