4 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
26 #include <sys/types.h>
31 #include "diagnostics/diagnostics.h"
33 #define LOG_TAG "CRASH_MANAGER"
36 #include "shared/log.h"
37 #include "shared/util.h"
38 #include "shared/config.h"
40 #define SHARE_BASE_DIR "/run/diagnostics/priv/fifo"
41 #define TMP_FILE_TEMPLATE "file_XXXXXX"
43 #define JSON_FILE_EXT ".json"
44 #define ZIP_FILE_EXT ".zip"
46 enum diagnostics_type {
53 static char *type_to_str(enum diagnostics_entry entry) {
64 static char *get_temp_file_name()
67 if (asprintf(&result, "%s/%s", SHARE_BASE_DIR, TMP_FILE_TEMPLATE) == -1) {
68 _E("asprintf() error: %m\n");
72 if (mktemp(result) == NULL || result[0] == '\0') {
73 _E("mktemp() error: %m\n");
81 static bool is_report_file(const char *path, const char *reports_dir)
86 char *r_path = realpath(path, NULL);
88 _E("realpath() for %s error: %m\n", path);
92 if (access(r_path, F_OK) == -1) {
93 _E("access() for %s error: %m\n", path);
97 char *start = strstr(r_path, reports_dir);
100 _I("%s is not within %s\n", r_path, reports_dir);
107 static enum diagnostics_type check_report_type(const char *path)
111 if (strstr(path, JSON_FILE_EXT) == &path[strlen(path) - strlen(JSON_FILE_EXT)]) {
112 _D("Report type of %s is JSON_FILE\n", path);
116 if (strstr(path, ZIP_FILE_EXT) == &path[strlen(path) - strlen(ZIP_FILE_EXT)]) {
117 _D("Report type of %s is FULL_REPORT\n", path);
118 return BT_FULL_REPORT;
121 struct stat file_stat;
122 if (stat(path, &file_stat) == -1) {
123 _E("stat() for %s error: %m\n", path);
127 if (stat(path, &file_stat) == 0 && S_ISDIR(file_stat.st_mode)) {
128 _D("Report type of %s is DIR", path);
132 _I("Report type of %s is UNKNOWN", path);
136 static bool ends_with(const char *string, const char *end)
141 ssize_t end_len = strlen(end);
142 ssize_t string_len = strlen(string);
144 if (end_len == 0 || end_len > string_len)
147 return strcasecmp(&string[string_len - end_len], end) == 0;
150 static bool file_match(const char *file_name, enum diagnostics_entry entry)
156 return ends_with(file_name, JSON_FILE_EXT);
162 static bool extract_file(zip_t *archive, int index, const char *out_file_name)
165 zip_file_t *zfile = NULL;
167 int extracted_fd = open(out_file_name, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
168 if (extracted_fd < 0) {
169 _E("open() file \"%s\" for write error: %m\n", out_file_name);
173 struct zip_stat stat;
174 if (zip_stat_index(archive, index, ZIP_FL_UNCHANGED, &stat) == -1) {
175 printf("zip_stat_index() error\n");
179 zfile = zip_fopen_index(archive, index, ZIP_FL_UNCHANGED);
181 _E("zip_fopen_index() error\n");
186 zip_uint64_t sum = 0;
188 while (sum < stat.size) {
189 zip_int64_t len = zip_fread(zfile, buff, sizeof(buff));
191 _E("zip_fread() error\n");
194 if (write(extracted_fd, buff, len) == -1) {
195 _E("write() error: %m\n");
206 if (extracted_fd >= 0)
212 static int search_file_in_zip(zip_t *archive, enum diagnostics_entry entry)
214 zip_int64_t count = zip_get_num_entries(archive, ZIP_FL_UNCHANGED);
216 for (zip_int64_t i = 0; i < count; i++) {
217 const char *entry_name = zip_get_name(archive, i, ZIP_FL_ENC_GUESS);
218 if (entry_name == NULL) {
219 _E("zip_get_name() error\n");
223 if (!file_match(entry_name, entry))
231 static int share_compressed_file(const char *path, enum diagnostics_entry entry)
236 int fd = -BR_ERR_INTERNAL;
238 char *out_file = get_temp_file_name();
240 if (out_file == NULL)
241 return -BR_ERR_INTERNAL;
243 zip_t *archive = zip_open(path, ZIP_RDONLY, &err);
245 _E("zip_open() %s error: %d\n", path, err);
250 int file_index = search_file_in_zip(archive, entry);
251 if (file_index < 0) {
252 _I("Archive \"%s\" doesn't contain file type: %s", path, type_to_str(entry));
257 if (extract_file(archive, file_index, out_file)) {
258 fd = open(out_file, O_RDONLY);
260 _E("open() file \"%s\" for read error: %m", out_file);
263 _D("share file %s from \"%s\" as \"%s\"", type_to_str(entry), path, out_file);
274 static int share_file(const char *path)
278 const char *dest_file = get_temp_file_name();
280 if (dest_file == NULL)
281 return -BR_ERR_INTERNAL;
283 _D("share file \"%s\" as \"%s\"", path, dest_file);
285 if (copy_file(dest_file, path) == -1) {
286 _E("copy_file() error");
287 return -BR_ERR_INTERNAL;
290 int fd = open(dest_file, O_RDONLY);
292 _E("open() file: \"%s\" error: %m\n", path);
293 return -BR_ERR_INTERNAL;
300 static int share_uncompressed_file(const char *path, enum diagnostics_entry entry)
306 int result = -BR_ERR_PARAM;
307 if ((dir = opendir(path)) == NULL) {
308 _E("opendir() for \"%s\" error: %m\n", path);
309 result = -BR_ERR_INTERNAL;
313 while((ent = readdir(dir)) != NULL) {
314 if (file_match(ent->d_name, entry)) {
315 char file_path[PATH_MAX];
316 int ret = snprintf(file_path, PATH_MAX, "%s/%s", path, ent->d_name);
319 _E("sprintf() error: %m");
320 result = -BR_ERR_INTERNAL;
322 } else if (ret >= PATH_MAX) {
323 _E("sprintf(): result string is too long");
324 result = -BR_ERR_INTERNAL;
327 result = share_file(file_path);
333 _I("Report \"%s\" doesn't contain requested entry type.", path);
342 static int share_simple_file(const char *path, enum diagnostics_entry entry)
346 if (entry != INFO_JSON) {
347 _E("Unsupported file type for report \"%s\" (%s)\n", path, type_to_str(entry));
348 return -BR_ERR_PARAM;
351 return share_file(path);
354 int diagnostics_report_get_file(const char *report_path,
355 const enum diagnostics_entry entry)
360 if (!config_init(&config, CRASH_MANAGER_CONFIG_PATH))
361 return -BR_ERR_INTERNAL;
363 bool is_report = is_report_file(report_path, config.crash_root_path);
364 config_free(&config);
367 _E("File \"%s\" doesn't look like a report.", report_path);
368 return -BR_ERR_PARAM;
371 enum diagnostics_type rtype = check_report_type(report_path);
375 return share_simple_file(report_path, entry);
378 if (entry == FULL_REPORT)
379 return share_file(report_path);
380 return share_compressed_file(report_path, entry);
383 return share_uncompressed_file(report_path, entry);
386 _E("%s is an unsupported report file.", report_path);
387 return -BR_ERR_PARAM;