blob: 4169f5a2384ca94db29cb09ca6593fe76e222902 [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
developer1d312742023-09-11 11:05:46 +080022#include "common.h"
developere5e687d2023-08-08 16:05:33 +080023#include "dump.h"
24
developere5e687d2023-08-08 16:05:33 +080025static int save_dump_data(char *dump_root_dir,
26 struct dump_data_header *dd_hdr,
27 char *dd)
28{
29 size_t dump_file_size = dd_hdr->info.size + sizeof(struct dump_info);
30 char dump_time_str[32];
31 struct stat st = { 0 };
32 char *dump_file = NULL;
33 char *dump_dir = NULL;
developerf6c5ced2023-10-03 16:23:42 +080034 size_t path_len;
35 int ret;
developere5e687d2023-08-08 16:05:33 +080036 int fd;
37
38 ret = time_to_str((time_t *)&dd_hdr->info.dump_time_sec,
39 dump_time_str, sizeof(dump_time_str));
40 if (ret < 0) {
41 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +080042 LOG_FMT("time_to_str(%lu) fail(%d)\n"),
developere5e687d2023-08-08 16:05:33 +080043 dd_hdr->info.dump_time_sec, ret);
developerf6c5ced2023-10-03 16:23:42 +080044 return ret;
developere5e687d2023-08-08 16:05:33 +080045 }
46
developerf6c5ced2023-10-03 16:23:42 +080047 /* create the dump directory */
48 path_len = strlen(dump_root_dir) + 1 + strlen(dump_time_str) + 1;
49 dump_dir = malloc(path_len);
50 if (!dump_dir)
51 return -ENOMEM;
52
53 ret = snprintf(dump_dir, path_len, "%s/%s", dump_root_dir, dump_time_str);
54 if (ret < 0)
55 goto free_dump_dir;
56
57 ret = mkdir(dump_dir, 0775);
58 if (ret && errno != EEXIST) {
59 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +080060 LOG_FMT("mkdir(%s) fail(%s)\n"),
developerf6c5ced2023-10-03 16:23:42 +080061 dump_dir, strerror(errno));
62 goto free_dump_dir;
developere5e687d2023-08-08 16:05:33 +080063 }
developere5e687d2023-08-08 16:05:33 +080064
developerf6c5ced2023-10-03 16:23:42 +080065 /* TODO: only keep latest three dump directories */
66
67 /* create the dump file */
68 path_len = strlen(dump_dir) + 1 + strlen(dd_hdr->info.name) + 1;
69 dump_file = malloc(path_len);
developere5e687d2023-08-08 16:05:33 +080070 if (!dump_file) {
71 ret = -ENOMEM;
72 goto free_dump_dir;
73 }
developere5e687d2023-08-08 16:05:33 +080074
developerf6c5ced2023-10-03 16:23:42 +080075 ret = snprintf(dump_file, path_len, "%s/%s", dump_dir, dd_hdr->info.name);
76 if (ret < 0)
77 goto free_dump_file;
developere5e687d2023-08-08 16:05:33 +080078
developer8762a192023-09-04 09:16:22 +080079 fd = open(dump_file, O_WRONLY | O_CREAT, 0664);
developere5e687d2023-08-08 16:05:33 +080080 if (fd < 0) {
81 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +080082 LOG_FMT("open(%s) fail(%s)\n"),
developere5e687d2023-08-08 16:05:33 +080083 dump_file, strerror(errno));
developerf6c5ced2023-10-03 16:23:42 +080084 ret = fd;
developere5e687d2023-08-08 16:05:33 +080085 goto free_dump_file;
86 }
87
developerf6c5ced2023-10-03 16:23:42 +080088 /* write the dump information at the begining of dump file */
89 ret = lseek(fd, 0, SEEK_SET);
90 if (ret < 0) {
91 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +080092 LOG_FMT("lseek fail(%s)\n"),
developerf6c5ced2023-10-03 16:23:42 +080093 strerror(errno));
94 goto close_dump_file;
95 }
96
developere5e687d2023-08-08 16:05:33 +080097 write(fd, &dd_hdr->info, sizeof(struct dump_info));
98
developerf6c5ced2023-10-03 16:23:42 +080099 /* write the dump data start from dump information plus data offset */
100 ret = lseek(fd, dd_hdr->data_offset, SEEK_CUR);
101 if (ret < 0) {
102 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800103 LOG_FMT("lseek fail(%s)\n"),
developerf6c5ced2023-10-03 16:23:42 +0800104 strerror(errno));
105 goto close_dump_file;
106 }
developere5e687d2023-08-08 16:05:33 +0800107
developerf6c5ced2023-10-03 16:23:42 +0800108 write(fd, dd, dd_hdr->data_len);
developere5e687d2023-08-08 16:05:33 +0800109
110 if (dd_hdr->last_frag) {
developerf6c5ced2023-10-03 16:23:42 +0800111 ret = stat(dump_file, &st);
112 if (ret < 0) {
113 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800114 LOG_FMT("stat(%s) fail(%s)\n"),
developerf6c5ced2023-10-03 16:23:42 +0800115 dump_file, strerror(errno));
116 goto close_dump_file;
117 }
118
developere5e687d2023-08-08 16:05:33 +0800119 if ((size_t)st.st_size != dump_file_size) {
120 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800121 LOG_FMT("file(%s) size %zu != %zu\n"),
developere5e687d2023-08-08 16:05:33 +0800122 dump_file, st.st_size, dump_file_size);
developerf6c5ced2023-10-03 16:23:42 +0800123 ret = -EINVAL;
124 goto close_dump_file;
developere5e687d2023-08-08 16:05:33 +0800125 }
126 }
127
developerf6c5ced2023-10-03 16:23:42 +0800128 ret = 0;
129
130close_dump_file:
131 close(fd);
132
developere5e687d2023-08-08 16:05:33 +0800133free_dump_file:
134 free(dump_file);
developere5e687d2023-08-08 16:05:33 +0800135
136free_dump_dir:
137 free(dump_dir);
developere5e687d2023-08-08 16:05:33 +0800138
developere5e687d2023-08-08 16:05:33 +0800139 return ret;
140}
141
142static int read_retry(int fd, void *buf, int len)
143{
144 int out_len = 0;
145 int ret;
146
147 while (len > 0) {
148 ret = read(fd, buf, len);
149 if (ret < 0) {
150 if (errno == EINTR || errno == EAGAIN)
151 continue;
152
developerf6c5ced2023-10-03 16:23:42 +0800153 return ret;
developere5e687d2023-08-08 16:05:33 +0800154 }
155
156 if (!ret)
developerf6c5ced2023-10-03 16:23:42 +0800157 break;
developere5e687d2023-08-08 16:05:33 +0800158
159 out_len += ret;
160 len -= ret;
161 buf += ret;
162 }
163
164 return out_len;
165}
166
developer1d312742023-09-11 11:05:46 +0800167int tops_tool_save_dump_data(int argc, char *argv[])
developere5e687d2023-08-08 16:05:33 +0800168{
developer1d312742023-09-11 11:05:46 +0800169 char *dump_root_dir = argv[2];
developere5e687d2023-08-08 16:05:33 +0800170 int ret = 0;
171 int fd;
172
developerf6c5ced2023-10-03 16:23:42 +0800173 if (!dump_root_dir)
174 return -EINVAL;
developere5e687d2023-08-08 16:05:33 +0800175
176 /* reserve 256 bytes for saving name of dump directory and dump file */
177 if (strlen(dump_root_dir) > (PATH_MAX - 256)) {
178 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800179 LOG_FMT("dump_root_dir(%s) length %zu > %u\n"),
developere5e687d2023-08-08 16:05:33 +0800180 dump_root_dir, strlen(dump_root_dir), PATH_MAX - 256);
developerf6c5ced2023-10-03 16:23:42 +0800181 return -EINVAL;
developere5e687d2023-08-08 16:05:33 +0800182 }
183
developerf6c5ced2023-10-03 16:23:42 +0800184 ret = mkdir_p(dump_root_dir, 0775);
185 if (ret < 0) {
186 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800187 LOG_FMT("mkdir_p(%s) fail(%d)\n"),
developerf6c5ced2023-10-03 16:23:42 +0800188 dump_root_dir, ret);
189 return ret;
developere5e687d2023-08-08 16:05:33 +0800190 }
191
192 fd = open(DUMP_DATA_PATH, O_RDONLY);
193 if (fd < 0) {
194 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800195 LOG_FMT("open(%s) fail(%s)\n"),
developere5e687d2023-08-08 16:05:33 +0800196 DUMP_DATA_PATH, strerror(errno));
developerf6c5ced2023-10-03 16:23:42 +0800197 return fd;
developere5e687d2023-08-08 16:05:33 +0800198 }
199
200 while (1) {
201 char dd[RELAY_DUMP_SUBBUF_SIZE - sizeof(struct dump_data_header)];
202 struct dump_data_header dd_hdr;
203 struct pollfd pfd = {
204 .fd = fd,
205 .events = POLLIN | POLLHUP | POLLERR,
206 };
207
developerf6c5ced2023-10-03 16:23:42 +0800208 ret = poll(&pfd, 1, -1);
209 if (ret < 0) {
210 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800211 LOG_FMT("poll fail(%s)\n"),
developerf6c5ced2023-10-03 16:23:42 +0800212 strerror(errno));
213 break;
214 }
developere5e687d2023-08-08 16:05:33 +0800215
216 ret = read_retry(fd, &dd_hdr, sizeof(struct dump_data_header));
217 if (ret < 0) {
218 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800219 LOG_FMT("read dd_hdr fail(%d)\n"), ret);
developere5e687d2023-08-08 16:05:33 +0800220 break;
221 }
222
223 if (!ret)
224 continue;
225
226 if (dd_hdr.data_len == 0) {
227 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800228 LOG_FMT("read empty data\n"));
developere5e687d2023-08-08 16:05:33 +0800229 continue;
230 }
231
232 if (dd_hdr.data_len > sizeof(dd)) {
233 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800234 LOG_FMT("data length %u > %lu\n"),
developere5e687d2023-08-08 16:05:33 +0800235 dd_hdr.data_len, sizeof(dd));
developerf6c5ced2023-10-03 16:23:42 +0800236 ret = -ENOMEM;
developere5e687d2023-08-08 16:05:33 +0800237 break;
238 }
239
240 ret = read_retry(fd, dd, dd_hdr.data_len);
241 if (ret < 0) {
242 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800243 LOG_FMT("read dd fail(%d)\n"), ret);
developere5e687d2023-08-08 16:05:33 +0800244 break;
245 }
246
247 if ((uint32_t)ret != dd_hdr.data_len) {
248 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800249 LOG_FMT("read dd length %u != %u\n"),
developere5e687d2023-08-08 16:05:33 +0800250 (uint32_t)ret, dd_hdr.data_len);
developerf6c5ced2023-10-03 16:23:42 +0800251 ret = -EAGAIN;
developere5e687d2023-08-08 16:05:33 +0800252 break;
253 }
254
255 ret = save_dump_data(dump_root_dir, &dd_hdr, dd);
256 if (ret) {
257 fprintf(stderr,
developer1d312742023-09-11 11:05:46 +0800258 LOG_FMT("save_dump_data(%s) fail(%d)\n"),
developere5e687d2023-08-08 16:05:33 +0800259 dump_root_dir, ret);
260 break;
261 }
262 }
263
264 close(fd);
265
developere5e687d2023-08-08 16:05:33 +0800266 return ret;
267}