summaryrefslogtreecommitdiffstats
path: root/src/registry_log.c
blob: 3229a34b4b08bb632d331113fa20290178172dc1 (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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "registry_internals.h"

void registry_log(const char action, REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name) {
    if(likely(registry.log_fp)) {
        if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
                action,
                p->last_t,
                p->guid,
                m->guid,
                name,
                u->url) < 0))
            error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");

        // we increase the counter even on failures
        // so that the registry will be saved periodically
        registry.log_count++;

        // this must be outside the log_lock(), or a deadlock will happen.
        // registry_db_save() checks the same inside the log_lock, so only
        // one thread will save the db
        if(unlikely(registry_db_should_be_saved()))
            registry_db_save();
    }
}

int registry_log_open(void) {
    if(registry.log_fp)
        fclose(registry.log_fp);

    registry.log_fp = fopen(registry.log_filename, "a");
    if(registry.log_fp) {
        if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0)
            error("Cannot set line buffering on registry log file.");
        return 0;
    }

    error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename);
    return -1;
}

void registry_log_close(void) {
    if(registry.log_fp) {
        fclose(registry.log_fp);
        registry.log_fp = NULL;
    }
}

void registry_log_recreate(void) {
    if(registry.log_fp != NULL) {
        registry_log_close();

        // open it with truncate
        registry.log_fp = fopen(registry.log_filename, "w");
        if(registry.log_fp) fclose(registry.log_fp);
        else error("Cannot truncate registry log '%s'", registry.log_filename);

        registry.log_fp = NULL;
        registry_log_open();
    }
}

ssize_t registry_log_load(void) {
    ssize_t line = -1;

    // closing the log is required here
    // otherwise we will append to it the values we read
    registry_log_close();

    debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename);
    FILE *fp = fopen(registry.log_filename, "r");
    if(!fp)
        error("Registry: cannot open registry file: %s", registry.log_filename);
    else {
        char *s, buf[4096 + 1];
        line = 0;
        size_t len = 0;

        while ((s = fgets_trim_len(buf, 4096, fp, &len))) {
            line++;

            switch (s[0]) {
                case 'A': // accesses
                case 'D': // deletes

                    // verify it is valid
                    if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) {
                        error("Registry: log line %zd is wrong (len = %zu).", line, len);
                        continue;
                    }
                    s[1] = s[10] = s[47] = s[84] = '\0';

                    // get the variables
                    time_t when = strtoul(&s[2], NULL, 16);
                    char *person_guid = &s[11];
                    char *machine_guid = &s[48];
                    char *name = &s[85];

                    // skip the name to find the url
                    char *url = name;
                    while(*url && *url != '\t') url++;
                    if(!*url) {
                        error("Registry: log line %zd does not have a url.", line);
                        continue;
                    }
                    *url++ = '\0';

                    // make sure the person exists
                    // without this, a new person guid will be created
                    REGISTRY_PERSON *p = registry_person_find(person_guid);
                    if(!p) p = registry_person_allocate(person_guid, when);

                    if(s[0] == 'A')
                        registry_request_access(p->guid, machine_guid, url, name, when);
                    else
                        registry_request_delete(p->guid, machine_guid, url, name, when);

                    registry.log_count++;
                    break;

                default:
                    error("Registry: ignoring line %zd of filename '%s': %s.", line, registry.log_filename, s);
                    break;
            }
        }

        fclose(fp);
    }

    // open the log again
    registry_log_open();

    return line;
}