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