debian experimental exim-daemon-heavy config
[exim.git] / src / OS / os.c-Linux
CommitLineData
61ec970d
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1997 - 2018 */
61ec970d
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Linux-specific code. This is concatenated onto the generic
9src/os.c file. */
10
11
12/*************************************************
13* Load average computation *
14*************************************************/
15
16/*Linux has an apparently unique way of getting the load average, so we provide
17a unique function here, and define OS_LOAD_AVERAGE to stop src/os.c trying to
18provide the function. However, when compiling os.c for utilities, we may not
19want this at all, so check that it isn't set first. */
20
7e8bec7a 21#if !defined(OS_LOAD_AVERAGE) && defined(__linux__)
61ec970d
PH
22#define OS_LOAD_AVERAGE
23
24/* Linux has 2 ways of returning load average:
25
26 (1) Do a read on /proc/loadavg
27 (2) Use the sysinfo library function and syscall
28
29The latter is simpler but in Linux 2.0 - 2.2 (and probably later releases) is
30exceptionally slow - 10-50ms per call is not unusual and about 100x slow the
31first method. This cripples high performance mail servers by increasing CPU
32utilisation by 3-5x.
33
34In Exim's very early days, it used the 1st method. Later, it switched to the
352nd method. Now it tries the 1st method and falls back to the 2nd if /proc is
36unavailable. */
37
38#include <sys/sysinfo.h>
39
40static int
41linux_slow_getloadavg(void)
42{
43struct sysinfo s;
44double avg;
45if (sysinfo(&s) < 0) return -1;
46avg = (double) (s.loads[0]) / (1<<SI_LOAD_SHIFT);
47return (int)(avg * 1000.0);
48}
49
50int
51os_getloadavg(void)
52{
53char buffer[40];
54double avg;
55int count;
56int fd = open ("/proc/loadavg", O_RDONLY);
57if (fd == -1) return linux_slow_getloadavg();
58count = read (fd, buffer, sizeof(buffer));
59(void)close (fd);
60if (count <= 0) return linux_slow_getloadavg();
61count = sscanf (buffer, "%lf", &avg);
62if (count < 1) return linux_slow_getloadavg();
63return (int)(avg * 1000.0);
64}
65#endif /* OS_LOAD_AVERAGE */
66
67
68
69
70
71/*************************************************
72* Finding interface addresses *
73*************************************************/
74
75/* This function is not required for utilities; we cut it out if
76FIND_RUNNING_INTERFACES is already defined. */
77
78#ifndef FIND_RUNNING_INTERFACES
79
80/* This code, contributed by Jason Gunthorpe, appears to be the current
81way of finding IPv6 interfaces in Linux. It first calls the common function in
82order to find IPv4 interfaces, then grobbles around to find the others. Jason
83said, "This is so horrible, don't look. Slightly ripped from net-tools
84ifconfig." It gets called by virtue of os_find_running_interfaces being defined
85as a macro for os_find_running_interfaces_linux in the os.h-Linux file. */
86
87ip_address_item *
88os_find_running_interfaces_linux(void)
89{
90ip_address_item *yield = NULL;
91
92#if HAVE_IPV6
93ip_address_item *last = NULL;
94ip_address_item *next;
95char addr6p[8][5];
96unsigned int plen, scope, dad_status, if_idx;
c3680ef0 97char devname[20+1];
61ec970d
PH
98FILE *f;
99#endif
100
101yield = os_common_find_running_interfaces();
102
103#if HAVE_IPV6
104
105/* Open the /proc file; give up if we can't. */
106
107if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) return yield;
108
109/* Pick out the data from within the file, and add it on to the chain */
110
111last = yield;
112if (last != NULL) while (last->next != NULL) last = last->next;
113
114while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
7e8bec7a
PH
115 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
116 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
117 &if_idx, &plen, &scope, &dad_status, devname) != EOF)
61ec970d
PH
118 {
119 struct sockaddr_in6 addr;
120
121 /* This data has to survive for ever, so use malloc. */
122
123 next = store_malloc(sizeof(ip_address_item));
124 next->next = NULL;
125 next->port = 0;
126 sprintf(CS next->address, "%s:%s:%s:%s:%s:%s:%s:%s",
7e8bec7a
PH
127 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
128 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
61ec970d
PH
129
130 /* Normalize the representation */
131
132 inet_pton(AF_INET6, CS next->address, &addr.sin6_addr);
133 inet_ntop(AF_INET6, &addr.sin6_addr, CS next->address, sizeof(next->address));
134
135 if (yield == NULL) yield = last = next; else
136 {
137 last->next = next;
138 last = next;
139 }
140
141 DEBUG(D_interface)
142 debug_printf("Actual local interface address is %s (%s)\n", last->address,
143 devname);
144 }
145fclose(f);
146#endif /* HAVE_IPV6 */
147
148return yield;
149}
150
151#endif /* FIND_RUNNING_INTERFACES */
152
7d758a6a
JH
153
154/*************
155* Sendfile *
156*************/
157#include <sys/sendfile.h>
158
159ssize_t
160os_sendfile(int out, int in, off_t * off, size_t cnt)
161{
162return sendfile(out, in, off, cnt);
163}
164
61ec970d 165/* End of os.c-Linux */