source: trunk/server/lib/replace/replace.c@ 862

Last change on this file since 862 was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

File size: 17.4 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 replacement routines for broken systems
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jelmer Vernooij 2005-2008
6 Copyright (C) Matthieu Patou 2010
7
8 ** NOTE! The following LGPL license applies to the replace
9 ** library. This does NOT imply that all of Samba is released
10 ** under the LGPL
11
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
16
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
24*/
25
26#include "replace.h"
27
28#include "system/filesys.h"
29#include "system/time.h"
30#include "system/passwd.h"
31#include "system/syslog.h"
32#include "system/locale.h"
33#include "system/wait.h"
34
35#ifdef _WIN32
36#define mkdir(d,m) _mkdir(d)
37#endif
38
39void replace_dummy(void);
40void replace_dummy(void) {}
41
42#ifndef HAVE_FTRUNCATE
43 /*******************************************************************
44ftruncate for operating systems that don't have it
45********************************************************************/
46int rep_ftruncate(int f, off_t l)
47{
48#ifdef HAVE_CHSIZE
49 return chsize(f,l);
50#elif defined(F_FREESP)
51 struct flock fl;
52
53 fl.l_whence = 0;
54 fl.l_len = 0;
55 fl.l_start = l;
56 fl.l_type = F_WRLCK;
57 return fcntl(f, F_FREESP, &fl);
58#else
59#error "you must have a ftruncate function"
60#endif
61}
62#endif /* HAVE_FTRUNCATE */
63
64
65#ifndef HAVE_STRLCPY
66/* like strncpy but does not 0 fill the buffer and always null
67 terminates. bufsize is the size of the destination buffer */
68size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
69{
70 size_t len = strlen(s);
71 size_t ret = len;
72 if (bufsize <= 0) return 0;
73 if (len >= bufsize) len = bufsize-1;
74 memcpy(d, s, len);
75 d[len] = 0;
76 return ret;
77}
78#endif
79
80#ifndef HAVE_STRLCAT
81/* like strncat but does not 0 fill the buffer and always null
82 terminates. bufsize is the length of the buffer, which should
83 be one more than the maximum resulting string length */
84size_t rep_strlcat(char *d, const char *s, size_t bufsize)
85{
86 size_t len1 = strlen(d);
87 size_t len2 = strlen(s);
88 size_t ret = len1 + len2;
89
90 if (len1+len2 >= bufsize) {
91 if (bufsize < (len1+1)) {
92 return ret;
93 }
94 len2 = bufsize - (len1+1);
95 }
96 if (len2 > 0) {
97 memcpy(d+len1, s, len2);
98 d[len1+len2] = 0;
99 }
100 return ret;
101}
102#endif
103
104#ifndef HAVE_MKTIME
105/*******************************************************************
106a mktime() replacement for those who don't have it - contributed by
107C.A. Lademann <cal@zls.com>
108Corrections by richard.kettlewell@kewill.com
109********************************************************************/
110
111#define MINUTE 60
112#define HOUR 60*MINUTE
113#define DAY 24*HOUR
114#define YEAR 365*DAY
115time_t rep_mktime(struct tm *t)
116{
117 struct tm *u;
118 time_t epoch = 0;
119 int n;
120 int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
121 y, m, i;
122
123 if(t->tm_year < 70)
124 return((time_t)-1);
125
126 n = t->tm_year + 1900 - 1;
127 epoch = (t->tm_year - 70) * YEAR +
128 ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
129
130 y = t->tm_year + 1900;
131 m = 0;
132
133 for(i = 0; i < t->tm_mon; i++) {
134 epoch += mon [m] * DAY;
135 if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
136 epoch += DAY;
137
138 if(++m > 11) {
139 m = 0;
140 y++;
141 }
142 }
143
144 epoch += (t->tm_mday - 1) * DAY;
145 epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
146
147 if((u = localtime(&epoch)) != NULL) {
148 t->tm_sec = u->tm_sec;
149 t->tm_min = u->tm_min;
150 t->tm_hour = u->tm_hour;
151 t->tm_mday = u->tm_mday;
152 t->tm_mon = u->tm_mon;
153 t->tm_year = u->tm_year;
154 t->tm_wday = u->tm_wday;
155 t->tm_yday = u->tm_yday;
156 t->tm_isdst = u->tm_isdst;
157 }
158
159 return(epoch);
160}
161#endif /* !HAVE_MKTIME */
162
163
164#ifndef HAVE_INITGROUPS
165/****************************************************************************
166 some systems don't have an initgroups call
167****************************************************************************/
168int rep_initgroups(char *name, gid_t id)
169{
170#ifndef HAVE_SETGROUPS
171 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
172 errno = ENOSYS;
173 return -1;
174#else /* HAVE_SETGROUPS */
175
176#include <grp.h>
177
178 gid_t *grouplst = NULL;
179 int max_gr = NGROUPS_MAX;
180 int ret;
181 int i,j;
182 struct group *g;
183 char *gr;
184
185 if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
186 errno = ENOMEM;
187 return -1;
188 }
189
190 grouplst[0] = id;
191 i = 1;
192 while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
193 if (g->gr_gid == id)
194 continue;
195 j = 0;
196 gr = g->gr_mem[0];
197 while (gr && (*gr != (char)NULL)) {
198 if (strcmp(name,gr) == 0) {
199 grouplst[i] = g->gr_gid;
200 i++;
201 gr = (char *)NULL;
202 break;
203 }
204 gr = g->gr_mem[++j];
205 }
206 }
207 endgrent();
208 ret = setgroups(i, grouplst);
209 free(grouplst);
210 return ret;
211#endif /* HAVE_SETGROUPS */
212}
213#endif /* HAVE_INITGROUPS */
214
215
216#if (defined(SecureWare) && defined(SCO))
217/* This is needed due to needing the nap() function but we don't want
218 to include the Xenix libraries since that will break other things...
219 BTW: system call # 0x0c28 is the same as calling nap() */
220long nap(long milliseconds) {
221 return syscall(0x0c28, milliseconds);
222 }
223#endif
224
225
226#ifndef HAVE_MEMMOVE
227/*******************************************************************
228safely copies memory, ensuring no overlap problems.
229this is only used if the machine does not have its own memmove().
230this is not the fastest algorithm in town, but it will do for our
231needs.
232********************************************************************/
233void *rep_memmove(void *dest,const void *src,int size)
234{
235 unsigned long d,s;
236 int i;
237 if (dest==src || !size) return(dest);
238
239 d = (unsigned long)dest;
240 s = (unsigned long)src;
241
242 if ((d >= (s+size)) || (s >= (d+size))) {
243 /* no overlap */
244 memcpy(dest,src,size);
245 return(dest);
246 }
247
248 if (d < s) {
249 /* we can forward copy */
250 if (s-d >= sizeof(int) &&
251 !(s%sizeof(int)) &&
252 !(d%sizeof(int)) &&
253 !(size%sizeof(int))) {
254 /* do it all as words */
255 int *idest = (int *)dest;
256 int *isrc = (int *)src;
257 size /= sizeof(int);
258 for (i=0;i<size;i++) idest[i] = isrc[i];
259 } else {
260 /* simplest */
261 char *cdest = (char *)dest;
262 char *csrc = (char *)src;
263 for (i=0;i<size;i++) cdest[i] = csrc[i];
264 }
265 } else {
266 /* must backward copy */
267 if (d-s >= sizeof(int) &&
268 !(s%sizeof(int)) &&
269 !(d%sizeof(int)) &&
270 !(size%sizeof(int))) {
271 /* do it all as words */
272 int *idest = (int *)dest;
273 int *isrc = (int *)src;
274 size /= sizeof(int);
275 for (i=size-1;i>=0;i--) idest[i] = isrc[i];
276 } else {
277 /* simplest */
278 char *cdest = (char *)dest;
279 char *csrc = (char *)src;
280 for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
281 }
282 }
283 return(dest);
284}
285#endif /* HAVE_MEMMOVE */
286
287#ifndef HAVE_STRDUP
288/****************************************************************************
289duplicate a string
290****************************************************************************/
291char *rep_strdup(const char *s)
292{
293 size_t len;
294 char *ret;
295
296 if (!s) return(NULL);
297
298 len = strlen(s)+1;
299 ret = (char *)malloc(len);
300 if (!ret) return(NULL);
301 memcpy(ret,s,len);
302 return(ret);
303}
304#endif /* HAVE_STRDUP */
305
306#ifndef HAVE_SETLINEBUF
307void rep_setlinebuf(FILE *stream)
308{
309 setvbuf(stream, (char *)NULL, _IOLBF, 0);
310}
311#endif /* HAVE_SETLINEBUF */
312
313#ifndef HAVE_VSYSLOG
314#ifdef HAVE_SYSLOG
315void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
316{
317 char *msg = NULL;
318 vasprintf(&msg, format, arglist);
319 if (!msg)
320 return;
321 syslog(facility_priority, "%s", msg);
322 free(msg);
323}
324#endif /* HAVE_SYSLOG */
325#endif /* HAVE_VSYSLOG */
326
327#ifndef HAVE_STRNLEN
328/**
329 Some platforms don't have strnlen
330**/
331 size_t rep_strnlen(const char *s, size_t max)
332{
333 size_t len;
334
335 for (len = 0; len < max; len++) {
336 if (s[len] == '\0') {
337 break;
338 }
339 }
340 return len;
341}
342#endif
343
344#ifndef HAVE_STRNDUP
345/**
346 Some platforms don't have strndup.
347**/
348char *rep_strndup(const char *s, size_t n)
349{
350 char *ret;
351
352 n = strnlen(s, n);
353 ret = malloc(n+1);
354 if (!ret)
355 return NULL;
356 memcpy(ret, s, n);
357 ret[n] = 0;
358
359 return ret;
360}
361#endif
362
363#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
364int rep_waitpid(pid_t pid,int *status,int options)
365{
366 return wait4(pid, status, options, NULL);
367}
368#endif
369
370#ifndef HAVE_SETEUID
371int rep_seteuid(uid_t euid)
372{
373#ifdef HAVE_SETRESUID
374 return setresuid(-1, euid, -1);
375#else
376 errno = ENOSYS;
377 return -1;
378#endif
379}
380#endif
381
382#ifndef HAVE_SETEGID
383int rep_setegid(gid_t egid)
384{
385#ifdef HAVE_SETRESGID
386 return setresgid(-1, egid, -1);
387#else
388 errno = ENOSYS;
389 return -1;
390#endif
391}
392#endif
393
394/*******************************************************************
395os/2 also doesn't have chroot
396********************************************************************/
397#ifndef HAVE_CHROOT
398int rep_chroot(const char *dname)
399{
400 errno = ENOSYS;
401 return -1;
402}
403#endif
404
405/*****************************************************************
406 Possibly replace mkstemp if it is broken.
407*****************************************************************/
408
409#ifndef HAVE_SECURE_MKSTEMP
410int rep_mkstemp(char *template)
411{
412 /* have a reasonable go at emulating it. Hope that
413 the system mktemp() isn't completely hopeless */
414 char *p = mktemp(template);
415 if (!p)
416 return -1;
417 return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
418}
419#endif
420
421#ifndef HAVE_MKDTEMP
422char *rep_mkdtemp(char *template)
423{
424 char *dname;
425
426 if ((dname = mktemp(template))) {
427 if (mkdir(dname, 0700) >= 0) {
428 return dname;
429 }
430 }
431
432 return NULL;
433}
434#endif
435
436/*****************************************************************
437 Watch out: this is not thread safe.
438*****************************************************************/
439
440#ifndef HAVE_PREAD
441ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
442{
443 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
444 return -1;
445 }
446 return read(__fd, __buf, __nbytes);
447}
448#endif
449
450/*****************************************************************
451 Watch out: this is not thread safe.
452*****************************************************************/
453
454#ifndef HAVE_PWRITE
455ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
456{
457 if (lseek(__fd, __offset, SEEK_SET) != __offset) {
458 return -1;
459 }
460 return write(__fd, __buf, __nbytes);
461}
462#endif
463
464#ifndef HAVE_STRCASESTR
465char *rep_strcasestr(const char *haystack, const char *needle)
466{
467 const char *s;
468 size_t nlen = strlen(needle);
469 for (s=haystack;*s;s++) {
470 if (toupper(*needle) == toupper(*s) &&
471 strncasecmp(s, needle, nlen) == 0) {
472 return (char *)((uintptr_t)s);
473 }
474 }
475 return NULL;
476}
477#endif
478
479#ifndef HAVE_STRTOK_R
480/* based on GLIBC version, copyright Free Software Foundation */
481char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
482{
483 char *token;
484
485 if (s == NULL) s = *save_ptr;
486
487 s += strspn(s, delim);
488 if (*s == '\0') {
489 *save_ptr = s;
490 return NULL;
491 }
492
493 token = s;
494 s = strpbrk(token, delim);
495 if (s == NULL) {
496 *save_ptr = token + strlen(token);
497 } else {
498 *s = '\0';
499 *save_ptr = s + 1;
500 }
501
502 return token;
503}
504#endif
505
506
507#ifndef HAVE_STRTOLL
508long long int rep_strtoll(const char *str, char **endptr, int base)
509{
510#ifdef HAVE_STRTOQ
511 return strtoq(str, endptr, base);
512#elif defined(HAVE___STRTOLL)
513 return __strtoll(str, endptr, base);
514#elif SIZEOF_LONG == SIZEOF_LONG_LONG
515 return (long long int) strtol(str, endptr, base);
516#else
517# error "You need a strtoll function"
518#endif
519}
520#else
521#ifdef HAVE_BSD_STRTOLL
522#ifdef HAVE_STRTOQ
523long long int rep_strtoll(const char *str, char **endptr, int base)
524{
525 long long int nb = strtoq(str, endptr, base);
526 /* In linux EINVAL is only returned if base is not ok */
527 if (errno == EINVAL) {
528 if (base == 0 || (base >1 && base <37)) {
529 /* Base was ok so it's because we were not
530 * able to make the convertion.
531 * Let's reset errno.
532 */
533 errno = 0;
534 }
535 }
536 return nb;
537}
538#else
539#error "You need the strtoq function"
540#endif /* HAVE_STRTOQ */
541#endif /* HAVE_BSD_STRTOLL */
542#endif /* HAVE_STRTOLL */
543
544
545#ifndef HAVE_STRTOULL
546unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
547{
548#ifdef HAVE_STRTOUQ
549 return strtouq(str, endptr, base);
550#elif defined(HAVE___STRTOULL)
551 return __strtoull(str, endptr, base);
552#elif SIZEOF_LONG == SIZEOF_LONG_LONG
553 return (unsigned long long int) strtoul(str, endptr, base);
554#else
555# error "You need a strtoull function"
556#endif
557}
558#else
559#ifdef HAVE_BSD_STRTOLL
560#ifdef HAVE_STRTOUQ
561unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
562{
563 unsigned long long int nb = strtouq(str, endptr, base);
564 /* In linux EINVAL is only returned if base is not ok */
565 if (errno == EINVAL) {
566 if (base == 0 || (base >1 && base <37)) {
567 /* Base was ok so it's because we were not
568 * able to make the convertion.
569 * Let's reset errno.
570 */
571 errno = 0;
572 }
573 }
574 return nb;
575}
576#else
577#error "You need the strtouq function"
578#endif /* HAVE_STRTOUQ */
579#endif /* HAVE_BSD_STRTOLL */
580#endif /* HAVE_STRTOULL */
581
582#ifndef HAVE_SETENV
583int rep_setenv(const char *name, const char *value, int overwrite)
584{
585 char *p;
586 size_t l1, l2;
587 int ret;
588
589 if (!overwrite && getenv(name)) {
590 return 0;
591 }
592
593 l1 = strlen(name);
594 l2 = strlen(value);
595
596 p = malloc(l1+l2+2);
597 if (p == NULL) {
598 return -1;
599 }
600 memcpy(p, name, l1);
601 p[l1] = '=';
602 memcpy(p+l1+1, value, l2);
603 p[l1+l2+1] = 0;
604
605 ret = putenv(p);
606 if (ret != 0) {
607 free(p);
608 }
609
610 return ret;
611}
612#endif
613
614#ifndef HAVE_UNSETENV
615int rep_unsetenv(const char *name)
616{
617 extern char **environ;
618 size_t len = strlen(name);
619 size_t i, count;
620
621 if (environ == NULL || getenv(name) == NULL) {
622 return 0;
623 }
624
625 for (i=0;environ[i];i++) /* noop */ ;
626
627 count=i;
628
629 for (i=0;i<count;) {
630 if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
631 /* note: we do _not_ free the old variable here. It is unsafe to
632 do so, as the pointer may not have come from malloc */
633 memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
634 count--;
635 } else {
636 i++;
637 }
638 }
639
640 return 0;
641}
642#endif
643
644#ifndef HAVE_UTIME
645int rep_utime(const char *filename, const struct utimbuf *buf)
646{
647 errno = ENOSYS;
648 return -1;
649}
650#endif
651
652#ifndef HAVE_UTIMES
653int rep_utimes(const char *filename, const struct timeval tv[2])
654{
655 struct utimbuf u;
656
657 u.actime = tv[0].tv_sec;
658 if (tv[0].tv_usec > 500000) {
659 u.actime += 1;
660 }
661
662 u.modtime = tv[1].tv_sec;
663 if (tv[1].tv_usec > 500000) {
664 u.modtime += 1;
665 }
666
667 return utime(filename, &u);
668}
669#endif
670
671#ifndef HAVE_DUP2
672int rep_dup2(int oldfd, int newfd)
673{
674 errno = ENOSYS;
675 return -1;
676}
677#endif
678
679#ifndef HAVE_CHOWN
680/**
681chown isn't used much but OS/2 doesn't have it
682**/
683int rep_chown(const char *fname, uid_t uid, gid_t gid)
684{
685 errno = ENOSYS;
686 return -1;
687}
688#endif
689
690#ifndef HAVE_LINK
691int rep_link(const char *oldpath, const char *newpath)
692{
693 errno = ENOSYS;
694 return -1;
695}
696#endif
697
698#ifndef HAVE_READLINK
699int rep_readlink(const char *path, char *buf, size_t bufsiz)
700{
701 errno = ENOSYS;
702 return -1;
703}
704#endif
705
706#ifndef HAVE_SYMLINK
707int rep_symlink(const char *oldpath, const char *newpath)
708{
709 errno = ENOSYS;
710 return -1;
711}
712#endif
713
714#ifndef HAVE_LCHOWN
715int rep_lchown(const char *fname,uid_t uid,gid_t gid)
716{
717 errno = ENOSYS;
718 return -1;
719}
720#endif
721
722#ifndef HAVE_REALPATH
723char *rep_realpath(const char *path, char *resolved_path)
724{
725 /* As realpath is not a system call we can't return ENOSYS. */
726 errno = EINVAL;
727 return NULL;
728}
729#endif
730
731
732#ifndef HAVE_MEMMEM
733void *rep_memmem(const void *haystack, size_t haystacklen,
734 const void *needle, size_t needlelen)
735{
736 if (needlelen == 0) {
737 return discard_const(haystack);
738 }
739 while (haystacklen >= needlelen) {
740 char *p = (char *)memchr(haystack, *(const char *)needle,
741 haystacklen-(needlelen-1));
742 if (!p) return NULL;
743 if (memcmp(p, needle, needlelen) == 0) {
744 return p;
745 }
746 haystack = p+1;
747 haystacklen -= (p - (const char *)haystack) + 1;
748 }
749 return NULL;
750}
751#endif
752
753#if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF)
754int rep_vdprintf(int fd, const char *format, va_list ap)
755{
756 char *s = NULL;
757 int ret;
758
759 vasprintf(&s, format, ap);
760 if (s == NULL) {
761 errno = ENOMEM;
762 return -1;
763 }
764 ret = write(fd, s, strlen(s));
765 free(s);
766 return ret;
767}
768#endif
769
770#if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF)
771int rep_dprintf(int fd, const char *format, ...)
772{
773 int ret;
774 va_list ap;
775
776 va_start(ap, format);
777 ret = vdprintf(fd, format, ap);
778 va_end(ap);
779
780 return ret;
781}
782#endif
783
784#ifndef HAVE_GET_CURRENT_DIR_NAME
785char *rep_get_current_dir_name(void)
786{
787 char buf[PATH_MAX+1];
788 char *p;
789 p = getcwd(buf, sizeof(buf));
790 if (p == NULL) {
791 return NULL;
792 }
793 return strdup(p);
794}
795#endif
796
797#if !defined(HAVE_STRERROR_R) || !defined(STRERROR_R_PROTO_COMPATIBLE)
798int rep_strerror_r(int errnum, char *buf, size_t buflen)
799{
800 char *s = strerror(errnum);
801 if (strlen(s)+1 > buflen) {
802 errno = ERANGE;
803 return -1;
804 }
805 strncpy(buf, s, buflen);
806 return 0;
807}
808#endif
809
810#ifndef HAVE_CLOCK_GETTIME
811int rep_clock_gettime(clockid_t clk_id, struct timespec *tp)
812{
813 struct timeval tval;
814 switch (clk_id) {
815 case 0: /* CLOCK_REALTIME :*/
816#ifdef HAVE_GETTIMEOFDAY_TZ
817 gettimeofday(&tval,NULL);
818#else
819 gettimeofday(&tval);
820#endif
821 tp->tv_sec = tval.tv_sec;
822 tp->tv_nsec = tval.tv_usec * 1000;
823 break;
824 default:
825 errno = EINVAL;
826 return -1;
827 }
828 return 0;
829}
830#endif
Note: See TracBrowser for help on using the repository browser.