r4082: support alter_context requests
[samba.git] / source / lib / replace.c
1 /* 
2    Unix SMB/CIFS implementation.
3    replacement routines for broken systems
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "system/wait.h"
23 #include "system/time.h"
24 #include "system/network.h"
25
26  void replace_dummy(void);
27  void replace_dummy(void) {}
28
29 #ifndef HAVE_FTRUNCATE
30  /*******************************************************************
31 ftruncate for operating systems that don't have it
32 ********************************************************************/
33  int ftruncate(int f,off_t l)
34 {
35       struct  flock   fl;
36
37       fl.l_whence = 0;
38       fl.l_len = 0;
39       fl.l_start = l;
40       fl.l_type = F_WRLCK;
41       return fcntl(f, F_FREESP, &fl);
42 }
43 #endif /* HAVE_FTRUNCATE */
44
45
46 #ifndef HAVE_STRLCPY
47 /* like strncpy but does not 0 fill the buffer and always null 
48    terminates. bufsize is the size of the destination buffer */
49  size_t strlcpy(char *d, const char *s, size_t bufsize)
50 {
51         size_t len = strlen(s);
52         size_t ret = len;
53         if (bufsize <= 0) return 0;
54         if (len >= bufsize) len = bufsize-1;
55         memcpy(d, s, len);
56         d[len] = 0;
57         return ret;
58 }
59 #endif
60
61 #ifndef HAVE_STRLCAT
62 /* like strncat but does not 0 fill the buffer and always null 
63    terminates. bufsize is the length of the buffer, which should
64    be one more than the maximum resulting string length */
65  size_t strlcat(char *d, const char *s, size_t bufsize)
66 {
67         size_t len1 = strlen(d);
68         size_t len2 = strlen(s);
69         size_t ret = len1 + len2;
70
71         if (len1+len2 >= bufsize) {
72                 len2 = bufsize - (len1+1);
73         }
74         if (len2 > 0) {
75                 memcpy(d+len1, s, len2);
76                 d[len1+len2] = 0;
77         }
78         return ret;
79 }
80 #endif
81
82 #ifndef HAVE_MKTIME
83 /*******************************************************************
84 a mktime() replacement for those who don't have it - contributed by 
85 C.A. Lademann <cal@zls.com>
86 Corrections by richard.kettlewell@kewill.com
87 ********************************************************************/
88
89 #define  MINUTE  60
90 #define  HOUR    60*MINUTE
91 #define  DAY             24*HOUR
92 #define  YEAR    365*DAY
93  time_t mktime(struct tm *t)
94 {
95   struct tm       *u;
96   time_t  epoch = 0;
97   int n;
98   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
99   y, m, i;
100
101   if(t->tm_year < 70)
102     return((time_t)-1);
103
104   n = t->tm_year + 1900 - 1;
105   epoch = (t->tm_year - 70) * YEAR + 
106     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
107
108   y = t->tm_year + 1900;
109   m = 0;
110
111   for(i = 0; i < t->tm_mon; i++) {
112     epoch += mon [m] * DAY;
113     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
114       epoch += DAY;
115     
116     if(++m > 11) {
117       m = 0;
118       y++;
119     }
120   }
121
122   epoch += (t->tm_mday - 1) * DAY;
123   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
124   
125   if((u = localtime(&epoch)) != NULL) {
126     t->tm_sec = u->tm_sec;
127     t->tm_min = u->tm_min;
128     t->tm_hour = u->tm_hour;
129     t->tm_mday = u->tm_mday;
130     t->tm_mon = u->tm_mon;
131     t->tm_year = u->tm_year;
132     t->tm_wday = u->tm_wday;
133     t->tm_yday = u->tm_yday;
134     t->tm_isdst = u->tm_isdst;
135   }
136
137   return(epoch);
138 }
139 #endif /* !HAVE_MKTIME */
140
141
142
143 #ifndef HAVE_RENAME
144 /* Rename a file. (from libiberty in GNU binutils)  */
145  int rename(const char *zfrom, const char *zto)
146 {
147   if (link (zfrom, zto) < 0)
148     {
149       if (errno != EEXIST)
150         return -1;
151       if (unlink (zto) < 0
152           || link (zfrom, zto) < 0)
153         return -1;
154     }
155   return unlink (zfrom);
156 }
157 #endif /* HAVE_RENAME */
158
159
160 #ifndef HAVE_INNETGR
161 #if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
162 /*
163  * Search for a match in a netgroup. This replaces it on broken systems.
164  */
165  int innetgr(const char *group,const char *host,const char *user,const char *dom)
166 {
167         char *hst, *usr, *dm;
168   
169         setnetgrent(group);
170         while (getnetgrent(&hst, &usr, &dm)) {
171                 if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
172                     ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
173                     ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
174                         endnetgrent();
175                         return (1);
176                 }
177         }
178         endnetgrent();
179         return (0);
180 }
181 #endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
182 #endif /* HAVE_INNETGR */
183
184
185
186 #ifndef HAVE_INITGROUPS
187 /****************************************************************************
188  some systems don't have an initgroups call 
189 ****************************************************************************/
190  int initgroups(char *name,gid_t id)
191 {
192 #ifndef HAVE_SETGROUPS
193         static int done;
194         if (!done) {
195                 DEBUG(1,("WARNING: running without setgroups\n"));
196                 done=1;
197         }
198         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
199         return(0);
200 #else /* HAVE_SETGROUPS */
201         gid_t *grouplst = NULL;
202         int max_gr = groups_max();
203         int ret;
204         int    i,j;
205         struct group *g;
206         char   *gr;
207         
208         if((grouplst = malloc_array_p(gid_t, max_gr)) == NULL) {
209                 DEBUG(0,("initgroups: malloc fail !\n"));
210                 return -1;
211         }
212
213         grouplst[0] = id;
214         i = 1;
215         while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
216                 if (g->gr_gid == id)
217                         continue;
218                 j = 0;
219                 gr = g->gr_mem[0];
220                 while (gr && (*gr != (char)NULL)) {
221                         if (strcmp(name,gr) == 0) {
222                                 grouplst[i] = g->gr_gid;
223                                 i++;
224                                 gr = (char *)NULL;
225                                 break;
226                         }
227                         gr = g->gr_mem[++j];
228                 }
229         }
230         endgrent();
231         ret = sys_setgroups(i,grouplst);
232         SAFE_FREE(grouplst);
233         return ret;
234 #endif /* HAVE_SETGROUPS */
235 }
236 #endif /* HAVE_INITGROUPS */
237
238
239 #if (defined(SecureWare) && defined(SCO))
240 /* This is needed due to needing the nap() function but we don't want
241    to include the Xenix libraries since that will break other things...
242    BTW: system call # 0x0c28 is the same as calling nap() */
243  long nap(long milliseconds) {
244          return syscall(0x0c28, milliseconds);
245  }
246 #endif
247
248
249 #ifndef HAVE_MEMMOVE
250 /*******************************************************************
251 safely copies memory, ensuring no overlap problems.
252 this is only used if the machine does not have it's own memmove().
253 this is not the fastest algorithm in town, but it will do for our
254 needs.
255 ********************************************************************/
256  void *memmove(void *dest,const void *src,int size)
257 {
258         unsigned long d,s;
259         int i;
260         if (dest==src || !size) return(dest);
261
262         d = (unsigned long)dest;
263         s = (unsigned long)src;
264
265         if ((d >= (s+size)) || (s >= (d+size))) {
266                 /* no overlap */
267                 memcpy(dest,src,size);
268                 return(dest);
269         }
270
271         if (d < s) {
272                 /* we can forward copy */
273                 if (s-d >= sizeof(int) && 
274                     !(s%sizeof(int)) && 
275                     !(d%sizeof(int)) && 
276                     !(size%sizeof(int))) {
277                         /* do it all as words */
278                         int *idest = (int *)dest;
279                         int *isrc = (int *)src;
280                         size /= sizeof(int);
281                         for (i=0;i<size;i++) idest[i] = isrc[i];
282                 } else {
283                         /* simplest */
284                         char *cdest = (char *)dest;
285                         char *csrc = (char *)src;
286                         for (i=0;i<size;i++) cdest[i] = csrc[i];
287                 }
288         } else {
289                 /* must backward copy */
290                 if (d-s >= sizeof(int) && 
291                     !(s%sizeof(int)) && 
292                     !(d%sizeof(int)) && 
293                     !(size%sizeof(int))) {
294                         /* do it all as words */
295                         int *idest = (int *)dest;
296                         int *isrc = (int *)src;
297                         size /= sizeof(int);
298                         for (i=size-1;i>=0;i--) idest[i] = isrc[i];
299                 } else {
300                         /* simplest */
301                         char *cdest = (char *)dest;
302                         char *csrc = (char *)src;
303                         for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
304                 }      
305         }
306         return(dest);
307 }
308 #endif /* HAVE_MEMMOVE */
309
310 #ifndef HAVE_STRDUP
311 /****************************************************************************
312 duplicate a string
313 ****************************************************************************/
314  char *strdup(const char *s)
315 {
316         size_t len;
317         char *ret;
318
319         if (!s) return(NULL);
320
321         len = strlen(s)+1;
322         ret = (char *)malloc(len);
323         if (!ret) return(NULL);
324         memcpy(ret,s,len);
325         return(ret);
326 }
327 #endif /* HAVE_STRDUP */
328
329 #ifndef WITH_PTHREADS
330 /* REWRITE: not thread safe */
331 #ifdef REPLACE_INET_NTOA
332  char *rep_inet_ntoa(struct in_addr ip)
333 {
334         uint8_t *p = (uint8_t *)&ip.s_addr;
335         static char buf[18];
336         slprintf(buf, 17, "%d.%d.%d.%d", 
337                  (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
338         return buf;
339 }
340 #endif /* REPLACE_INET_NTOA */
341 #endif
342
343 #ifndef HAVE_STRTOUL
344 #ifndef ULONG_MAX
345 #define ULONG_MAX       ((unsigned long)(~0L))          /* 0xFFFFFFFF */
346 #endif
347
348 /*
349  * Convert a string to an unsigned long integer.
350  * Taken from libg++ - libiberty code.
351  *
352  * Ignores `locale' stuff.  Assumes that the upper and lower case
353  * alphabets and digits are each contiguous.
354  */
355  unsigned long strtoul(const char *nptr, char **endptr, int base)
356 {
357         const char *s = nptr;
358         unsigned long acc;
359         int c;
360         unsigned long cutoff;
361         int neg = 0, any, cutlim;
362
363         /*
364          * See strtol for comments as to the logic used.
365          */
366         do {
367                 c = *s++;
368         } while (isspace(c));
369         if (c == '-') {
370                 neg = 1;
371                 c = *s++;
372         } else if (c == '+')
373                 c = *s++;
374         if ((base == 0 || base == 16) &&
375             c == '0' && (*s == 'x' || *s == 'X')) {
376                 c = s[1];
377                 s += 2;
378                 base = 16;
379         }
380         if (base == 0)
381                 base = c == '0' ? 8 : 10;
382         cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
383         cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base);
384         for (acc = 0, any = 0;; c = *s++) {
385                 if (isdigit(c))
386                         c -= '0';
387                 else if (isalpha(c))
388                         c -= isupper(c) ? 'A' - 10 : 'a' - 10;
389                 else
390                         break;
391                 if (c >= base)
392                         break;
393                 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
394                         any = -1;
395                 else {
396                         any = 1;
397                         acc *= base;
398                         acc += c;
399                 }
400         }
401         if (any < 0) {
402                 acc = ULONG_MAX;
403                 errno = ERANGE;
404         } else if (neg)
405                 acc = -acc;
406         if (endptr != 0)
407                 *endptr = (char *) (any ? s - 1 : nptr);
408         return (acc);
409 }
410 #endif /* HAVE_STRTOUL */
411
412 #ifndef HAVE_SETLINEBUF
413  int setlinebuf(FILE *stream)
414 {
415         return setvbuf(stream, (char *)NULL, _IOLBF, 0);
416 }
417 #endif /* HAVE_SETLINEBUF */
418
419 #ifndef HAVE_VSYSLOG
420 #ifdef HAVE_SYSLOG
421  void vsyslog (int facility_priority, char *format, va_list arglist)
422 {
423         char *msg = NULL;
424         vasprintf(&msg, format, arglist);
425         if (!msg)
426                 return;
427         syslog(facility_priority, "%s", msg);
428         SAFE_FREE(msg);
429 }
430 #endif /* HAVE_SYSLOG */
431 #endif /* HAVE_VSYSLOG */
432
433 /*******************************************************************
434 yield the difference between *A and *B, in seconds, ignoring leap seconds
435 ********************************************************************/
436 static int tm_diff(struct tm *a, struct tm *b)
437 {
438         int ay = a->tm_year + (1900 - 1);
439         int by = b->tm_year + (1900 - 1);
440         int intervening_leap_days =
441                 (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
442         int years = ay - by;
443         int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
444         int hours = 24*days + (a->tm_hour - b->tm_hour);
445         int minutes = 60*hours + (a->tm_min - b->tm_min);
446         int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
447
448         return seconds;
449 }
450
451 /*******************************************************************
452   return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
453   ******************************************************************/
454 int get_time_zone(time_t t)
455 {
456         struct tm *tm = gmtime(&t);
457         struct tm tm_utc;
458         if (!tm)
459                 return 0;
460         tm_utc = *tm;
461         tm = localtime(&t);
462         if (!tm)
463                 return 0;
464         return tm_diff(&tm_utc,tm);
465 }
466
467 #ifndef HAVE_TIMEGM
468 /*
469   yes, I know this looks insane, but its really needed. The function in the 
470   Linux timegm() manpage does not work on solaris.
471 */
472  time_t timegm(struct tm *tm) 
473 {
474         struct tm tm2, tm3;
475         time_t t;
476
477         tm2 = *tm;
478
479         t = mktime(&tm2);
480         tm3 = *localtime(&t);
481         tm2 = *tm;
482         tm2.tm_isdst = tm3.tm_isdst;
483         t = mktime(&tm2);
484         t -= get_time_zone(t);
485
486         return t;
487 }
488 #endif
489
490 #ifndef HAVE_SETENV
491  int setenv(const char *name, const char *value, int overwrite) 
492 {
493         char *p = NULL;
494         int ret = -1;
495
496         asprintf(&p, "%s=%s", name, value);
497
498         if (overwrite || getenv(name)) {
499                 if (p) ret = putenv(p);
500         } else {
501                 ret = 0;
502         }
503
504         return ret;     
505 }
506 #endif
507
508
509 #ifndef HAVE_STRTOULL
510  unsigned long long int strtoull(const char *str, char **endptr, int base)
511 {
512 #ifdef HAVE_STRTOUQ
513         return strtouq(str, endptr, base);
514 #else
515 #error "system must support 64 bit integer read from strings"
516 #endif
517 }
518 #endif
519
520
521 #ifndef HAVE_STRNDUP
522 /**
523  Some platforms don't have strndup.
524 **/
525  char *strndup(const char *s, size_t n)
526 {
527         char *ret;
528         
529         n = strnlen(s, n);
530         ret = malloc(n+1);
531         if (!ret)
532                 return NULL;
533         memcpy(ret, s, n);
534         ret[n] = 0;
535
536         return ret;
537 }
538 #endif
539
540 #ifndef HAVE_STRNLEN
541 /**
542  Some platforms don't have strnlen
543 **/
544  size_t strnlen(const char *s, size_t n)
545 {
546         int i;
547         for (i=0; s[i] && i<n; i++)
548                 /* noop */ ;
549         return i;
550 }
551 #endif
552
553 int sys_waitpid(pid_t pid,int *status,int options)
554 {
555 #ifdef HAVE_WAITPID
556   return waitpid(pid,status,options);
557 #else /* USE_WAITPID */
558   return wait4(pid, status, options, NULL);
559 #endif /* USE_WAITPID */
560 }