<commit_before>/*
 * Copyright (C) Tildeslash Ltd. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 *
 * You must obey the GNU Affero General Public License in all respects
 * for all of the code used other than OpenSSL.
 */

#include "config.h"

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif



#include "monit.h"
#include "state.h"

// libmonit
#include "exceptions/IOException.h"


/**
 * The list of persistent properties:
 *
 *    1.) service name + service type
 *        Monit configuration may change, so the state restore needs to ignore
 *        the removed services or services which type doesn't match (the
 *        service name was reused for different check). The current service
 *        runtime is thus paired with the saved service state by name and type.
 *
 *    2.) monitoring state
 *        Keep the monitoring enabled or disabled on Monit restart. Useful for
 *        example when Monit is running in active/passive cluster, so the
 *        service monitoring mode doesn't reset when Monit needs to be reloaded
 *        and the service won't enter unwanted passive/passive or active/active
 *        state on multiple hosts. Another example is service which timed out
 *        due to excessive errors or the monitoring was intentionally disabled
 *        by admin for maintenance - do not re-enable monitoring on Monit reload.
 *
 *    3.) service restart counters
 *
 *    4.) inode number and read position for the file check
 *        Allows to skip the content match test for the content which was checked
 *        already to suppress duplicate events.
 *
 * Data is stored in binary form in the statefile using the following format:
 *    <MAGIC><VERSION>{<SERVICE_STATE>}+
 *
 * When the persistent field needs to be added, update the State_Version along
 * with State_update() and State_save(). The version allows to recognize the
 * service state structure and file format.
 *
 * The backward compatibility of monitoring state restore is very important if
 * Monit runs in cluster => keep previous formats compatibility.
 *
 * @file
 */


/* ------------------------------------------------------------- Definitions */


/* Extended format version */
typedef enum {
        StateVersion0 = 0,
        StateVersion1
} State_Version;


/* Format version 0 (Monit <= 5.3) */
typedef struct mystate0 {
        char               name[STRLEN];
        int                mode;                // obsolete since Monit 5.1
        int                nstart;
        int                ncycle;
        int                monitor;
        unsigned long long error;               // obsolete since Monit 5.0
} State0_T;


/* Extended format version 1 */
typedef struct mystate1 {
        char               name[STRLEN];
        int                type;
        int                monitor;
        int                nstart;
        int                ncycle;
        union {
                struct {
                        unsigned long long inode;
                        unsigned long long readpos;
                } file;
        } priv;
} State1_T;


static int file = -1;


/* ----------------------------------------------------------------- Private */


static void update_v0(int services) {
        for (int i = 0; i < services; i++) {
                State0_T state;
                if (read(file, &state, sizeof(state)) != sizeof(state))
                        THROW(IOException, "Unable to read service state");
                Service_T service;
                if ((service = Util_getService(state.name))) {
                        service->nstart = state.nstart;
                        service->ncycle = state.ncycle;
                        if (state.monitor == Monitor_Not)
                                service->monitor = state.monitor;
                        else if (service->monitor == Monitor_Not)
                                service->monitor = Monitor_Init;
                }
        }
}


static void update_v1() {
        State1_T state;
        while (read(file, &state, sizeof(state)) == sizeof(state)) {
                Service_T service;
                if ((service = Util_getService(state.name)) && service->type == state.type) {
                        service->nstart = state.nstart;
                        service->ncycle = state.ncycle;
                        if (state.monitor == Monitor_Not)
                                service->monitor = state.monitor;
                        else if (service->monitor == Monitor_Not)
                                service->monitor = Monitor_Init;
                        if (service->type == Service_File) {
                                service->inf->priv.file.inode = state.priv.file.inode;
                                service->inf->priv.file.readpos = state.priv.file.readpos;
                        }
                }
        }
}


/* ------------------------------------------------------------------ Public */


boolean_t State_open() {
        State_close();
        if ((file = open(Run.files.state, O_RDWR | O_CREAT, 0600)) == -1) {
                LogError("Cannot open for write -- %s\n", STRERROR);
                return false;
        }
        atexit(State_close);
        return true;
}


void State_close() {
        if (file != -1) {
                if (close(file) == -1)
                        LogError("State file '%s': close error -- %s\n", Run.files.state, STRERROR);
                else
                        file = -1;
        }
}
<commit_msg>log the error origin<commit_after>/*
 * Copyright (C) Tildeslash Ltd. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 *
 * You must obey the GNU Affero General Public License in all respects
 * for all of the code used other than OpenSSL.
 */

