Import of tac_plus.v8.tar.gz: 173206 bytes, md5:
[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 #include "tac_plus.h"
21
22 #ifdef STDLIB_MALLOC
23
24 #include <stdlib.h>
25
26 #else /* !STDLIB_MALLOC */
27
28 #include <malloc.h>
29
30 #endif /* STDLIB_MALLOC */
31
32 char *
33 tac_malloc(size)
34 int size;
35 {
36     char *p;
37
38     /* some mallocs don't like requests for zero length */
39     if (size == 0) {
40         size++;
41     }
42
43     p = (char *) malloc(size);
44
45     if (p == NULL) {
46         report(LOG_ERR, "malloc %d failure", size);
47         tac_exit(1);
48     }
49     return (p);
50 }
51
52 char *
53 tac_realloc(ptr, size)
54 char *ptr;
55 int size;
56 {
57     char *p;
58
59     if (ptr == NULL) {
60         /* realloc(0, size) is not portable */
61         p = tac_malloc(size);
62     } else {
63         p = (char *)realloc(ptr, size);
64     }
65
66     if (p == NULL) {
67         report(LOG_ERR, "realloc %d failure", size);
68         tac_exit(1);
69     }
70     return (p);
71 }
72
73 tac_exit(status)
74 int status;
75 {
76     if (debug & DEBUG_FORK_FLAG)
77         report(LOG_DEBUG, "exit status=%d", status);
78     exit(status);
79 }
80
81 char *
82 tac_strdup(p)
83 char *p;
84 {
85     char *n = strdup(p);
86
87     if (n == NULL) {
88         report(LOG_ERR, "strdup allocation failure");
89         tac_exit(1);
90     }
91     return (n);
92 }
93
94 char *
95 tac_make_string(p, len)
96 u_char *p;
97 int len;
98 {
99     char *string;
100     int new_len = len;
101
102     /* 
103      * Add space for a null terminator if needed. Also, no telling
104      * what various mallocs will do when asked for a length of zero.
105      */
106     if (len == 0 || p[len - 1])
107         new_len++;
108
109     string = (char *) tac_malloc(new_len);
110
111     bzero(string, new_len);
112     bcopy(p, string, len);
113     return (string);
114 }
115
116 /* return a pointer to the end of substring in string, or NULL. Substring 
117    must begin at start of string.
118 */
119 char *
120 tac_find_substring(substring, string)
121 char *substring, *string;
122 {
123     int len;
124
125     if (!(substring && string)) {
126         return(NULL);
127     }
128
129     len = strlen(substring);
130
131     if (len > (int) strlen(string)) {
132         return(NULL);
133     }
134         
135     if (strncmp(substring, string, len)) {
136         /* no match */
137         return(NULL);
138     }
139     return(string + len);
140 }
141
142 #ifdef NEED_BZERO
143 int
144 bzero(p, len)
145     register char *p;
146     int len;
147 {
148     register int n;
149
150     if (len <= 0) {
151         return;
152     }
153     for (n=0; n < len; n++) {
154         p[n] = 0;
155     }
156 }
157
158 int
159 bcopy(s1, s2, len)
160     register char *s1, *s2;
161     int len;
162 {
163     register int n;
164
165     if ((n = len) <= 0)
166         return;
167     do
168         *s2++ = *s1++;
169     while (--n);
170 }
171
172 int 
173 bcmp(s1,s2,n)
174     char *s1,*s2;
175     int n;
176 {     
177     while (n-- > 0) {
178         if (*s1++ != *s2++) {
179             return(1);
180         }
181     }
182     return 0;
183 }
184 #endif /* NEED_BZERO */
185
186 /* Lock a file descriptor using fcntl. Returns 1 on successfully
187    acquiring the lock. The lock disappears when we close the file.
188
189    Note that if the locked file is on an NFS-mounted partition, you
190    are at the mercy of SUN's lockd, which is probably a bad idea 
191 */
192
193 int
194 tac_lockfd (filename, lockfd)
195 char *filename;
196 int lockfd;
197 {
198     int tries;
199     struct flock flock;
200     int status;
201
202     flock.l_type   = F_WRLCK;
203     flock.l_whence = SEEK_SET; /* relative to bof */
204     flock.l_start  = 0L; /* from offset zero */
205     flock.l_len    = 0L; /* lock to eof */
206
207     if (debug & DEBUG_LOCK_FLAG) {
208         syslog(LOG_ERR, "Attempting to lock %s fd %d", filename, lockfd);
209     }
210
211     for (tries = 0; tries < 10; tries++) {
212         errno = 0;
213         status = fcntl(lockfd, F_SETLK, &flock);
214         if (status == -1) {
215             if (errno == EACCES || errno == EAGAIN) {
216                 sleep(1);
217                 continue;
218             } else {
219                 syslog(LOG_ERR, "fcntl lock error status %d on %s %d %s", 
220                        status, filename, lockfd, sys_errlist[errno]);
221                 return(0);
222             }
223         }
224         /* successful lock */
225         break;
226     }
227
228     if (errno != 0) {
229         syslog(LOG_ERR, "Cannot lock %s fd %d in %d tries %s", 
230                filename, lockfd, tries+1, sys_errlist[errno]);
231
232         /* who is hogging this lock */
233         flock.l_type   = F_WRLCK;
234         flock.l_whence = SEEK_SET; /* relative to bof */
235         flock.l_start  = 0L; /* from offset zero */
236         flock.l_len    = 0L; /* lock to eof */
237 #ifdef HAS_FLOCK_SYSID
238         flock.l_sysid  = 0L;
239 #endif
240         flock.l_pid    = 0;
241
242         status = fcntl(lockfd, F_GETLK, &flock);
243         if ((status == -1) || (flock.l_type == F_UNLCK)) {
244             syslog(LOG_ERR, "Cannot determine %s lockholder status=%d type=%d",
245                    filename, status, flock.l_type);
246             return(0);
247         }
248
249         if (debug & DEBUG_LOCK_FLAG) {
250             syslog(LOG_ERR, "Lock on %s is being held by sys=%u pid=%d",
251                    filename, 
252 #ifdef HAS_FLOCK_SYSID
253                    flock.l_sysid, 
254 #else
255                    0,
256 #endif
257                    flock.l_pid);
258         }
259         return(0);
260     }
261
262     if (debug & DEBUG_LOCK_FLAG) {
263         syslog(LOG_ERR, "Successfully locked %s fd %d after %d tries", 
264                filename, lockfd, tries+1);
265     }
266     return(1);
267 }
268
269 /* Unlock a file descriptor using fcntl. Returns 1 on successfully
270    releasing a lock. The lock dies when we close the file.
271
272    Note that if the locked file is on an NFS-mounted partition, you
273    are at the mercy of SUN's lockd, which is probably a bad idea 
274 */
275
276 int
277 tac_unlockfd (filename,lockfd)
278 char *filename;
279 int lockfd;
280 {
281     struct flock flock;
282     int status;
283
284     flock.l_type   = F_WRLCK;
285     flock.l_whence = SEEK_SET; /* relative to bof */
286     flock.l_start  = 0L; /* from offset zero */
287     flock.l_len    = 0L; /* lock to eof */
288
289     if (debug & DEBUG_LOCK_FLAG) {
290         syslog(LOG_ERR, "Attempting to unlock %s fd %d", filename, lockfd);
291     }
292
293     status = fcntl(lockfd, F_UNLCK, &flock);
294     if (status == -1) {
295         syslog(LOG_ERR, "fcntl unlock error status %d on %s %d %s", 
296                status, filename, lockfd, sys_errlist[errno]);
297         return(1);
298     }
299
300     if (debug & DEBUG_LOCK_FLAG) {
301         syslog(LOG_ERR, "Successfully unlocked %s fd %d", 
302                filename, lockfd);
303     }
304     return(0);
305 }