1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-11-19 19:45:15 +00:00
conky/src/net_stat.cc

583 lines
14 KiB
C++
Raw Normal View History

/* -*- mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
* vim: ts=4 sw=4 noet ai cindent syntax=cpp
*
* Conky, a system monitor, based on torsmo
*
* Any original torsmo code is licensed under the BSD license
*
* All code written since the fork of torsmo is licensed under the GPL
*
* Please see COPYING for details
*
* Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
2010-01-01 23:46:17 +00:00
* Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
* (see AUTHORS)
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "conky.h"
#include "logging.h"
#include "specials.h"
#include "net/if.h"
#include "text_object.h"
#include "net_stat.h"
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
/* network interface stuff */
2010-08-25 17:40:24 +00:00
enum if_up_strictness_ {
IFUP_UP,
IFUP_LINK,
IFUP_ADDR
};
template<>
conky::lua_traits<if_up_strictness_>::Map conky::lua_traits<if_up_strictness_>::map = {
{ "up", IFUP_UP },
{ "link", IFUP_LINK },
{ "address", IFUP_ADDR }
};
static conky::simple_config_setting<if_up_strictness_> if_up_strictness("if_up_strictness",
IFUP_UP, true);
struct net_stat netstats[MAX_NET_INTERFACES];
struct net_stat *get_net_stat(const char *dev, void *free_at_crash1, void *free_at_crash2)
{
unsigned int i;
if (!dev) {
return 0;
}
/* find interface stat */
for (i = 0; i < MAX_NET_INTERFACES; i++) {
if (netstats[i].dev && strcmp(netstats[i].dev, dev) == 0) {
return &netstats[i];
}
}
/* wasn't found? add it */
for (i = 0; i < MAX_NET_INTERFACES; i++) {
if (netstats[i].dev == 0) {
2010-08-29 21:50:32 +00:00
netstats[i].dev = strndup(dev, text_buffer_size.get(*state));
return &netstats[i];
}
}
CRIT_ERR(free_at_crash1, free_at_crash2, "too many interfaces used (limit is %d)", MAX_NET_INTERFACES);
return 0;
}
void parse_net_stat_arg(struct text_object *obj, const char *arg, void *free_at_crash)
{
2011-02-10 22:27:14 +00:00
bool shownetmask = false;
2011-02-11 12:05:00 +00:00
bool showscope = false;
2011-02-10 22:27:14 +00:00
char dev[21]; //a netdev can only be 20 chars long
int i=0;
if (!arg)
arg = DEFAULTNETDEV;
2011-02-10 22:27:14 +00:00
if (*arg == '-') { //there are flags
for(i=1; arg[i] != ' ' && arg[i] != 0; i++) {
if(arg[i]=='n') shownetmask = true;
2011-02-11 12:05:00 +00:00
if(arg[i]=='s') showscope = true;
2011-02-10 22:27:14 +00:00
}
}
sscanf(arg+i, "%20s", dev);
if(*dev==0) strcpy(dev, DEFAULTNETDEV);
struct net_stat *netstat = get_net_stat(dev, obj, free_at_crash);
2011-02-10 23:27:12 +00:00
#ifdef BUILD_IPV6
2011-02-10 22:27:14 +00:00
netstat->v6show_nm = shownetmask;
2011-02-11 12:05:00 +00:00
netstat->v6show_sc = showscope;
2011-02-10 23:27:12 +00:00
#endif /* BUILD_IPV6 */
2011-02-10 22:27:14 +00:00
obj->data.opaque = netstat;
}
void parse_net_stat_bar_arg(struct text_object *obj, const char *arg, void *free_at_crash)
{
if (arg) {
2009-12-04 00:13:36 +00:00
arg = scan_bar(obj, arg, 1);
obj->data.opaque = get_net_stat(arg, obj, free_at_crash);
} else {
// default to DEFAULTNETDEV
2010-08-29 21:50:32 +00:00
char *buf = strndup(DEFAULTNETDEV, text_buffer_size.get(*state));
obj->data.opaque = get_net_stat(buf, obj, free_at_crash);
free(buf);
}
}
void print_downspeed(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
human_readable(ns->recv_speed, p, p_max_size);
}
void print_downspeedf(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
spaced_print(p, p_max_size, "%.1f", 8, ns->recv_speed / 1024.0);
}
void print_upspeed(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
human_readable(ns->trans_speed, p, p_max_size);
}
void print_upspeedf(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
spaced_print(p, p_max_size, "%.1f", 8, ns->trans_speed / 1024.0);
}
void print_totaldown(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
human_readable(ns->recv, p, p_max_size);
}
void print_totalup(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
human_readable(ns->trans, p, p_max_size);
}
void print_addr(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
if ((ns->addr.sa_data[2] & 255) == 0 &&
(ns->addr.sa_data[3] & 255) == 0 &&
(ns->addr.sa_data[4] & 255) == 0 &&
(ns->addr.sa_data[5] & 255) == 0) {
snprintf(p, p_max_size, "No Address");
} else {
snprintf(p, p_max_size, "%u.%u.%u.%u",
ns->addr.sa_data[2] & 255,
ns->addr.sa_data[3] & 255,
ns->addr.sa_data[4] & 255,
ns->addr.sa_data[5] & 255);
}
}
#ifdef __linux__
void print_addrs(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
if (NULL != ns->addrs && strlen(ns->addrs) > 2) {
ns->addrs[strlen(ns->addrs) - 2] = 0; /* remove ", " from end of string */
strncpy(p, ns->addrs, p_max_size);
} else {
strncpy(p, "0.0.0.0", p_max_size);
}
}
#ifdef BUILD_IPV6
void print_v6addrs(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
char *current_char = p;
struct v6addr *current_v6 = ns->v6addrs;
if (!ns)
return;
if( ! ns->v6addrs) {
2011-02-11 12:05:00 +00:00
strncpy(p, "::", p_max_size);
if(ns->v6show_nm) strcat(p, "/128");
if(ns->v6show_sc) strcat(p, "(/)");
return;
}
while(current_v6) {
char extracompress = 0; //0 until the first '0000', 1 after the first '0000', 2 after the first non-'0000' after a '0000'
for(int i=0; i<8; i++) { //loop trough the 8 parts of the ipv6
//skip the zeros in front of each part
int j=0;
while(j<4) if(*(current_v6->addr+(i*4)+j) == '0') j++; else break;
if(j==4) {
if(*(current_v6->addr+(i*4)+3) == '0') { //4 zeros
switch(extracompress) {
case 0: //first time this happens, so replace by '::'
*current_char = ':';
current_char++;
if(current_char == p+1) { //to make sure there is no ':::' when the first '0000' isn't at the beginning
*current_char = ':';
current_char++;
}
extracompress=1;
continue;
case 1: //again, ignore them, they are included in the '::'
continue;
default: //again, but only remove the first 3 zero's because extra-compression may no longer be applied
j=3; //but if there are 4 zero's, keep the last
}
} else j=0; //no zeros to skip
}
if(extracompress == 1) extracompress = 2;
//place each part followed by : in the ip
strncpy(current_char, current_v6->addr+(i*4)+j, 4-j);
*(current_char+4-j)=':';
current_char+=5-j;
}
2011-02-10 22:27:14 +00:00
current_char--;
//netmask
if(ns->v6show_nm) {
char netmaskstr[5]; //max 5 chars (/128 + null-terminator)
sprintf(netmaskstr, "/%u", current_v6->netmask);
strcpy(current_char, netmaskstr);
current_char += strlen(netmaskstr);
}
2011-02-11 12:05:00 +00:00
//scope
if(ns->v6show_sc) {
sprintf(current_char, "(%c)", current_v6->scope);
current_char += 3;
}
2011-02-10 22:27:14 +00:00
//next (or last) address
current_v6 = current_v6->next;
if(current_v6) {
2011-02-10 22:27:14 +00:00
strcpy(current_char, ", ");
current_char+=2;
} else *current_char=0;
}
}
#endif /* BUILD_IPV6 */
#endif /* __linux__ */
#ifdef BUILD_X11
void parse_net_stat_graph_arg(struct text_object *obj, const char *arg, void *free_at_crash)
{
char *buf = 0;
buf = scan_graph(obj, arg, 0);
// default to DEFAULTNETDEV
if (buf) {
obj->data.opaque = get_net_stat(buf, obj, free_at_crash);
free(buf);
return;
}
obj->data.opaque = get_net_stat(DEFAULTNETDEV, obj, free_at_crash);
}
2009-12-04 00:53:53 +00:00
double downspeedgraphval(struct text_object *obj)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
2009-12-04 00:53:53 +00:00
return (ns ? (ns->recv_speed / 1024.0) : 0);
}
2009-12-04 00:53:53 +00:00
double upspeedgraphval(struct text_object *obj)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
2009-12-04 00:53:53 +00:00
return (ns ? (ns->trans_speed / 1024.0) : 0);
}
#endif /* BUILD_X11 */
#ifdef BUILD_WLAN
void print_wireless_essid(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns) {
for(unsigned int i = 0; *(netstats[i].dev) != 0; i++) {
if(*(netstats[i].essid) != 0) {
snprintf(p, p_max_size, "%s", netstats[i].essid);
return;
}
}
return;
}
snprintf(p, p_max_size, "%s", ns->essid);
}
void print_wireless_mode(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
snprintf(p, p_max_size, "%s", ns->mode);
}
void print_wireless_channel(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
if(ns->channel != 0) {
snprintf(p, p_max_size, "%i", ns->channel);
} else {
snprintf(p, p_max_size, "/");
}
}
2010-06-07 08:50:02 +00:00
void print_wireless_frequency(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
if(ns->freq[0] != 0) {
snprintf(p, p_max_size, "%s", ns->freq);
} else {
snprintf(p, p_max_size, "/");
}
}
void print_wireless_bitrate(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
snprintf(p, p_max_size, "%s", ns->bitrate);
}
void print_wireless_ap(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
snprintf(p, p_max_size, "%s", ns->ap);
}
void print_wireless_link_qual(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
spaced_print(p, p_max_size, "%d", 4, ns->link_qual);
}
void print_wireless_link_qual_max(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
spaced_print(p, p_max_size, "%d", 4, ns->link_qual_max);
}
void print_wireless_link_qual_perc(struct text_object *obj, char *p, int p_max_size)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return;
if (ns->link_qual_max > 0) {
spaced_print(p, p_max_size, "%.0f", 5,
(double) ns->link_qual /
ns->link_qual_max * 100);
} else {
spaced_print(p, p_max_size, "unk", 5);
}
}
2009-12-04 00:13:36 +00:00
double wireless_link_barval(struct text_object *obj)
{
struct net_stat *ns = (struct net_stat *)obj->data.opaque;
if (!ns)
return 0;
2009-12-04 00:13:36 +00:00
return (double)ns->link_qual / ns->link_qual_max;
}
#endif /* BUILD_WLAN */
void clear_net_stats(void)
{
#ifdef BUILD_IPV6
struct v6addr *nextv6;
#endif /* BUILD_IPV6 */
int i;
for (i = 0; i < MAX_NET_INTERFACES; i++) {
free_and_zero(netstats[i].dev);
#ifdef BUILD_IPV6
while(netstats[i].v6addrs) {
nextv6 = netstats[i].v6addrs;
netstats[i].v6addrs = netstats[i].v6addrs->next;
free_and_zero(nextv6);
}
#endif /* BUILD_IPV6 */
}
memset(netstats, 0, sizeof(netstats));
}
void parse_if_up_arg(struct text_object *obj, const char *arg)
{
2010-08-29 21:50:32 +00:00
obj->data.opaque = strndup(arg, text_buffer_size.get(*state));
}
void free_if_up(struct text_object *obj)
{
free_and_zero(obj->data.opaque);
}
/* We should check if this is ok with OpenBSD and NetBSD as well. */
int interface_up(struct text_object *obj)
{
int fd;
struct ifreq ifr;
char *dev = (char*)obj->data.opaque;
if (!dev)
return 0;
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
CRIT_ERR(NULL, NULL, "could not create sockfd");
return 0;
}
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
/* if device does not exist, treat like not up */
if (errno != ENODEV && errno != ENXIO)
perror("SIOCGIFFLAGS");
goto END_FALSE;
}
if (!(ifr.ifr_flags & IFF_UP)) /* iface is not up */
goto END_FALSE;
2010-08-25 17:40:24 +00:00
if (if_up_strictness.get(*state) == IFUP_UP)
goto END_TRUE;
if (!(ifr.ifr_flags & IFF_RUNNING))
goto END_FALSE;
2010-08-25 17:40:24 +00:00
if (if_up_strictness.get(*state) == IFUP_LINK)
goto END_TRUE;
if (ioctl(fd, SIOCGIFADDR, &ifr)) {
perror("SIOCGIFADDR");
goto END_FALSE;
}
if (((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr))->sin_addr.s_addr)
goto END_TRUE;
END_FALSE:
close(fd);
return 0;
END_TRUE:
close(fd);
return 1;
}
struct _dns_data {
_dns_data() : nscount(0), ns_list(0) {}
int nscount;
char **ns_list;
};
static _dns_data dns_data;
2009-11-29 19:55:42 +00:00
void free_dns_data(struct text_object *obj)
{
int i;
2009-11-29 19:55:42 +00:00
(void)obj;
for (i = 0; i < dns_data.nscount; i++)
free(dns_data.ns_list[i]);
if (dns_data.ns_list)
free(dns_data.ns_list);
memset(&dns_data, 0, sizeof(dns_data));
}
int update_dns_data(void)
{
FILE *fp;
char line[256];
//static double last_dns_update = 0.0;
/* maybe updating too often causes higher load because of /etc lying on a real FS
if (current_update_time - last_dns_update < 10.0)
return 0;
last_dns_update = current_update_time;
*/
2009-11-29 19:55:42 +00:00
free_dns_data(NULL);
if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
return 0;
while(!feof(fp)) {
if (fgets(line, 255, fp) == NULL) {
break;
}
if (!strncmp(line, "nameserver ", 11)) {
line[strlen(line) - 1] = '\0'; // remove trailing newline
dns_data.nscount++;
dns_data.ns_list = (char**)realloc(dns_data.ns_list, dns_data.nscount * sizeof(char *));
2010-08-29 21:50:32 +00:00
dns_data.ns_list[dns_data.nscount - 1] = strndup(line + 11, text_buffer_size.get(*state));
}
}
fclose(fp);
return 0;
}
void parse_nameserver_arg(struct text_object *obj, const char *arg)
{
obj->data.l = arg ? atoi(arg) : 0;
}
void print_nameserver(struct text_object *obj, char *p, int p_max_size)
{
if (dns_data.nscount > obj->data.l)
snprintf(p, p_max_size, "%s", dns_data.ns_list[obj->data.l]);
}