#include "config.h"

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif



#include "monit.h"
#include "state.h"

// libmonit
#include "exceptions/IOException.h"


/**
 * The list of persistent properties:
 *
 *    1.) service name + service type
 *        Monit configuration may change, so the state restore needs to ignore
 *        the removed services or services which type doesn't match (the
 *        service name was reused for different check). The current service
 *        runtime is thus paired with the saved service state by name and type.
 *
 *    2.) monitoring state
 *        Keep the monitoring enabled or disabled on Monit restart. Useful for
 *        example when Monit is running in active/passive cluster, so the
 *        service monitoring mode doesn't reset when Monit needs to be reloaded
 *        and the service won't enter unwanted passive/passive or active/active
 *        state on multiple hosts. Another example is service which timed out
 *        due to excessive errors or the monitoring was intentionally disabled
 *        by admin for maintenance - do not re-enable monitoring on Monit reload.
 *
 *    3.) service restart counters
 *
 *    4.) inode number and read position for the file check
 *        Allows to skip the content match test for the content which was checked
 *        already to suppress duplicate events.
 *
 * Data is stored in binary form in the statefile using the following format:
 *    <MAGIC><VERSION>{<SERVICE_STATE>}+
 *
 * When the persistent field needs to be added, update the State_Version along
 * with State_update() and State_save(). The version allows to recognize the
 * service state structure and file format.
 *
 * The backward compatibility of monitoring state restore is very important if
 * Monit runs in cluster => keep previous formats compatibility.
 *
 * @file
 */


/* ------------------------------------------------------------- Definitions */


/* Extended format version */
typedef enum {
        StateVersion0 = 0,
        StateVersion1
} State_Version;


/* Format version 0 (Monit <= 5.3) */
typedef struct mystate0 {
        char               name[STRLEN];
        int                mode;                // obsolete since Monit 5.1
        int                nstart;
        int                ncycle;
        int                monitor;
        unsigned long long error;               // obsolete since Monit 5.0
} State0_T;


/* Extended format version 1 */
typedef struct mystate1 {
        char               name[STRLEN];
        int                type;
        int                monitor;
        int                nstart;
        int                ncycle;
        union {
                struct {
                        unsigned long long inode;
                        unsigned long long readpos;
                } file;
        } priv;
} State1_T;


static int file = -1;


/* ----------------------------------------------------------------- Private */


static void update_v0(int services) {
        for (int i = 0; i < services; i++) {
                State0_T state;
                if (read(file, &state, sizeof(state)) != sizeof(state))
                        THROW(IOException, "Unable to read service state");
                Service_T service;
                if ((service = Util_getService(state.name))) {
                        service->nstart = state.nstart;
                        service->ncycle = state.ncycle;
                        if (state.monitor == Monitor_Not)
                                service->monitor = state.monitor;
                        else if (service->monitor == Monitor_Not)
                                service->monitor = Monitor_Init;
                }
        }
}


static void update_v1() {
        State1_T state;
        while (read(file, &state, sizeof(state)) == sizeof(state)) {
                Service_T service;
                if ((service = Util_getService(state.name)) && service->type == state.type) {
                        service->nstart = state.nstart;
                        service->ncycle = state.ncycle;
                        if (state.monitor == Monitor_Not)
                                service->monitor = state.monitor;
                        else if (service->monitor == Monitor_Not)
                                service->monitor = Monitor_Init;
                        if (service->type == Service_File) {
                                service->inf->priv.file.inode = state.priv.file.inode;
                                service->inf->priv.file.readpos = state.priv.file.readpos;
                        }
                }
        }
}


/* ------------------------------------------------------------------ Public */


boolean_t State_open() {
        State_close();
        if ((file = open(Run.files.state, O_RDWR | O_CREAT, 0600)) == -1) {
                LogError("State file '%s': cannot open for write -- %s\n", Run.files.state, STRERROR);
                return false;
        }
        atexit(State_close);
        return true;
}


void State_close() {
        if (file != -1) {
                if (close(file) == -1)
                        LogError("State file '%s': close error -- %s\n", Run.files.state, STRERROR);
                else
                        file = -1;
        }
}

{'fraction_non_alphanumeric': 0.10903142357148292, 'fraction_numerical': 0.0051738568059042835, 'mean_word_length': 1.6835443037974684, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '855130', 'n_tokens_mistral': 3371, 'n_tokens_neox': 3186, 'n_words': 1240}