File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bmon / src / in_sysfs.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:19:56 2012 UTC (12 years, 4 months ago) by misho
Branches: bmon, MAIN
CVS tags: v2_1_0p0, v2_1_0, HEAD
bmon

    1: /*
    2:  * in_sysfs.c           /sys input (Linux)
    3:  *
    4:  * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch>
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a
    7:  * copy of this software and associated documentation files (the "Software"),
    8:  * to deal in the Software without restriction, including without limitation
    9:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   10:  * and/or sell copies of the Software, and to permit persons to whom the
   11:  * Software is furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included
   14:  * in all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   17:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   21:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   22:  * DEALINGS IN THE SOFTWARE.
   23:  *
   24:  * TODO: Give cached FD's some timer to they can be closed if unused
   25:  */
   26: 
   27: #include <bmon/bmon.h>
   28: #include <bmon/input.h>
   29: #include <bmon/item.h>
   30: #include <bmon/node.h>
   31: #include <bmon/utils.h>
   32: #include <inttypes.h>
   33: 
   34: #if defined SYS_LINUX
   35: 
   36: #if HAVE_DIRENT_H
   37: # include <dirent.h>
   38: # define NAMLEN(dirent) strlen((dirent)->d_name)
   39: #else
   40: # define dirent direct
   41: # define NAMLEN(dirent) (dirent)->d_namlen
   42: # if HAVE_SYS_NDIR_H
   43: #  include <sys/ndir.h>
   44: # endif
   45: # if HAVE_SYS_DIR_H
   46: #  include <sys/dir.h>
   47: # endif
   48: # if HAVE_NDIR_H
   49: #  include <ndir.h>
   50: # endif
   51: #endif
   52: 
   53: static char * c_dir = "/sys";
   54: static int    c_cache = 1;
   55: 
   56: struct sysfs_fd_cache
   57: {
   58: 	char *filename;
   59: 	FILE *fd;
   60: 	struct sysfs_fd_cache *next;
   61: };
   62: 
   63: #define FD_HTSIZE 2048
   64: 
   65: struct sysfs_fd_cache * fd_ht[FD_HTSIZE];
   66: 
   67: static uint32_t hash(register const char *s)
   68: {
   69: #define ROTATE_RIGHT(x, n) (x = (x >> (n & 0x1f)) | (x << (32 - (n & 0x1f))))
   70: 
   71:     uint32_t ret = 0xcafebabe;
   72:     uint8_t  temp;
   73: 
   74:     do {
   75:         temp = *s++;
   76:         ret ^= temp ^ ((ret >> 8) & 0xff);
   77:         ROTATE_RIGHT(ret, ret);
   78:     } while(temp);
   79: 
   80: #undef ROTATE_RIGHT
   81: 
   82:     return ret % FD_HTSIZE;
   83: }
   84: 
   85: static struct sysfs_fd_cache * cache_get(const char *filename)
   86: {
   87: 	struct sysfs_fd_cache *f;
   88: 	uint32_t h = hash(filename);
   89: 
   90: 	for (f = fd_ht[h]; f; f = f->next)
   91: 		if (!strcmp(f->filename, filename))
   92: 			return f;
   93: 
   94: 	return NULL;
   95: }
   96: 
   97: static struct sysfs_fd_cache * cache_put(struct sysfs_fd_cache *f)
   98: {
   99: 	uint32_t h = hash(f->filename);
  100: 
  101: 	f->next = fd_ht[h];
  102: 	fd_ht[h] = f;
  103: 
  104: 	return f;
  105: }
  106: 
  107: static FILE * get_cached_fd(const char *filename)
  108: {
  109: 	struct sysfs_fd_cache *f = cache_get(filename);
  110: 
  111: 	if (NULL == f) {
  112: 		f = xcalloc(1, sizeof(*f));
  113: 		f->filename = strdup(filename);
  114: 		f->fd = fopen(filename, "r");
  115: 
  116: 		if (NULL == f->fd)
  117: 			quit("Cannot open file %s: %s\n", filename, strerror(errno));
  118: 
  119: 		return cache_put(f)->fd;
  120: 	}
  121: 
  122: 	fseek(f->fd, 0, SEEK_SET);
  123: 	return f->fd;
  124: }
  125: 
  126: static b_cnt_t read_int(const char *prefix, const char *file)
  127: {
  128: 	FILE *f;
  129: 	b_cnt_t r;
  130: 	char p[FILENAME_MAX];
  131: 
  132: 	snprintf(p, sizeof(p), "%s/%s", prefix, file);
  133: 
  134: 	if (c_cache)
  135: 		f = get_cached_fd(p);
  136: 	else {
  137: 		f = fopen(p, "r");
  138: 		if (NULL == f)
  139: 			quit("Cannot open file %s: %s\n", p, strerror(errno));
  140: 	}
  141: 			
  142: 
  143: 	if (fscanf(f, "%" SCNu64 "\n", &r) != 1)
  144: 		quit("fscanf failed: format error\n");
  145: 
  146: 	if (!c_cache)
  147: 		fclose(f);
  148: 
  149: 	return r;
  150: }
  151: 
  152: static void sysfs_read(void)
  153: {
  154: 	item_t *n;
  155: 	DIR *d;
  156: 	struct dirent *de;
  157: 	char topdir[FILENAME_MAX];
  158: 
  159: 	snprintf(topdir, sizeof(topdir), "%s/class/net", c_dir);
  160: 
  161: 	d = opendir(topdir);
  162: 
  163: 	if (!d)
  164: 		quit("Failed to open directory %s: %s\n", topdir, strerror(errno));
  165: 
  166: 	while ((de = readdir(d))) {
  167: 		if (de->d_type == DT_DIR && de->d_name[0] != '.') {
  168: 			char p[FILENAME_MAX];
  169: 
  170: 			snprintf(p, sizeof(p), "%s/%s/statistics",
  171: 				topdir, de->d_name);
  172: 
  173: 			n = lookup_item(get_local_node(), de->d_name, 0, 0);
  174: 
  175: 			if (NULL == n)
  176: 				continue;
  177: 
  178: 			n->i_major_attr = BYTES;
  179: 			n->i_minor_attr = PACKETS;
  180: 			
  181: 			update_attr(n, BYTES, read_int(p, "rx_bytes"),
  182: 				    read_int(p, "tx_bytes"), RX_PROVIDED|TX_PROVIDED);
  183: 			update_attr(n, PACKETS, read_int(p, "rx_packets"),
  184: 				    read_int(p, "tx_packets"), RX_PROVIDED|TX_PROVIDED);
  185: 			update_attr(n, ERRORS, read_int(p, "rx_errors"),
  186: 				read_int(p, "tx_errors"), RX_PROVIDED|TX_PROVIDED);
  187: 			update_attr(n, DROP, read_int(p, "rx_dropped"),
  188: 				read_int(p, "tx_dropped"), RX_PROVIDED|TX_PROVIDED);
  189: 			update_attr(n, FIFO, read_int(p, "rx_fifo_errors"),
  190: 				read_int(p, "tx_fifo_errors"), RX_PROVIDED|TX_PROVIDED);
  191: 			update_attr(n, FRAME, read_int(p, "rx_frame_errors"),
  192: 				0, RX_PROVIDED);
  193: 			update_attr(n, COMPRESSED, read_int(p, "rx_compressed"),
  194: 				read_int(p, "tx_compressed"), RX_PROVIDED|TX_PROVIDED);
  195: 			update_attr(n, MULTICAST, read_int(p, "multicast"),
  196: 				0, RX_PROVIDED);
  197: 			update_attr(n, COLLISIONS, 0,
  198: 				read_int(p, "collisions"), TX_PROVIDED);
  199: 			update_attr(n, CRC_ERRORS, read_int(p, "rx_crc_errors"),
  200: 				0, RX_PROVIDED);
  201: 			update_attr(n, LENGTH_ERRORS, read_int(p, "rx_length_errors"),
  202: 				0, RX_PROVIDED);
  203: 			update_attr(n, MISSED_ERRORS, read_int(p, "rx_missed_errors"),
  204: 				0, RX_PROVIDED);
  205: 			update_attr(n, OVER_ERRORS, read_int(p, "rx_over_errors"),
  206: 				0, RX_PROVIDED);
  207: 			update_attr(n, ABORTED_ERRORS, 0,
  208: 				read_int(p, "tx_aborted_errors"), TX_PROVIDED);
  209: 			update_attr(n, CARRIER_ERRORS, 0,
  210: 				read_int(p, "tx_carrier_errors"), TX_PROVIDED);
  211: 			update_attr(n, HEARTBEAT_ERRORS, 0,
  212: 				read_int(p, "tx_heartbeat_errors"), TX_PROVIDED);
  213: 			update_attr(n, WINDOW_ERRORS, 0,
  214: 				read_int(p, "tx_window_errors"), TX_PROVIDED);
  215: 
  216: 			notify_update(n, NULL);
  217: 			increase_lifetime(n, 1);
  218: 		}
  219: 	}
  220: 
  221: 	closedir(d);
  222: }
  223: 
  224: static void print_help(void)
  225: {
  226: 	printf(
  227: 	"sysfs - sysfs statistic collector for Linux" \
  228: 	"\n" \
  229: 	"  Reads statistics from sysfs (/sys/class/net). File descriptors are\n" \
  230: 	"  cached and not closed to minimize I/O operations. This might cause\n" \
  231: 	"  problems due to the huge amount of open file descriptors.\n" \
  232: 	"  Author: Thomas Graf <tgraf@suug.ch>\n" \
  233: 	"\n" \
  234: 	"  Options:\n" \
  235: 	"    dir=DIR        Sysfs directory (default: /sys)\n" \
  236: 	"    nocache        Don't cache file descriptors.\n");
  237: }
  238: 
  239: static void sysfs_set_opts(tv_t *attrs)
  240: {
  241: 	while (attrs) {
  242: 		if (!strcasecmp(attrs->type, "dir") && attrs->value)
  243: 			c_dir = attrs->value;
  244: 		else if (!strcasecmp(attrs->type, "nocache"))
  245: 			c_cache = 0;
  246: 		else if (!strcasecmp(attrs->type, "help")) {
  247: 			print_help();
  248: 			exit(0);
  249: 		}
  250: 		attrs = attrs->next;
  251: 	}
  252: }
  253: 
  254: static int sysfs_probe(void)
  255: {
  256: 	DIR *d;
  257: 	char topdir[FILENAME_MAX];
  258: 
  259: 	snprintf(topdir, sizeof(topdir), "%s/class/net", c_dir);
  260: 	d = opendir(topdir);
  261: 
  262: 	if (d) {
  263: 		closedir(d);
  264: 		return 1;
  265: 	}
  266: 	return 0;
  267: }
  268: 
  269: static struct input_module sysfs_ops = {
  270: 	.im_name = "sysfs",
  271: 	.im_read = sysfs_read,
  272: 	.im_set_opts = sysfs_set_opts,
  273: 	.im_probe = sysfs_probe,
  274: };
  275: 
  276: static void __init proc_init(void)
  277: {
  278: 	register_input_module(&sysfs_ops);
  279: }
  280: 
  281: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>