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