summaryrefslogtreecommitdiffstats
path: root/srv/c.c
blob: e00b7d729c8f1fca34b3fa75ef13be068ede2eab (plain) (blame)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/param.h>
#include <string.h>
#define S0(x) (x ? x : "")
struct entry {
	uint64_t time __attribute__((packed));
	uint64_t value __attribute__((packed));
} __attribute__((packed));
int najdi (struct entry * db, int first, int last, uint64_t čas) {
	if (first == last)
		return first;
	if (last-first == 1) {
		if (MAX(čas, be64toh(db[first].time))-MIN(čas, be64toh(db[first].time)) < MAX(čas, be64toh(db[last].time))-MIN(čas, be64toh(db[last].time)))
			return first;
		else
			return last;
	}
	uint64_t pol = be64toh(db[(first+last)/2].time);
	if (pol < čas)
		return najdi(db, (first+last)/2, last, čas);
	else
		return najdi(db, first, (first+last)/2-1, čas);
}
int main (int argc, char ** argv) {
	int r = 0;
	if (argc < 1+2)
		error_at_line(1, 0, __FILE__, __LINE__,
"uporaba: %s db infor/preveri/rast/seštevek/uredi [natančnost] [začetek UNIX] [konec UNIX]\n\t"
"informacije: pove UNIXus prvega in UNIXus zadnjega zapisa\n\t"
"preveri: najde znane napake v podatkovni zbirki\n\t"
"rast: TSV s podatki <UNIXus>:<Wh skupno> najgosteje na [natančnost=0] ms\n\t"
"seštevek: TSV s podatki <UNIXus>:<vatnih ur v [natančnost=10e3] ms>\n\t"
"uredi: uredi pokvarjeno podatkovno zbirko, daemon ne sme teči med urejanjem\n\t"
"če je nastavljena okoljska spremenljivka SEK, bodo izhodni časi v UNIX sekundah",
			S0(argv[0]));
	int fd = -1;
	struct entry * db = NULL;
	if ((fd = open(argv[1], (argv[2][0] == 'u' ? O_RDWR : O_RDONLY) | O_CLOEXEC)) == -1)
		error_at_line(2, 0, __FILE__, __LINE__, "open");
	struct stat statbuf;
	if (fstat(fd, &statbuf) == -1) {
		error_at_line(0, errno, __FILE__, __LINE__, "fstat");
		r = 3;
		goto r;
	}
	unsigned entries = statbuf.st_size / sizeof(struct entry);
	if (!(db = mmap(NULL, statbuf.st_size, (argv[2][0] == 'u' ? PROT_WRITE | PROT_READ : PROT_READ), MAP_SHARED, fd, 0))) {
		error_at_line(0, errno, __FILE__, __LINE__, "mmap");
		r = 4;
		goto r;
	}
	if (argv[2][0] == 'u') {
		unsigned o = 0;
		for (unsigned r = 0; r < entries; r++) {
			if (!be64toh(db[r].time)) {
				o++;
				continue;
			}
			memmove(db+r-o, db+r, sizeof(*db));
		}
		ftruncate(fd, sizeof(*db)*(entries-o));
		printf("odstranjenih %u zapisov\n", o);
		goto r;
	}
	if (argv[2][0] == 'i') {
		uint64_t začetek = be64toh(db[0].time);
		uint64_t konec = be64toh(db[entries-1].time);
		char * enota = "us";
		if (getenv("SEK")) {
			začetek /= 1e6;
			konec /= 1e6;
			enota = "";
		}
		printf("začetek\t%" PRIu64 " UNIX%s\t%" PRIu64 " Wh\nkonec\t%" PRIu64 " UNIX%s\t%" PRIu64 " Wh\nzapisov: %u\n", začetek, enota, be64toh(db[0].value), konec, enota, be64toh(db[entries-1].value), entries);
		goto r;
	}
	if (argv[2][0] == 'p') {
		uint64_t prev_time = 0;
		uint64_t prev_value = 0;
		fprintf(stderr, "opis možnih napak:\n\tčas se je zavrtel nazaj ponazarja napako na strežniku, saj ni imel nastavljenega časa. podatkovne zbirke s to napako so trenutno neuporabne.\n\tštevec se je resetiral pomeni, da je merilnik dobil ukaz reset oziroma je bil vzpostavljen nov merilnik, ki meri od začetka. v prihodnosti bo ta bralnik sproti nadomestil vrednosti ob branju pri tej napaki, trenutno pa tega ne stori.\n\tničelni zapis v podatkovni zbirki se zgodi, ko med tekom daemona nenadno zmanjka elektrike - takrat obstaja možnost, da se bodo po ponovem zagonu v datoteko vpisali ničelni zapisi. podatkovne zbirke s to napako je treba urediti z ukazom uredi, drugače ni uporabna v bralniku.\n");
		for (unsigned i = 0; i < entries; i++) {
			if (!be64toh(db[i].time)) {
				printf("ničelni zapis v podatkovni zbriki (med pisanjem se je zgodil izpad elektrike): i=%u prev_time=%" PRIu64 "\n", i, prev_time);
				continue;
			}
			if (be64toh(db[i].time) < prev_time)
				printf("čas se je zavrtel nazaj: i=%u a=%" PRIu64 " b=%" PRIu64 "\n", i, prev_time, be64toh(db[i].time));
			if (be64toh(db[i].value) < prev_value)
				printf("števec se je resetiral: i=%u a=%" PRIu64 " b=%" PRIu64 "\n", i, prev_value, be64toh(db[i].value));
			prev_time = be64toh(db[i].time);
			prev_value = be64toh(db[i].value);
		}
		goto r;
	}
	unsigned long long natančnost = 0;
	if (argv[2][0] == 's')
		natančnost = 10e3;
	if (argc >= 1+3)
		natančnost = atoi(argv[3]);
	unsigned začetek = 0;
	if (argc >= 1+4)
		začetek = najdi(db, 0, entries-1, atoi(argv[4])*1e6);
	uint64_t konec = -1;
	if (argc >= 1+5)
		konec = atoi(argv[5])*(uint64_t)1e6;
	if (argv[2][0] == 's') {
		uint64_t us = 0;
		uint64_t Wh = 0;
		unsigned long long prev_time = be64toh(db[začetek].time);
		unsigned long long prev_value = be64toh(db[začetek].value);
		for (unsigned i = začetek; i < entries; i++) {
			if (be64toh(db[i].time) > konec)
				break;
			if (us + (be64toh(db[i].time)-prev_time) >= natančnost*1000) {
				uint64_t čas_začetek = be64toh(db[i].time)-us;
				uint64_t čas_konec = be64toh(db[i].time);
				if (getenv("SEK")) {
					čas_začetek /= 1e6;
					čas_konec /= 1e6;
				}
				printf("%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\n", čas_začetek, Wh, čas_konec, us);
				us = 0;
				Wh = 0;
			}
			us += (be64toh(db[i].time)-prev_time);
			Wh += (be64toh(db[i].value)-prev_value);
			prev_time = be64toh(db[i].time);
			prev_value = be64toh(db[i].value);
		}
	} else {
		unsigned long long prev_print = 0;
		for (unsigned i = začetek; i < entries; i++) {
			if (be64toh(db[i].time) > konec)
				break;
			if (be64toh(db[i].time)-prev_print > natančnost*1000) {
				uint64_t čas = be64toh(db[i].time);
				if (getenv("SEK"))
					čas /= 1e6;
				printf("%" PRIu64 "\t%" PRIu64 "\n", čas, be64toh(db[i].value));
				prev_print = be64toh(db[i].time);
			}
		}
	}
r:
	if (db != NULL)
		if (munmap(db, statbuf.st_size) == -1)
			error_at_line(98, errno, __FILE__, __LINE__, "munmap");
	if (fd == -1)
		if (close(fd) == -1)
			error_at_line(99, errno, __FILE__, __LINE__, "fclose");
	return r;
}