<commit_before>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Fluent Bit
 *  ==========
 *  Copyright (C) 2019      The Fluent Bit Authors
 *  Copyright (C) 2015-2018 Treasure Data Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_input.h>
#include <fluent-bit/flb_config.h>
#include <fluent-bit/flb_pack.h>

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

#include <msgpack.h>

#include "in_thermal.h"

struct flb_input_plugin in_thermal_plugin;

/* Default collection time: every 1 second (0 nanoseconds) */
#define DEFAULT_INTERVAL_SEC    1
#define DEFAULT_INTERVAL_NSEC   0

#define IN_THERMAL_N_MAX          32
#define IN_THERMAL_FILENAME_LEN   1024
#define IN_THERMAL_TYPE_LEN       256

struct temp_info
{
    char   name[IN_THERMAL_FILENAME_LEN]; /*                     .../thermal_zoneX/...  */
    char   type[IN_THERMAL_TYPE_LEN];     /* from /sys/class/thermal/thermal_zoneX/type */
    double temp;                          /* from /sys/class/thermal/thermal_zoneX/temp */
};

/* Retrieve temperature(s) from the system (via /sys/class/thermal) */
static inline int proc_temperature(struct flb_in_thermal_config *ctx, struct temp_info *info, int n)
{
    int i, j;
    DIR *d;
    struct dirent *e;
    char filename[IN_THERMAL_FILENAME_LEN];
    FILE *f;
    int temp;

    d = opendir("/sys/class/thermal");
    if (d == NULL) {
        return -1;
    }

    i = 0;
    while (i<n && (e = readdir(d))) {
        if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) {
            continue;
        }

        if (e->d_type == DT_REG) {
            continue;
        }

#ifdef FLB_HAVE_REGEX
        if (ctx->name_regex && !flb_regex_match(ctx->name_regex,
                                                (unsigned char *) e->d_name,
                                                strlen(e->d_name))) {
            continue;
        }
#endif

        if (!strncmp(e->d_name, "thermal_zone", 12)) {
            strncpy(info[i].name, e->d_name, IN_THERMAL_FILENAME_LEN);
            if (snprintf(filename, IN_THERMAL_FILENAME_LEN,
                         "/sys/class/thermal/%s/type", e->d_name) <=0 ) {
                continue;
            }

            f = fopen(filename, "r");
            if (!f) {
                flb_errno();
                flb_error("[in_thermal] cannot read %s", filename);
                continue;
            }

            if (f && fgets(info[i].type, IN_THERMAL_TYPE_LEN, f) && strlen(info[i].type)>1) {
                 /* Remove trailing \n */
                for (j=0; info[i].type[j]; ++j) {
                    if (info[i].type[j]=='\n') {
                        info[i].type[j] = 0;
                        break;
                    }
                }
                fclose(f);

#ifdef FLB_HAVE_REGEX
                if (ctx->type_regex && !flb_regex_match(ctx->type_regex, (unsigned char *) info[i].type, strlen(info[i].type))) {
                    continue;
                }
#endif

                if (snprintf(filename, IN_THERMAL_FILENAME_LEN, "/sys/class/thermal/%s/temp", e->d_name)<=0) {
                    continue;
                }
                f = fopen(filename, "r");
                if (f && fscanf(f, "%d", &temp)==1) {
                    info[i].temp = temp/1000.0;
                    ++i;
                }
            }
            fclose(f);
        }
    }
    closedir(d);
    return i;
}

/* Init temperature input */
static int in_thermal_init(struct flb_input_instance *in,
                       struct flb_config *config, void *data)
{
    int ret;
    struct flb_in_thermal_config *ctx;
    (void) data;
    const char *pval = NULL;
    struct temp_info info[IN_THERMAL_N_MAX];

    /* Allocate space for the configuration */
    ctx = flb_calloc(1, sizeof(struct flb_in_thermal_config));
    if (!ctx) {
        perror("calloc");
        return -1;
    }
    ctx->i_ins = in;

