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