fix compiling for freebsd
[monky] / src / net_stat.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  * vim: ts=4 sw=4 noet ai cindent syntax=c
3  *
4  * Conky, a system monitor, based on torsmo
5  *
6  * Any original torsmo code is licensed under the BSD license
7  *
8  * All code written since the fork of torsmo is licensed under the GPL
9  *
10  * Please see COPYING for details
11  *
12  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
13  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14  *      (see AUTHORS)
15  * All rights reserved.
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * You should have received a copy of the GNU General Public License
27  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28  *
29  */
30
31 #include "config.h"
32 #include "conky.h"
33 #include "logging.h"
34 #include "specials.h"
35 #include "net/if.h"
36 #include "text_object.h"
37 #include "net_stat.h"
38 #include <netinet/in.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <sys/ioctl.h>
42 #include <unistd.h>
43
44 /* network interface stuff */
45
46 struct net_stat netstats[MAX_NET_INTERFACES];
47
48 struct net_stat *get_net_stat(const char *dev, void *free_at_crash1, void *free_at_crash2)
49 {
50         unsigned int i;
51
52         if (!dev) {
53                 return 0;
54         }
55
56         /* find interface stat */
57         for (i = 0; i < MAX_NET_INTERFACES; i++) {
58                 if (netstats[i].dev && strcmp(netstats[i].dev, dev) == 0) {
59                         return &netstats[i];
60                 }
61         }
62
63         /* wasn't found? add it */
64         for (i = 0; i < MAX_NET_INTERFACES; i++) {
65                 if (netstats[i].dev == 0) {
66                         netstats[i].dev = strndup(dev, text_buffer_size);
67                         return &netstats[i];
68                 }
69         }
70
71         CRIT_ERR(free_at_crash1, free_at_crash2, "too many interfaces used (limit is %d)", MAX_NET_INTERFACES);
72         return 0;
73 }
74
75 void parse_net_stat_arg(struct text_object *obj, const char *arg, void *free_at_crash)
76 {
77         if (!arg)
78                 arg = DEFAULTNETDEV;
79
80         obj->data.opaque = get_net_stat(arg, obj, free_at_crash);
81 }
82
83 void parse_net_stat_bar_arg(struct text_object *obj, const char *arg, void *free_at_crash)
84 {
85         if (arg) {
86                 arg = scan_bar(obj, arg);
87                 obj->data.opaque = get_net_stat(arg, obj, free_at_crash);
88         } else {
89                 // default to DEFAULTNETDEV
90                 char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
91                 obj->data.opaque = get_net_stat(buf, obj, free_at_crash);
92                 free(buf);
93         }
94 }
95
96 void print_downspeed(struct text_object *obj, char *p, int p_max_size)
97 {
98         struct net_stat *ns = obj->data.opaque;
99
100         if (!ns)
101                 return;
102
103         human_readable(ns->recv_speed, p, p_max_size);
104 }
105
106 void print_downspeedf(struct text_object *obj, char *p, int p_max_size)
107 {
108         struct net_stat *ns = obj->data.opaque;
109
110         if (!ns)
111                 return;
112
113         spaced_print(p, p_max_size, "%.1f", 8, ns->recv_speed / 1024.0);
114 }
115
116 void print_upspeed(struct text_object *obj, char *p, int p_max_size)
117 {
118         struct net_stat *ns = obj->data.opaque;
119
120         if (!ns)
121                 return;
122
123         human_readable(ns->trans_speed, p, p_max_size);
124 }
125
126 void print_upspeedf(struct text_object *obj, char *p, int p_max_size)
127 {
128         struct net_stat *ns = obj->data.opaque;
129
130         if (!ns)
131                 return;
132
133         spaced_print(p, p_max_size, "%.1f", 8, ns->trans_speed / 1024.0);
134 }
135
136 void print_totaldown(struct text_object *obj, char *p, int p_max_size)
137 {
138         struct net_stat *ns = obj->data.opaque;
139
140         if (!ns)
141                 return;
142
143         human_readable(ns->recv, p, p_max_size);
144 }
145
146 void print_totalup(struct text_object *obj, char *p, int p_max_size)
147 {
148         struct net_stat *ns = obj->data.opaque;
149
150         if (!ns)
151                 return;
152
153         human_readable(ns->trans, p, p_max_size);
154 }
155
156 void print_addr(struct text_object *obj, char *p, int p_max_size)
157 {
158         struct net_stat *ns = obj->data.opaque;
159
160         if (!ns)
161                 return;
162
163         if ((ns->addr.sa_data[2] & 255) == 0 &&
164             (ns->addr.sa_data[3] & 255) == 0 &&
165             (ns->addr.sa_data[4] & 255) == 0 &&
166             (ns->addr.sa_data[5] & 255) == 0) {
167                 snprintf(p, p_max_size, "No Address");
168         } else {
169                 snprintf(p, p_max_size, "%u.%u.%u.%u",
170                          ns->addr.sa_data[2] & 255,
171                          ns->addr.sa_data[3] & 255,
172                          ns->addr.sa_data[4] & 255,
173                          ns->addr.sa_data[5] & 255);
174         }
175 }
176
177 #ifdef __linux__
178 void print_addrs(struct text_object *obj, char *p, int p_max_size)
179 {
180         struct net_stat *ns = obj->data.opaque;
181
182         if (!ns)
183                 return;
184
185         if (NULL != ns->addrs && strlen(ns->addrs) > 2) {
186                 ns->addrs[strlen(ns->addrs) - 2] = 0; /* remove ", " from end of string */
187                 strncpy(p, ns->addrs, p_max_size);
188         } else {
189                 strncpy(p, "0.0.0.0", p_max_size);
190         }
191 }
192 #endif /* __linux__ */
193
194 #ifdef X11
195 void parse_net_stat_graph_arg(struct text_object *obj, const char *arg, void *free_at_crash)
196 {
197         char *buf = 0;
198         buf = scan_graph(obj, arg, 0);
199
200         // default to DEFAULTNETDEV
201         if (buf) {
202                 obj->data.opaque = get_net_stat(buf, obj, free_at_crash);
203                 free(buf);
204                 return;
205         }
206         obj->data.opaque = get_net_stat(DEFAULTNETDEV, obj, free_at_crash);
207 }
208
209 void print_downspeedgraph(struct text_object *obj, char *p)
210 {
211         struct net_stat *ns = obj->data.opaque;
212
213         if (!ns)
214                 return;
215
216         new_graph(obj, p, ns->recv_speed / 1024.0);
217 }
218
219 void print_upspeedgraph(struct text_object *obj, char *p)
220 {
221         struct net_stat *ns = obj->data.opaque;
222
223         if (!ns)
224                 return;
225
226         new_graph(obj, p, ns->trans_speed / 1024.0);
227 }
228 #endif /* X11 */
229
230 #ifdef __linux__
231 #ifdef HAVE_IWLIB
232 void print_wireless_essid(struct text_object *obj, char *p, int p_max_size)
233 {
234         struct net_stat *ns = obj->data.opaque;
235
236         if (!ns)
237                 return;
238
239         snprintf(p, p_max_size, "%s", ns->essid);
240 }
241 void print_wireless_mode(struct text_object *obj, char *p, int p_max_size)
242 {
243         struct net_stat *ns = obj->data.opaque;
244
245         if (!ns)
246                 return;
247
248         snprintf(p, p_max_size, "%s", ns->mode);
249 }
250 void print_wireless_bitrate(struct text_object *obj, char *p, int p_max_size)
251 {
252         struct net_stat *ns = obj->data.opaque;
253
254         if (!ns)
255                 return;
256
257         snprintf(p, p_max_size, "%s", ns->bitrate);
258 }
259 void print_wireless_ap(struct text_object *obj, char *p, int p_max_size)
260 {
261         struct net_stat *ns = obj->data.opaque;
262
263         if (!ns)
264                 return;
265
266         snprintf(p, p_max_size, "%s", ns->ap);
267 }
268 void print_wireless_link_qual(struct text_object *obj, char *p, int p_max_size)
269 {
270         struct net_stat *ns = obj->data.opaque;
271
272         if (!ns)
273                 return;
274
275         spaced_print(p, p_max_size, "%d", 4, ns->link_qual);
276 }
277 void print_wireless_link_qual_max(struct text_object *obj, char *p, int p_max_size)
278 {
279         struct net_stat *ns = obj->data.opaque;
280
281         if (!ns)
282                 return;
283
284         spaced_print(p, p_max_size, "%d", 4, ns->link_qual_max);
285 }
286 void print_wireless_link_qual_perc(struct text_object *obj, char *p, int p_max_size)
287 {
288         struct net_stat *ns = obj->data.opaque;
289
290         if (!ns)
291                 return;
292
293         if (ns->link_qual_max > 0) {
294                 spaced_print(p, p_max_size, "%.0f", 5,
295                                 (double) ns->link_qual /
296                                 ns->link_qual_max * 100);
297         } else {
298                 spaced_print(p, p_max_size, "unk", 5);
299         }
300 }
301 void print_wireless_link_bar(struct text_object *obj, char *p, int p_max_size)
302 {
303         struct net_stat *ns = obj->data.opaque;
304
305         if (!ns)
306                 return;
307
308 #ifdef X11
309         if(output_methods & TO_X) {
310                 new_bar(obj, p, ((double) ns->link_qual /
311                                         ns->link_qual_max) * 255.0);
312         } else
313 #endif /* X11 */
314                 new_bar_in_shell(obj, p, p_max_size, ((double) ns->link_qual /
315                                         ns->link_qual_max) * 100.0);
316 }
317 #endif /* HAVE_IWLIB */
318 #endif /* __linux__ */
319
320 void clear_net_stats(void)
321 {
322         int i;
323         for (i = 0; i < MAX_NET_INTERFACES; i++) {
324                 if (netstats[i].dev) {
325                         free(netstats[i].dev);
326                 }
327         }
328         memset(netstats, 0, sizeof(netstats));
329 }
330
331 void parse_if_up_arg(struct text_object *obj, const char *arg)
332 {
333         obj->data.opaque = strndup(arg, text_buffer_size);
334 }
335
336 void free_if_up(struct text_object *obj)
337 {
338         if (obj->data.opaque) {
339                 free(obj->data.opaque);
340                 obj->data.opaque = NULL;
341         }
342 }
343
344 /* We should check if this is ok with OpenBSD and NetBSD as well. */
345 int interface_up(struct text_object *obj)
346 {
347         int fd;
348         struct ifreq ifr;
349         char *dev = obj->data.opaque;
350
351         if (!dev)
352                 return 0;
353
354         if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
355                 CRIT_ERR(NULL, NULL, "could not create sockfd");
356                 return 0;
357         }
358         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
359         if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
360                 /* if device does not exist, treat like not up */
361                 if (errno != ENODEV && errno != ENXIO)
362                         perror("SIOCGIFFLAGS");
363                 goto END_FALSE;
364         }
365
366         if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
367                 goto END_FALSE;
368         if (ifup_strictness == IFUP_UP)
369                 goto END_TRUE;
370
371         if (!(ifr.ifr_flags & IFF_RUNNING))
372                 goto END_FALSE;
373         if (ifup_strictness == IFUP_LINK)
374                 goto END_TRUE;
375
376         if (ioctl(fd, SIOCGIFADDR, &ifr)) {
377                 perror("SIOCGIFADDR");
378                 goto END_FALSE;
379         }
380         if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
381                 goto END_TRUE;
382
383 END_FALSE:
384         close(fd);
385         return 0;
386 END_TRUE:
387         close(fd);
388         return 1;
389 }
390
391 static struct {
392         int nscount;
393         char **ns_list;
394 } dns_data = {
395         .nscount = 0,
396         .ns_list = NULL,
397 };
398
399 void free_dns_data(void)
400 {
401         int i;
402         for (i = 0; i < dns_data.nscount; i++)
403                 free(dns_data.ns_list[i]);
404         if (dns_data.ns_list)
405                 free(dns_data.ns_list);
406         memset(&dns_data, 0, sizeof(dns_data));
407 }
408
409 void update_dns_data(void)
410 {
411         FILE *fp;
412         char line[256];
413         //static double last_dns_update = 0.0;
414
415         /* maybe updating too often causes higher load because of /etc lying on a real FS
416         if (current_update_time - last_dns_update < 10.0)
417                 return;
418
419         last_dns_update = current_update_time;
420         */
421
422         free_dns_data();
423
424         if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
425                 return;
426         while(!feof(fp)) {
427                 if (fgets(line, 255, fp) == NULL) {
428                         break;
429                 }
430                 if (!strncmp(line, "nameserver ", 11)) {
431                         line[strlen(line) - 1] = '\0';  // remove trailing newline
432                         dns_data.nscount++;
433                         dns_data.ns_list = realloc(dns_data.ns_list, dns_data.nscount * sizeof(char *));
434                         dns_data.ns_list[dns_data.nscount - 1] = strndup(line + 11, text_buffer_size);
435                 }
436         }
437         fclose(fp);
438 }
439
440 void parse_nameserver_arg(struct text_object *obj, const char *arg)
441 {
442         obj->data.l = arg ? atoi(arg) : 0;
443 }
444
445 void print_nameserver(struct text_object *obj, char *p, int p_max_size)
446 {
447         if (dns_data.nscount > obj->data.l)
448                 snprintf(p, p_max_size, "%s", dns_data.ns_list[obj->data.l]);
449 }