X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/9acf6b941e1356590e94e8e4a0bcf5dd3318087c..0fef2df059417b3cc2cc555f65c6064b7dca5442:/src/src/os.c diff --git a/src/src/os.c b/src/src/os.c index 2b6f79c3f..87a336935 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -2,13 +2,22 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) The Exim Maintainers 2021 - 2022 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifdef STAND_ALONE -#include -#include -#include +# include +# include +# include +#else +# define DEBUG(x) if (debug_selector & (x)) +#endif + +#ifndef CS +# define CS (char *) +# define US (unsigned char *) #endif /* This source file contains "default" system-dependent functions which @@ -43,9 +52,9 @@ sigemptyset(&(act.sa_mask)); act.sa_flags = SA_RESTART; sigaction(sig, &act, NULL); -#ifdef STAND_ALONE +# ifdef STAND_ALONE printf("Used SA_RESTART\n"); -#endif +# endif /* SunOS4 and Ultrix default to non-interruptable signals, with SV_INTERRUPT for making them interruptable. This seems to be a dying fashion. */ @@ -53,9 +62,9 @@ for making them interruptable. This seems to be a dying fashion. */ #elif defined SV_INTERRUPT signal(sig, handler); -#ifdef STAND_ALONE +# ifdef STAND_ALONE printf("Used default signal()\n"); -#endif +# endif /* If neither SA_RESTART nor SV_INTERRUPT is available we don't know how to @@ -64,9 +73,9 @@ set up a restarting signal, so simply suppress the facility. */ #else signal(sig, SIG_IGN); -#ifdef STAND_ALONE +# ifdef STAND_ALONE printf("Used SIG_IGN\n"); -#endif +# endif #endif } @@ -354,9 +363,9 @@ here as there is the -hal variant, and other systems might follow this road one day. */ #if !defined(OS_LOAD_AVERAGE) && defined(HAVE_KSTAT) -#define OS_LOAD_AVERAGE +# define OS_LOAD_AVERAGE -#include +# include int os_getloadavg(void) @@ -390,7 +399,7 @@ return avg; #if !defined(OS_LOAD_AVERAGE) && defined(HAVE_DEV_KMEM) #define OS_LOAD_AVERAGE -#include +# include static int avg_kd = -1; static long avg_offset; @@ -413,7 +422,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); @@ -474,7 +483,7 @@ Returns: a chain of ip_address_items, each pointing to a textual #ifdef HAVE_GETIFADDRS -#include +# include ip_address_item * os_common_find_running_interfaces(void) @@ -488,12 +497,13 @@ 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) +for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != AF_INET + struct sockaddr * ifa_addr = ifa->ifa_addr; + if (!ifa_addr) continue; + if (ifa_addr->sa_family != AF_INET #if HAVE_IPV6 - && ifa->ifa_addr->sa_family != AF_INET6 + && ifa_addr->sa_family != AF_INET6 #endif /* HAVE_IPV6 */ ) continue; @@ -504,12 +514,12 @@ for (ifa = ifalist; ifa != NULL; ifa = ifa->ifa_next) /* 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 = store_get(sizeof(ip_address_item), GET_UNTAINTED); next->next = NULL; next->port = 0; - (void)host_ntoa(-1, ifa->ifa_addr, next->address, NULL); + (void)host_ntoa(-1, ifa_addr, next->address, NULL); - if (yield == NULL) + if (!yield) yield = last = next; else { @@ -612,7 +622,6 @@ int vs; ip_address_item *yield = NULL; ip_address_item *last = NULL; ip_address_item *next; -char *cp; char buf[MAX_INTERFACES*sizeof(struct V_ifreq)]; struct sockaddr *addrp; size_t len = 0; @@ -623,13 +632,13 @@ what we want to know. */ if ((vs = socket(FAMILY, SOCK_DGRAM, 0)) < 0) { - #if HAVE_IPV6 +#if HAVE_IPV6 DEBUG(D_interface) debug_printf("Unable to create IPv6 socket to find interface addresses:\n " "error %d %s\nTrying for an IPv4 socket\n", errno, strerror(errno)); vs = socket(AF_INET, SOCK_DGRAM, 0); if (vs < 0) - #endif +#endif log_write(0, LOG_PANIC_DIE, "Unable to create IPv4 socket to find interface " "addresses: %d %s", errno, strerror(errno)); } @@ -645,7 +654,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)); @@ -678,9 +687,9 @@ buffer is not guaranteed to be aligned. Thus, we must first copy the basic struct to some aligned memory before looking at the field in the fixed part to find its length, and then recopy the correct length. */ -for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len) +for (char * 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); @@ -710,7 +719,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; /************* @@ -726,7 +735,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; @@ -740,7 +749,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len) /* 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 = store_get(sizeof(ip_address_item), GET_UNTAINTED); next->next = NULL; next->port = 0; (void)host_ntoa(-1, addrp, next->address, NULL); @@ -772,13 +781,13 @@ interfaces. We just return the loopback address(es). */ ip_address_item * os_common_find_running_interfaces(void) { -ip_address_item *yield = store_get(sizeof(address_item)); +ip_address_item *yield = store_get(sizeof(address_item), GET_UNTAINTED); yield->address = US"127.0.0.1"; yield->port = 0; yield->next = NULL; #if HAVE_IPV6 -yield->next = store_get(sizeof(address_item)); +yield->next = store_get(sizeof(address_item), GET_UNTAINTED); yield->next->address = US"::1"; yield->next->port = 0; yield->next->next = NULL; @@ -809,7 +818,7 @@ programmer creates their own structs. */ #if !defined(OS_GET_DNS_RESOLVER_RES) && !defined(COMPILE_UTILITY) -#include +# 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 @@ -828,43 +837,59 @@ return type. res_state os_get_dns_resolver_res(void) { - return &_res; +return &_res; } #endif /* OS_GET_DNS_RESOLVER_RES */ - /* ----------------------------------------------------------------------- */ /*********************************************************** -* Time-related functions * +* unsetenv() * ***********************************************************/ -/* At least Solaris, and probably others, don't have this */ +/* Most modern systems define int unsetenv(const char*), +* some don't. */ -#ifndef _BSD_SOURCE +#if !defined(OS_UNSETENV) +int +os_unsetenv(const unsigned char * name) +{ +return unsetenv(CS name); +} +#endif -# include -# include +/* ----------------------------------------------------------------------- */ + +/*********************************************************** +* 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() */ -time_t -timegm(struct tm * tm) +#if !defined(OS_GETCWD) +unsigned char * +os_getcwd(unsigned char * buffer, size_t size) { -time_t ret; -char *tz; - -tz = getenv("TZ"); -setenv("TZ", "", 1); -tzset(); -ret = mktime(tm); -if (tz) - setenv("TZ", tz, 1); -else - unsetenv("TZ"); -tzset(); -return ret; +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 /* ----------------------------------------------------------------------- */ @@ -872,7 +897,6 @@ return ret; - /************************************************* ************************************************** * Stand-alone test program * @@ -902,7 +926,7 @@ int rc; printf("Testing restarting signal; wait for handler message, then type a line\n"); strcpy(buffer, "*** default ***\n"); os_restarting_signal(SIGALRM, sigalrm_handler); -alarm(2); +ALARM(2); if ((rc = read(fd, buffer, sizeof(buffer))) < 0) printf("No data read\n"); else @@ -910,12 +934,12 @@ else buffer[rc] = 0; printf("Read: %s", buffer); } -alarm(0); +ALARM_CLR(0); printf("Testing non-restarting signal; should read no data after handler message\n"); strcpy(buffer, "*** default ***\n"); os_non_restarting_signal(SIGALRM, sigalrm_handler); -alarm(2); +ALARM(2); if ((rc = read(fd, buffer, sizeof(buffer))) < 0) printf("No data read\n"); else @@ -923,7 +947,7 @@ else buffer[rc] = 0; printf("Read: %s", buffer); } -alarm(0); +ALARM_CLR(0); printf("Testing load averages (last test - ^C to kill)\n"); for (;;)