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