    /* Collection time setting */
    pval = flb_input_get_property("interval_sec", in);
    if (pval != NULL && atoi(pval) >= 0) {
        ctx->interval_sec = atoi(pval);
    }
    else {
        ctx->interval_sec = DEFAULT_INTERVAL_SEC;
    }

    pval = flb_input_get_property("interval_nsec", in);
    if (pval != NULL && atoi(pval) >= 0) {
        ctx->interval_nsec = atoi(pval);
    }
    else {
        ctx->interval_nsec = DEFAULT_INTERVAL_NSEC;
    }

    if (ctx->interval_sec <= 0 && ctx->interval_nsec <= 0) {
        /* Illegal settings. Override them. */
        ctx->interval_sec = DEFAULT_INTERVAL_SEC;
        ctx->interval_nsec = DEFAULT_INTERVAL_NSEC;
    }

#ifdef FLB_HAVE_REGEX
    ctx->name_regex = NULL;
    pval = flb_input_get_property("name_regex", in);
    if (pval) {
        ctx->name_regex = flb_regex_create(pval);
        if (!ctx->name_regex) {
            flb_error("[in_thermal] invalid 'name_regex' config value");
        }
    }

    ctx->type_regex = NULL;
    pval = flb_input_get_property("type_regex", in);
    if (pval) {
        ctx->type_regex = flb_regex_create(pval);
        if (!ctx->type_regex) {
            flb_error("[in_thermal] invalid 'type_regex' config value");
        }
    }
#endif

    ctx->prev_device_num = proc_temperature(ctx, info,  IN_THERMAL_N_MAX);
    if (!ctx->prev_device_num) {
        flb_warn("[in_thermal] thermal device file not found");
    }

    /* Set the context */
    flb_input_set_context(in, ctx);

    /* Set our collector based on time, temperature every 1 second */
    ret = flb_input_set_collector_time(in,
                                       in_thermal_collect,
                                       ctx->interval_sec,
                                       ctx->interval_nsec,
                                       config);
    if (ret == -1) {
        flb_error("[in_thermal] Could not set collector for temperature input plugin");
        return -1;
    }
    ctx->coll_fd = ret;

    return 0;
}

/* Callback to gather temperature */
int in_thermal_collect(struct flb_input_instance *i_ins,
                   struct flb_config *config, void *in_context)
{
    int n;
    int i;
    msgpack_packer mp_pck;
    msgpack_sbuffer mp_sbuf;
    (void) config;
    struct temp_info info[IN_THERMAL_N_MAX];
    struct flb_in_thermal_config *ctx = in_context;

    /* Get the current temperature(s) */
    n = proc_temperature(ctx, info, IN_THERMAL_N_MAX);
    if (n != ctx->prev_device_num) {
        flb_info("[in_thermal] the number of thermal devices changed %d -> %d",
                 ctx->prev_device_num, n);
    }
    ctx->prev_device_num = n;
    if (!n) {
        return 0;
    }

    msgpack_sbuffer_init(&mp_sbuf);
    msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write);

    /*
     * Store the new data into the MessagePack buffer
     */

    for (i=0; i<n; ++i) {
        msgpack_pack_array(&mp_pck, 2);
        flb_pack_time_now(&mp_pck);
        msgpack_pack_map(&mp_pck, 3);

        msgpack_pack_str(&mp_pck, 4);
        msgpack_pack_str_body(&mp_pck, "name", 4);
        msgpack_pack_str(&mp_pck, strlen(info[i].name));
        msgpack_pack_str_body(&mp_pck, info[i].name, strlen(info[i].name));

        msgpack_pack_str(&mp_pck, 4);
        msgpack_pack_str_body(&mp_pck, "type", 4);
        msgpack_pack_str(&mp_pck, strlen(info[i].type));
        msgpack_pack_str_body(&mp_pck, info[i].type, strlen(info[i].type));

        msgpack_pack_str(&mp_pck, 4);
        msgpack_pack_str_body(&mp_pck, "temp", 4);
        msgpack_pack_double(&mp_pck, info[i].temp);

        flb_trace("[in_thermal] %s temperature %0.2f", info[i].name, info[i].temp);
    }

    flb_input_chunk_append_raw(i_ins, NULL, 0, mp_sbuf.data, mp_sbuf.size);
    msgpack_sbuffer_destroy(&mp_sbuf);

    return 0;
}

