tidying
[users/heiko/exim.git] / src / src / os.c
index ff4d94940ef84b39811ad2ace5f0905c9cf17a3b..6eadc38b15833d3223629fea92ba9e4663a9b3f5 100644 (file)
@@ -1,16 +1,19 @@
-/* $Cambridge: exim/src/src/os.c,v 1.4 2005/12/01 14:21:25 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 #ifdef STAND_ALONE
 /* See the file NOTICE for conditions of use and distribution. */
 
 #ifdef STAND_ALONE
-#include <signal.h>
-#include <stdio.h>
-#include <time.h>
+# include <signal.h>
+# include <stdio.h>
+# include <time.h>
+#endif
+
+#ifndef CS
+# define CS (char *)
+# define US (unsigned char *)
 #endif
 
 /* This source file contains "default" system-dependent functions which
 #endif
 
 /* This source file contains "default" system-dependent functions which
@@ -167,8 +170,8 @@ that have nothing. It provides a basic translation for the common standard
 signal numbers. I've been extra cautious with the ifdef's here. Probably more
 than is necessary... */
 
 signal numbers. I've been extra cautious with the ifdef's here. Probably more
 than is necessary... */
 
-char *
-os_strsignal(int n)
+const char *
+os_strsignal(const int n)
 {
 switch (n)
   {
 {
 switch (n)
   {
@@ -284,8 +287,8 @@ switch (n)
 exit codes into text, but this function is implemented this way so that if any
 OS does have such a thing, it could be used instead of this build-in one. */
 
 exit codes into text, but this function is implemented this way so that if any
 OS does have such a thing, it could be used instead of this build-in one. */
 
-char *
-os_strexit(int n)
+const char *
+os_strexit(const int n)
 {
 switch (n)
   {
 {
 switch (n)
   {
@@ -415,7 +418,7 @@ if (avg_kd < 0)
   }
 
 if (lseek (avg_kd, avg_offset, 0) == -1L
   }
 
 if (lseek (avg_kd, avg_offset, 0) == -1L
-    || read (avg_kd, (char *)(&avg), sizeof (avg)) != sizeof(avg))
+    || read (avg_kd, CS (&avg), sizeof (avg)) != sizeof(avg))
   return -1;
 
 return (int)(((double)avg/FSCALE)*1000.0);
   return -1;
 
 return (int)(((double)avg/FSCALE)*1000.0);
@@ -463,6 +466,75 @@ calls the common function; on Linux it calls the Linux function.
 This function finds the addresses of all the running interfaces on the machine.
 A chain of blocks containing the textual form of the addresses is returned.
 
 This function finds the addresses of all the running interfaces on the machine.
 A chain of blocks containing the textual form of the addresses is returned.
 
+getifaddrs() provides a sane consistent way to query this on modern OSs,
+otherwise fall back to a maze of twisty ioctl() calls
+
+Arguments:    none
+Returns:      a chain of ip_address_items, each pointing to a textual
+              version of an IP address, with the port field set to zero
+*/
+
+
+#ifndef NO_FIND_INTERFACES
+
+#ifdef HAVE_GETIFADDRS
+
+#include <ifaddrs.h>
+
+ip_address_item *
+os_common_find_running_interfaces(void)
+{
+struct ifaddrs *ifalist = NULL;
+ip_address_item *yield = NULL;
+ip_address_item *last = NULL;
+ip_address_item  *next;
+
+if (getifaddrs(&ifalist) != 0)
+  log_write(0, LOG_PANIC_DIE, "Unable to call getifaddrs: %d %s",
+    errno, strerror(errno));
+
+struct ifaddrs *ifa;
+for (ifa = ifalist; ifa != NULL; ifa = ifa->ifa_next)
+  {
+  if (ifa->ifa_addr->sa_family != AF_INET
+#if HAVE_IPV6
+    && ifa->ifa_addr->sa_family != AF_INET6
+#endif /* HAVE_IPV6 */
+    )
+    continue;
+
+  if ( !(ifa->ifa_flags & IFF_UP) ) /* Only want 'UP' interfaces */
+    continue;
+
+  /* Create a data block for the address, fill in the data, and put it on the
+  chain. */
+
+  next = store_get(sizeof(ip_address_item));
+  next->next = NULL;
+  next->port = 0;
+  (void)host_ntoa(-1, ifa->ifa_addr, next->address, NULL);
+
+  if (yield == NULL)
+    yield = last = next;
+  else
+    {
+    last->next = next;
+    last = next;
+    }
+
+  DEBUG(D_interface) debug_printf("Actual local interface address is %s (%s)\n",
+    last->address, ifa->ifa_name);
+  }
+
+/* free the list of addresses, and return the chain of data blocks. */
+
+freeifaddrs (ifalist);
+return yield;
+}
+
+#else /* HAVE_GETIFADDRS */
+
+/*
 Problems:
 
   (1) Solaris 2 has the SIOGIFNUM call to get the number of interfaces, but
 Problems:
 
   (1) Solaris 2 has the SIOGIFNUM call to get the number of interfaces, but
@@ -486,15 +558,8 @@ Problems:
   the former, calling the latter does no harm, but it causes grief on Linux and
   BSD systems in the case of IP aliasing, so a means of cutting it out is
   provided.
   the former, calling the latter does no harm, but it causes grief on Linux and
   BSD systems in the case of IP aliasing, so a means of cutting it out is
   provided.
-
-Arguments:    none
-Returns:      a chain of ip_address_items, each pointing to a textual
-              version of an IP address, with the port field set to zero
 */
 
 */
 
-
-#ifndef NO_FIND_INTERFACES
-
 /* If there is IPv6 support, and SIOCGLIFCONF is defined, define macros to
 use these new, longer versions of the old IPv4 interfaces. Otherwise, define
 the macros to use the historical versions. */
 /* If there is IPv6 support, and SIOCGLIFCONF is defined, define macros to
 use these new, longer versions of the old IPv4 interfaces. Otherwise, define
 the macros to use the historical versions. */
@@ -556,7 +621,7 @@ char *cp;
 char buf[MAX_INTERFACES*sizeof(struct V_ifreq)];
 struct sockaddr *addrp;
 size_t len = 0;
 char buf[MAX_INTERFACES*sizeof(struct V_ifreq)];
 struct sockaddr *addrp;
 size_t len = 0;
-char addrbuf[256];
+char addrbuf[512];
 
 /* We have to create a socket in order to do ioctls on it to find out
 what we want to know. */
 
 /* We have to create a socket in order to do ioctls on it to find out
 what we want to know. */
@@ -585,7 +650,7 @@ ifc.V_ifc_family = V_FAMILY_QUERY;
 ifc.V_ifc_flags = 0;
 #endif
 
 ifc.V_ifc_flags = 0;
 #endif
 
-if (ioctl(vs, V_GIFCONF, (char *)&ifc) < 0)
+if (ioctl(vs, V_GIFCONF, CS &ifc) < 0)
   log_write(0, LOG_PANIC_DIE, "Unable to get interface configuration: %d %s",
     errno, strerror(errno));
 
   log_write(0, LOG_PANIC_DIE, "Unable to get interface configuration: %d %s",
     errno, strerror(errno));
 
@@ -620,7 +685,7 @@ find its length, and then recopy the correct length. */
 
 for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   {
 
 for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   {
-  memcpy((char *)&ifreq, cp, sizeof(ifreq));
+  memcpy(CS &ifreq, cp, sizeof(ifreq));
 
   #ifndef HAVE_SA_LEN
   len = sizeof(struct V_ifreq);
 
   #ifndef HAVE_SA_LEN
   len = sizeof(struct V_ifreq);
@@ -650,7 +715,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   interface hasn't been "plumbed" to any protocol (IPv4 or IPv6). Therefore,
   we now just treat this case as "down" as well. */
 
   interface hasn't been "plumbed" to any protocol (IPv4 or IPv6). Therefore,
   we now just treat this case as "down" as well. */
 
-  if (ioctl(vs, V_GIFFLAGS, (char *)&ifreq) < 0)
+  if (ioctl(vs, V_GIFFLAGS, CS &ifreq) < 0)
     {
     continue;
     /*************
     {
     continue;
     /*************
@@ -666,7 +731,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   GIFFLAGS may have wrecked the data. */
 
   #ifndef SIOCGIFCONF_GIVES_ADDR
   GIFFLAGS may have wrecked the data. */
 
   #ifndef SIOCGIFCONF_GIVES_ADDR
-  if (ioctl(vs, V_GIFADDR, (char *)&ifreq) < 0)
+  if (ioctl(vs, V_GIFADDR, CS &ifreq) < 0)
     log_write(0, LOG_PANIC_DIE, "Unable to get IP address for %s interface: "
       "%d %s", ifreq.V_ifr_name, errno, strerror(errno));
   addrp = &ifreq.V_ifr_addr;
     log_write(0, LOG_PANIC_DIE, "Unable to get IP address for %s interface: "
       "%d %s", ifreq.V_ifr_name, errno, strerror(errno));
   addrp = &ifreq.V_ifr_addr;
@@ -701,6 +766,8 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
 return yield;
 }
 
 return yield;
 }
 
+#endif /* HAVE_GETIFADDRS */
+
 #else  /* NO_FIND_INTERFACES */
 
 /* Some experimental or developing OS (e.g. GNU/Hurd) do not have the ioctls,
 #else  /* NO_FIND_INTERFACES */
 
 /* Some experimental or developing OS (e.g. GNU/Hurd) do not have the ioctls,
@@ -733,6 +800,98 @@ return yield;
 
 
 
 
 
 
+/* ----------------------------------------------------------------------- */
+
+/***********************************************************
+*                 DNS Resolver Base Finder                 *
+***********************************************************/
+
+/* We need to be able to set options for the system resolver(5), historically
+made available as _res.  At least one OS (NetBSD) now no longer provides this
+directly, instead making you call a function per thread to get a handle.
+Other OSs handle thread-safe resolver differently, in ways which fail if the
+programmer creates their own structs. */
+
+#if !defined(OS_GET_DNS_RESOLVER_RES) && !defined(COMPILE_UTILITY)
+
+#include <resolv.h>
+
+/* confirmed that res_state is typedef'd as a struct* on BSD and Linux, will
+find out how unportable it is on other OSes, but most resolver implementations
+should be descended from ISC's bind.
+
+Linux and BSD do:
+  define _res (*__res_state())
+identically.  We just can't rely on __foo functions.  It's surprising that use
+of _res has been as portable as it has, for so long.
+
+So, since _res works everywhere, and everything can decode the struct, I'm
+going to gamble that res_state is a typedef everywhere and use that as the
+return type.
+*/
+
+res_state
+os_get_dns_resolver_res(void)
+{
+  return &_res;
+}
+
+#endif /* OS_GET_DNS_RESOLVER_RES */
+
+/* ----------------------------------------------------------------------- */
+
+/***********************************************************
+*                 unsetenv()                               *
+***********************************************************/
+
+/* Most modern systems define int unsetenv(const char*),
+* some don't. */
+
+#if !defined(OS_UNSETENV)
+int
+os_unsetenv(const unsigned char * name)
+{
+return unsetenv(CS name);
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+/***********************************************************
+*               getcwd()                                   *
+***********************************************************/
+
+/* Glibc allows getcwd(NULL, 0) to do auto-allocation. Some systems
+do auto-allocation, but need the size of the buffer, and others
+may not even do this. If the OS supports getcwd(NULL, 0) we'll use
+this, for all other systems we provide our own getcwd() */
+
+#if !defined(OS_GETCWD)
+unsigned char *
+os_getcwd(unsigned char * buffer, size_t size)
+{
+return US  getcwd(CS buffer, size);
+}
+#else
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+unsigned char *
+os_getcwd(unsigned char * buffer, size_t size)
+{
+char * b = CS buffer;
+
+if (!size) size = PATH_MAX;
+if (!b && !(b = malloc(size))) return NULL;
+if (!(b = getcwd(b, size))) return NULL;
+return buffer ? buffer : realloc(b, strlen(b) + 1);
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+
+
 
 /*************************************************
 **************************************************
 
 /*************************************************
 **************************************************