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