static void in_thermal_pause(void *data, struct flb_config *config)
{
    struct flb_in_thermal_config *ctx = data;
    flb_input_collector_pause(ctx->coll_fd, ctx->i_ins);
}

static void in_thermal_resume(void *data, struct flb_config *config)
{
    struct flb_in_thermal_config *ctx = data;
    flb_input_collector_resume(ctx->coll_fd, ctx->i_ins);
}

static int in_thermal_exit(void *data, struct flb_config *config)
{
    (void) *config;
    struct flb_in_thermal_config *ctx = data;
#ifdef FLB_HAVE_REGEX
    if (ctx && ctx->name_regex) {
        flb_regex_destroy(ctx->name_regex);
    }
    if (ctx && ctx->type_regex) {
        flb_regex_destroy(ctx->type_regex);
    }
#endif
    flb_free(ctx);
    return 0;
}

/* Plugin reference */
struct flb_input_plugin in_thermal_plugin = {
    .name         = "thermal",
    .description  = "Thermal",
    .cb_init      = in_thermal_init,
    .cb_pre_run   = NULL,
    .cb_collect   = in_thermal_collect,
    .cb_flush_buf = NULL,
    .cb_pause     = in_thermal_pause,
    .cb_resume    = in_thermal_resume,
    .cb_exit      = in_thermal_exit
};
<commit_msg>in_thermal: validate file handle before to close it<commit_after>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Fluent Bit
 *  ==========
 *  Copyright (C) 2019      The Fluent Bit Authors
 *  Copyright (C) 2015-2018 Treasure Data Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_input.h>
#include <fluent-bit/flb_config.h>
#include <fluent-bit/flb_pack.h>

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

#include <msgpack.h>

#include "in_thermal.h"

struct flb_input_plugin in_thermal_plugin;

/* Default collection time: every 1 second (0 nanoseconds) */
#define DEFAULT_INTERVAL_SEC    1
#define DEFAULT_INTERVAL_NSEC   0

#define IN_THERMAL_N_MAX          32
#define IN_THERMAL_FILENAME_LEN   1024
#define IN_THERMAL_TYPE_LEN       256

struct temp_info
{
    char   name[IN_THERMAL_FILENAME_LEN]; /*                     .../thermal_zoneX/...  */
    char   type[IN_THERMAL_TYPE_LEN];     /* from /sys/class/thermal/thermal_zoneX/type */
    double temp;                          /* from /sys/class/thermal/thermal_zoneX/temp */
};

