libreplace: replace inet_ntoa() when it is missing
[jelmer/samba4-debian.git] / source / lib / replace / replace.c
index ae70634215be54bf94285530cf0dec28886007fb..c16bded9633a825d229cf0cfd01db967ef576d1c 100644 (file)
@@ -2,39 +2,47 @@
    Unix SMB/CIFS implementation.
    replacement routines for broken systems
    Copyright (C) Andrew Tridgell 1992-1998
+
+     ** NOTE! The following LGPL license applies to the replace
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
    
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "system/wait.h"
+#include "replace.h"
+
+#include "system/filesys.h"
 #include "system/time.h"
+#include "system/passwd.h"
+#include "system/syslog.h"
 #include "system/network.h"
+#include "system/locale.h"
+#include "system/wait.h"
 
- void replace_dummy(void);
- void replace_dummy(void) {}
+void replace_dummy(void);
+void replace_dummy(void) {}
 
 #ifndef HAVE_FTRUNCATE
  /*******************************************************************
 ftruncate for operating systems that don't have it
 ********************************************************************/
- int ftruncate(int f,off_t l)
+int rep_ftruncate(int f, off_t l)
 {
 #ifdef HAVE_CHSIZE
       return chsize(f,l);
-#else
+#elif defined(F_FREESP)
       struct  flock   fl;
 
       fl.l_whence = 0;
@@ -42,6 +50,8 @@ ftruncate for operating systems that don't have it
       fl.l_start = l;
       fl.l_type = F_WRLCK;
       return fcntl(f, F_FREESP, &fl);
+#else
+#error "you must have a ftruncate function"
 #endif
 }
 #endif /* HAVE_FTRUNCATE */
@@ -50,7 +60,7 @@ ftruncate for operating systems that don't have it
 #ifndef HAVE_STRLCPY
 /* like strncpy but does not 0 fill the buffer and always null 
    terminates. bufsize is the size of the destination buffer */
