rjw | 1f88458 | 2022-01-06 17:20:42 +0800 | [diff] [blame^] | 1 | /* uint64_t ...*/ |
| 2 | #include <inttypes.h> |
| 3 | #include <stdbool.h> |
| 4 | |
| 5 | /* vprintf, vsnprintf */ |
| 6 | #include <stdio.h> |
| 7 | |
| 8 | /* exit(), atoi() */ |
| 9 | #include <stdlib.h> |
| 10 | |
| 11 | /* getopt, optind */ |
| 12 | #include <unistd.h> |
| 13 | |
| 14 | /* sysenv */ |
| 15 | #include "mrdump_defaults.h" |
| 16 | |
| 17 | /* strcmp */ |
| 18 | #include <string.h> |
| 19 | |
| 20 | #include <getopt.h> |
| 21 | /* mrdump related */ |
| 22 | #include "mrdump_log.h" |
| 23 | #include "mrdump_common.h" |
| 24 | #include "mrdump_status.h" |
| 25 | #include "mrdump_support_ext4.h" |
| 26 | #include "mrdump_support_mpart.h" |
| 27 | |
| 28 | static void usage(const char *prog) __attribute__((noreturn)); |
| 29 | static void usage(const char *prog) |
| 30 | { |
| 31 | printf("Usage\n" |
| 32 | "\t%1$s is-supported\n\n" |
| 33 | "\t%1$s status-get\n" |
| 34 | "\t%1$s status-log\n" |
| 35 | "\t%1$s status-clear\n\n" |
| 36 | "\t%1$s file-setup\n" |
| 37 | "\t%1$s file-allocate n\n" |
| 38 | "\t\tn is 0(disable file output) 1(halfmem) 2(fullmem) >256\n" |
| 39 | "\t%1$s file-extract-core [-r] filename\n" |
| 40 | "\t\t-r\tre-init pre-allocated file\n" |
| 41 | "\t%1$s file-info\n\n" |
| 42 | "\t%1$s mem-size-set n\n" |
| 43 | "\t\tn is between 64 ~ 16384(m), 0 is output total-mem-size\n\n" |
| 44 | "\t%1$s output-set output\n" |
| 45 | "\t\tsetting mrdump output device\n" |
| 46 | "\t\t none\n" |
| 47 | "\t\t null\n" |
| 48 | "\t\t usb\n" |
| 49 | "\t\t partition: mrdump partition\n" |
| 50 | "\t\t internal-storage: ext4, f2fs\n" |
| 51 | "\t%1$s output-get\n" |
| 52 | "\t\tgetting mrdump output device\n", |
| 53 | prog); |
| 54 | exit(1); |
| 55 | } |
| 56 | |
| 57 | static void dump_status_ok(const struct mrdump_status_result *result) |
| 58 | { |
| 59 | printf("Ok\n"); |
| 60 | printf("\tMode: %s\n\tOutput: ", result->mode); |
| 61 | |
| 62 | switch (result->output) { |
| 63 | case MRDUMP_OUTPUT_NULL: |
| 64 | printf("null\n"); |
| 65 | break; |
| 66 | case MRDUMP_OUTPUT_USB: |
| 67 | printf("usb\n"); |
| 68 | break; |
| 69 | case MRDUMP_OUTPUT_DATA_FS: |
| 70 | printf("ext4/data partition\n"); |
| 71 | break; |
| 72 | case MRDUMP_OUTPUT_PARTITION: |
| 73 | printf("dynamic mrdump partition\n"); |
| 74 | break; |
| 75 | default: |
| 76 | printf("not supported\n"); |
| 77 | break; |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | static int file_setup_command(int argc, char * __attribute__((unused)) argv[]) |
| 82 | { |
| 83 | if (!mrdump_is_supported()) { |
| 84 | error("file-setup not allowed in this mode.\n"); |
| 85 | } |
| 86 | if (argc != 1) { |
| 87 | error("Invalid file-setup command argument\n"); |
| 88 | } |
| 89 | mrdump_file_setup(false); |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | static void file_allocate_command(int argc, char *argv[]) |
| 94 | { |
| 95 | if (!mrdump_is_supported()) { |
| 96 | error("file-allocate not allowed in this mode.\n"); |
| 97 | } |
| 98 | if (argc != 2) { |
| 99 | error("Invaid file-allocate command argument\n"); |
| 100 | } |
| 101 | int size_m = atoi(argv[1]); |
| 102 | |
| 103 | if (size_m < 0) |
| 104 | size_m = 0; |
| 105 | |
| 106 | if ((size_m <= 2) || (size_m >= MRDUMP_EXT4_MIN_ALLOCATE)) { |
| 107 | // enable condition: only 0, 1, 2, >256 |
| 108 | mrdump_file_set_maxsize(size_m); |
| 109 | } |
| 110 | else { |
| 111 | error("Invalid dump size %d\n", size_m); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | static int file_extract_core_command(int argc, char *argv[]) |
| 116 | { |
| 117 | int opt; |
| 118 | bool reinit = false; |
| 119 | |
| 120 | while ((opt = getopt(argc, argv, "r")) != -1) { |
| 121 | switch (opt) { |
| 122 | case 'r': |
| 123 | reinit = true; |
| 124 | break; |
| 125 | default: |
| 126 | error("Invalid file-extract-core parameter\n"); |
| 127 | } |
| 128 | } |
| 129 | if (optind >= argc) { |
| 130 | error("Expected filename after options\n"); |
| 131 | } |
| 132 | |
| 133 | const char *fn = argv[optind]; |
| 134 | const char *output_dev = sysenv_get("mrdump_output"); |
| 135 | |
| 136 | MD_LOGI("%s: mrdump_output= %s\n",__func__, output_dev); |
| 137 | |
| 138 | if (output_dev) { |
| 139 | if (!strncmp(output_dev, "partition", 9)) { |
| 140 | MD_LOGI("%s: partition solution\n",__func__); |
| 141 | if (mrdump_file_fetch_zip_coredump_partition(fn)) { |
| 142 | return 0; |
| 143 | } |
| 144 | } |
| 145 | else if (!strncmp(output_dev, "internal-storage", 21)) { |
| 146 | MD_LOGI("%s: ext4 solution\n",__func__); |
| 147 | if (mrdump_file_fetch_zip_coredump(fn)) { |
| 148 | mrdump_file_setup(reinit); |
| 149 | return 0; |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | error("Fetching Coredump data failed\n"); |
| 155 | } |
| 156 | |
| 157 | static int file_info_command(int argc, char * __attribute__((unused)) argv[]) |
| 158 | { |
| 159 | if (argc != 1) { |
| 160 | error("Invalid file-info command argument\n"); |
| 161 | } |
| 162 | |
| 163 | struct mrdump_pafile_info info; |
| 164 | if (mrdump_file_get_info(MRDUMP_EXT4_ALLOCATE_FILE, &info)) { |
| 165 | printf("\tInfo LBA : %" PRIu32 "\n" |
| 166 | "\tAddress LBA : %" PRIu32 "\n" |
| 167 | "\tFile Size : %" PRIu64 "\n" |
| 168 | "\tCoredump Size : %" PRIu64 "\n" |
| 169 | "\tTimestamp : %" PRIx64 "\n", |
| 170 | info.info_lba, info.addr_lba, |
| 171 | info.filesize, info.coredump_size, |
| 172 | info.timestamp |
| 173 | ); |
| 174 | return 0; |
| 175 | } |
| 176 | else { |
| 177 | error("Cannot get pre-allocate file info\n"); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | static void mem_size_set_command(int argc, char *argv[]) |
| 182 | { |
| 183 | char msize[5]; |
| 184 | |
| 185 | if (argc != 2) { |
| 186 | error("Invaid mem-size-set command argument\n"); |
| 187 | } |
| 188 | |
| 189 | int size_m = atoi(argv[1]); |
| 190 | if ((size_m == 0) || ((size_m >= 64) && (size_m <= 16 * 1024))) { |
| 191 | if (size_m != 0) { |
| 192 | snprintf(msize, sizeof(msize), "%d", size_m); |
| 193 | if (sysenv_set("mrdump_mem_size", msize) == 0) { |
| 194 | MD_LOGI("mem-size-set done.\n"); |
| 195 | } |
| 196 | } |
| 197 | else { |
| 198 | if (sysenv_set("mrdump_mem_size", "") == 0) { |
| 199 | MD_LOGI("total-mem-size done.\n"); |
| 200 | } |
| 201 | else { |
| 202 | error("failed to set memory dump size, plz try again later.\n"); |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | else { |
| 207 | error("Invalid memory dump size\n"); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | static void output_set_command(int argc, char *argv[]) |
| 212 | { |
| 213 | if(argc < 2) { |
| 214 | error("Invalid output device, valid input [none, null, usb, partition, internal-storage]\n"); |
| 215 | } |
| 216 | else { |
| 217 | const char *output_dev = argv[1]; |
| 218 | int need_reboot = 0; |
| 219 | const char *prev_output_dev = sysenv_get("mrdump_output"); |
| 220 | |
| 221 | if (strcmp(prev_output_dev, "partition") == 0) { |
| 222 | if (mrdump_check_partition()) { |
| 223 | need_reboot = 1; |
| 224 | } |
| 225 | } |
| 226 | if (strcmp(output_dev, "partition") == 0) { |
| 227 | if (!mrdump_check_partition()) { |
| 228 | error("mrdump partition doesn't exist, cannot dump to partition.\n"); |
| 229 | } |
| 230 | need_reboot = 1; |
| 231 | } |
| 232 | else if (strcmp(output_dev, "none") && |
| 233 | strcmp(output_dev, "null") && |
| 234 | strcmp(output_dev, "usb") && |
| 235 | strcmp(output_dev, "internal-storage")) { |
| 236 | error("Unknown output %s\n", output_dev); |
| 237 | } |
| 238 | |
| 239 | if (sysenv_set("mrdump_output", output_dev) == 0) { |
| 240 | MD_LOGI("mrdump_output = %s\n", output_dev); |
| 241 | } |
| 242 | else { |
| 243 | error("output-set failed.(%s)\n", output_dev); |
| 244 | } |
| 245 | |
| 246 | if (strcmp(output_dev, "internal-storage") == 0) { |
| 247 | mrdump_file_set_maxsize(DEFAULT_FULLMEM); |
| 248 | } |
| 249 | else { |
| 250 | mrdump_file_set_maxsize(DEFAULT_DISABLE); |
| 251 | } |
| 252 | |
| 253 | if (need_reboot) { |
| 254 | if (0 > execl("/system/bin/reboot", "reboot", NULL, NULL)) |
| 255 | error("%s: failed to reboot into LK for partition resize.\n", __func__); |
| 256 | } |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | static void status_get_command(int __attribute((unused)) argc, |
| 261 | char * __attribute ((unused)) argv[]) |
| 262 | { |
| 263 | struct mrdump_status_result result; |
| 264 | if (mrdump_status_get(&result)) { |
| 265 | printf("MT-RAMDUMP\n\tStatus:"); |
| 266 | switch (result.status) { |
| 267 | case MRDUMP_STATUS_NONE: |
| 268 | printf("None\n"); |
| 269 | break; |
| 270 | case MRDUMP_STATUS_FAILED: |
| 271 | printf("Failed\n"); |
| 272 | break; |
| 273 | case MRDUMP_STATUS_OK: |
| 274 | dump_status_ok(&result); |
| 275 | break; |
| 276 | } |
| 277 | } |
| 278 | else { |
| 279 | error("MT-RAMDUMP get status failed\n"); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | static int parse_log_level(const char *log_level) |
| 284 | { |
| 285 | if (strcmp(log_level, "debug") == 0) |
| 286 | return LOG_DEBUG; |
| 287 | else if (strcmp(log_level, "info") == 0) |
| 288 | return LOG_INFO; |
| 289 | else if (strcmp(log_level, "warn") == 0) |
| 290 | return LOG_WARNING; |
| 291 | else if (strcmp(log_level, "error") == 0) |
| 292 | return LOG_ERR; |
| 293 | return LOG_WARNING; |
| 294 | } |
| 295 | |
| 296 | int main(int argc, char *argv[]) |
| 297 | { |
| 298 | int log_level = LOG_WARNING; |
| 299 | int log_syslog = 0; |
| 300 | |
| 301 | static struct option long_options[]= { |
| 302 | {"help", no_argument, 0, 0}, |
| 303 | {"log-level", required_argument, 0, 0}, |
| 304 | {"log-syslog", no_argument, 0, 0}, |
| 305 | {0, 0, 0, 0}, |
| 306 | }; |
| 307 | |
| 308 | while (1) { |
| 309 | int option_index, c; |
| 310 | c = getopt_long(argc, argv, "+", long_options, &option_index); |
| 311 | if (c == -1) |
| 312 | break; |
| 313 | |
| 314 | switch (c) { |
| 315 | case 0: |
| 316 | if (strcmp(long_options[option_index].name, "log-level") == 0) { |
| 317 | log_level = parse_log_level(optarg); |
| 318 | } |
| 319 | else if (strcmp(long_options[option_index].name, "log-syslog") == 0) { |
| 320 | log_syslog = 1; |
| 321 | } |
| 322 | else if (strcmp(long_options[option_index].name, "help") == 0) { |
| 323 | usage(argv[0]); |
| 324 | } |
| 325 | break; |
| 326 | |
| 327 | default: |
| 328 | usage(argv[0]); |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | mdlog_init(log_level, log_syslog); |
| 333 | |
| 334 | const int command_argc = argc - optind; |
| 335 | if (command_argc < 1) { |
| 336 | error("No command given\n"); |
| 337 | } |
| 338 | const char *command = argv[optind]; |
| 339 | char **command_argv = &argv[optind]; |
| 340 | |
| 341 | if (strcmp(command, "is-supported") == 0) { |
| 342 | if (mrdump_is_supported()) { |
| 343 | printf("MT-RAMDUMP support ok\n"); |
| 344 | } |
| 345 | else { |
| 346 | printf("MT-RAMDUMP not support\n"); |
| 347 | } |
| 348 | } |
| 349 | else if (strcmp(command, "status-get") == 0) { |
| 350 | status_get_command(command_argc, command_argv); |
| 351 | } |
| 352 | else if (strcmp(command, "status-log") == 0) { |
| 353 | struct mrdump_status_result result; |
| 354 | bool res = mrdump_status_get(&result); |
| 355 | |
| 356 | printf("=>status line:\n%s\n=>log:\n%s\n", result.status_line, result.log_buf); |
| 357 | if (!res) { |
| 358 | error("MT-RAMDUMP get status failed\n"); |
| 359 | } |
| 360 | } |
| 361 | else if (strcmp(command, "status-clear") == 0) { |
| 362 | if (!mrdump_is_supported()) { |
| 363 | error("MT-RAMDUMP not support\n"); |
| 364 | } |
| 365 | if (!mrdump_status_clear()) { |
| 366 | error("MT-RAMDUMP Status clear failed\n"); |
| 367 | } |
| 368 | } |
| 369 | else if (strcmp(command, "file-setup") == 0) { |
| 370 | file_setup_command(command_argc, command_argv); |
| 371 | } |
| 372 | else if (strcmp(command, "file-allocate") == 0) { |
| 373 | file_allocate_command(command_argc, command_argv); |
| 374 | } |
| 375 | else if (strcmp(command, "file-extract-core") == 0) { |
| 376 | file_extract_core_command(command_argc, command_argv); |
| 377 | } |
| 378 | else if (strcmp(command, "file-info") == 0) { |
| 379 | file_info_command(command_argc, command_argv); |
| 380 | } |
| 381 | else if (strcmp(command, "mem-size-set") == 0) { |
| 382 | mem_size_set_command(command_argc, command_argv); |
| 383 | } |
| 384 | else if (strcmp(command, "output-set") == 0) { |
| 385 | output_set_command(command_argc, command_argv); |
| 386 | } |
| 387 | else if (strcmp(command, "partition") == 0) { |
| 388 | /* ignored "-Wunused-result" */ |
| 389 | if (1 == mrdump_check_partition()) {;} |
| 390 | } |
| 391 | else if (strcmp(command, "output-get") == 0) { |
| 392 | const char *output_dev = sysenv_get("mrdump_output"); |
| 393 | if (!output_dev) { |
| 394 | printf("default\n"); |
| 395 | } |
| 396 | else { |
| 397 | printf("%s\n", output_dev); |
| 398 | } |
| 399 | } |
| 400 | else { |
| 401 | error("Unknown command %s\n", command); |
| 402 | } |
| 403 | |
| 404 | return 0; |
| 405 | } |