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.

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

mercurial