- size_t strlcpy(char *d, const char *s, size_t bufsize)
+size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
 {
        size_t len = strlen(s);
        size_t ret = len;
@@ -66,7 +76,7 @@ ftruncate for operating systems that don't have it
 /* like strncat but does not 0 fill the buffer and always null 
    terminates. bufsize is the length of the buffer, which should
    be one more than the maximum resulting string length */
- size_t strlcat(char *d, const char *s, size_t bufsize)
+size_t rep_strlcat(char *d, const char *s, size_t bufsize)
 {
        size_t len1 = strlen(d);
        size_t len2 = strlen(s);
@@ -94,7 +104,7 @@ Corrections by richard.kettlewell@kewill.com
 #define  HOUR    60*MINUTE
 #define  DAY             24*HOUR
 #define  YEAR    365*DAY
- time_t mktime(struct tm *t)
+time_t rep_mktime(struct tm *t)
 {
   struct tm       *u;
   time_t  epoch = 0;
@@ -143,63 +153,22 @@ Corrections by richard.kettlewell@kewill.com
 #endif /* !HAVE_MKTIME */
 
 
-
-#ifndef HAVE_RENAME
-/* Rename a file. (from libiberty in GNU binutils)  */
- int rename(const char *zfrom, const char *zto)
-{
-  if (link (zfrom, zto) < 0)
-    {
-      if (errno != EEXIST)
-       return -1;
-      if (unlink (zto) < 0
-         || link (zfrom, zto) < 0)
-       return -1;
-    }
-  return unlink (zfrom);
-}
-#endif /* HAVE_RENAME */
-
-
-#ifndef HAVE_INNETGR
-#if defined(HAVE_SETNETGRENT) && defined(HAVE_GETNETGRENT) && defined(HAVE_ENDNETGRENT)
-/*
- * Search for a match in a netgroup. This replaces it on broken systems.
- */
- int innetgr(const char *group,const char *host,const char *user,const char *dom)
-{
-       char *hst, *usr, *dm;
-  
-       setnetgrent(group);
-       while (getnetgrent(&hst, &usr, &dm)) {
-               if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
-                   ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
-                   ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
-                       endnetgrent();
-                       return (1);
-               }
-       }
-       endnetgrent();
-       return (0);
-}
-#endif /* HAVE_SETNETGRENT HAVE_GETNETGRENT HAVE_ENDNETGRENT */
-#endif /* HAVE_INNETGR */
-
-
-
 #ifndef HAVE_INITGROUPS
 /****************************************************************************
  some systems don't have an initgroups call 
 ****************************************************************************/
- int initgroups(char *name, gid_t id)
+int rep_initgroups(char *name, gid_t id)
 {
 #ifndef HAVE_SETGROUPS
        /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
        errno = ENOSYS;
        return -1;
 #else /* HAVE_SETGROUPS */
+
+#include <grp.h>
+
        gid_t *grouplst = NULL;
-       int max_gr = groups_max();
+       int max_gr = 32;
        int ret;
        int    i,j;
        struct group *g;
@@ -240,7 +209,7 @@ Corrections by richard.kettlewell@kewill.com
 /* This is needed due to needing the nap() function but we don't want
    to include the Xenix libraries since that will break other things...
    BTW: system call # 0x0c28 is the same as calling nap() */
- long nap(long milliseconds) {
+long nap(long milliseconds) {
         return syscall(0x0c28, milliseconds);
  }
 #endif
@@ -249,11 +218,11 @@ Corrections by richard.kettlewell@kewill.com
 #ifndef HAVE_MEMMOVE
 /*******************************************************************
 safely copies memory, ensuring no overlap problems.
-this is only used if the machine does not have it's own memmove().
+this is only used if the machine does not have its own memmove().
 this is not the fastest algorithm in town, but it will do for our
 needs.
 ********************************************************************/
- void *memmove(void *dest,const void *src,int size)
+void *rep_memmove(void *dest,const void *src,int size)
 {
        unsigned long d,s;
        int i;
@@ -311,7 +280,7 @@ needs.
 /****************************************************************************
 duplicate a string
 ****************************************************************************/
- char *strdup(const char *s)
+char *rep_strdup(const char *s)
 {
        size_t len;
        char *ret;
@@ -326,30 +295,16 @@ duplicate a string
 }
 #endif /* HAVE_STRDUP */
 
-#ifndef WITH_PTHREADS
-/* REWRITE: not thread safe */
-#ifdef REPLACE_INET_NTOA
- char *rep_inet_ntoa(struct in_addr ip)
-{
-       uint8_t *p = (uint8_t *)&ip.s_addr;
-       static char buf[18];
-       slprintf(buf, 17, "%d.%d.%d.%d", 
-                (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
-       return buf;
-}
-#endif /* REPLACE_INET_NTOA */
-#endif
-
 #ifndef HAVE_SETLINEBUF
- int setlinebuf(FILE *stream)
+void rep_setlinebuf(FILE *stream)
 {
-       return setvbuf(stream, (char *)NULL, _IOLBF, 0);
+       setvbuf(stream, (char *)NULL, _IOLBF, 0);
 }
 #endif /* HAVE_SETLINEBUF */
 
 #ifndef HAVE_VSYSLOG
 #ifdef HAVE_SYSLOG
- void vsyslog (int facility_priority, char *format, va_list arglist)
+void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
 {
        char *msg = NULL;
        vasprintf(&msg, format, arglist);
@@ -361,102 +316,192 @@ duplicate a string
 #endif /* HAVE_SYSLOG */
 #endif /* HAVE_VSYSLOG */
 
-/*******************************************************************
-yield the difference between *A and *B, in seconds, ignoring leap seconds
-********************************************************************/
-static int tm_diff(struct tm *a, struct tm *b)
+#ifndef HAVE_STRNLEN
+/**
+ Some platforms don't have strnlen
+**/
+ size_t rep_strnlen(const char *s, size_t max)
 {
-       int ay = a->tm_year + (1900 - 1);
-       int by = b->tm_year + (1900 - 1);
-       int intervening_leap_days =
-               (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
-       int years = ay - by;
-       int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
-       int hours = 24*days + (a->tm_hour - b->tm_hour);
-       int minutes = 60*hours + (a->tm_min - b->tm_min);
-       int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
-
-       return seconds;
+        size_t len;
+  
+        for (len = 0; len < max; len++) {
+                if (s[len] == '\0') {
+                        break;
+                }
+        }
+        return len;  
 }
+#endif
+  
+#ifndef HAVE_STRNDUP
+/**
+ Some platforms don't have strndup.
+**/
+char *rep_strndup(const char *s, size_t n)
+{
+       char *ret;
+       
+       n = strnlen(s, n);
+       ret = malloc(n+1);
+       if (!ret)
+               return NULL;
+       memcpy(ret, s, n);
+       ret[n] = 0;
 
-/*******************************************************************
-  return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
-  ******************************************************************/
-int get_time_zone(time_t t)
+       return ret;
+}
+#endif
+
+#ifndef HAVE_WAITPID
+int rep_waitpid(pid_t pid,int *status,int options)
 {
-       struct tm *tm = gmtime(&t);
-       struct tm tm_utc;
-       if (!tm)
-               return 0;
-       tm_utc = *tm;
-       tm = localtime(&t);
-       if (!tm)
-               return 0;
-       return tm_diff(&tm_utc,tm);
+  return wait4(pid, status, options, NULL);
 }
+#endif
 
-#ifndef HAVE_TIMEGM
-/*
-  yes, I know this looks insane, but its really needed. The function in the 
-  Linux timegm() manpage does not work on solaris.
-*/
- time_t timegm(struct tm *tm) 
+#ifndef HAVE_SETEUID
+int rep_seteuid(uid_t euid)
 {
-       struct tm tm2, tm3;
-       time_t t;
+#ifdef HAVE_SETRESUID
+       return setresuid(-1, euid, -1);
+#else
+#  error "You need a seteuid function"
+#endif
+}
+#endif
 
-       tm2 = *tm;
+#ifndef HAVE_SETEGID
+int rep_setegid(gid_t egid)
+{
+#ifdef HAVE_SETRESGID
+       return setresgid(-1, egid, -1);
+#else
+#  error "You need a setegid function"
+#endif
+}
+#endif
 
-       t = mktime(&tm2);
-       tm3 = *localtime(&t);
-       tm2 = *tm;
-       tm2.tm_isdst = tm3.tm_isdst;
-       t = mktime(&tm2);
-       t -= get_time_zone(t);
+/*******************************************************************
+os/2 also doesn't have chroot
+********************************************************************/
+#ifndef HAVE_CHROOT
+int rep_chroot(const char *dname)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
 
-       return t;
+/*****************************************************************
+ Possibly replace mkstemp if it is broken.
+*****************************************************************/  
+
+#ifndef HAVE_SECURE_MKSTEMP
+int rep_mkstemp(char *template)
+{
+       /* have a reasonable go at emulating it. Hope that
+          the system mktemp() isn't completly hopeless */
+       char *p = mktemp(template);
+       if (!p)
+               return -1;
+       return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
 }
 #endif
 
-#ifndef HAVE_SETENV
- int setenv(const char *name, const char *value, int overwrite) 
+#ifndef HAVE_MKDTEMP
+char *rep_mkdtemp(char *template)
 {
-       char *p = NULL;
-       int ret = -1;
+       char *dname;
+       
+       if ((dname = mktemp(template))) {
+               if (mkdir(dname, 0700) >= 0) {
+                       return dname;
+               }
+       }
 
-       asprintf(&p, "%s=%s", name, value);
+       return NULL;
+}
+#endif
 
-       if (overwrite || getenv(name)) {
-               if (p) ret = putenv(p);
-       } else {
-               ret = 0;
-       }
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
 
-       return ret;     
+#ifndef HAVE_PREAD
+ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
+{
+       if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+               return -1;
+       }
+       return read(__fd, __buf, __nbytes);
 }
 #endif
 
+/*****************************************************************
+ Watch out: this is not thread safe.
+*****************************************************************/
 
-#ifndef HAVE_STRTOULL
- unsigned long long int strtoull(const char *str, char **endptr, int base)
+#ifndef HAVE_PWRITE
+ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
 {
-#ifdef HAVE_STRTOUQ
-       return strtouq(str, endptr, base);
-#elif defined(HAVE___STRTOULL) 
-       return __strtoull(str, endptr, base);
-#else
-# error "You need a strtoull function"
+       if (lseek(__fd, __offset, SEEK_SET) != __offset) {
+               return -1;
+       }
+       return write(__fd, __buf, __nbytes);
+}
+#endif
+
+#ifndef HAVE_STRCASESTR
+char *rep_strcasestr(const char *haystack, const char *needle)
+{
+       const char *s;
+       size_t nlen = strlen(needle);
+       for (s=haystack;*s;s++) {
+               if (toupper(*needle) == toupper(*s) &&
+                   strncasecmp(s, needle, nlen) == 0) {
+                       return (char *)((intptr_t)s);
+               }
+       }
+       return NULL;
+}
 #endif
+
+#ifndef HAVE_STRTOK_R
+/* based on GLIBC version, copyright Free Software Foundation */
+char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
+{
+       char *token;
+
+       if (s == NULL) s = *save_ptr;
+
+       s += strspn(s, delim);
+       if (*s == '\0') {
+               *save_ptr = s;
+               return NULL;
+       }
+
+       token = s;
+       s = strpbrk(token, delim);
+       if (s == NULL) {
+               *save_ptr = token + strlen(token);
+       } else {
+               *s = '\0';
+               *save_ptr = s + 1;
+       }
+
+       return token;
 }
 #endif
 
 #ifndef HAVE_STRTOLL
- long long int strtoll(const char *str, char **endptr, int base)
+long long int rep_strtoll(const char *str, char **endptr, int base)
 {
 #ifdef HAVE_STRTOQ
        return strtoq(str, endptr, base);
 #elif defined(HAVE___STRTOLL) 
        return __strtoll(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+       return (long long int) strtol(str, endptr, base);
 #else
 # error "You need a strtoll function"
 #endif
@@ -464,54 +509,101 @@ int get_time_zone(time_t t)
 #endif
 
 
-#ifndef HAVE_STRNDUP
-/**
- Some platforms don't have strndup.
-**/
- char *strndup(const char *s, size_t n)
+#ifndef HAVE_STRTOULL
+unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
 {
-       char *ret;
-       
-       n = strnlen(s, n);
-       ret = malloc(n+1);
-       if (!ret)
-               return NULL;
-       memcpy(ret, s, n);
-       ret[n] = 0;
-
-       return ret;
+#ifdef HAVE_STRTOUQ
+       return strtouq(str, endptr, base);
+#elif defined(HAVE___STRTOULL) 
+       return __strtoull(str, endptr, base);
+#elif SIZEOF_LONG == SIZEOF_LONG_LONG
+       return (unsigned long long int) strtoul(str, endptr, base);
+#else
+# error "You need a strtoull function"
+#endif
 }
 #endif
 
-#ifndef HAVE_STRNLEN
-/**
- Some platforms don't have strnlen
-**/
- size_t strnlen(const char *s, size_t n)
+#ifndef HAVE_SETENV
+int rep_setenv(const char *name, const char *value, int overwrite) 
 {
-       int i;
-       for (i=0; s[i] && i<n; i++)
-               /* noop */ ;
-       return i;
+       char *p;
+       size_t l1, l2;
+       int ret;
+
+       if (!overwrite && getenv(name)) {
+               return 0;
+       }
+
+       l1 = strlen(name);
+       l2 = strlen(value);
+
+       p = malloc(l1+l2+2);
+       if (p == NULL) {
+               return -1;
+       }
+       memcpy(p, name, l1);
+       p[l1] = '=';
+       memcpy(p+l1+1, value, l2);
+       p[l1+l2+1] = 0;
+
+       ret = putenv(p);
+       if (ret != 0) {
+               free(p);
+       }
+
+       return ret;
 }
 #endif
 
-int sys_waitpid(pid_t pid,int *status,int options)
+#ifndef HAVE_UNSETENV
+int rep_unsetenv(const char *name)
 {
-#ifdef HAVE_WAITPID
-  return waitpid(pid,status,options);
-#else /* USE_WAITPID */
-  return wait4(pid, status, options, NULL);
-#endif /* USE_WAITPID */
+       extern char **environ;
+       size_t len = strlen(name);
+       size_t i, count;
+
+       if (environ == NULL || getenv(name) == NULL) {
+               return 0;
+       }
+
+       for (i=0;environ[i];i++) /* noop */ ;
+
+       count=i;
+       
+       for (i=0;i<count;) {
+               if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
+                       /* note: we do _not_ free the old variable here. It is unsafe to 
+                          do so, as the pointer may not have come from malloc */
+                       memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
+                       count--;
+               } else {
+                       i++;
+               }
+       }
+
+       return 0;
 }
+#endif
 
-#ifndef HAVE_SETEUID
- int seteuid(uid_t euid)
+#ifndef HAVE_SOCKETPAIR
+int rep_socketpair(int d, int type, int protocol, int sv[2])
 {
-#ifdef HAVE_SETRESUID
-       return setresuid(-1, euid, -1);
-#else
-#  error "You need a seteuid function"
-#endif
+       if (d != AF_UNIX) {
+               errno = EAFNOSUPPORT;
+               return -1;
+       }
+
+       if (protocol != 0) {
+               errno = EPROTONOSUPPORT;
+               return -1;
+       }
+
+       if (type != SOCK_STREAM) {
+               errno = EOPNOTSUPP;
+               return -1;
+       }
+
+       return pipe(sv);
 }
 #endif