summaryrefslogtreecommitdiffstats
path: root/composer.json
blob: 1bcc263d5a028436de2260bcb10548b551da8c03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
    "type": "project",
    "license": "AGPL-3.0",
    "description": "An RSS/Atom feed reader. Requires Nextcloud backgroundjobs or an updater script to be enabled to update your feeds. See the README.md in the apps top directory",
    "homepage": "https://github.com/nextcloud/news",
    "authors": [
        {
            "name": "Bernhard Posselt",
            "email": "dev@bernhard-posselt.com",
            "homepage": "https://bernhard-posselt.com",
            "role": "Developer"
        },
        {
            "name": "Alessandro Cosentino",
            "homepage": "http://algorithmsforthekitchen.com/",
            "email": "cosenal@gmail.com",
            "role": "Developer"
        },
        {
            "name": "Jan-Christoph Borchardt",
            "email": "hey@jancborchardt.net",
            "homepage": "http://jancborchardt.net/",
            "role": "Designer"
        }
    ],
    "support": {
        "irc": "irc://irc.freenode.org/nextcloud-news",
        "issues": "https://github.com/nextcloud/news/issues",
        "source": "https://github.com/nextcloud/news/"
    },
    "require": {
        "ezyang/htmlpurifier": "4.7",
        "fguillot/picofeed": "0.1.25",
        "pear/net_url2": "2.2",
        "riimu/kit-pathjoin": "1.1.2"
    }
}
ground-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
// SPDX-License-Identifier: GPL-3.0-or-later

#include "plugin_proc.h"

struct edac_count {
    bool updated;
    char *filename;
    procfile *ff;
    kernel_uint_t count;
    RRDDIM *rd;
};

struct edac_dimm {
	char *name;

    struct edac_count ce;
    struct edac_count ue;

    RRDSET *st;

    struct edac_dimm *prev, *next;
};

struct mc {
    char *name;

    struct edac_count ce;
    struct edac_count ue;
    struct edac_count ce_noinfo;
    struct edac_count ue_noinfo;

    RRDSET *st;

    struct edac_dimm *dimms;

    struct mc *prev, *next;
};

static struct mc *mc_root = NULL;
static char *mc_dirname = NULL;

static void find_all_mc() {
    char name[FILENAME_MAX + 1];
    snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/edac/mc");
    mc_dirname = config_get("plugin:proc:/sys/devices/system/edac/mc", "directory to monitor", name);

    DIR *dir = opendir(mc_dirname);
    if(unlikely(!dir)) {
        collector_error("Cannot read EDAC memory errors directory '%s'", mc_dirname);
        return;
    }

    struct dirent *de = NULL;
    while((de = readdir(dir))) {
        if(de->d_type == DT_DIR && de->d_name[0] == 'm' && de->d_name[1] == 'c' && isdigit(de->d_name[2])) {
            struct mc *m = callocz(1, sizeof(struct mc));
            m->name = strdupz(de->d_name);

            struct stat st;

            snprintfz(name, FILENAME_MAX, "%s/%s/ce_count", mc_dirname, de->d_name);
            if(stat(name, &st) != -1)
                m->ce.filename = strdupz(name);

            snprintfz(name, FILENAME_MAX, "%s/%s/ue_count", mc_dirname, de->d_name);
            if(stat(name, &st) != -1)
                m->ue.filename = strdupz(name);

            snprintfz(name, FILENAME_MAX, "%s/%s/ce_noinfo_count", mc_dirname, de->d_name);
            if(stat(name, &st) != -1)
                m->ce_noinfo.filename = strdupz(name);

            snprintfz(name, FILENAME_MAX, "%s/%s/ue_noinfo_count", mc_dirname, de->d_name);
            if(stat(name, &st) != -1)
                m->ue_noinfo.filename = strdupz(name);

            if(!m->ce.filename && !m->ue.filename && !m->ce_noinfo.filename && !m->ue_noinfo.filename) {
                freez(m->name);
                freez(m);
            }
            else
                DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(mc_root, m, prev, next);
        }
    }
    closedir(dir);

    for(struct mc *m = mc_root; m ;m = m->next) {
        snprintfz(name, FILENAME_MAX, "%s/%s", mc_dirname, m->name);
        dir = opendir(name);
        if(!dir) {
            collector_error("Cannot read EDAC memory errors directory '%s'", name);
            continue;
        }

        while((de = readdir(dir))) {
            // it can be dimmX or rankX directory
            // https://www.kernel.org/doc/html/v5.0/admin-guide/ras.html#f5

            if (de->d_type == DT_DIR &&
                ((strncmp(de->d_name, "rank", 4) == 0 || strncmp(de->d_name, "dimm", 4) == 0)) &&
                isdigit(de->d_name[4])) {

                struct edac_dimm *d = callocz(1, sizeof(struct edac_dimm));
                d->name = strdupz(de->d_name);

                struct stat st;

                snprintfz(name, FILENAME_MAX, "%s/%s/%s/dimm_ce_count", mc_dirname, m->name, de->d_name);
                if(stat(name, &st) != -1)
                    d->ce.filename = strdupz(name);

                snprintfz(name, FILENAME_MAX, "%s/%s/%s/dimm_ue_count", mc_dirname, m->name, de->d_name);
                if(stat(name, &st) != -1)
                    d->ue.filename = strdupz(name);

                if(!d->ce.filename && !d->ue.filename) {
                    freez(d->name);
                    freez(d);
                }
                else
                    DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(m->dimms, d, prev, next);
            }
        }
        closedir(dir);
    }
}

