blob: d3a8bf1077d0f38dfe73b3e58df72f10cd3009bb [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Alvin Kuo <Alvin.Kuo@mediatek.com>
6 */
7
8#include <limits.h>
9#include <stdlib.h>
10#include <stdint.h>
11#include <string.h>
12#include <unistd.h>
13#include <stdio.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <time.h>
17#include <poll.h>
18
19#include <sys/types.h>
20#include <sys/stat.h>
21
22#include "dump.h"
23
24static int time_to_str(time_t *time_sec, char *time_str, unsigned int time_str_size)
25{
26 struct tm *ptm;
27 int ret;
28
29 ptm = gmtime(time_sec);
30 if (!ptm)
31 return -1;
32
33 ret = strftime(time_str, time_str_size, "%Y%m%d%H%M%S", ptm);
34 if (!ret)
35 return -2;
36
37 return 0;
38}
39
40static int save_dump_data(char *dump_root_dir,
41 struct dump_data_header *dd_hdr,
42 char *dd)
43{
44 size_t dump_file_size = dd_hdr->info.size + sizeof(struct dump_info);
45 char dump_time_str[32];
46 struct stat st = { 0 };
47 char *dump_file = NULL;
48 char *dump_dir = NULL;
49 int ret = 0;
50 int fd;
51
52 ret = time_to_str((time_t *)&dd_hdr->info.dump_time_sec,
53 dump_time_str, sizeof(dump_time_str));
54 if (ret < 0) {
55 fprintf(stderr,
56 DUMP_LOG_FMT("time_to_str(%lu) fail(%d)\n"),
57 dd_hdr->info.dump_time_sec, ret);
58 ret = -1;
59 goto out;
60 }
61
62 dump_dir = malloc(strlen(dump_root_dir) + 1 +
63 strlen(dump_time_str) + 1);
64 if (!dump_dir) {
65 ret = -ENOMEM;
66 goto out;
67 }
68 sprintf(dump_dir, "%s/%s", dump_root_dir, dump_time_str);
69
70 dump_file = malloc(strlen(dump_dir) + 1 +
71 strlen(dd_hdr->info.name) + 1);
72 if (!dump_file) {
73 ret = -ENOMEM;
74 goto free_dump_dir;
75 }
76 sprintf(dump_file, "%s/%s", dump_dir, dd_hdr->info.name);
77
78 if (stat(dump_dir, &st)) {
79 ret = mkdir(dump_dir, 0775);
80 if (ret) {
81 fprintf(stderr,
82 DUMP_LOG_FMT("mkdir(%s) fail(%s)\n"),
83 dump_dir, strerror(errno));
84 ret = -1;
85 goto free_dump_file;
86 }
87
88 /* TODO: only keep latest three dump directories */
89 }
90
91 fd = open(dump_file, 0664);
92 if (fd < 0) {
93 fprintf(stderr,
94 DUMP_LOG_FMT("open(%s) fail(%s)\n"),
95 dump_file, strerror(errno));
96 ret = -1;
97 goto free_dump_file;
98 }
99
100 /* write information of dump at begining of the file */
101 lseek(fd, 0, SEEK_SET);
102 write(fd, &dd_hdr->info, sizeof(struct dump_info));
103
104 /* write data of dump start from data offset of the file */
105 lseek(fd, dd_hdr->data_offset, SEEK_CUR);
106 write(fd, dd, dd_hdr->data_len);
107
108 close(fd);
109
110 if (dd_hdr->last_frag) {
111 stat(dump_file, &st);
112 if ((size_t)st.st_size != dump_file_size) {
113 fprintf(stderr,
114 DUMP_LOG_FMT("file(%s) size %zu != %zu\n"),
115 dump_file, st.st_size, dump_file_size);
116 ret = -1;
117 goto free_dump_file;
118 }
119 }
120
121free_dump_file:
122 free(dump_file);
123 dump_file = NULL;
124
125free_dump_dir:
126 free(dump_dir);
127 dump_dir = NULL;
128
129out:
130 return ret;
131}
132
133static int read_retry(int fd, void *buf, int len)
134{
135 int out_len = 0;
136 int ret;
137
138 while (len > 0) {
139 ret = read(fd, buf, len);
140 if (ret < 0) {
141 if (errno == EINTR || errno == EAGAIN)
142 continue;
143
144 return -1;
145 }
146
147 if (!ret)
148 return 0;
149
150 out_len += ret;
151 len -= ret;
152 buf += ret;
153 }
154
155 return out_len;
156}
157
158static int mkdir_p(char *path, mode_t mode)
159{
160 struct stat st = { 0 };
161 char *cpy_path = NULL;
162 char *cur_path = NULL;
163 char *tmp_path = NULL;
164 int ret = 0;
165 char *dir;
166
167 cpy_path = malloc(strlen(path) + 1);
168 if (!cpy_path) {
169 ret = -ENOMEM;
170 goto out;
171 }
172 strcpy(cpy_path, path);
173
174 cur_path = malloc(strlen(path) + 1);
175 if (!cur_path) {
176 ret = -ENOMEM;
177 goto free_cpy_path;
178 }
179 memset(cur_path, 0, strlen(path) + 1);
180
181 for (dir = strtok(cpy_path, "/");
182 dir != NULL;
183 dir = strtok(NULL, "/")) {
184 /* keep current path */
185 tmp_path = malloc(strlen(cur_path) + 1);
186 if (!tmp_path) {
187 ret = -ENOMEM;
188 goto free_cur_path;
189 }
190 strcpy(tmp_path, cur_path);
191
192 /* append directory in current path */
193 sprintf(cur_path, "%s/%s", tmp_path, dir);
194
195 free(tmp_path);
196 tmp_path = NULL;
197
198 if (stat(cur_path, &st)) {
199 ret = mkdir(cur_path, mode);
200 if (ret) {
201 fprintf(stderr,
202 DUMP_LOG_FMT("mkdir(%s) fail(%s)\n"),
203 cur_path, strerror(errno));
204 goto free_cur_path;
205 }
206 }
207 }
208
209free_cur_path:
210 free(cur_path);
211 cur_path = NULL;
212
213free_cpy_path:
214 free(cpy_path);
215 cpy_path = NULL;
216
217out:
218 return ret;
219}
220
221int tops_save_dump_data(char *dump_root_dir)
222{
223 struct stat st = { 0 };
224 int ret = 0;
225 int fd;
226
227 if (!dump_root_dir) {
228 ret = -1;
229 goto out;
230 }
231
232 /* reserve 256 bytes for saving name of dump directory and dump file */
233 if (strlen(dump_root_dir) > (PATH_MAX - 256)) {
234 fprintf(stderr,
235 DUMP_LOG_FMT("dump_root_dir(%s) length %zu > %u\n"),
236 dump_root_dir, strlen(dump_root_dir), PATH_MAX - 256);
237 return -1;
238 }
239
240 if (stat(dump_root_dir, &st)) {
241 ret = mkdir_p(dump_root_dir, 0775);
242 if (ret) {
243 fprintf(stderr,
244 DUMP_LOG_FMT("mkdir_p(%s) fail(%d)\n"),
245 dump_root_dir, ret);
246 ret = -1;
247 goto out;
248 }
249 }
250
251 fd = open(DUMP_DATA_PATH, O_RDONLY);
252 if (fd < 0) {
253 fprintf(stderr,
254 DUMP_LOG_FMT("open(%s) fail(%s)\n"),
255 DUMP_DATA_PATH, strerror(errno));
256 ret = -1;
257 goto out;
258 }
259
260 while (1) {
261 char dd[RELAY_DUMP_SUBBUF_SIZE - sizeof(struct dump_data_header)];
262 struct dump_data_header dd_hdr;
263 struct pollfd pfd = {
264 .fd = fd,
265 .events = POLLIN | POLLHUP | POLLERR,
266 };
267
268 poll(&pfd, 1, -1);
269
270 ret = read_retry(fd, &dd_hdr, sizeof(struct dump_data_header));
271 if (ret < 0) {
272 fprintf(stderr,
273 DUMP_LOG_FMT("read dd_hdr fail(%d)\n"), ret);
274 ret = -1;
275 break;
276 }
277
278 if (!ret)
279 continue;
280
281 if (dd_hdr.data_len == 0) {
282 fprintf(stderr,
283 DUMP_LOG_FMT("read empty data\n"));
284 continue;
285 }
286
287 if (dd_hdr.data_len > sizeof(dd)) {
288 fprintf(stderr,
289 DUMP_LOG_FMT("data length %u > %lu\n"),
290 dd_hdr.data_len, sizeof(dd));
291 ret = -1;
292 break;
293 }
294
295 ret = read_retry(fd, dd, dd_hdr.data_len);
296 if (ret < 0) {
297 fprintf(stderr,
298 DUMP_LOG_FMT("read dd fail(%d)\n"), ret);
299 ret = -1;
300 break;
301 }
302
303 if ((uint32_t)ret != dd_hdr.data_len) {
304 fprintf(stderr,
305 DUMP_LOG_FMT("read dd length %u != %u\n"),
306 (uint32_t)ret, dd_hdr.data_len);
307 ret = -1;
308 break;
309 }
310
311 ret = save_dump_data(dump_root_dir, &dd_hdr, dd);
312 if (ret) {
313 fprintf(stderr,
314 DUMP_LOG_FMT("save_dump_data(%s) fail(%d)\n"),
315 dump_root_dir, ret);
316 break;
317 }
318 }
319
320 close(fd);
321
322out:
323 return ret;
324}