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
8 ** NOTE! The following LGPL license applies to the replace
9 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
28 #include "system/filesys.h"
29 #include "system/time.h"
30 #include "system/network.h"
31 #include "system/passwd.h"
32 #include "system/syslog.h"
33 #include "system/locale.h"
34 #include "system/wait.h"
36 #ifdef HAVE_SYS_SYSCALL_H
37 #include <sys/syscall.h>
41 #define mkdir(d,m) _mkdir(d)
44 void replace_dummy(void);
45 void replace_dummy(void) {}
47 #ifndef HAVE_FTRUNCATE
48 /*******************************************************************
49 ftruncate for operating systems that don't have it
50 ********************************************************************/
51 int rep_ftruncate(int f
, off_t l
)
55 #elif defined(F_FREESP)
62 return fcntl(f
, F_FREESP
, &fl
);
64 #error "you must have a ftruncate function"
67 #endif /* HAVE_FTRUNCATE */
72 * Like strncpy but does not 0 fill the buffer and always null
73 * terminates. bufsize is the size of the destination buffer.
74 * Returns the length of s.
76 size_t rep_strlcpy(char *d
, const char *s
, size_t bufsize
)
78 size_t len
= strlen(s
);
94 /* like strncat but does not 0 fill the buffer and always null
95 terminates. bufsize is the length of the buffer, which should
96 be one more than the maximum resulting string length */
97 size_t rep_strlcat(char *d
, const char *s
, size_t bufsize
)
99 size_t len1
= strnlen(d
, bufsize
);
100 size_t len2
= strlen(s
);
101 size_t ret
= len1
+ len2
;
103 if (len1
+len2
>= bufsize
) {
104 if (bufsize
< (len1
+1)) {
107 len2
= bufsize
- (len1
+1);
110 memcpy(d
+len1
, s
, len2
);
118 /*******************************************************************
119 a mktime() replacement for those who don't have it - contributed by
120 C.A. Lademann <cal@zls.com>
121 Corrections by richard.kettlewell@kewill.com
122 ********************************************************************/
125 #define HOUR 60*MINUTE
128 time_t rep_mktime(struct tm
*t
)
133 int mon
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
139 n
= t
->tm_year
+ 1900 - 1;
140 epoch
= (t
->tm_year
- 70) * YEAR
+
141 ((n
/ 4 - n
/ 100 + n
/ 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY
;
143 y
= t
->tm_year
+ 1900;
146 for(i
= 0; i
< t
->tm_mon
; i
++) {
147 epoch
+= mon
[m
] * DAY
;
148 if(m
== 1 && y
% 4 == 0 && (y
% 100 != 0 || y
% 400 == 0))
157 epoch
+= (t
->tm_mday
- 1) * DAY
;
158 epoch
+= t
->tm_hour
* HOUR
+ t
->tm_min
* MINUTE
+ t
->tm_sec
;
160 if((u
= localtime(&epoch
)) != NULL
) {
161 t
->tm_sec
= u
->tm_sec
;
162 t
->tm_min
= u
->tm_min
;
163 t
->tm_hour
= u
->tm_hour
;
164 t
->tm_mday
= u
->tm_mday
;
165 t
->tm_mon
= u
->tm_mon
;
166 t
->tm_year
= u
->tm_year
;
167 t
->tm_wday
= u
->tm_wday
;
168 t
->tm_yday
= u
->tm_yday
;
169 t
->tm_isdst
= u
->tm_isdst
;
174 #endif /* !HAVE_MKTIME */
177 #ifndef HAVE_INITGROUPS
178 /****************************************************************************
179 some systems don't have an initgroups call
180 ****************************************************************************/
181 int rep_initgroups(char *name
, gid_t id
)
183 #ifndef HAVE_SETGROUPS
184 /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
187 #else /* HAVE_SETGROUPS */
191 gid_t
*grouplst
= NULL
;
192 int max_gr
= NGROUPS_MAX
;
198 if((grouplst
= malloc(sizeof(gid_t
) * max_gr
)) == NULL
) {
205 while (i
< max_gr
&& ((g
= (struct group
*)getgrent()) != (struct group
*)NULL
)) {
210 while (gr
&& (*gr
!= (char)NULL
)) {
211 if (strcmp(name
,gr
) == 0) {
212 grouplst
[i
] = g
->gr_gid
;
221 ret
= setgroups(i
, grouplst
);
224 #endif /* HAVE_SETGROUPS */
226 #endif /* HAVE_INITGROUPS */
230 /*******************************************************************
231 safely copies memory, ensuring no overlap problems.
232 this is only used if the machine does not have its own memmove().
233 this is not the fastest algorithm in town, but it will do for our
235 ********************************************************************/
236 void *rep_memmove(void *dest
,const void *src
,int size
)
240 if (dest
==src
|| !size
) return(dest
);
242 d
= (unsigned long)dest
;
243 s
= (unsigned long)src
;
245 if ((d
>= (s
+size
)) || (s
>= (d
+size
))) {
247 memcpy(dest
,src
,size
);
252 /* we can forward copy */
253 if (s
-d
>= sizeof(int) &&
256 !(size
%sizeof(int))) {
257 /* do it all as words */
258 int *idest
= (int *)dest
;
259 int *isrc
= (int *)src
;
261 for (i
=0;i
<size
;i
++) idest
[i
] = isrc
[i
];
264 char *cdest
= (char *)dest
;
265 char *csrc
= (char *)src
;
266 for (i
=0;i
<size
;i
++) cdest
[i
] = csrc
[i
];
269 /* must backward copy */
270 if (d
-s
>= sizeof(int) &&
273 !(size
%sizeof(int))) {
274 /* do it all as words */
275 int *idest
= (int *)dest
;
276 int *isrc
= (int *)src
;
278 for (i
=size
-1;i
>=0;i
--) idest
[i
] = isrc
[i
];
281 char *cdest
= (char *)dest
;
282 char *csrc
= (char *)src
;
283 for (i
=size
-1;i
>=0;i
--) cdest
[i
] = csrc
[i
];
288 #endif /* HAVE_MEMMOVE */
291 /****************************************************************************
293 ****************************************************************************/
294 char *rep_strdup(const char *s
)
299 if (!s
) return(NULL
);
302 ret
= (char *)malloc(len
);
303 if (!ret
) return(NULL
);
307 #endif /* HAVE_STRDUP */
309 #ifndef HAVE_SETLINEBUF
310 void rep_setlinebuf(FILE *stream
)
312 setvbuf(stream
, (char *)NULL
, _IOLBF
, 0);
314 #endif /* HAVE_SETLINEBUF */
318 void rep_vsyslog (int facility_priority
, const char *format
, va_list arglist
)
321 vasprintf(&msg
, format
, arglist
);
324 syslog(facility_priority
, "%s", msg
);
327 #endif /* HAVE_SYSLOG */
328 #endif /* HAVE_VSYSLOG */
332 Some platforms don't have strnlen
334 size_t rep_strnlen(const char *s
, size_t max
)
338 for (len
= 0; len
< max
; len
++) {
339 if (s
[len
] == '\0') {
349 Some platforms don't have strndup.
351 char *rep_strndup(const char *s
, size_t n
)
366 #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
367 int rep_waitpid(pid_t pid
,int *status
,int options
)
369 return wait4(pid
, status
, options
, NULL
);
374 int rep_seteuid(uid_t euid
)
376 #ifdef HAVE_SETRESUID
377 return setresuid(-1, euid
, -1);
386 int rep_setegid(gid_t egid
)
388 #ifdef HAVE_SETRESGID
389 return setresgid(-1, egid
, -1);
397 /*******************************************************************
398 os/2 also doesn't have chroot
399 ********************************************************************/
401 int rep_chroot(const char *dname
)
408 /*****************************************************************
409 Possibly replace mkstemp if it is broken.
410 *****************************************************************/
412 #ifndef HAVE_SECURE_MKSTEMP
413 int rep_mkstemp(char *template)
415 /* have a reasonable go at emulating it. Hope that
416 the system mktemp() isn't completely hopeless */
418 if (template[0] == 0)
420 return open(template, O_CREAT
|O_EXCL
|O_RDWR
, 0600);
425 char *rep_mkdtemp(char *template)
429 if ((dname
= mktemp(template))) {
430 if (mkdir(dname
, 0700) >= 0) {
439 /*****************************************************************
440 Watch out: this is not thread safe.
441 *****************************************************************/
444 ssize_t
rep_pread(int __fd
, void *__buf
, size_t __nbytes
, off_t __offset
)
446 if (lseek(__fd
, __offset
, SEEK_SET
) != __offset
) {
449 return read(__fd
, __buf
, __nbytes
);
453 /*****************************************************************
454 Watch out: this is not thread safe.
455 *****************************************************************/
458 ssize_t
rep_pwrite(int __fd
, const void *__buf
, size_t __nbytes
, off_t __offset
)
460 if (lseek(__fd
, __offset
, SEEK_SET
) != __offset
) {
463 return write(__fd
, __buf
, __nbytes
);
467 #ifndef HAVE_STRCASESTR
468 char *rep_strcasestr(const char *haystack
, const char *needle
)
471 size_t nlen
= strlen(needle
);
472 for (s
=haystack
;*s
;s
++) {
473 if (toupper(*needle
) == toupper(*s
) &&
474 strncasecmp(s
, needle
, nlen
) == 0) {
475 return (char *)((uintptr_t)s
);
483 char *rep_strsep(char **pps
, const char *delim
)
491 p
+= strcspn(p
, delim
);
502 #ifndef HAVE_STRTOK_R
503 /* based on GLIBC version, copyright Free Software Foundation */
504 char *rep_strtok_r(char *s
, const char *delim
, char **save_ptr
)
508 if (s
== NULL
) s
= *save_ptr
;
510 s
+= strspn(s
, delim
);
517 s
= strpbrk(token
, delim
);
519 *save_ptr
= token
+ strlen(token
);
531 long long int rep_strtoll(const char *str
, char **endptr
, int base
)
534 return strtoq(str
, endptr
, base
);
535 #elif defined(HAVE___STRTOLL)
536 return __strtoll(str
, endptr
, base
);
537 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
538 return (long long int) strtol(str
, endptr
, base
);
540 # error "You need a strtoll function"
544 #ifdef HAVE_BSD_STRTOLL
546 long long int rep_strtoll(const char *str
, char **endptr
, int base
)
548 int saved_errno
= errno
;
549 long long int nb
= strtoll(str
, endptr
, base
);
550 /* With glibc EINVAL is only returned if base is not ok */
551 if (errno
== EINVAL
) {
552 if (base
== 0 || (base
>1 && base
<37)) {
553 /* Base was ok so it's because we were not
554 * able to make the conversion.
562 #endif /* HAVE_BSD_STRTOLL */
563 #endif /* HAVE_STRTOLL */
566 #ifndef HAVE_STRTOULL
567 unsigned long long int rep_strtoull(const char *str
, char **endptr
, int base
)
570 return strtouq(str
, endptr
, base
);
571 #elif defined(HAVE___STRTOULL)
572 return __strtoull(str
, endptr
, base
);
573 #elif SIZEOF_LONG == SIZEOF_LONG_LONG
574 return (unsigned long long int) strtoul(str
, endptr
, base
);
576 # error "You need a strtoull function"
580 #ifdef HAVE_BSD_STRTOLL
582 unsigned long long int rep_strtoull(const char *str
, char **endptr
, int base
)
584 int saved_errno
= errno
;
585 unsigned long long int nb
= strtoull(str
, endptr
, base
);
586 /* With glibc EINVAL is only returned if base is not ok */
587 if (errno
== EINVAL
) {
588 if (base
== 0 || (base
>1 && base
<37)) {
589 /* Base was ok so it's because we were not
590 * able to make the conversion.
598 #endif /* HAVE_BSD_STRTOLL */
599 #endif /* HAVE_STRTOULL */
602 int rep_setenv(const char *name
, const char *value
, int overwrite
)
608 if (!overwrite
&& getenv(name
)) {
621 memcpy(p
+l1
+1, value
, l2
);
633 #ifndef HAVE_UNSETENV
634 int rep_unsetenv(const char *name
)
636 extern char **environ
;
637 size_t len
= strlen(name
);
640 if (environ
== NULL
|| getenv(name
) == NULL
) {
644 for (i
=0;environ
[i
];i
++) /* noop */ ;
649 if (strncmp(environ
[i
], name
, len
) == 0 && environ
[i
][len
] == '=') {
650 /* note: we do _not_ free the old variable here. It is unsafe to
651 do so, as the pointer may not have come from malloc */
652 memmove(&environ
[i
], &environ
[i
+1], (count
-i
)*sizeof(char *));
664 int rep_utime(const char *filename
, const struct utimbuf
*buf
)
672 int rep_utimes(const char *filename
, const struct timeval tv
[2])
676 u
.actime
= tv
[0].tv_sec
;
677 if (tv
[0].tv_usec
> 500000) {
681 u
.modtime
= tv
[1].tv_sec
;
682 if (tv
[1].tv_usec
> 500000) {
686 return utime(filename
, &u
);
691 int rep_dup2(int oldfd
, int newfd
)
700 chown isn't used much but OS/2 doesn't have it
702 int rep_chown(const char *fname
, uid_t uid
, gid_t gid
)
710 int rep_link(const char *oldpath
, const char *newpath
)
717 #ifndef HAVE_READLINK
718 int rep_readlink(const char *path
, char *buf
, size_t bufsiz
)
726 int rep_symlink(const char *oldpath
, const char *newpath
)
734 int rep_lchown(const char *fname
,uid_t uid
,gid_t gid
)
741 #ifndef HAVE_REALPATH
742 char *rep_realpath(const char *path
, char *resolved_path
)
744 /* As realpath is not a system call we can't return ENOSYS. */
752 void *rep_memmem(const void *haystack
, size_t haystacklen
,
753 const void *needle
, size_t needlelen
)
755 if (needlelen
== 0) {
756 return discard_const(haystack
);
758 while (haystacklen
>= needlelen
) {
759 char *p
= (char *)memchr(haystack
, *(const char *)needle
,
760 haystacklen
-(needlelen
-1));
762 if (memcmp(p
, needle
, needlelen
) == 0) {
766 haystacklen
-= (p
- (const char *)haystack
) + 1;
772 #if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF)
773 int rep_vdprintf(int fd
, const char *format
, va_list ap
)
778 vasprintf(&s
, format
, ap
);
783 ret
= write(fd
, s
, strlen(s
));
789 #if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF)
790 int rep_dprintf(int fd
, const char *format
, ...)
795 va_start(ap
, format
);
796 ret
= vdprintf(fd
, format
, ap
);
803 #ifndef HAVE_GET_CURRENT_DIR_NAME
804 char *rep_get_current_dir_name(void)
806 char buf
[PATH_MAX
+1];
808 p
= getcwd(buf
, sizeof(buf
));
816 #ifndef HAVE_STRERROR_R
817 int rep_strerror_r(int errnum
, char *buf
, size_t buflen
)
819 char *s
= strerror(errnum
);
820 if (strlen(s
)+1 > buflen
) {
824 strncpy(buf
, s
, buflen
);
827 #elif (!defined(STRERROR_R_XSI_NOT_GNU))
829 int rep_strerror_r(int errnum
, char *buf
, size_t buflen
)
831 char *s
= strerror_r(errnum
, buf
, buflen
);
833 /* Shouldn't happen, should always get a string */
837 strlcpy(buf
, s
, buflen
);
838 if (strlen(s
) > buflen
- 1) {
847 #ifndef HAVE_CLOCK_GETTIME
848 int rep_clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
852 case 0: /* CLOCK_REALTIME :*/
853 #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
854 gettimeofday(&tval
,NULL
);
858 tp
->tv_sec
= tval
.tv_sec
;
859 tp
->tv_nsec
= tval
.tv_usec
* 1000;
869 #ifndef HAVE_MEMALIGN
870 void *rep_memalign( size_t align
, size_t size
)
872 #if defined(HAVE_POSIX_MEMALIGN)
874 int ret
= posix_memalign( &p
, align
, size
);
880 /* On *BSD systems memaligns doesn't exist, but memory will
881 * be aligned on allocations of > pagesize. */
882 #if defined(SYSCONF_SC_PAGESIZE)
883 size_t pagesize
= (size_t)sysconf(_SC_PAGESIZE
);
884 #elif defined(HAVE_GETPAGESIZE)
885 size_t pagesize
= (size_t)getpagesize();
887 size_t pagesize
= (size_t)-1;
889 if (pagesize
== (size_t)-1) {
893 if (size
< pagesize
) {
901 #ifndef HAVE_GETPEEREID
902 int rep_getpeereid(int s
, uid_t
*uid
, gid_t
*gid
)
904 #if defined(HAVE_PEERCRED)
906 socklen_t cred_len
= sizeof(struct ucred
);
910 ret
= getsockopt(s
, SOL_SOCKET
, SO_PEERCRED
, (void *)&cred
, &cred_len
);
915 if (cred_len
!= sizeof(struct ucred
)) {
931 int rep_usleep(useconds_t sec
)
935 * Fake it with select...
938 tval
.tv_usec
= usecs
/1000;
939 select(0,NULL
,NULL
,NULL
,&tval
);
942 #endif /* HAVE_USLEEP */
944 #ifndef HAVE_SETPROCTITLE
945 void rep_setproctitle(const char *fmt
, ...)
949 #ifndef HAVE_SETPROCTITLE_INIT
950 void rep_setproctitle_init(int argc
, char *argv
[], char *envp
[])
955 #ifndef HAVE_MEMSET_S
957 # define RSIZE_MAX (SIZE_MAX >> 1)
960 int rep_memset_s(void *dest
, size_t destsz
, int ch
, size_t count
)
966 if (destsz
> RSIZE_MAX
||
972 #if defined(HAVE_MEMSET_EXPLICIT)
973 memset_explicit(dest
, destsz
, ch
, count
);
974 #else /* HAVE_MEMSET_EXPLICIT */
975 memset(dest
, ch
, count
);
976 # if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
977 /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */
978 __asm__
volatile("" : : "g"(dest
) : "memory");
979 # endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
980 #endif /* HAVE_MEMSET_EXPLICIT */
984 #endif /* HAVE_MEMSET_S */
986 #ifndef HAVE_GETPROGNAME
987 # ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
988 # define PROGNAME_SIZE 32
989 static char rep_progname
[PROGNAME_SIZE
];
990 # endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
992 const char *rep_getprogname(void)
994 #ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME
995 return program_invocation_short_name
;
996 #else /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
998 char cmdline
[4096] = {0};
1005 if (rep_progname
[0] != '\0') {
1006 return rep_progname
;
1009 len
= snprintf(rep_progname
, sizeof(rep_progname
), "%s", "<unknown>");
1015 if (pid
<= 1 || pid
== (pid_t
)-1) {
1019 len
= snprintf(cmdline
,
1023 if (len
<= 0 || len
== sizeof(cmdline
)) {
1027 fp
= fopen(cmdline
, "r");
1032 nread
= fread(cmdline
, 1, sizeof(cmdline
) - 1, fp
);
1043 cmdline
[nread
] = '\0';
1045 p
= strrchr(cmdline
, '/');
1053 if (len
> PROGNAME_SIZE
) {
1054 p
[PROGNAME_SIZE
- 1] = '\0';
1057 (void)snprintf(rep_progname
, sizeof(rep_progname
), "%s", p
);
1059 return rep_progname
;
1060 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
1062 #endif /* HAVE_GETPROGNAME */
1064 #ifndef HAVE_COPY_FILE_RANGE
1065 ssize_t
rep_copy_file_range(int fd_in
,
1072 # ifdef HAVE_SYSCALL_COPY_FILE_RANGE
1073 return syscall(__NR_copy_file_range
,
1080 # endif /* HAVE_SYSCALL_COPY_FILE_RANGE */
1084 #endif /* HAVE_COPY_FILE_RANGE */
1086 #ifndef HAVE_OPENAT2
1088 /* fallback known wellknown __NR_openat2 values */
1089 #ifndef __NR_openat2
1090 # if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H)
1091 # if defined(__i386__)
1092 # define __NR_openat2 437
1093 # elif defined(__x86_64__) && defined(__LP64__)
1094 # define __NR_openat2 437 /* 437 0x1B5 */
1095 # elif defined(__x86_64__) && defined(__ILP32__)
1096 # define __NR_openat2 1073742261 /* 1073742261 0x400001B5 */
1097 # elif defined(__aarch64__)
1098 # define __NR_openat2 437
1099 # elif defined(__arm__)
1100 # define __NR_openat2 437
1101 # elif defined(__sparc__)
1102 # define __NR_openat2 437
1104 # endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */
1105 #endif /* !__NR_openat2 */
1107 #ifdef DISABLE_OPATH
1109 * systems without O_PATH also don't have openat2,
1110 * so make sure we at a realistic combination.
1113 #endif /* DISABLE_OPATH */
1115 long rep_openat2(int dirfd
, const char *pathname
,
1116 struct open_how
*how
, size_t size
)
1119 return syscall(__NR_openat2
,
1129 #endif /* !HAVE_OPENAT2 */