static kernel_uint_t read_edac_count(struct edac_count *t) {
    t->updated = false;
    t->count = 0;

    if(t->filename) {
        if(unlikely(!t->ff)) {
            t->ff = procfile_open(t->filename, " \t", PROCFILE_FLAG_DEFAULT);
            if(unlikely(!t->ff))
                return 0;
        }

        t->ff = procfile_readall(t->ff);
        if(unlikely(!t->ff || procfile_lines(t->ff) < 1 || procfile_linewords(t->ff, 0) < 1))
            return 0;

        t->count = str2ull(procfile_lineword(t->ff, 0, 0), NULL);
        t->updated = true;
    }

    return t->count;
}

static bool read_edac_mc_file(const char *mc, const char *filename, char *out, size_t out_size) {
    char f[FILENAME_MAX + 1];
    snprintfz(f, FILENAME_MAX, "%s/%s/%s", mc_dirname, mc, filename);
    if(read_file(f, out, out_size) != 0) {
        collector_error("EDAC: cannot read file '%s'", f);
        return false;
    }
    return true;
}

static bool read_edac_mc_rank_file(const char *mc, const char *rank, const char *filename, char *out, size_t out_size) {
    char f[FILENAME_MAX + 1];
    snprintfz(f, FILENAME_MAX, "%s/%s/%s/%s", mc_dirname, mc, rank, filename);
    if(read_file(f, out, out_size) != 0) {
        collector_error("EDAC: cannot read file '%s'", f);
        return false;
    }
    return true;
}

int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt __maybe_unused) {
    if(unlikely(!mc_root)) {
        find_all_mc();

        if(!mc_root)
            // don't call this again
            return 1;
    }

    for(struct mc *m = mc_root; m; m = m->next) {
        read_edac_count(&m->ce);
        read_edac_count(&m->ce_noinfo);
        read_edac_count(&m->ue);
        read_edac_count(&m->ue_noinfo);

        for(struct edac_dimm *d = m->dimms; d ;d = d->next) {
            read_edac_count(&d->ce);
            read_edac_count(&d->ue);
        }
    }

    // --------------------------------------------------------------------

    for(struct mc *m = mc_root; m ; m = m->next) {
        if(unlikely(!m->ce.