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