Annotation of embedaddon/bmon/src/in_sysfs.c, revision 1.1.1.1
1.1 misho 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>