X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/214e2000de8e57b8fcfa7489f53c7aaf5dc77cdd..777e3beace88a39457ee4a856a094e16649f333f:/src/src/os.c diff --git a/src/src/os.c b/src/src/os.c index ff4d94940..6e88b844a 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -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 * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ #ifdef STAND_ALONE -#include -#include -#include +# include +# include +# include +#endif + +#ifndef CS +# define CS (char *) +# define US (unsigned char *) #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... */ -char * -os_strsignal(int n) +const char * +os_strsignal(const int 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. */ -char * -os_strexit(int n) +const char * +os_strexit(const int n) { switch (n) { @@ -415,7 +418,7 @@ if (avg_kd < 0) } 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); @@ -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. +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 + +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 @@ -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. - -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. */ @@ -556,7 +621,7 @@ char *cp; 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. */ @@ -585,7 +650,7 @@ ifc.V_ifc_family = V_FAMILY_QUERY; 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)); @@ -620,7 +685,7 @@ find its length, and then recopy the correct length. */ 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); @@ -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. */ - if (ioctl(vs, V_GIFFLAGS, (char *)&ifreq) < 0) + if (ioctl(vs, V_GIFFLAGS, CS &ifreq) < 0) { 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 - 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; @@ -701,6 +766,8 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len) return yield; } +#endif /* HAVE_GETIFADDRS */ + #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 + +/* 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 + +/* ----------------------------------------------------------------------- */ + + + /************************************************* **************************************************