Release bumped to "gts4".
[tac_plus.git] / utils.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
4    Permission to use, copy, modify, and distribute this software for
5    any purpose and without fee is hereby granted, provided that this
6    copyright and permission notice appear on all copies of the
7    software and supporting documentation, the name of Cisco Systems,
8    Inc. not be used in advertising or publicity pertaining to
9    distribution of the program without specific prior permission, and
10    notice be given in supporting documentation that modification,
11    copying and distribution is by permission of Cisco Systems, Inc.
12
13    Cisco Systems, Inc. makes no representations about the suitability
14    of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
15    IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16    WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdlib.h>     /* malloc() can be found in <stdlib.h> OR <malloc.h> */
24 #ifdef HAVE_MALLOC_H
25 #include <malloc.h>
26 #endif
27 #include <string.h>
28 #ifdef HAVE_FCNTL_H
29 #include <fcntl.h>      /* for "struct flock" */
30 #endif
31 #include <errno.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #ifdef HAVE_SYSLOG_H
36 #include <syslog.h>
37 #endif
38 #ifdef HAVE_SYS_SYSLOG_H
39 #include <sys/syslog.h>
40 #endif
41
42 #include "utils.h"
43 #include "report.h"
44 #include "main.h"
45
46
47 void *tac_malloc TAC_ARGS((int size));
48
49 void *
50 tac_malloc(size)
51 int size;
52 {
53     char *p;
54
55     /* some mallocs don't like requests for zero length */
56     if (size == 0) {
57         size++;
58     }
59
60     p = (char *) malloc(size);
61
62     if (p == NULL) {
63         report(LOG_ERR, "malloc %d failure", size);
64         tac_exit(1);
65     }
66     return (p);
67 }
68
69 void *tac_realloc TAC_ARGS((void *ptr, int size));
70
71 void *
72 tac_realloc(ptr, size)
73 void *ptr;
74 int size;
75 {
76     char *p;
77
78     if (ptr == NULL) {
79         /* realloc(0, size) is not portable */
80         p = tac_malloc(size);
81     } else {
82         p = (char *)realloc(ptr, size);
83     }
84
85     if (p == NULL) {
86         report(LOG_ERR, "realloc %d failure", size);
87         tac_exit(1);
88     }
89     return (p);
90 }
91
92 void tac_exit TAC_ARGS((int status)) G_GNUC_NORETURN;
93
94 void
95 tac_exit(status)
96 int status;
97 {
98     if (debug & DEBUG_FORK_FLAG)
99         report(LOG_DEBUG, "exit status=%d", status);
100     exit(status);
101 }
102
103 char *tac_strdup TAC_ARGS((const char *p));
104
105 char *
106 tac_strdup(p)
107 const char *p;
108 {
109     char *n = strdup(p);
110
111     if (n == NULL) {
112         report(LOG_ERR, "strdup allocation failure");
113         tac_exit(1);
114     }
115     return (n);
116 }
117
118 char *tac_make_string TAC_ARGS((u_char *p, int len));
119
120 char *
121 tac_make_string(p, len)
122 u_char *p;
123 int len;
124 {
125     char *string;
126     int new_len = len;
127
128     /*
129      * Add space for a null terminator if needed. Also, no telling
130      * what various mallocs will do when asked for a length of zero.
131      */
132     if (len == 0 || p[len - 1])
133         new_len++;
134
135     string = (char *) tac_malloc(new_len);
136
137     bzero(string, new_len);
138     bcopy(p, string, len);
139     return (string);
140 }
141
142 /* return a pointer to the end of substring in string, or NULL. Substring
143    must begin at start of string.
144 */
145
146 const char *tac_find_substring TAC_ARGS((const char *substring, const char *string));
147
148 const char *
149 tac_find_substring(substring, string)
150 const char *substring;
151 const char *string;
152 {
153     int len;
154
155     if (!(substring && string)) {
156         return(NULL);
157     }
158
159     len = strlen(substring);
160
161     if (len > (int) strlen(string)) {
162         return(NULL);
163     }
164
165     if (strncmp(substring, string, len)) {
166         /* no match */
167         return(NULL);
168     }
169     return(string + len);
170 }
171
172 #ifdef NEED_BZERO
173 int
174 bzero(p, len)
175     register char *p;
176     int len;
177 {
178     register int n;
179
180     if (len <= 0) {
181         return;
182     }
183     for (n=0; n < len; n++) {
184         p[n] = 0;
185     }
186 }
187
188 int
189 bcopy(s1, s2, len)
190     register char *s1, *s2;
191     int len;
192 {
193     register int n;
194
195     if ((n = len) <= 0)
196         return;
197     do
198         *s2++ = *s1++;
199     while (--n);
200 }
201
202 int
203 bcmp(s1,s2,n)
204     char *s1,*s2;
205     int n;
206 {
207     while (n-- > 0) {
208         if (*s1++ != *s2++) {
209             return(1);
210         }
211     }
212     return 0;
213 }
214 #endif /* NEED_BZERO */
215
216 /* Lock a file descriptor using fcntl. Returns 1 on successfully
217    acquiring the lock. The lock disappears when we close the file.
218
219    Note that if the locked file is on an NFS-mounted partition, you
220    are at the mercy of SUN's lockd, which is probably a bad idea
221 */
222
223 int tac_lockfd TAC_ARGS((char *filename, int lockfd));
224
225 int
226 tac_lockfd (filename, lockfd)
227 char *filename;
228 int lockfd;
229 {
230     int tries;
231     struct flock flock;
232     int status;
233
234     flock.l_type   = F_WRLCK;
235     flock.l_whence = SEEK_SET; /* relative to bof */
236     flock.l_start  = 0L; /* from offset zero */
237     flock.l_len    = 0L; /* lock to eof */
238
239     if (debug & DEBUG_LOCK_FLAG) {
240         syslog(LOG_ERR, "Attempting to lock %s fd %d", filename, lockfd);
241     }
242
243     for (tries = 0; tries < 10; tries++) {
244         errno = 0;
245         status = fcntl(lockfd, F_SETLK, &flock);
246         if (status == -1) {
247             if (errno == EACCES || errno == EAGAIN) {
248                 sleep(1);
249                 continue;
250             } else {
251                 syslog(LOG_ERR, "fcntl lock error status %d on %s %d %s",
252                        status, filename, lockfd, sys_errlist[errno]);
253                 return(0);
254             }
255         }
256         /* successful lock */
257         break;
258     }
259
260     if (errno != 0) {
261         syslog(LOG_ERR, "Cannot lock %s fd %d in %d tries %s",
262                filename, lockfd, tries+1, sys_errlist[errno]);
263
264         /* who is hogging this lock */
265         flock.l_type   = F_WRLCK;
266         flock.l_whence = SEEK_SET; /* relative to bof */
267         flock.l_start  = 0L; /* from offset zero */
268         flock.l_len    = 0L; /* lock to eof */
269 #ifdef HAS_FLOCK_SYSID
270         flock.l_sysid  = 0L;
271 #endif
272         flock.l_pid    = 0;
273
274         status = fcntl(lockfd, F_GETLK, &flock);
275         if ((status == -1) || (flock.l_type == F_UNLCK)) {
276             syslog(LOG_ERR, "Cannot determine %s lockholder status=%d type=%d",
277                    filename, status, flock.l_type);
278             return(0);
279         }
280
281         if (debug & DEBUG_LOCK_FLAG) {
282             syslog(LOG_ERR, "Lock on %s is being held by sys=%u pid=%d",
283                    filename,
284 #ifdef HAS_FLOCK_SYSID
285                    flock.l_sysid,
286 #else
287                    0,
288 #endif
289                    flock.l_pid);
290         }
291         return(0);
292     }
293
294     if (debug & DEBUG_LOCK_FLAG) {
295         syslog(LOG_ERR, "Successfully locked %s fd %d after %d tries",
296                filename, lockfd, tries+1);
297     }
298     return(1);
299 }
300
301 /* Unlock a file descriptor using fcntl. Returns 1 on successfully
302    releasing a lock. The lock dies when we close the file.
303
304    Note that if the locked file is on an NFS-mounted partition, you
305    are at the mercy of SUN's lockd, which is probably a bad idea
306 */
307
308 #if 0 /* unused */
309 static int
310 tac_unlockfd (filename,lockfd)
311 char *filename;
312 int lockfd;
313 {
314     struct flock flock;
315     int status;
316
317     flock.l_type   = F_WRLCK;
318     flock.l_whence = SEEK_SET; /* relative to bof */
319     flock.l_start  = 0L; /* from offset zero */
320     flock.l_len    = 0L; /* lock to eof */
321
322     if (debug & DEBUG_LOCK_FLAG) {
323         syslog(LOG_ERR, "Attempting to unlock %s fd %d", filename, lockfd);
324     }
325
326     status = fcntl(lockfd, F_UNLCK, &flock);
327     if (status == -1) {
328         syslog(LOG_ERR, "fcntl unlock error status %d on %s %d %s",
329                status, filename, lockfd, sys_errlist[errno]);
330         return(1);
331     }
332
333     if (debug & DEBUG_LOCK_FLAG) {
334         syslog(LOG_ERR, "Successfully unlocked %s fd %d",
335                filename, lockfd);
336     }
337     return(0);
338 }
339 #endif /* unused */
340
341 /* Management of bidirectional lists.
342 */
343
344 #ifdef TAC_LIST_PARANOIA
345
346 static void tac_list_check_magic TAC_ARGS((const struct tac_list *list));
347
348 static void
349 tac_list_check_magic(list)
350 const struct tac_list *list;
351 {
352    if (list->_magic != TAC_LIST_MAGIC)
353         report(LOG_ERR, "MAGIC fail for tac_list");
354 }
355
356 static void tac_list_node_check_magic TAC_ARGS((const struct tac_list_node *node));
357
358 static void
359 tac_list_node_check_magic(node)
360 const struct tac_list_node *node;
361 {
362    if (node->_magic != TAC_LIST_NODE_MAGIC)
363         report(LOG_ERR, "MAGIC fail for tac_list_node");
364 }
365 #else /* TAC_LIST_PARANOIA */
366
367 #define tac_list_check_magic(list)
368 #define tac_list_node_check_magic(node)
369
370 #endif /* TAC_LIST_PARANOIA */
371
372
373 void tac_list_init TAC_ARGS((struct tac_list *list));
374
375 void
376 tac_list_init(list)
377 struct tac_list *list;
378 {
379 #ifdef TAC_LIST_PARANOIA
380     list->_magic = TAC_LIST_MAGIC;
381 #endif
382     list->_head = NULL;
383     list->_tail = NULL;
384
385     tac_list_check_magic(list);
386 }
387
388 void tac_list_node_init TAC_ARGS((struct tac_list_node *node));
389
390 void
391 tac_list_node_init(node)
392 struct tac_list_node *node;
393 {
394 #ifdef TAC_LIST_PARANOIA
395     node->_magic = TAC_LIST_NODE_MAGIC;
396 #endif
397     node->_list = NULL;
398
399     tac_list_node_check_magic(node);
400 }
401
402 struct tac_list *tac_list_node_get_list TAC_ARGS((struct tac_list_node *node));
403
404 struct tac_list *
405 tac_list_node_get_list(node)
406 struct tac_list_node *node;
407 {
408     tac_list_node_check_magic(node);
409
410     return (node->_list);
411 }
412
413 struct tac_list_node *tac_list_first_node TAC_ARGS((struct tac_list *list));
414
415 struct tac_list_node *
416 tac_list_first_node(list)
417 struct tac_list *list;
418 {
419     tac_list_check_magic(list);
420
421     return (list->_head);
422 }
423
424 #if 0 /* unused */
425 struct tac_list_node *tac_list_last_node TAC_ARGS((struct tac_list *list));
426
427 struct tac_list_node *
428 tac_list_last_node(list)
429 struct tac_list *list;
430 {
431     tac_list_check_magic(list);
432
433     return (list->_tail);
434 }
435 #endif /* unused */
436
437 void tac_list_addhead TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
438
439 void
440 tac_list_addhead(list, node)
441 struct tac_list *list;
442 struct tac_list_node *node;
443 {
444     tac_list_check_magic(list);
445     tac_list_node_check_magic(node);
446
447     if ((node->_next = list->_head))
448         node->_next->_prev = node;
449     list->_head = node;
450     node->_prev = NULL;
451     if (!list->_tail)
452         list->_tail = node;
453     node->_list = list;
454 }
455
456 void tac_list_addtail TAC_ARGS((struct tac_list *list, struct tac_list_node *node));
457
458 void
459 tac_list_addtail(list, node)
460 struct tac_list *list;
461 struct tac_list_node *node;
462 {
463     tac_list_check_magic(list);
464     tac_list_node_check_magic(node);
465
466     if ((node->_prev = list->_tail))
467         node->_prev->_next = node;
468     list->_tail = node;
469     node->_next = NULL;
470     if (!list->_head)
471         list->_head = node;
472     node->_list = list;
473 }
474
475 struct tac_list_node *tac_list_node_next TAC_ARGS((struct tac_list_node *node));
476
477 struct tac_list_node *
478 tac_list_node_next(node)
479 struct tac_list_node *node;
480 {
481     tac_list_node_check_magic(node);
482
483     return (node->_next);
484 }
485     
486 #if 0 /* unused */
487 struct tac_list_node *tac_list_node_prev TAC_ARGS((struct tac_list_node *node));
488
489 struct tac_list_node *
490 tac_list_node_prev(node)
491 struct tac_list_node *node;
492 {
493     tac_list_node_check_magic(node);
494
495     return (node->_prev);
496 }
497 #endif /* unused */
498
499 void tac_list_node_remove TAC_ARGS((struct tac_list_node *node));
500
501 void
502 tac_list_node_remove(node)
503 struct tac_list_node *node;
504 {
505     tac_list_node_check_magic(node);
506     tac_list_check_magic(node->_list);
507
508     if (node->_next)
509         node->_next->_prev = node->_prev;
510     else
511         node->_list->_tail = node->_prev;
512
513     if (node->_prev)
514         node->_prev->_next = node->_next;
515     else
516         node->_list->_head = node->_next;
517
518     node->_list = NULL;
519 }