0c62ec9bfa5795526b232074e03ce4abc36b9c87
[tprouty/samba.git] / source / lib / replace.c
1 /* 
2    Unix SMB/CIFS implementation.
3    replacement routines for broken systems
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as 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
21 #include "includes.h"
22
23  void replace_dummy(void);
24  void replace_dummy(void) {}
25
26 #ifndef HAVE_FTRUNCATE
27  /*******************************************************************
28 ftruncate for operating systems that don't have it
29 ********************************************************************/
30  int ftruncate(int f,SMB_OFF_T l)
31 {
32       struct  flock   fl;
33
34       fl.l_whence = 0;
35       fl.l_len = 0;
36       fl.l_start = l;
37       fl.l_type = F_WRLCK;
38       return fcntl(f, F_FREESP, &fl);
39 }
40 #endif /* HAVE_FTRUNCATE */
41
42
43 #ifndef HAVE_STRLCPY
44 /* like strncpy but does not 0 fill the buffer and always null 
45    terminates. bufsize is the size of the destination buffer */
46  size_t strlcpy(char *d, const char *s, size_t bufsize)
47 {
48         size_t len = strlen(s);
49         size_t ret = len;
50         if (bufsize <= 0) return 0;
51         if (len >= bufsize) len = bufsize-1;
52         memcpy(d, s, len);
53         d[len] = 0;
54         return ret;
55 }
56 #endif
57
58 #ifndef HAVE_STRLCAT
59 /* like strncat but does not 0 fill the buffer and always null 
60    terminates. bufsize is the length of the buffer, which should
61    be one more than the maximum resulting string length */
62  size_t strlcat(char *d, const char *s, size_t bufsize)
63 {
64         size_t len1 = strlen(d);
65         size_t len2 = strlen(s);
66         size_t ret = len1 + len2;
67
68         if (len1+len2 >= bufsize) {
69                 len2 = bufsize - (len1+1);
70         }
71         if (len2 > 0) {
72                 memcpy(d+len1, s, len2);
73                 d[len1+len2] = 0;
74         }
75         return ret;
76 }
77 #endif
78
79 #ifndef HAVE_MKTIME
80 /*******************************************************************
81 a mktime() replacement for those who don't have it - contributed by 
82 C.A. Lademann <cal@zls.com>
83 Corrections by richard.kettlewell@kewill.com
84 ********************************************************************/
85
86 #define  MINUTE  60
87 #define  HOUR    60*MINUTE
88 #define  DAY             24*HOUR
89 #define  YEAR    365*DAY
90  time_t mktime(struct tm *t)
91 {
92   struct tm       *u;
93   time_t  epoch = 0;
94   int n;
95   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
96   y, m, i;
97
98   if(t->tm_year < 70)
99     return((time_t)-1);
100
101   n = t->tm_year + 1900 - 1;
102   epoch = (t->tm_year - 70) * YEAR + 
103     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
104
105   y = t->tm_year + 1900;
106   m = 0;
107
108   for(i = 0; i < t->tm_mon; i++) {
109     epoch += mon [m] * DAY;
110     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
111       epoch += DAY;
112     
113     if(++m > 11) {
114       m = 0;
115       y++;
116     }
117   }
118
119   epoch += (t->tm_mday - 1) * DAY;
120   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
121   
122   if((u = localtime(&epoch)) != NULL) {
123     t->tm_sec = u->tm_sec;
124     t->tm_min = u->tm_min;
125     t->tm_hour = u->tm_hour;
126     t->tm_mday = u->tm_mday;
127     t->tm_mon = u->tm_mon;
128     t->tm_year = u->tm_year;
129     t->tm_wday = u->tm_wday;
130     t->tm_yday = u->tm_yday;
131     t->tm_isdst = u->tm_isdst;
132   }
133
134   return(epoch);
135 }
136 #endif /* !HAVE_MKTIME */
137
138
139
140 #ifndef HAVE_RENAME
141 /* Rename a file. (from libiberty in GNU binutils)  */
142  int rename(const char *zfrom, const char *zto)
143 {
144   if (link (zfrom, zto) < 0)
145     {
146       if (errno != EEXIST)
147         return -1;
148       if (unlink (zto) < 0
149           || link (zfrom, zto) < 0)
150         return -1;
151     }
152   return unlink (zfrom);
153 }
154 #endif /* HAVE_RENAME */
155
156
157 #ifndef HAVE_INNETGR
158 #if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
159 /*
160  * Search for a match in a netgroup. This replaces it on broken systems.
161  */
162  int innetgr(const char *group,const char *host,const char *user,const char *dom)
163 {
164         char *hst, *usr, *dm;
165   
166         setnetgrent(group);
167         while (getnetgrent(&hst, &usr, &dm)) {
168                 if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
169                     ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
170                     ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
171                         endnetgrent();
172                         return (1);
173                 }
174         }
175         endnetgrent();
176         return (0);
177 }
178 #endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
179 #endif /* HAVE_INNETGR */
180
181
182
183 #ifndef HAVE_INITGROUPS
184 /****************************************************************************
185  some systems don't have an initgroups call 
186 ****************************************************************************/
187  int initgroups(char *name,gid_t id)
188 {
189 #ifndef HAVE_SETGROUPS
190         static int done;
191         if (!done) {
192                 DEBUG(1,("WARNING: running without setgroups\n"));
193                 done=1;
194         }
195         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
196         return(0);
197 #else /* HAVE_SETGROUPS */
198         gid_t *grouplst = NULL;
199         int max_gr = groups_max();
200         int ret;
201         int    i,j;
202         struct group *g;
203         char   *gr;
204         
205         if((grouplst = (gid_t *)malloc(sizeof(gid_t) * max_gr)) == NULL) {
206                 DEBUG(0,("initgroups: malloc fail !\n"));
207                 return -1;
208         }
209
210         grouplst[0] = id;
211         i = 1;
212         while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
213                 if (g->gr_gid == id)
214                         continue;
215                 j = 0;
216                 gr = g->gr_mem[0];
217                 while (gr && (*gr != (char)NULL)) {
218                         if (strcmp(name,gr) == 0) {
219                                 grouplst[i] = g->gr_gid;
220                                 i++;
221                                 gr = (char *)NULL;
222                                 break;
223                         }
224                         gr = g->gr_mem[++j];
225                 }
226         }
227         endgrent();
228         ret = sys_setgroups(i,grouplst);
229         SAFE_FREE(grouplst);
230         return ret;
231 #endif /* HAVE_SETGROUPS */
232 }
233 #endif /* HAVE_INITGROUPS */
234
235
236 #if (defined(SecureWare) && defined(SCO))
237 /* This is needed due to needing the nap() function but we don't want
238    to include the Xenix libraries since that will break other things...
239    BTW: system call # 0x0c28 is the same as calling nap() */
240  long nap(long milliseconds) {
241          return syscall(0x0c28, milliseconds);
242  }
243 #endif
244
245
246 #ifndef HAVE_MEMMOVE
247 /*******************************************************************
248 safely copies memory, ensuring no overlap problems.
249 this is only used if the machine does not have it's own memmove().
250 this is not the fastest algorithm in town, but it will do for our
251 needs.
252 ********************************************************************/
253  void *memmove(void *dest,const void *src,int size)
254 {
255         unsigned long d,s;
256         int i;
257         if (dest==src || !size) return(dest);
258
259         d = (unsigned long)dest;
260         s = (unsigned long)src;
261
262         if ((d >= (s+size)) || (s >= (d+size))) {
263                 /* no overlap */
264                 memcpy(dest,src,size);
265                 return(dest);
266         }
267
268         if (d < s) {
269                 /* we can forward copy */
270                 if (s-d >= sizeof(int) && 
271                     !(s%sizeof(int)) && 
272                     !(d%sizeof(int)) && 
273                     !(size%sizeof(int))) {
274                         /* do it all as words */
275                         int *idest = (int *)dest;
276                         int *isrc = (int *)src;
277                         size /= sizeof(int);
278                         for (i=0;i<size;i++) idest[i] = isrc[i];
279                 } else {
280                         /* simplest */
281                         char *cdest = (char *)dest;
282                         char *csrc = (char *)src;
283                         for (i=0;i<size;i++) cdest[i] = csrc[i];
284                 }
285         } else {
286                 /* must backward copy */
287                 if (d-s >= sizeof(int) && 
288                     !(s%sizeof(int)) && 
289                     !(d%sizeof(int)) && 
290                     !(size%sizeof(int))) {
291                         /* do it all as words */
292                         int *idest = (int *)dest;
293                         int *isrc = (int *)src;
294                         size /= sizeof(int);
295                         for (i=size-1;i>=0;i--) idest[i] = isrc[i];
296                 } else {
297                         /* simplest */
298                         char *cdest = (char *)dest;
299                         char *csrc = (char *)src;
300                         for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
301                 }      
302         }
303         return(dest);
304 }
305 #endif /* HAVE_MEMMOVE */
306
307 #ifndef HAVE_STRDUP
308 /****************************************************************************
309 duplicate a string
310 ****************************************************************************/
311  char *strdup(const char *s)
312 {
313         size_t len;
314         char *ret;
315
316         if (!s) return(NULL);
317
318         len = strlen(s)+1;
319         ret = (char *)malloc(len);
320         if (!ret) return(NULL);
321         memcpy(ret,s,len);
322         return(ret);
323 }
324 #endif /* HAVE_STRDUP */
325
326 #ifdef REPLACE_INET_NTOA
327 char *rep_inet_ntoa(struct in_addr ip)
328 {
329         unsigned char *p = (unsigned char *)&ip.s_addr;
330         static char buf[18];
331         slprintf(buf, 17, "%d.%d.%d.%d", 
332                  (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
333         return buf;
334 }
335 #endif /* REPLACE_INET_NTOA */
336
337 #ifndef HAVE_STRTOUL
338 #ifndef ULONG_MAX
339 #define ULONG_MAX       ((unsigned long)(~0L))          /* 0xFFFFFFFF */
340 #endif
341
342 /*
343  * Convert a string to an unsigned long integer.
344  * Taken from libg++ - libiberty code.
345  *
346  * Ignores `locale' stuff.  Assumes that the upper and lower case
347  * alphabets and digits are each contiguous.
348  */
349  unsigned long strtoul(const char *nptr, char **endptr, int base)
350 {
351         const char *s = nptr;
352         unsigned long acc;
353         int c;
354         unsigned long cutoff;
355         int neg = 0, any, cutlim;
356
357         /*
358          * See strtol for comments as to the logic used.
359          */
360         do {
361                 c = *s++;
362         } while (isspace(c));
363         if (c == '-') {
364                 neg = 1;
365                 c = *s++;
366         } else if (c == '+')
367                 c = *s++;
368         if ((base == 0 || base == 16) &&
369             c == '0' && (*s == 'x' || *s == 'X')) {
370                 c = s[1];
371                 s += 2;
372                 base = 16;
373         }
374         if (base == 0)
375                 base = c == '0' ? 8 : 10;
376         cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
377         cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base);
378         for (acc = 0, any = 0;; c = *s++) {
379                 if (isdigit(c))
380                         c -= '0';
381                 else if (isalpha(c))
382                         c -= isupper(c) ? 'A' - 10 : 'a' - 10;
383                 else
384                         break;
385                 if (c >= base)
386                         break;
387                 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
388                         any = -1;
389                 else {
390                         any = 1;
391                         acc *= base;
392                         acc += c;
393                 }
394         }
395         if (any < 0) {
396                 acc = ULONG_MAX;
397                 errno = ERANGE;
398         } else if (neg)
399                 acc = -acc;
400         if (endptr != 0)
401                 *endptr = (char *) (any ? s - 1 : nptr);
402         return (acc);
403 }
404 #endif /* HAVE_STRTOUL */
405
406 #ifndef HAVE_SETLINEBUF
407  int setlinebuf(FILE *stream)
408 {
409         return setvbuf(stream, (char *)NULL, _IOLBF, 0);
410 }
411 #endif /* HAVE_SETLINEBUF */
412
413 #ifndef HAVE_VSYSLOG
414 #ifdef HAVE_SYSLOG
415  void vsyslog (int facility_priority, char *format, va_list arglist)
416 {
417         char *msg = NULL;
418         vasprintf(&msg, format, arglist);
419         if (!msg)
420                 return;
421         syslog(facility_priority, "%s", msg);
422         SAFE_FREE(msg);
423 }
424 #endif /* HAVE_SYSLOG */
425 #endif /* HAVE_VSYSLOG */
426
427
428 #ifndef HAVE_TIMEGM
429 /*
430   yes, I know this looks insane, but its really needed. The function in the 
431   Linux timegm() manpage does not work on solaris.
432 */
433  time_t timegm(struct tm *tm) 
434 {
435         struct tm tm2, tm3;
436         time_t t;
437
438         tm2 = *tm;
439
440         t = mktime(&tm2);
441         tm3 = *localtime(&t);
442         tm2 = *tm;
443         tm2.tm_isdst = tm3.tm_isdst;
444         t = mktime(&tm2);
445         t -= TimeDiff(t);
446
447         return t;
448 }
449 #endif
450
451 #ifndef HAVE_SETENV
452  int setenv(const char *name, const char *value, int overwrite) 
453 {
454         char *p = NULL;
455         int ret = -1;
456
457         asprintf(&p, "%s=%s", name, value);
458
459         if (overwrite || getenv(name)) {
460                 if (p) ret = putenv(p);
461         } else {
462                 ret = 0;
463         }
464
465         return ret;     
466 }
467 #endif