r9374: HPUX is also missing setegid()
[samba.git] / source4 / 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    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 #ifdef HAVE_CHSIZE
36       return chsize(f,l);
37 #else
38       struct  flock   fl;
39
40       fl.l_whence = 0;
41       fl.l_len = 0;
42       fl.l_start = l;
43       fl.l_type = F_WRLCK;
44       return fcntl(f, F_FREESP, &fl);
45 #endif
46 }
47 #endif /* HAVE_FTRUNCATE */
48
49
50 #ifndef HAVE_STRLCPY
51 /* like strncpy but does not 0 fill the buffer and always null 
52    terminates. bufsize is the size of the destination buffer */
53  size_t strlcpy(char *d, const char *s, size_t bufsize)
54 {
55         size_t len = strlen(s);
56         size_t ret = len;
57         if (bufsize <= 0) return 0;
58         if (len >= bufsize) len = bufsize-1;
59         memcpy(d, s, len);
60         d[len] = 0;
61         return ret;
62 }
63 #endif
64
65 #ifndef HAVE_STRLCAT
66 /* like strncat but does not 0 fill the buffer and always null 
67    terminates. bufsize is the length of the buffer, which should
68    be one more than the maximum resulting string length */
69  size_t strlcat(char *d, const char *s, size_t bufsize)
70 {
71         size_t len1 = strlen(d);
72         size_t len2 = strlen(s);
73         size_t ret = len1 + len2;
74
75         if (len1+len2 >= bufsize) {
76                 len2 = bufsize - (len1+1);
77         }
78         if (len2 > 0) {
79                 memcpy(d+len1, s, len2);
80                 d[len1+len2] = 0;
81         }
82         return ret;
83 }
84 #endif
85
86 #ifndef HAVE_MKTIME
87 /*******************************************************************
88 a mktime() replacement for those who don't have it - contributed by 
89 C.A. Lademann <cal@zls.com>
90 Corrections by richard.kettlewell@kewill.com
91 ********************************************************************/
92
93 #define  MINUTE  60
94 #define  HOUR    60*MINUTE
95 #define  DAY             24*HOUR
96 #define  YEAR    365*DAY
97  time_t mktime(struct tm *t)
98 {
99   struct tm       *u;
100   time_t  epoch = 0;
101   int n;
102   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
103   y, m, i;
104
105   if(t->tm_year < 70)
106     return((time_t)-1);
107
108   n = t->tm_year + 1900 - 1;
109   epoch = (t->tm_year - 70) * YEAR + 
110     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
111
112   y = t->tm_year + 1900;
113   m = 0;
114
115   for(i = 0; i < t->tm_mon; i++) {
116     epoch += mon [m] * DAY;
117     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
118       epoch += DAY;
119     
120     if(++m > 11) {
121       m = 0;
122       y++;
123     }
124   }
125
126   epoch += (t->tm_mday - 1) * DAY;
127   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
128   
129   if((u = localtime(&epoch)) != NULL) {
130     t->tm_sec = u->tm_sec;
131     t->tm_min = u->tm_min;
132     t->tm_hour = u->tm_hour;
133     t->tm_mday = u->tm_mday;
134     t->tm_mon = u->tm_mon;
135     t->tm_year = u->tm_year;
136     t->tm_wday = u->tm_wday;
137     t->tm_yday = u->tm_yday;
138     t->tm_isdst = u->tm_isdst;
139   }
140
141   return(epoch);
142 }
143 #endif /* !HAVE_MKTIME */
144
145
146
147 #ifndef HAVE_RENAME
148 /* Rename a file. (from libiberty in GNU binutils)  */
149  int rename(const char *zfrom, const char *zto)
150 {
151   if (link (zfrom, zto) < 0)
152     {
153       if (errno != EEXIST)
154         return -1;
155       if (unlink (zto) < 0
156           || link (zfrom, zto) < 0)
157         return -1;
158     }
159   return unlink (zfrom);
160 }
161 #endif /* HAVE_RENAME */
162
163
164 #ifndef HAVE_INNETGR
165 #if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
166 /*
167  * Search for a match in a netgroup. This replaces it on broken systems.
168  */
169  int innetgr(const char *group,const char *host,const char *user,const char *dom)
170 {
171         char *hst, *usr, *dm;
172   
173         setnetgrent(group);
174         while (getnetgrent(&hst, &usr, &dm)) {
175                 if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
176                     ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
177                     ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
178                         endnetgrent();
179                         return (1);
180                 }
181         }
182         endnetgrent();
183         return (0);
184 }
185 #endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
186 #endif /* HAVE_INNETGR */
187
188
189
190 #ifndef HAVE_INITGROUPS
191 /****************************************************************************
192  some systems don't have an initgroups call 
193 ****************************************************************************/
194  int initgroups(char *name, gid_t id)
195 {
196 #ifndef HAVE_SETGROUPS
197         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
198         errno = ENOSYS;
199         return -1;
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(sizeof(gid_t) * max_gr)) == NULL) {
209                 errno = ENOMEM;
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 = setgroups(i, grouplst);
232         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_SETLINEBUF
344  int setlinebuf(FILE *stream)
345 {
346         return setvbuf(stream, (char *)NULL, _IOLBF, 0);
347 }
348 #endif /* HAVE_SETLINEBUF */
349
350 #ifndef HAVE_VSYSLOG
351 #ifdef HAVE_SYSLOG
352  void vsyslog (int facility_priority, char *format, va_list arglist)
353 {
354         char *msg = NULL;
355         vasprintf(&msg, format, arglist);
356         if (!msg)
357                 return;
358         syslog(facility_priority, "%s", msg);
359         free(msg);
360 }
361 #endif /* HAVE_SYSLOG */
362 #endif /* HAVE_VSYSLOG */
363
364 /*******************************************************************
365 yield the difference between *A and *B, in seconds, ignoring leap seconds
366 ********************************************************************/
367 static int tm_diff(struct tm *a, struct tm *b)
368 {
369         int ay = a->tm_year + (1900 - 1);
370         int by = b->tm_year + (1900 - 1);
371         int intervening_leap_days =
372                 (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
373         int years = ay - by;
374         int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
375         int hours = 24*days + (a->tm_hour - b->tm_hour);
376         int minutes = 60*hours + (a->tm_min - b->tm_min);
377         int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
378
379         return seconds;
380 }
381
382 /*******************************************************************
383   return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
384   ******************************************************************/
385 int get_time_zone(time_t t)
386 {
387         struct tm *tm = gmtime(&t);
388         struct tm tm_utc;
389         if (!tm)
390                 return 0;
391         tm_utc = *tm;
392         tm = localtime(&t);
393         if (!tm)
394                 return 0;
395         return tm_diff(&tm_utc,tm);
396 }
397
398 #ifndef HAVE_TIMEGM
399 /*
400   yes, I know this looks insane, but its really needed. The function in the 
401   Linux timegm() manpage does not work on solaris.
402 */
403  time_t timegm(struct tm *tm) 
404 {
405         struct tm tm2, tm3;
406         time_t t;
407
408         tm2 = *tm;
409
410         t = mktime(&tm2);
411         tm3 = *localtime(&t);
412         tm2 = *tm;
413         tm2.tm_isdst = tm3.tm_isdst;
414         t = mktime(&tm2);
415         t -= get_time_zone(t);
416
417         return t;
418 }
419 #endif
420
421 #ifndef HAVE_SETENV
422  int setenv(const char *name, const char *value, int overwrite) 
423 {
424         char *p = NULL;
425         int ret = -1;
426
427         asprintf(&p, "%s=%s", name, value);
428
429         if (overwrite || getenv(name)) {
430                 if (p) ret = putenv(p);
431         } else {
432                 ret = 0;
433         }
434
435         return ret;     
436 }
437 #endif
438
439
440 #ifndef HAVE_STRTOULL
441  unsigned long long int strtoull(const char *str, char **endptr, int base)
442 {
443 #ifdef HAVE_STRTOUQ
444         return strtouq(str, endptr, base);
445 #elif defined(HAVE___STRTOULL) 
446         return __strtoull(str, endptr, base);
447 #else
448 # error "You need a strtoull function"
449 #endif
450 }
451 #endif
452
453 #ifndef HAVE_STRTOLL
454  long long int strtoll(const char *str, char **endptr, int base)
455 {
456 #ifdef HAVE_STRTOQ
457         return strtoq(str, endptr, base);
458 #elif defined(HAVE___STRTOLL) 
459         return __strtoll(str, endptr, base);
460 #else
461 # error "You need a strtoll function"
462 #endif
463 }
464 #endif
465
466
467 #ifndef HAVE_STRNDUP
468 /**
469  Some platforms don't have strndup.
470 **/
471  char *strndup(const char *s, size_t n)
472 {
473         char *ret;
474         
475         n = strnlen(s, n);
476         ret = malloc(n+1);
477         if (!ret)
478                 return NULL;
479         memcpy(ret, s, n);
480         ret[n] = 0;
481
482         return ret;
483 }
484 #endif
485
486 #ifndef HAVE_STRNLEN
487 /**
488  Some platforms don't have strnlen
489 **/
490  size_t strnlen(const char *s, size_t n)
491 {
492         int i;
493         for (i=0; s[i] && i<n; i++)
494                 /* noop */ ;
495         return i;
496 }
497 #endif
498
499 int sys_waitpid(pid_t pid,int *status,int options)
500 {
501 #ifdef HAVE_WAITPID
502   return waitpid(pid,status,options);
503 #else /* USE_WAITPID */
504   return wait4(pid, status, options, NULL);
505 #endif /* USE_WAITPID */
506 }
507
508 #ifndef HAVE_SETEUID
509  int seteuid(uid_t euid)
510 {
511 #ifdef HAVE_SETRESUID
512         return setresuid(-1, euid, -1);
513 #else
514 #  error "You need a seteuid function"
515 #endif
516 }
517 #endif
518
519 #ifndef HAVE_SETEGID
520  int setegid(gid_t egid)
521 {
522 #ifdef HAVE_SETRESGID
523         return setresgid(-1, egid, -1);
524 #else
525 #  error "You need a setegid function"
526 #endif
527 }
528 #endif