-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.c
206 lines (188 loc) · 5.72 KB
/
utils.c
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include "utils.h"
#include "log.h"
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <execinfo.h>
void set_nonblocking(const int fd) {
const int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1)
EXITF("fcntl F_GETFL");
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
EXITF("fcntl F_SETFL O_NONBLOCK");
}
input_t calculate_lrc(input_t* p, const input_t* const pe) {
uint8_t lrc = 0;
assert(p < pe);
for (; p != pe; p++)
lrc ^= *p;
return lrc;
}
byte_t hex2nibble(const char h) {
switch (h) {
case 'A' ... 'F': return h - 'A' + 10;
case 'a' ... 'f': return h - 'a' + 10;
case '0' ... '9': return h - '0';
}
// FIXME: Any better idea what to do with bad hexadecimal number?
return '\0';
}
byte_t unhex(const char h[static const 2]) {
return (hex2nibble(h[0]) << 4) | hex2nibble(h[1]);
}
unsigned xsnprintf(char* const buf, const size_t s, const char* const fmt, ...) {
va_list ap;
va_start(ap, fmt);
const int r = vsnprintf(buf, s, fmt, ap);
va_end(ap);
if (r < 0)
EXITF("vsnprintf");
return r;
}
unsigned snprintfx(char* const buf, const size_t s, const char* const fmt, ...) {
va_list ap;
va_start(ap, fmt);
const int r = vsnprintf(buf, s, fmt, ap);
va_end(ap);
if (r >= 0) {
if (r < (ssize_t)s)
return r;
else
errno = ENOBUFS;
}
EXITF("vsnprintf");
}
char* trim_whitespaces(char* const s) {
char* p = s;
while (isspace(*p))
p++;
for (char* e = p + strlen(p) - 1; e != p && isspace(*e); e--)
*e = '\0';
return p;
}
static char class_to_char(const enum FrobMessageType m) {
switch (m & FROB_MESSAGE_CLASS_MASK) {
case FROB_T: return 'T';
case FROB_D: return 'D';
case FROB_S: return 'S';
case FROB_P: return 'P';
case FROB_I: return 'I';
case FROB_A: return 'A';
case FROB_K: return 'K';
case FROB_M: return 'M';
case FROB_L: return 'L';
case FROB_B: return 'B';
}
LOGE("0x%x", m);
assert(false);
return '?';
}
const char* frob_type_to_string(const enum FrobMessageType m) {
static char buf[3];
buf[0] = class_to_char(m);
buf[1] = (m & FROB_MESSAGE_NUMBER_MASK) + '0';
buf[2] = '\0';
return buf;
}
char frob_trx_type_to_code(const enum FrobTransactionType t) {
switch (t) {
case FROB_TRANSACTION_TYPE_PAYMENT: return 'S';
case FROB_TRANSACTION_TYPE_VOID: return 'C';
}
assert(false);
return '?';
}
#if 1
int parse_message(const input_t* const p, const input_t* const pe, struct frob_msg* const msg) {
const input_t* cur = p;
const char* err;
int e;
if ((e = frob_header_extract(&cur, pe, &msg->header)) != 0) {
err = "Header";
goto bail;
}
if ((e = frob_body_extract(msg->header.type, &cur, pe, &msg->body)) != 0) {
err = "Body";
goto bail;
}
if ((e = frob_extract_additional_attributes(&cur, pe, &msg->attr)) != 0) {
err = "Attributes";
goto bail;
}
// Complete message shall be processed, ie cursor shall point to the end of message
assert(cur == pe);
return 0;
bail:
LOGEX("%s parsing failed: %s", err, strerror(e));
LOGDXP(char tmp[4*(pe-p)],"\t%s", PRETTY(p, pe, tmp));
LOGDX("\t%*s", (int)(cur - p), "^");
return -1;
}
#endif
// Has similar semantics to read(2) except that it restarts itself if
// it was interrupted by a signal or until file is fully read
// If whole file was read returns positive integer less than s - bytes read.
// if only part of file was read returns s.
// if error occurs returns -1 and sets errno accordingly
static ssize_t rread(const int fd, const size_t s, input_t buf[static const s]) {
ssize_t l;
ssize_t r = 0;
do {
while ((l = read(fd, buf + r, s - r)) < 0 && errno == EINTR)
continue;
if (l < 0)
return -1;
r += l;
} while (l != 0);
return r;
}
ssize_t eread(const int fd, const size_t s, input_t buf[static const s]) {
const ssize_t ret = rread(fd, s, buf);
if (ret < 0 || (ret >= 0 && (size_t)ret < s))
return ret;
assert((size_t)ret == s);
errno = EFBIG;
return -1;
}
ssize_t slurp(const char* const name, const size_t s, input_t buf[static const s]) {
const int fd = open(name, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return fd;
const ssize_t ret = eread(fd, s, buf);
const int backup = errno;
if (close(fd) < 0 && ret < 0)
ABORTF("Double fault while accessing %s. eread: %s; close", name, strerror(backup));
(void)backup;
return ret;
}
int snprint_hex(const size_t sbuf, input_t buf[static const sbuf], const size_t sbin, const byte_t bin[static const sbin]) {
if (sbuf >= sbin * 2 + 1) {
for (size_t i = 0; i < sbin; i++)
if (snprintf((char*)buf + i * 2, 3, "%02X", bin[i]) != 2)
return -1;
}
return sbin * 2;
}
size_t xslurp(const char* const name, const size_t s, input_t buf[static const s]) {
const ssize_t ret = slurp(name, s, buf);
if (ret < 0)
EXITF("slurp %s", name);
return ret;
}
int xsnprint_hex(const size_t sbuf, input_t buf[static const sbuf], const size_t sbin, const byte_t bin[static const sbin]) {
const int ret = snprint_hex(sbuf, buf, sbin, bin);
if (ret < 0)
EXITF("snprint_hex");
return ret;
}
NORETURN void exitb(const char* const name) {
static void* stack[128];
backtrace_symbols_fd(stack, backtrace(stack, lengthof(stack)), STDERR_FILENO);
// call invoke_safe_mem_constraint_handler instead of exit
EXITF("%s", name);
}