r19240: move the NO_CONFIG_H check to libreplace
[sfrench/samba-autobuild/.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 "system/filesys.h"
28 #include "system/time.h"
29 #include "system/passwd.h"
30 #include "system/syslog.h"
31 #include "system/network.h"
32 #include "system/locale.h"
33 #include "system/wait.h"
34
35 void replace_dummy(void);
36 void replace_dummy(void) {}
37
38 #ifndef HAVE_FTRUNCATE
39  /*******************************************************************
40 ftruncate for operating systems that don't have it
41 ********************************************************************/
42 int rep_ftruncate(int f, off_t l)
43 {
44 #ifdef HAVE_CHSIZE
45       return chsize(f,l);
46 #elif defined(F_FREESP)
47       struct  flock   fl;
48
49       fl.l_whence = 0;
50       fl.l_len = 0;
51       fl.l_start = l;
52       fl.l_type = F_WRLCK;
53       return fcntl(f, F_FREESP, &fl);
54 #else
55 #error "you must have a ftruncate function"
56 #endif
57 }
58 #endif /* HAVE_FTRUNCATE */
59
60
61 #ifndef HAVE_STRLCPY
62 /* like strncpy but does not 0 fill the buffer and always null 
63    terminates. bufsize is the size of the destination buffer */
64 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
65 {
66         size_t len = strlen(s);
67         size_t ret = len;
68         if (bufsize <= 0) return 0;
69         if (len >= bufsize) len = bufsize-1;
70         memcpy(d, s, len);
71         d[len] = 0;
72         return ret;
73 }
74 #endif
75
76 #ifndef HAVE_STRLCAT
77 /* like strncat but does not 0 fill the buffer and always null 
78    terminates. bufsize is the length of the buffer, which should
79    be one more than the maximum resulting string length */
80 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
81 {
82         size_t len1 = strlen(d);
83         size_t len2 = strlen(s);
84         size_t ret = len1 + len2;
85
86         if (len1+len2 >= bufsize) {
87                 len2 = bufsize - (len1+1);
88         }
89         if (len2 > 0) {
90                 memcpy(d+len1, s, len2);
91                 d[len1+len2] = 0;
92         }
93         return ret;
94 }
95 #endif
96
97 #ifndef HAVE_MKTIME
98 /*******************************************************************
99 a mktime() replacement for those who don't have it - contributed by 
100 C.A. Lademann <cal@zls.com>
101 Corrections by richard.kettlewell@kewill.com
102 ********************************************************************/
103
104 #define  MINUTE  60
105 #define  HOUR    60*MINUTE
106 #define  DAY             24*HOUR
107 #define  YEAR    365*DAY
108 time_t rep_mktime(struct tm *t)
109 {
110   struct tm       *u;
111   time_t  epoch = 0;
112   int n;
113   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
114   y, m, i;
115
116   if(t->tm_year < 70)
117     return((time_t)-1);
118
119   n = t->tm_year + 1900 - 1;
120   epoch = (t->tm_year - 70) * YEAR + 
121     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
122
123   y = t->tm_year + 1900;
124   m = 0;
125
126   for(i = 0; i < t->tm_mon; i++) {
127     epoch += mon [m] * DAY;
128     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
129       epoch += DAY;
130     
131     if(++m > 11) {
132       m = 0;
133       y++;
134     }
135   }
136
137   epoch += (t->tm_mday - 1) * DAY;
138   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
139   
140   if((u = localtime(&epoch)) != NULL) {
141     t->tm_sec = u->tm_sec;
142     t->tm_min = u->tm_min;
143     t->tm_hour = u->tm_hour;
144     t->tm_mday = u->tm_mday;
145     t->tm_mon = u->tm_mon;
146     t->tm_year = u->tm_year;
147     t->tm_wday = u->tm_wday;
148     t->tm_yday = u->tm_yday;
149     t->tm_isdst = u->tm_isdst;
150   }
151
152   return(epoch);
153 }
154 #endif /* !HAVE_MKTIME */
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 rep_innetgr(const char *group, const char *host, const char *user, 
163                                 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 rep_initgroups(char *name, gid_t id)
189 {
190 #ifndef HAVE_SETGROUPS
191         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
192         errno = ENOSYS;
193         return -1;
194 #else /* HAVE_SETGROUPS */
195
196 #include <grp.h>
197
198         gid_t *grouplst = NULL;
199         int max_gr = 32;
200         int ret;
201         int    i,j;
202         struct group *g;
203         char   *gr;
204         
205         if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
206                 errno = ENOMEM;
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 = setgroups(i, grouplst);
229         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 *rep_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 *rep_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 #ifndef WITH_PTHREADS
327 /* REWRITE: not thread safe */
328 #ifdef REPLACE_INET_NTOA
329 char *rep_inet_ntoa(struct in_addr ip)
330 {
331         uint8_t *p = (uint8_t *)&ip.s_addr;
332         static char buf[18];
333         slprintf(buf, 17, "%d.%d.%d.%d", 
334                  (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
335         return buf;
336 }
337 #endif /* REPLACE_INET_NTOA */
338 #endif
339
340 #ifndef HAVE_SETLINEBUF
341 void rep_setlinebuf(FILE *stream)
342 {
343         setvbuf(stream, (char *)NULL, _IOLBF, 0);
344 }
345 #endif /* HAVE_SETLINEBUF */
346
347 #ifndef HAVE_VSYSLOG
348 #ifdef HAVE_SYSLOG
349 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
350 {
351         char *msg = NULL;
352         vasprintf(&msg, format, arglist);
353         if (!msg)
354                 return;
355         syslog(facility_priority, "%s", msg);
356         free(msg);
357 }
358 #endif /* HAVE_SYSLOG */
359 #endif /* HAVE_VSYSLOG */
360
361 #ifndef HAVE_STRNLEN
362 /**
363  Some platforms don't have strnlen
364 **/
365  size_t rep_strnlen(const char *s, size_t max)
366 {
367         size_t len;
368   
369         for (len = 0; len < max; len++) {
370                 if (s[len] == '\0') {
371                         break;
372                 }
373         }
374         return len;  
375 }
376 #endif
377   
378 #ifndef HAVE_STRNDUP
379 /**
380  Some platforms don't have strndup.
381 **/
382 char *rep_strndup(const char *s, size_t n)
383 {
384         char *ret;
385         
386         n = strnlen(s, n);
387         ret = malloc(n+1);
388         if (!ret)
389                 return NULL;
390         memcpy(ret, s, n);
391         ret[n] = 0;
392
393         return ret;
394 }
395 #endif
396
397 #ifndef HAVE_WAITPID
398 int rep_waitpid(pid_t pid,int *status,int options)
399 {
400   return wait4(pid, status, options, NULL);
401 }
402 #endif
403
404 #ifndef HAVE_SETEUID
405 int rep_seteuid(uid_t euid)
406 {
407 #ifdef HAVE_SETRESUID
408         return setresuid(-1, euid, -1);
409 #else
410 #  error "You need a seteuid function"
411 #endif
412 }
413 #endif
414
415 #ifndef HAVE_SETEGID
416 int rep_setegid(gid_t egid)
417 {
418 #ifdef HAVE_SETRESGID
419         return setresgid(-1, egid, -1);
420 #else
421 #  error "You need a setegid function"
422 #endif
423 }
424 #endif
425
426 /*******************************************************************
427 os/2 also doesn't have chroot
428 ********************************************************************/
429 #ifndef HAVE_CHROOT
430 int rep_chroot(const char *dname)
431 {
432         errno = ENOSYS;
433         return -1;
434 }
435 #endif
436
437 /*****************************************************************
438  Possibly replace mkstemp if it is broken.
439 *****************************************************************/  
440
441 #ifndef HAVE_SECURE_MKSTEMP
442 int rep_mkstemp(char *template)
443 {
444         /* have a reasonable go at emulating it. Hope that
445            the system mktemp() isn't completly hopeless */
446         char *p = mktemp(template);
447         if (!p)
448                 return -1;
449         return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
450 }
451 #endif
452
453 #ifndef HAVE_MKDTEMP
454 char *rep_mkdtemp(char *template)
455 {
456         char *dname;
457         
458         if ((dname = mktemp(template))) {
459                 if (mkdir(dname, 0700) >= 0) {
460                         return dname;
461                 }
462         }
463
464         return NULL;
465 }
466 #endif
467
468 #ifndef HAVE_PREAD
469 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
470 {
471         if (lseek(__fd, __offset, SEEK_SET) != __offset) {
472                 return -1;
473         }
474         return read(__fd, __buf, __nbytes);
475 }
476 #endif
477
478 #ifndef HAVE_PWRITE
479 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
480 {
481         if (lseek(__fd, __offset, SEEK_SET) != __offset) {
482                 return -1;
483         }
484         return write(__fd, __buf, __nbytes);
485 }
486 #endif
487
488 #ifndef HAVE_STRCASESTR
489 char *rep_strcasestr(const char *haystack, const char *needle)
490 {
491         const char *s;
492         size_t nlen = strlen(needle);
493         for (s=haystack;*s;s++) {
494                 if (toupper(*needle) == toupper(*s) &&
495                     strncasecmp(s, needle, nlen) == 0) {
496                         return (char *)((intptr_t)s);
497                 }
498         }
499         return NULL;
500 }
501 #endif
502
503 #ifndef HAVE_STRTOK_R
504 /* based on GLIBC version, copyright Free Software Foundation */
505 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
506 {
507         char *token;
508
509         if (s == NULL) s = *save_ptr;
510
511         s += strspn(s, delim);
512         if (*s == '\0') {
513                 *save_ptr = s;
514                 return NULL;
515         }
516
517         token = s;
518         s = strpbrk(token, delim);
519         if (s == NULL) {
520                 *save_ptr = token + strlen(token);
521         } else {
522                 *s = '\0';
523                 *save_ptr = s + 1;
524         }
525
526         return token;
527 }
528 #endif
529
530 #ifndef HAVE_STRTOLL
531 long long int rep_strtoll(const char *str, char **endptr, int base)
532 {
533 #ifdef HAVE_STRTOQ
534         return strtoq(str, endptr, base);
535 #elif defined(HAVE___STRTOLL) 
536         return __strtoll(str, endptr, base);
537 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
538         return (long long int) strtol(str, endptr, base);
539 #else
540 # error "You need a strtoll function"
541 #endif
542 }
543 #endif
544
545
546 #ifndef HAVE_STRTOULL
547 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
548 {
549 #ifdef HAVE_STRTOUQ
550         return strtouq(str, endptr, base);
551 #elif defined(HAVE___STRTOULL) 
552         return __strtoull(str, endptr, base);
553 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
554         return (unsigned long long int) strtoul(str, endptr, base);
555 #else
556 # error "You need a strtoull function"
557 #endif
558 }
559 #endif
560
561 #ifndef HAVE_SETENV
562 int rep_setenv(const char *name, const char *value, int overwrite) 
563 {
564         char *p;
565         size_t l1, l2;
566         int ret;
567
568         if (!overwrite && getenv(name)) {
569                 return 0;
570         }
571
572         l1 = strlen(name);
573         l2 = strlen(value);
574
575         p = malloc(l1+l2+2);
576         if (p == NULL) {
577                 return -1;
578         }
579         memcpy(p, name, l1);
580         p[l1] = '=';
581         memcpy(p+l1+1, value, l2);
582         p[l1+l2+1] = 0;
583
584         ret = putenv(p);
585         if (ret != 0) {
586                 free(p);
587         }
588
589         return ret;
590 }
591 #endif
592