/* Retrieve temperature(s) from the system (via /sys/class/thermal) */
static inline int proc_temperature(struct flb_in_thermal_config *ctx, struct temp_info *info, int n)
{
    int i, j;
    DIR *d;
    struct dirent *e;
    char filename[IN_THERMAL_FILENAME_LEN];
    FILE *f;
    int temp;

    d = opendir("/sys/class/thermal");
    if (d == NULL) {
        return -1;
    }

    i = 0;
    while (i<n && (e = readdir(d))) {
        if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) {
            continue;
        }

        if (e->d_type == DT_REG) {
            continue;
        }

#ifdef FLB_HAVE_REGEX
        if (ctx->name_regex && !flb_regex_match(ctx->name_regex,
                                                (unsigned char *) e->d_name,
                                                strlen(e->d_name))) {
            continue;
        }
#endif

        if (!strncmp(e->d_name, "thermal_zone", 12)) {
            strncpy(info[i].name, e->d_name, IN_THERMAL_FILENAME_LEN);
            if (snprintf(filename, IN_THERMAL_FILENAME_LEN,
                         "/sys/class/thermal/%s/type", e->d_name) <=0 ) {
                continue;
            }

            f = fopen(filename, "r");
            if (!f) {
                flb_errno();
                flb_error("[in_thermal] cannot read %s", filename);
                continue;
            }

            if (f && fgets(info[i].type, IN_THERMAL_TYPE_LEN, f) && strlen(info[i].type)>1) {
                 /* Remove trailing \n */
                for (j=0; info[i].type[j]; ++j) {
                    if (info[i].type[j]=='\n') {
                        info[i].type[j] = 0;
                        break;
                    }
                }
                fclose(f);

#ifdef FLB_HAVE_REGEX
                if (ctx->type_regex && !flb_regex_match(ctx->type_regex, (unsigned char *) info[i].type, strlen(info[i].type))) {
                    continue;
                }
#endif

                if (snprintf(filename, IN_THERMAL_FILENAME_LEN, "/sys/class/thermal/%s/temp", e->d_name)<=0) {
                    continue;
                }
                f = fopen(filename, "r");
                if (f && fscanf(f, "%d", &temp)==1) {
                    info[i].temp = temp/1000.0;
                    ++i;
                }
            }

            if (f) {
                fclose(f);
            }
        }
    }
    closedir(d);
    return i;
}

/* Init temperature input */
static int in_thermal_init(struct flb_input_instance *in,
                       struct flb_config *config, void *data)
{
    int ret;
    struct flb_in_thermal_config *ctx;
    (void) data;
    const char *pval = NULL;
    struct temp_info info[IN_THERMAL_N_MAX];

    /* Allocate space for the configuration */
    ctx = flb_calloc(1, sizeof(struct flb_in_thermal_config));
    if (!ctx) {
        perror("calloc");
        return -1;
    }
    ctx->i_ins = in;

    /* Collection time setting */
    pval = flb_input_get_property("interval_sec", in);
    if (pval != NULL && atoi(pval) >= 0) {
        ctx->interval_sec = atoi(pval);
    }
    else {
        ctx->interval_sec = DEFAULT_INTERVAL_SEC;
    }

    pval = flb_input_get_property("interval_nsec", in);
    if (pval != NULL && atoi(pval) >= 0) {
        ctx->interval_nsec = atoi(pval);
    }
    else {
        ctx->interval_nsec = DEFAULT_INTERVAL_NSEC;
    }

    if (ctx->interval_sec <= 0 && ctx->interval_nsec <= 0) {
        /* Illegal settings. Override them. */
        ctx->interval_sec = DEFAULT_INTERVAL_SEC;
        ctx->interval_nsec = DEFAULT_INTERVAL_NSEC;
    }

#ifdef FLB_HAVE_REGEX
    ctx->name_regex = NULL;
    pval = flb_input_get_property("name_regex", in);
    if (pval) {
        ctx->name_regex = flb_regex_create(pval);
        if (!ctx->name_regex) {
            flb_error("[in_thermal] invalid 'name_regex' config value");
        }
    }

    ctx->type_regex = NULL;
    pval = flb_input_get_property("type_regex", in);
    if (pval) {
        ctx->type_regex = flb_regex_create(pval);
        if (!ctx->type_regex) {
            flb_error("[in_thermal] invalid 'type_regex' config value");
        }
    }
#endif

    ctx->prev_device_num = proc_temperature(ctx, info,  IN_THERMAL_N_MAX);
    if (!ctx->prev_device_num) {
        flb_warn("[in_thermal] thermal device file not found");
    }

    /* Set the context */
    flb_input_set_context(in, ctx);

    /* Set our collector based on time, temperature every 1 second */
    ret = flb_input_set_collector_time(in,
                                       in_thermal_collect,
                                       ctx->interval_sec,
                                       ctx->interval_nsec,
                                       config);
    if (ret == -1) {
        flb_error("[in_thermal] Could not set collector for temperature input plugin");
        return -1;
    }
    ctx->coll_fd = ret;

