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