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
|
/* SPDX-License-Identifier: GPL-2.0 */
/**
* \file stat.c Functions used for sending/receiving the status of para_server
* and para_audiod.
*/
#include "para.h"
#include "error.h"
#include "string.h"
/** The minimal length of a status item buffer. */
#define MIN_STAT_ITEM_LEN 9 /* 5 + 2 + 2, e.g. '0005 00:\n' */
/*
* Read the size prefix of a status item buffer and return its value.
*
* Each status item sent by para_server is prefixed with its length, a four
* digit hex number encoded in ascii format.
*/
static int read_size_header(const char *buf)
{
int i, len = 0;
for (i = 0; i < 4; i++) {
unsigned char c = buf[i];
len <<= 4;
if (c >= '0' && c <= '9') {
len += c - '0';
continue;
}
if (c >= 'a' && c <= 'f') {
len += c - 'a' + 10;
continue;
}
return -1;
}
if (buf[4] != ' ')
return -1;
return len;
}
/**
* Parse the status output of para_server or para_audiod.
*
* The item buffer is expected to contain status items in the format produced by
* parser-friendly output mode of the stat command.
*
* \param item_buf The source buffer.
* \param num_bytes The buffer length in bytes.
* \param items Will be updated accordingly. Old values are freed.
*
* \return Mask of status items that have changed. Parse errors are logged
* but are otherwise ignored.
*/
uint64_t parse_status_items(char *item_buf, size_t num_bytes, char **items)
{
uint64_t mask = 0ULL;
char *buf = item_buf;
int len = num_bytes;
for (;;) {
int i, ret, item_len, item_num = 0;
char *old, *new;
if (len < MIN_STAT_ITEM_LEN)
break;
ret = read_size_header(buf);
if (ret < 0)
goto parse_error;
item_len = ret;
if (item_len > len - 5) /* item not complete */
break;
for (i = 0; i < 2; i++) {
unsigned char c = buf[5 + i];
item_num <<= 4;
if (c >= '0' && c <= '9') {
item_num += c - '0';
continue;
}
if (c >= 'a' && c <= 'f') {
item_num += c - 'a' + 10;
continue;
}
goto parse_error;
}
if (buf[7] != ':' || buf[5 + item_len - 1] != '\n')
goto parse_error;
buf[5 + item_len - 1] = '\0';
old = items[item_num];
new = buf + 8;
if (item_num >= NUM_STAT_ITEMS)
PARA_WARNING_LOG("unknown status item %d: %s\n",
item_num, new);
else if (!old || strcmp(old, new)) {
free(old);
items[item_num] = para_strdup(new);
mask |= 1ULL << item_num;
}
buf += 5 + item_len;
len -= 5 + item_len;
assert(len >= 0 && buf <= item_buf + num_bytes);
}
if (len != 0) {
PARA_WARNING_LOG("len=%d, num_bytes=%zu\n", len, num_bytes);
PARA_WARNING_LOG("buf: %s\n", buf);
PARA_WARNING_LOG("mask: %" PRIu64 "\n", mask);
}
return mask;
parse_error:
PARA_ERROR_LOG("status item parse error\n");
return mask;
}
|