    return 0;
}

/* Callback to gather temperature */
int in_thermal_collect(struct flb_input_instance *i_ins,
                   struct flb_config *config, void *in_context)
{
    int n;
    int i;
    msgpack_packer mp_pck;
    msgpack_sbuffer mp_sbuf;
    (void) config;
    struct temp_info info[IN_THERMAL_N_MAX];
    struct flb_in_thermal_config *ctx = in_context;

    /* Get the current temperature(s) */
    n = proc_temperature(ctx, info, IN_THERMAL_N_MAX);
    if (n != ctx->prev_device_num) {
        flb_info("[in_thermal] the number of thermal devices changed %d -> %d",
                 ctx->prev_device_num, n);
    }
    ctx->prev_device_num = n;
    if (!n) {
        return 0;
    }

    msgpack_sbuffer_init(&mp_sbuf);
    msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write);

    /*
     * Store the new data into the MessagePack buffer
     */

    for (i=0; i<n; ++i) {
        msgpack_pack_array(&mp_pck, 2);
        flb_pack_time_now(&mp_pck);
        msgpack_pack_map(&mp_pck, 3);

        msgpack_pack_str(&mp_pck, 4);
        msgpack_pack_str_body(&mp_pck, "name", 4);
        msgpack_pack_str(&mp_pck, strlen(info[i].name));
        msgpack_pack_str_body(&mp_pck, info[i].name, strlen(info[i].name));

        msgpack_pack_str(&mp_pck, 4);
        msgpack_pack_str_body(&mp_pck, "type", 4);
        msgpack_pack_str(&mp_pck, strlen(info[i].type));
        msgpack_pack_str_body(&mp_pck, info[i].type, strlen(info[i].type));

        msgpack_pack_str(&mp_pck, 4);
        msgpack_pack_str_body(&mp_pck, "temp", 4);
        msgpack_pack_double(&mp_pck, info[i].temp);

        flb_trace("[in_thermal] %s temperature %0.2f", info[i].name, info[i].temp);
    }

    flb_input_chunk_append_raw(i_ins, NULL, 0, mp_sbuf.data, mp_sbuf.size);
    msgpack_sbuffer_destroy(&mp_sbuf);

    return 0;
}

static void in_thermal_pause(void *data, struct flb_config *config)
{
    struct flb_in_thermal_config *ctx = data;
    flb_input_collector_pause(ctx->coll_fd, ctx->i_ins);
}

static void in_thermal_resume(void *data, struct flb_config *config)
{
    struct flb_in_thermal_config *ctx = data;
    flb_input_collector_resume(ctx->coll_fd, ctx->i_ins);
}

static int in_thermal_exit(void *data, struct flb_config *config)
{
    (void) *config;
    struct flb_in_thermal_config *ctx = data;
#ifdef FLB_HAVE_REGEX
    if (ctx && ctx->name_regex) {
        flb_regex_destroy(ctx->name_regex);
    }
    if (ctx && ctx->type_regex) {
        flb_regex_destroy(ctx->type_regex);
    }
#endif
    flb_free(ctx);
    return 0;
}

/* Plugin reference */
struct flb_input_plugin in_thermal_plugin = {
    .name         = "thermal",
    .description  = "Thermal",
    .cb_init      = in_thermal_init,
    .cb_pre_run   = NULL,
    .cb_collect   = in_thermal_collect,
    .cb_flush_buf = NULL,
    .cb_pause     = in_thermal_pause,
    .cb_resume    = in_thermal_resume,
    .cb_exit      = in_thermal_exit
};

{'fraction_non_alphanumeric': 0.12514453905182382, 'fraction_numerical': 0.00746347103962998, 'mean_word_length': 2.186568414001005, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 119, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3605163', 'n_tokens_mistral': 6734, 'n_tokens_neox': 6430, 'n_words': 1353}