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