diff options
Diffstat (limited to 'OS/os.c-Linux')
-rw-r--r-- | OS/os.c-Linux | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/OS/os.c-Linux b/OS/os.c-Linux new file mode 100644 index 0000000..59d81f8 --- /dev/null +++ b/OS/os.c-Linux @@ -0,0 +1,165 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) University of Cambridge 1997 - 2018 */ +/* See the file NOTICE for conditions of use and distribution. */ + +/* Linux-specific code. This is concatenated onto the generic +src/os.c file. */ + + +/************************************************* +* Load average computation * +*************************************************/ + +/*Linux has an apparently unique way of getting the load average, so we provide +a unique function here, and define OS_LOAD_AVERAGE to stop src/os.c trying to +provide the function. However, when compiling os.c for utilities, we may not +want this at all, so check that it isn't set first. */ + +#if !defined(OS_LOAD_AVERAGE) && defined(__linux__) +#define OS_LOAD_AVERAGE + +/* Linux has 2 ways of returning load average: + + (1) Do a read on /proc/loadavg + (2) Use the sysinfo library function and syscall + +The latter is simpler but in Linux 2.0 - 2.2 (and probably later releases) is +exceptionally slow - 10-50ms per call is not unusual and about 100x slow the +first method. This cripples high performance mail servers by increasing CPU +utilisation by 3-5x. + +In Exim's very early days, it used the 1st method. Later, it switched to the +2nd method. Now it tries the 1st method and falls back to the 2nd if /proc is +unavailable. */ + +#include <sys/sysinfo.h> + +static int +linux_slow_getloadavg(void) +{ +struct sysinfo s; +double avg; +if (sysinfo(&s) < 0) return -1; +avg = (double) (s.loads[0]) / (1<<SI_LOAD_SHIFT); +return (int)(avg * 1000.0); +} + +int +os_getloadavg(void) +{ +char buffer[40]; +double avg; +int count; +int fd = open ("/proc/loadavg", O_RDONLY); +if (fd == -1) return linux_slow_getloadavg(); +count = read (fd, buffer, sizeof(buffer)); +(void)close (fd); +if (count <= 0) return linux_slow_getloadavg(); +count = sscanf (buffer, "%lf", &avg); +if (count < 1) return linux_slow_getloadavg(); +return (int)(avg * 1000.0); +} +#endif /* OS_LOAD_AVERAGE */ + + + + + +/************************************************* +* Finding interface addresses * +*************************************************/ + +/* This function is not required for utilities; we cut it out if +FIND_RUNNING_INTERFACES is already defined. */ + +#ifndef FIND_RUNNING_INTERFACES + +/* This code, contributed by Jason Gunthorpe, appears to be the current +way of finding IPv6 interfaces in Linux. It first calls the common function in +order to find IPv4 interfaces, then grobbles around to find the others. Jason +said, "This is so horrible, don't look. Slightly ripped from net-tools +ifconfig." It gets called by virtue of os_find_running_interfaces being defined +as a macro for os_find_running_interfaces_linux in the os.h-Linux file. */ + +ip_address_item * +os_find_running_interfaces_linux(void) +{ +ip_address_item *yield = NULL; + +#if HAVE_IPV6 +ip_address_item *last = NULL; +ip_address_item *next; +char addr6p[8][5]; +unsigned int plen, scope, dad_status, if_idx; +char devname[20+1]; +FILE *f; +#endif + +yield = os_common_find_running_interfaces(); + +#if HAVE_IPV6 + +/* Open the /proc file; give up if we can't. */ + +if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) return yield; + +/* Pick out the data from within the file, and add it on to the chain */ + +last = yield; +if (last != NULL) while (last->next != NULL) last = last->next; + +while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7], + &if_idx, &plen, &scope, &dad_status, devname) != EOF) + { + struct sockaddr_in6 addr; + + /* This data has to survive for ever, so use malloc. */ + + next = store_malloc(sizeof(ip_address_item)); + next->next = NULL; + next->port = 0; + sprintf(CS next->address, "%s:%s:%s:%s:%s:%s:%s:%s", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7]); + + /* Normalize the representation */ + + inet_pton(AF_INET6, CS next->address, &addr.sin6_addr); + inet_ntop(AF_INET6, &addr.sin6_addr, CS next->address, sizeof(next->address)); + + 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, + devname); + } +fclose(f); +#endif /* HAVE_IPV6 */ + +return yield; +} + +#endif /* FIND_RUNNING_INTERFACES */ + + +/************* +* Sendfile * +*************/ +#include <sys/sendfile.h> + +ssize_t +os_sendfile(int out, int in, off_t * off, size_t cnt) +{ +return sendfile(out, in, off, cnt); +} + +/* End of os.c-Linux */ |