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