Thu, 04 Oct 2012 20:30:05 +0200
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 }