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