source: trunk/src/sh_sem.c@ 580

Last change on this file since 580 was 522, checked in by katerina, 7 years ago

Fix for ticket #417 (bus error on Solaris/SPARC).

File size: 7.3 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000, 2015 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21#include <stdlib.h>
22#include <stdio.h>
23
24#if defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H)
25#include "samhain.h"
26#include "sh_sem.h"
27#include "sh_error_min.h"
28
29#include <signal.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/ipc.h>
33#include <sys/sem.h>
34#include <unistd.h>
35
36#undef FIL__
37#define FIL__ _("sh_sem.c")
38
39typedef enum {
40 exit_ok = 0,
41 exit_fail = 1,
42 exit_time = 2,
43 exit_err = 3
44} sh_estat;
45
46
47/* FreeBSD 6.1 defines this in <sys/sem.h> too... */
48#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
49/* union semun is defined by including <sys/sem.h> */
50#else
51#if !defined(HAVE_UNION_SEMUN)
52/* according to X/OPEN we have to define it ourselves */
53union semun {
54 int val;
55 struct semid_ds *buf;
56 unsigned short *array;
57};
58#endif
59#endif
60
61
62#define SH_SEMVMX 32767
63
64static int get_semaphore (void)
65{
66 key_t key = ftok(DEFAULT_DATAROOT, '#');
67 int semid;
68
69 if (key < 0)
70 return -1;
71 semid = semget (key, 0, IPC_PRIVATE);
72 if (semid < 0)
73 return -1;
74 return semid;
75}
76
77static void sem_purge(int sem_id)
78{
79 union semun tmp;
80
81 tmp.val = 0;
82
83 if (sem_id != -1)
84 semctl(sem_id, 0, IPC_RMID, tmp);
85 return;
86}
87
88static void sem_purge_stale()
89{
90 int stale_ID = get_semaphore();
91 if (stale_ID != -1)
92 sem_purge(stale_ID);
93 return;
94}
95
96static int report_err(int errnum, char * file, int line, char * func)
97{
98 char errbuf[SH_ERRBUF_SIZE];
99 sh_error_message(errnum, errbuf, sizeof(errbuf));
100 sh_error_handle((-1), file, line, errnum, MSG_E_SUBGEN,
101 errbuf, func);
102 return -1;
103}
104
105static int init_semaphore (int nsems)
106{
107 int i;
108 mode_t mask;
109 int semid;
110 int errnum;
111 union semun tmp;
112 key_t key = ftok(DEFAULT_DATAROOT, '#');
113
114 if (key < 0)
115 return report_err(errno, FIL__, __LINE__, _("ftok"));
116
117 mask = umask(0);
118 semid = semget (key, nsems, IPC_CREAT | IPC_EXCL | 0660);
119 errnum = errno;
120 umask(mask);
121
122 tmp.val = 1;
123
124 if (semid < 0)
125 return report_err(errnum, FIL__, __LINE__, _("semget"));
126 for (i=0; i<nsems; ++i)
127 if (semctl (semid, i, SETVAL, tmp) == -1)
128 return report_err(errnum, FIL__, __LINE__, _("semclt"));
129 return semid;
130}
131
132
133static int sem_set(int semid, int sem_no, int val)
134{
135 union semun tmp;
136
137 tmp.val = val;
138
139 if (semid < 0)
140 return -1;
141 if (semctl (semid, sem_no, SETVAL, tmp) == -1)
142 return -1;
143 return 0;
144}
145
146static int sem_get(int semid, int sem_no)
147{
148 union semun tmp;
149 if (semid < 0)
150 return -1;
151 tmp.val = 0;
152 return semctl (semid, sem_no, GETVAL, tmp);
153}
154
155
156static int sem_change(int semid, int sem_no, int amount)
157{
158 struct sembuf tmp;
159 int retval;
160
161 tmp.sem_num = sem_no;
162 tmp.sem_flg = SEM_UNDO;
163 tmp.sem_op = amount;
164
165 do { retval = semop(semid, &tmp, 1);
166 } while (retval == -1 && errno == EINTR);
167
168 return retval;
169}
170
171static int sem_try_change(int semid, int sem_no, int amount)
172{
173 struct sembuf tmp;
174 int retval;
175
176 tmp.sem_num = sem_no;
177 tmp.sem_flg = IPC_NOWAIT|SEM_UNDO;
178 tmp.sem_op = amount;
179
180 do { retval = semop(semid, &tmp, 1);
181 } while (retval == -1 && errno == EINTR);
182
183 return retval;
184}
185
186#define SH_SEMAPHORE_EXTERN(S) int S = get_semaphore()
187#define SH_SEMAPHORE_INIT(S, N) int S = init_semaphore(N)
188#define SH_SEMAPHORE_TRYLOCK(S) sem_try_change(S, 0, SH_SEM_LOCK)
189#define SH_SEMAPHORE_LOCK(S) sem_change(S, 0, SH_SEM_LOCK)
190#define SH_SEMAPHORE_UNLOCK(S) sem_change(S, 0, SH_SEM_UNLOCK)
191#define SH_SEMAPHORE_PURGE(S) sem_purge(S)
192
193static int sem_ID = -1;
194
195void sh_sem_open()
196{
197 if (sh.flag.isdaemon != S_TRUE)
198 return;
199
200 if (sem_ID < 0)
201 {
202 sem_purge_stale();
203 sem_ID = init_semaphore(2);
204 sem_set(sem_ID, 1, (int) 0);
205 }
206
207 return;
208}
209
210void sh_sem_trylock()
211{
212 SH_SEMAPHORE_TRYLOCK(sem_ID);
213 return;
214}
215
216void sh_sem_lock()
217{
218 SH_SEMAPHORE_LOCK(sem_ID);
219 return;
220}
221
222void sh_sem_unlock (long val)
223{
224 if (val >= 0)
225 {
226 val = (val > SH_SEMVMX) ? SH_SEMVMX : val; /* signed short int maxval */
227 sem_set(sem_ID, 1, (int) val);
228 }
229 SH_SEMAPHORE_UNLOCK(sem_ID);
230 return;
231}
232
233void sh_sem_close()
234{
235 SH_SEMAPHORE_PURGE(sem_ID);
236 return;
237}
238
239static volatile int alarm_triggered = 0;
240static void alarm_handler(int sig)
241{
242 (void) sig;
243 alarm_triggered = 1;
244 return;
245}
246
247int sh_sem_wait(const char * wait)
248{
249 int rc, flag = 0;
250 int time_wait = atoi(wait);
251
252 SH_SEMAPHORE_EXTERN(sem_id);
253
254 if (time_wait < 0) { time_wait *= (-1); time_wait -= 1; flag = 1; }
255 if (time_wait < 0 || time_wait > (24*3600))
256 {
257 fprintf(stderr, _("Invalid argument <%d>.\n"), time_wait);
258 _exit(exit_err);
259 }
260 if (sem_id == -1)
261 {
262 if (flag && errno == ENOENT) {
263 do { retry_msleep(1, 0); rc = get_semaphore(); } while (rc == -1);
264 sem_id = rc;
265 } else {
266 if (errno == ENOENT) {
267 fputs(_("Samhain IPC not initialized.\n"), stderr);
268 _exit(exit_err); }
269 else if (errno == EACCES)
270 fputs(_("No permission to access Samhain IPC.\n"), stderr);
271 _exit(exit_err);
272 }
273 }
274
275 retry_msleep(0, 50);
276
277 if (time_wait > 0)
278 {
279 signal(SIGALRM, alarm_handler);
280 alarm(time_wait);
281 }
282 rc = SH_SEMAPHORE_LOCK(sem_id);
283 if (rc == -1 && errno == EINTR)
284 {
285 if (alarm_triggered)
286 {
287 fputs(_("Timeout on wait.\n"), stderr);
288 _exit(exit_time);
289 }
290 }
291 else if (rc == -1)
292 {
293 if (errno == EACCES)
294 fputs(_("No permission to access Samhain IPC.\n"), stderr);
295 else
296 perror(_("semop"));
297 _exit(exit_err);
298 }
299
300 rc = sem_get(sem_id, 1);
301 if (rc == 0)
302 _exit(exit_ok);
303 else if (rc == SH_SEMVMX)
304 fprintf(stdout, _("%d or more issues reported\n"), rc);
305 else
306 fprintf(stdout, _("%d issues reported\n"), rc);
307 _exit(exit_fail);
308}
309
310#else
311
312void sh_sem_open() { return; }
313void sh_sem_trylock() { return; }
314void sh_sem_lock() { return; }
315void sh_sem_unlock(long val) { (void) val; return; }
316void sh_sem_close() { return; }
317int sh_sem_wait(const char * wait)
318{
319 (void) wait;
320 fputs(_("Function not implemented (OS does not support SysV semaphores).\n"),
321 stderr);
322 exit(exit_err);
323}
324
325#endif /* defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H) */
Note: See TracBrowser for help on using the repository browser.