Initial import
[samba] / 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
23  void replace_dummy(void);
24  void replace_dummy(void) {}
25
26 #ifndef HAVE_FTRUNCATE
27  /*******************************************************************
28 ftruncate for operating systems that don't have it
29 ********************************************************************/
30  int ftruncate(int f,SMB_OFF_T l)
31 {
32 #ifdef HAVE_CHSIZE
33         return chsize(f,l);
34 #else
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 #endif
43 }
44 #endif /* HAVE_FTRUNCATE */
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 >= bufsize) {
72                 return 0;
73         }
74         if (len1+len2 >= bufsize) {
75                 len2 = bufsize - (len1+1);
76         }
77         if (len2 > 0) {
78                 memcpy(d+len1, s, len2);
79                 d[len1+len2] = 0;
80         }
81         return ret;
82 }
83 #endif
84
85 #ifndef HAVE_MKTIME
86 /*******************************************************************
87 a mktime() replacement for those who don't have it - contributed by 
88 C.A. Lademann <cal@zls.com>
89 Corrections by richard.kettlewell@kewill.com
90 ********************************************************************/
91
92 #define  MINUTE  60
93 #define  HOUR    60*MINUTE
94 #define  DAY             24*HOUR
95 #define  YEAR    365*DAY
96  time_t mktime(struct tm *t)
97 {
98   struct tm       *u;
99   time_t  epoch = 0;
100   int n;
101   int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
102   y, m, i;
103
104   if(t->tm_year < 70)
105     return((time_t)-1);
106
107   n = t->tm_year + 1900 - 1;
108   epoch = (t->tm_year - 70) * YEAR + 
109     ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
110
111   y = t->tm_year + 1900;
112   m = 0;
113
114   for(i = 0; i < t->tm_mon; i++) {
115     epoch += mon [m] * DAY;
116     if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
117       epoch += DAY;
118     
119     if(++m > 11) {
120       m = 0;
121       y++;
122     }
123   }
124
125   epoch += (t->tm_mday - 1) * DAY;
126   epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
127   
128   if((u = localtime(&epoch)) != NULL) {
129     t->tm_sec = u->tm_sec;
130     t->tm_min = u->tm_min;
131     t->tm_hour = u->tm_hour;
132     t->tm_mday = u->tm_mday;
133     t->tm_mon = u->tm_mon;
134     t->tm_year = u->tm_year;
135     t->tm_wday = u->tm_wday;
136     t->tm_yday = u->tm_yday;
137     t->tm_isdst = u->tm_isdst;
138   }
139
140   return(epoch);
141 }
142 #endif /* !HAVE_MKTIME */
143
144
145
146 #ifndef HAVE_RENAME
147 /* Rename a file. (from libiberty in GNU binutils)  */
148  int rename(const char *zfrom, const char *zto)
149 {
150   if (link (zfrom, zto) < 0)
151     {
152       if (errno != EEXIST)
153         return -1;
154       if (unlink (zto) < 0
155           || link (zfrom, zto) < 0)
156         return -1;
157     }
158   return unlink (zfrom);
159 }
160 #endif /* HAVE_RENAME */
161
162
163 #ifndef HAVE_INNETGR
164 #if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
165 /*
166  * Search for a match in a netgroup. This replaces it on broken systems.
167  */
168  int innetgr(const char *group,const char *host,const char *user,const char *dom)
169 {
170         char *hst, *usr, *dm;
171   
172         setnetgrent(group);
173         while (getnetgrent(&hst, &usr, &dm)) {
174                 if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
175                     ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
176                     ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
177                         endnetgrent();
178                         return (1);
179                 }
180         }
181         endnetgrent();
182         return (0);
183 }
184 #endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
185 #endif /* HAVE_INNETGR */
186
187
188
189 #ifndef HAVE_INITGROUPS
190 /****************************************************************************
191  some systems don't have an initgroups call 
192 ****************************************************************************/
193  int initgroups(char *name,gid_t id)
194 {
195 #ifndef HAVE_SETGROUPS
196         static int done;
197         if (!done) {
198                 DEBUG(1,("WARNING: running without setgroups\n"));
199                 done=1;
200         }
201         /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
202         return(0);
203 #else /* HAVE_SETGROUPS */
204         gid_t *grouplst = NULL;
205         int max_gr = groups_max();
206         int ret;
207         int    i,j;
208         struct group *g;
209         char   *gr;
210         
211         if((grouplst = SMB_MALLOC_ARRAY(gid_t, max_gr)) == NULL) {
212                 DEBUG(0,("initgroups: malloc fail !\n"));
213                 return -1;
214         }
215
216         grouplst[0] = id;
217         i = 1;
218         while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
219                 if (g->gr_gid == id)
220                         continue;
221                 j = 0;
222                 gr = g->gr_mem[0];
223                 while (gr && (*gr != (char)NULL)) {
224                         if (strcmp(name,gr) == 0) {
225                                 grouplst[i] = g->gr_gid;
226                                 i++;
227                                 gr = (char *)NULL;
228                                 break;
229                         }
230                         gr = g->gr_mem[++j];
231                 }
232         }
233         endgrent();
234         ret = sys_setgroups(i,grouplst);
235         SAFE_FREE(grouplst);
236         return ret;
237 #endif /* HAVE_SETGROUPS */
238 }
239 #endif /* HAVE_INITGROUPS */
240
241
242 #if (defined(SecureWare) && defined(SCO))
243 /* This is needed due to needing the nap() function but we don't want
244    to include the Xenix libraries since that will break other things...
245    BTW: system call # 0x0c28 is the same as calling nap() */
246  long nap(long milliseconds) {
247          return syscall(0x0c28, milliseconds);
248  }
249 #endif
250
251
252 #ifndef HAVE_MEMMOVE
253 /*******************************************************************
254 safely copies memory, ensuring no overlap problems.
255 this is only used if the machine does not have it's own memmove().
256 this is not the fastest algorithm in town, but it will do for our
257 needs.
258 ********************************************************************/
259  void *memmove(void *dest,const void *src,int size)
260 {
261         unsigned long d,s;
262         int i;
263         if (dest==src || !size) return(dest);
264
265         d = (unsigned long)dest;
266         s = (unsigned long)src;
267
268         if ((d >= (s+size)) || (s >= (d+size))) {
269                 /* no overlap */
270                 memcpy(dest,src,size);
271                 return(dest);
272         }
273
274         if (d < s) {
275                 /* we can forward copy */
276                 if (s-d >= sizeof(int) && 
277                     !(s%sizeof(int)) && 
278                     !(d%sizeof(int)) && 
279                     !(size%sizeof(int))) {
280                         /* do it all as words */
281                         int *idest = (int *)dest;
282                         int *isrc = (int *)src;
283                         size /= sizeof(int);
284                         for (i=0;i<size;i++) idest[i] = isrc[i];
285                 } else {
286                         /* simplest */
287                         char *cdest = (char *)dest;
288                         char *csrc = (char *)src;
289                         for (i=0;i<size;i++) cdest[i] = csrc[i];
290                 }
291         } else {
292                 /* must backward copy */
293                 if (d-s >= sizeof(int) && 
294                     !(s%sizeof(int)) && 
295                     !(d%sizeof(int)) && 
296                     !(size%sizeof(int))) {
297                         /* do it all as words */
298                         int *idest = (int *)dest;
299                         int *isrc = (int *)src;
300                         size /= sizeof(int);
301                         for (i=size-1;i>=0;i--) idest[i] = isrc[i];
302                 } else {
303                         /* simplest */
304                         char *cdest = (char *)dest;
305                         char *csrc = (char *)src;
306                         for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
307                 }      
308         }
309         return(dest);
310 }
311 #endif /* HAVE_MEMMOVE */
312
313 #ifndef HAVE_STRDUP
314 /****************************************************************************
315 duplicate a string
316 ****************************************************************************/
317
318 #ifdef strdup
319 #undef strdup
320 #endif
321
322  char *strdup(const char *s)
323 {
324         size_t len;
325         char *ret;
326
327         if (!s) return(NULL);
328
329         len = strlen(s)+1;
330         ret = (char *)SMB_MALLOC(len);
331         if (!ret) return(NULL);
332         memcpy(ret,s,len);
333         return(ret);
334 }
335 #endif /* HAVE_STRDUP */
336
337 #ifdef REPLACE_INET_NTOA
338 char *rep_inet_ntoa(struct in_addr ip)
339 {
340         unsigned char *p = (unsigned char *)&ip.s_addr;
341         static char buf[18];
342         slprintf(buf, 17, "%d.%d.%d.%d", 
343                  (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
344         return buf;
345 }
346 #endif /* REPLACE_INET_NTOA */
347
348 #ifndef HAVE_STRTOUL
349 #ifndef ULONG_MAX
350 #define ULONG_MAX       ((unsigned long)(~0L))          /* 0xFFFFFFFF */
351 #endif
352
353 /*
354  * Convert a string to an unsigned long integer.
355  * Taken from libg++ - libiberty code.
356  *
357  * Ignores `locale' stuff.  Assumes that the upper and lower case
358  * alphabets and digits are each contiguous.
359  */
360  unsigned long strtoul(const char *nptr, char **endptr, int base)
361 {
362         const char *s = nptr;
363         unsigned long acc;
364         int c;
365         unsigned long cutoff;
366         int neg = 0, any, cutlim;
367
368         /*
369          * See strtol for comments as to the logic used.
370          */
371         do {
372                 c = *s++;
373         } while (isspace(c));
374         if (c == '-') {
375                 neg = 1;
376                 c = *s++;
377         } else if (c == '+')
378                 c = *s++;
379         if ((base == 0 || base == 16) &&
380             c == '0' && (*s == 'x' || *s == 'X')) {
381                 c = s[1];
382                 s += 2;
383                 base = 16;
384         }
385         if (base == 0)
386                 base = c == '0' ? 8 : 10;
387         cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
388         cutlim = (int)((unsigned long)ULONG_MAX % (unsigned long)base);
389         for (acc = 0, any = 0;; c = *s++) {
390                 if (isdigit(c))
391                         c -= '0';
392                 else if (isalpha(c))
393                         c -= isupper_ascii(c) ? 'A' - 10 : 'a' - 10;
394                 else
395                         break;
396                 if (c >= base)
397                         break;
398                 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
399                         any = -1;
400                 else {
401                         any = 1;
402                         acc *= base;
403                         acc += c;
404                 }
405         }
406         if (any < 0) {
407                 acc = ULONG_MAX;
408                 errno = ERANGE;
409         } else if (neg)
410                 acc = -acc;
411         if (endptr != 0)
412                 *endptr = (char *) (any ? s - 1 : nptr);
413         return (acc);
414 }
415 #endif /* HAVE_STRTOUL */
416
417 #ifndef HAVE_SETLINEBUF
418  int setlinebuf(FILE *stream)
419 {
420         return setvbuf(stream, (char *)NULL, _IOLBF, 0);
421 }
422 #endif /* HAVE_SETLINEBUF */
423
424 #ifndef HAVE_VSYSLOG
425 #ifdef HAVE_SYSLOG
426  void vsyslog (int facility_priority, const char *format, va_list arglist)
427 {
428         char *msg = NULL;
429         vasprintf(&msg, format, arglist);
430         if (!msg)
431                 return;
432         syslog(facility_priority, "%s", msg);
433         SAFE_FREE(msg);
434 }
435 #endif /* HAVE_SYSLOG */
436 #endif /* HAVE_VSYSLOG */
437
438
439 #ifndef HAVE_TIMEGM
440 /*
441   yes, I know this looks insane, but its really needed. The function in the 
442   Linux timegm() manpage does not work on solaris.
443 */
444  time_t timegm(struct tm *tm) 
445 {
446         struct tm tm2, tm3;
447         time_t t;
448
449         tm2 = *tm;
450
451         t = mktime(&tm2);
452         tm3 = *localtime(&t);
453         tm2 = *tm;
454         tm2.tm_isdst = tm3.tm_isdst;
455         t = mktime(&tm2);
456         t -= get_time_zone(t);
457
458         return t;
459 }
460 #endif