/* * tio - a serial device I/O tool * * Copyright (c) 2014-2022 Martin Lund * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #define __STDC_WANT_LIB_EXT2__ 1 // To access vasprintf #include "config.h" #include #include #include #include #include #include #include #include #include "options.h" #include "print.h" #include "error.h" #include "fs.h" #define IS_ESC_CSI_INTERMEDIATE_CHAR(c) ((c >= 0x20) && (c <= 0x3F)) #define IS_ESC_END_CHAR(c) ((c >= 0x30) && (c <= 0x7E)) #define IS_CTRL_CHAR(c) ((c >= 0x00) && (c <= 0x1F)) static FILE *fp = NULL; static char file_buffer[BUFSIZ]; static const char *log_filename = NULL; static char *date_time(void) { static char date_time_string[50]; struct tm *tm; struct timeval tv; gettimeofday(&tv, NULL); tm = localtime(&tv.tv_sec); strftime(date_time_string, sizeof(date_time_string), "%Y-%m-%dT%H:%M:%S", tm); return date_time_string; } int log_open(const char *filename) { char *automatic_filename; char *dir_plus_automatic_filename; if (filename == NULL) { // Generate filename if none provided if (option.auto_connect == AUTO_CONNECT_DIRECT) { // File name format ("tio_TARGET_YYYY-MM-DDTHH:MM:SS.log") asprintf(&automatic_filename, "tio_%s_%s.log", basename((char *)option.target), date_time()); } else { // If using 'new' or 'latest' autoconnect strategy we simply use strategy // name to name autogenerated log name as device names may vary asprintf(&automatic_filename, "tio_%s_%s.log", option_auto_connect_state_to_string(option.auto_connect), date_time()); } if (option.log_directory != NULL) { if (fs_dir_exists(option.log_directory) == false) { tio_error_printf("Log directory not found"); exit(EXIT_FAILURE); } asprintf(&dir_plus_automatic_filename, "%s/%s", option.log_directory, automatic_filename); filename = dir_plus_automatic_filename; } else { filename = automatic_filename; } } log_filename = filename; // Open log file if (option.log_append) { // Append to existing log file fp = fopen(filename, "a+"); } else { // Truncate existing log file fp = fopen(filename, "w+"); } if (fp == NULL) { tio_warning_printf("Could not open log file %s (%s)", filename, strerror(errno)); return -1; } // Enable line buffering setvbuf(fp, file_buffer, _IOLBF, BUFSIZ); return 0; } bool log_strip(char c) { static char previous_char = 0; static bool esc_sequence = false; bool strip = false; /* Detect if character should be stripped or not */ switch (c) { case 0xa: /* Line feed / new line */ /* Reset ESC sequence just in case something went wrong with the * escape sequence parsing. */ esc_sequence = false; break; case 0x1b: /* Escape */ strip = true; break; case 0x5b: /* Left bracket */ if (previous_char == 0x1b) { // Start of ESC sequence esc_sequence = true; strip = true; } break; default: if (IS_CTRL_CHAR(c)) { /* Strip ASCII control characters */ strip = true; break; } else if ((esc_sequence) && (IS_ESC_CSI_INTERMEDIATE_CHAR(c))) { strip = true; break; } else if ((esc_sequence) && (IS_ESC_END_CHAR(c))) { esc_sequence = false; strip = true; break; } break; } previous_char = c; return strip; } void log_printf(const char *format, ...) { if (fp == NULL) { return; } char *line; va_list(args); va_start(args, format); vasprintf(&line, format, args); va_end(args); fwrite(line, strlen(line), 1, fp); free(line); } void log_putc(char c) { if (fp == NULL) { return; } if (option.output_mode == OUTPUT_MODE_HEX) { fprintf(fp, "%02x ", (unsigned char) c); } else { if (option.log_strip) { if (log_strip(c) == false) { fputc(c, fp); } } else { fputc(c, fp); } } } void log_close(void) { if (fp != NULL) { fclose(fp); tio_printf("Saved log to file %s", log_filename); fp = NULL; log_filename = NULL; } } void log_exit(void) { if ((option.log) && (log_filename != NULL)) { log_close(); } } const char *log_get_filename(void) { return log_filename; }