Fix bug 5055
[Samba.git] / source / lib / replace / replace.c
blobb2a240e8ab4ad2c70eb30d94741dc2ee2bb84bbc
1 /*
2 Unix SMB/CIFS implementation.
3 replacement routines for broken systems
4 Copyright (C) Andrew Tridgell 1992-1998
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
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 3 of the License, or (at your option) any later version.
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.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 #include "replace.h"
26 #include "system/filesys.h"
27 #include "system/time.h"
28 #include "system/passwd.h"
29 #include "system/syslog.h"
30 #include "system/network.h"
31 #include "system/locale.h"
32 #include "system/wait.h"
34 void replace_dummy(void);
35 void replace_dummy(void) {}
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)
43 #ifdef HAVE_CHSIZE
44 return chsize(f,l);
45 #elif defined(F_FREESP)
46 struct flock fl;
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 #else
54 #error "you must have a ftruncate function"
55 #endif
57 #endif /* HAVE_FTRUNCATE */
60 #ifndef HAVE_STRLCPY
61 /* like strncpy but does not 0 fill the buffer and always null
62 terminates. bufsize is the size of the destination buffer */
63 size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
65 size_t len = strlen(s);
66 size_t ret = len;
67 if (bufsize <= 0) return 0;
68 if (len >= bufsize) len = bufsize-1;
69 memcpy(d, s, len);
70 d[len] = 0;
71 return ret;
73 #endif
75 #ifndef HAVE_STRLCAT
76 /* like strncat but does not 0 fill the buffer and always null
77 terminates. bufsize is the length of the buffer, which should
78 be one more than the maximum resulting string length */
79 size_t rep_strlcat(char *d, const char *s, size_t bufsize)
81 size_t len1 = strlen(d);
82 size_t len2 = strlen(s);
83 size_t ret = len1 + len2;
85 if (len1+len2 >= bufsize) {
86 len2 = bufsize - (len1+1);
88 if (len2 > 0) {
89 memcpy(d+len1, s, len2);
90 d[len1+len2] = 0;
92 return ret;
94 #endif
96 #ifndef HAVE_MKTIME
97 /*******************************************************************
98 a mktime() replacement for those who don't have it - contributed by
99 C.A. Lademann <cal@zls.com>
100 Corrections by richard.kettlewell@kewill.com
101 ********************************************************************/
103 #define MINUTE 60
104 #define HOUR 60*MINUTE
105 #define DAY 24*HOUR
106 #define YEAR 365*DAY
107 time_t rep_mktime(struct tm *t)
109 struct tm *u;
110 time_t epoch = 0;
111 int n;
112 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
113 y, m, i;
115 if(t->tm_year < 70)
116 return((time_t)-1);
118 n = t->tm_year + 1900 - 1;
119 epoch = (t->tm_year - 70) * YEAR +
120 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
122 y = t->tm_year + 1900;
123 m = 0;
125 for(i = 0; i < t->tm_mon; i++) {
126 epoch += mon [m] * DAY;
127 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
128 epoch += DAY;
130 if(++m > 11) {
131 m = 0;
132 y++;
136 epoch += (t->tm_mday - 1) * DAY;
137 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
139 if((u = localtime(&epoch)) != NULL) {
140 t->tm_sec = u->tm_sec;
141 t->tm_min = u->tm_min;
142 t->tm_hour = u->tm_hour;
143 t->tm_mday = u->tm_mday;
144 t->tm_mon = u->tm_mon;
145 t->tm_year = u->tm_year;
146 t->tm_wday = u->tm_wday;
147 t->tm_yday = u->tm_yday;
148 t->tm_isdst = u->tm_isdst;
151 return(epoch);
153 #endif /* !HAVE_MKTIME */
156 #ifndef HAVE_INITGROUPS
157 /****************************************************************************
158 some systems don't have an initgroups call
159 ****************************************************************************/
160 int rep_initgroups(char *name, gid_t id)
162 #ifndef HAVE_SETGROUPS
163 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
164 errno = ENOSYS;
165 return -1;
166 #else /* HAVE_SETGROUPS */
168 #include <grp.h>
170 gid_t *grouplst = NULL;
171 int max_gr = 32;
172 int ret;
173 int i,j;
174 struct group *g;
175 char *gr;
177 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
178 errno = ENOMEM;
179 return -1;
182 grouplst[0] = id;
183 i = 1;
184 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
185 if (g->gr_gid == id)
186 continue;
187 j = 0;
188 gr = g->gr_mem[0];
189 while (gr && (*gr != (char)NULL)) {
190 if (strcmp(name,gr) == 0) {
191 grouplst[i] = g->gr_gid;
192 i++;
193 gr = (char *)NULL;
194 break;
196 gr = g->gr_mem[++j];
199 endgrent();
200 ret = setgroups(i, grouplst);
201 free(grouplst);
202 return ret;
203 #endif /* HAVE_SETGROUPS */
205 #endif /* HAVE_INITGROUPS */
208 #if (defined(SecureWare) && defined(SCO))
209 /* This is needed due to needing the nap() function but we don't want
210 to include the Xenix libraries since that will break other things...
211 BTW: system call # 0x0c28 is the same as calling nap() */
212 long nap(long milliseconds) {
213 return syscall(0x0c28, milliseconds);
215 #endif
218 #ifndef HAVE_MEMMOVE
219 /*******************************************************************
220 safely copies memory, ensuring no overlap problems.
221 this is only used if the machine does not have its own memmove().
222 this is not the fastest algorithm in town, but it will do for our
223 needs.
224 ********************************************************************/
225 void *rep_memmove(void *dest,const void *src,int size)
227 unsigned long d,s;
228 int i;
229 if (dest==src || !size) return(dest);
231 d = (unsigned long)dest;
232 s = (unsigned long)src;
234 if ((d >= (s+size)) || (s >= (d+size))) {
235 /* no overlap */
236 memcpy(dest,src,size);
237 return(dest);
240 if (d < s) {
241 /* we can forward copy */
242 if (s-d >= sizeof(int) &&
243 !(s%sizeof(int)) &&
244 !(d%sizeof(int)) &&
245 !(size%sizeof(int))) {
246 /* do it all as words */
247 int *idest = (int *)dest;
248 int *isrc = (int *)src;
249 size /= sizeof(int);
250 for (i=0;i<size;i++) idest[i] = isrc[i];
251 } else {
252 /* simplest */
253 char *cdest = (char *)dest;
254 char *csrc = (char *)src;
255 for (i=0;i<size;i++) cdest[i] = csrc[i];
257 } else {
258 /* must backward copy */
259 if (d-s >= sizeof(int) &&
260 !(s%sizeof(int)) &&
261 !(d%sizeof(int)) &&
262 !(size%sizeof(int))) {
263 /* do it all as words */
264 int *idest = (int *)dest;
265 int *isrc = (int *)src;
266 size /= sizeof(int);
267 for (i=size-1;i>=0;i--) idest[i] = isrc[i];
268 } else {
269 /* simplest */
270 char *cdest = (char *)dest;
271 char *csrc = (char *)src;
272 for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
275 return(dest);
277 #endif /* HAVE_MEMMOVE */
279 #ifndef HAVE_STRDUP
280 /****************************************************************************
281 duplicate a string
282 ****************************************************************************/
283 char *rep_strdup(const char *s)
285 size_t len;
286 char *ret;
288 if (!s) return(NULL);
290 len = strlen(s)+1;
291 ret = (char *)malloc(len);
292 if (!ret) return(NULL);
293 memcpy(ret,s,len);
294 return(ret);
296 #endif /* HAVE_STRDUP */
298 #ifndef WITH_PTHREADS
299 /* REWRITE: not thread safe */
300 #ifdef REPLACE_INET_NTOA
301 char *rep_inet_ntoa(struct in_addr ip)
303 uint8_t *p = (uint8_t *)&ip.s_addr;
304 static char buf[18];
305 slprintf(buf, 17, "%d.%d.%d.%d",
306 (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
307 return buf;
309 #endif /* REPLACE_INET_NTOA */
310 #endif
312 #ifndef HAVE_SETLINEBUF
313 void rep_setlinebuf(FILE *stream)
315 setvbuf(stream, (char *)NULL, _IOLBF, 0);
317 #endif /* HAVE_SETLINEBUF */
319 #ifndef HAVE_VSYSLOG
320 #ifdef HAVE_SYSLOG
321 void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
323 char *msg = NULL;
324 vasprintf(&msg, format, arglist);
325 if (!msg)
326 return;
327 syslog(facility_priority, "%s", msg);
328 free(msg);
330 #endif /* HAVE_SYSLOG */
331 #endif /* HAVE_VSYSLOG */
333 #ifndef HAVE_STRNLEN
335 Some platforms don't have strnlen
337 size_t rep_strnlen(const char *s, size_t max)
339 size_t len;
341 for (len = 0; len < max; len++) {
342 if (s[len] == '\0') {
343 break;
346 return len;
348 #endif
350 #ifndef HAVE_STRNDUP
352 Some platforms don't have strndup.
354 char *rep_strndup(const char *s, size_t n)
356 char *ret;
358 n = strnlen(s, n);
359 ret = malloc(n+1);
360 if (!ret)
361 return NULL;
362 memcpy(ret, s, n);
363 ret[n] = 0;
365 return ret;
367 #endif
369 #ifndef HAVE_WAITPID
370 int rep_waitpid(pid_t pid,int *status,int options)
372 return wait4(pid, status, options, NULL);
374 #endif
376 #ifndef HAVE_SETEUID
377 int rep_seteuid(uid_t euid)
379 #ifdef HAVE_SETRESUID
380 return setresuid(-1, euid, -1);
381 #else
382 # error "You need a seteuid function"
383 #endif
385 #endif
387 #ifndef HAVE_SETEGID
388 int rep_setegid(gid_t egid)
390 #ifdef HAVE_SETRESGID
391 return setresgid(-1, egid, -1);
392 #else
393 # error "You need a setegid function"
394 #endif
396 #endif
398 /*******************************************************************
399 os/2 also doesn't have chroot
400 ********************************************************************/
401 #ifndef HAVE_CHROOT
402 int rep_chroot(const char *dname)
404 errno = ENOSYS;
405 return -1;
407 #endif
409 /*****************************************************************
410 Possibly replace mkstemp if it is broken.
411 *****************************************************************/
413 #ifndef HAVE_SECURE_MKSTEMP
414 int rep_mkstemp(char *template)
416 /* have a reasonable go at emulating it. Hope that
417 the system mktemp() isn't completly hopeless */
418 char *p = mktemp(template);
419 if (!p)
420 return -1;
421 return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
423 #endif
425 #ifndef HAVE_MKDTEMP
426 char *rep_mkdtemp(char *template)
428 char *dname;
430 if ((dname = mktemp(template))) {
431 if (mkdir(dname, 0700) >= 0) {
432 return dname;
436 return NULL;
438 #endif
440 /*****************************************************************
441 Watch out: this is not thread safe.
442 *****************************************************************/
444 #ifndef HAVE_PREAD
445 ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
447 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
448 return -1;
450 return read(__fd, __buf, __nbytes);
452 #endif
454 /*****************************************************************
455 Watch out: this is not thread safe.
456 *****************************************************************/
458 #ifndef HAVE_PWRITE
459 ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
461 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
462 return -1;
464 return write(__fd, __buf, __nbytes);
466 #endif
468 #ifndef HAVE_STRCASESTR
469 char *rep_strcasestr(const char *haystack, const char *needle)
471 const char *s;
472 size_t nlen = strlen(needle);
473 for (s=haystack;*s;s++) {
474 if (toupper(*needle) == toupper(*s) &&
475 strncasecmp(s, needle, nlen) == 0) {
476 return (char *)((intptr_t)s);
479 return NULL;
481 #endif
483 #ifndef HAVE_STRTOK_R
484 /* based on GLIBC version, copyright Free Software Foundation */
485 char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
487 char *token;
489 if (s == NULL) s = *save_ptr;
491 s += strspn(s, delim);
492 if (*s == '\0') {
493 *save_ptr = s;
494 return NULL;
497 token = s;
498 s = strpbrk(token, delim);
499 if (s == NULL) {
500 *save_ptr = token + strlen(token);
501 } else {
502 *s = '\0';
503 *save_ptr = s + 1;
506 return token;
508 #endif
510 #ifndef HAVE_STRTOLL
511 long long int rep_strtoll(const char *str, char **endptr, int base)
513 #ifdef HAVE_STRTOQ
514 return strtoq(str, endptr, base);
515 #elif defined(HAVE___STRTOLL)
516 return __strtoll(str, endptr, base);
517 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
518 return (long long int) strtol(str, endptr, base);
519 #else
520 # error "You need a strtoll function"
521 #endif
523 #endif
526 #ifndef HAVE_STRTOULL
527 unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
529 #ifdef HAVE_STRTOUQ
530 return strtouq(str, endptr, base);
531 #elif defined(HAVE___STRTOULL)
532 return __strtoull(str, endptr, base);
533 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
534 return (unsigned long long int) strtoul(str, endptr, base);
535 #else
536 # error "You need a strtoull function"
537 #endif
539 #endif
541 #ifndef HAVE_SETENV
542 int rep_setenv(const char *name, const char *value, int overwrite)
544 char *p;
545 size_t l1, l2;
546 int ret;
548 if (!overwrite && getenv(name)) {
549 return 0;
552 l1 = strlen(name);
553 l2 = strlen(value);
555 p = malloc(l1+l2+2);
556 if (p == NULL) {
557 return -1;
559 memcpy(p, name, l1);
560 p[l1] = '=';
561 memcpy(p+l1+1, value, l2);
562 p[l1+l2+1] = 0;
564 ret = putenv(p);
565 if (ret != 0) {
566 free(p);
569 return ret;
571 #endif
573 #ifndef HAVE_UNSETENV
574 int rep_unsetenv(const char *name)
576 extern char **environ;
577 size_t len = strlen(name);
578 size_t i, count;
580 if (environ == NULL || getenv(name) == NULL) {
581 return 0;
584 for (i=0;environ[i];i++) /* noop */ ;
586 count=i;
588 for (i=0;i<count;) {
589 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
590 /* note: we do _not_ free the old variable here. It is unsafe to
591 do so, as the pointer may not have come from malloc */
592 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
593 count--;
594 } else {
595 i++;
599 return 0;
601 #endif
603 #ifndef HAVE_SOCKETPAIR
604 int rep_socketpair(int d, int type, int protocol, int sv[2])
606 if (d != AF_UNIX) {
607 errno = EAFNOSUPPORT;
608 return -1;
611 if (protocol != 0) {
612 errno = EPROTONOSUPPORT;
613 return -1;
616 if (type != SOCK_STREAM) {
617 errno = EOPNOTSUPP;
618 return -1;
621 return pipe(sv);
623 #endif