blob: abdcf3f5aa464d885ee5d8f0969c1ede6e520ea2 [file] [log] [blame]
From f850acdbe3bf2e5812f56d303add96ec3dc8f0a8 Mon Sep 17 00:00:00 2001
From: Dumpeti Sathish Kumar <sdumpeti@codeaurora.org>
Date: Tue, 20 Apr 2021 19:38:20 +0530
Subject: [PATCH] ODL-support-on-Open-Source-Diag-Router
---
tools/diag-log_on_device.c | 643 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 643 insertions(+)
create mode 100644 tools/diag-log_on_device.c
diff --git a/tools/diag-log_on_device.c b/tools/diag-log_on_device.c
new file mode 100644
index 0000000..03a67f8
--- /dev/null
+++ b/tools/diag-log_on_device.c
@@ -0,0 +1,643 @@
+/*
+ * Copyright (c) 2021 The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/select.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define FILE_LIST_NAME_SIZE 100
+#define MAX_FILES_IN_FILE_LIST 100
+#define std_strlprintf snprintf
+#define LOG_FILENAME_PREFIX_LEN 9
+#define READ_BUF_SIZE 100000
+#define DISK_BUF_SIZE 8192
+#define CONTROL_CHAR 0x7E
+#define USER_SPACE_DATA_TYPE 0x00000020
+#define USER_SPACE_RAW_DATA_TYPE 0x00000080
+#define FILE_NAME_LEN 500
+#define MASK_FILE_BUF_SIZE 8192
+
+struct buffer_pool {
+ unsigned int bytes_in_buff;
+ unsigned char buffer_ptr[DISK_BUF_SIZE];
+};
+
+/*Static declaration of buffer. */
+struct buffer_pool pools[] = {
+ [0] = {
+ .bytes_in_buff = 0,
+ },
+ [1] = {
+ .bytes_in_buff = 0,
+ },
+
+};
+
+typedef uint32_t uint32;
+typedef uint8_t uint8;
+
+pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Thread Handlers */
+pthread_t read_thread_hdl; /* Diag Read thread handle */
+pthread_t write_thread_hdl; /* Diag disk write thread handle */
+
+/* Global Declarations */
+int curr_read = 0;
+int curr_write = 0;
+unsigned char read_buffer[READ_BUF_SIZE];
+char output_dir[FILE_NAME_LEN] = {"/tmp"};
+char mask_clear_file[] = "/tmp/diag_mask.cfg";
+int fd_dev = -1; // Socket Descriptor
+int fd_device = -1; //FIle Descriptor
+char timestamp_buf[30];
+char file_name_curr[FILE_NAME_LEN];
+static char *open_mask_file= NULL;
+static int diag_mask_file = 0;
+static int diag_timeout;
+int num_bytes_read;
+unsigned int max_file_num = 10;
+static unsigned int file_count = 0;
+int file_list_size;
+unsigned long max_file_size = 100000000;
+unsigned long min_file_size = 80000000;
+unsigned static long count_written_bytes;
+char* file_list = NULL;
+int file_list_index = -1;
+char file_name_del[FILE_NAME_LEN];
+int overflow_flag = 0;
+int cleanup_mask;
+
+
+/* Function to get timestamp */
+void get_time_string(char *buffer, int len)
+{
+ struct timeval tv;
+ struct tm *tm;
+ unsigned long long milliseconds = 0;
+ char timestamp_buf[30];
+
+ if (!buffer || len <= 0)
+ return;
+
+ gettimeofday(&tv, NULL);
+ tm = localtime(&tv.tv_sec);
+ if (!tm)
+ return;
+
+ milliseconds = (tv.tv_sec * 1000LL) + (tv.tv_usec / 1000);
+ strftime(timestamp_buf, 30, "%Y%m%d_%H%M%S", tm);
+ (void)snprintf(buffer, len, "%s%lld",
+ timestamp_buf, milliseconds);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "User space application for diag interface\n"
+ "\n"
+ "usage: diag [-of]\n"
+ "\n"
+ "options:\n"
+ "-o <output directory>\n"
+ "-f <Diag Configuration file>\n"
+ "-t <Log Timeout>\n"
+ "-n <number of log files>\n"
+ "-s <Size in MB>\n"
+ "-c <Cleanup Modem Mask>\n"
+ );
+ exit(1);
+}
+
+
+int send_empty_mask(int type)
+{
+ int fd_mask, ch, ret;
+ const uint8 size = 40;
+ unsigned char mask_buf[size];
+ int count_mask_bytes = 4;
+ *(int *)mask_buf = USER_SPACE_RAW_DATA_TYPE;
+ FILE *mask_fp = NULL;
+
+ if ((mask_fp = fopen(mask_clear_file, "rb")) == NULL) {
+ printf("can't open mask clear file: %s, errno: %d\n", mask_clear_file,errno);
+ return -1;
+ }
+ while(1)
+ {
+ ch = fgetc(mask_fp);
+ if(ch == EOF)
+ break;
+
+ mask_buf[count_mask_bytes] = ch;
+ if (mask_buf[count_mask_bytes] == CONTROL_CHAR) {
+ ret = write(fd_dev, mask_buf, count_mask_bytes-1);
+ if(ret < 0) {
+ printf("Write Error on the Socket: errno = %d\n", errno);
+ return -1;
+ }
+ *(int *)mask_buf = USER_SPACE_DATA_TYPE;
+ count_mask_bytes = 4;
+ } else {
+ count_mask_bytes++;
+ }
+ }
+ fclose(mask_fp);
+
+ return 0;
+}
+
+
+static void log_timeout(int sig, siginfo_t *siginfo, void *context)
+{
+ int ret;
+ printf ("Sending PID: %ld, UID: %ld\n",
+ (long)siginfo->si_pid, (long)siginfo->si_uid);
+ ret = send_empty_mask(0);
+ if(ret < 0)
+ printf("Couldn't open Mask clear file.\n");
+
+ close(fd_device);
+ close(fd_dev);
+ pthread_cancel(read_thread_hdl);
+ pthread_cancel(write_thread_hdl);
+}
+int close_logging_file()
+{
+ int status;
+ char timestamp_buf[30];
+ char new_filename[FILE_NAME_LEN];
+
+ close(fd_device);
+ /* check whether number of files in /tmp. Delete if we exceed the limit */
+ if(file_count > max_file_num) {
+ printf("Delete Oldest File.\n");
+ if (!delete_log()) {
+ file_count--;
+ }
+ }
+ get_time_string(timestamp_buf, sizeof(timestamp_buf));
+ snprintf(new_filename,
+ FILE_NAME_LEN, "%s%s%s%s",
+ output_dir,"/diag_log_",
+ timestamp_buf, ".qmdl");
+
+ fd_device = open(new_filename,
+ O_CREAT | O_RDWR | O_SYNC | O_TRUNC,
+ 0644);
+ if(fd_device < 0) {
+ printf(" File open error: %d\n", errno);
+ return -1;
+ }
+ else {
+ file_count++;
+ }
+ strncpy(file_name_curr, new_filename, FILE_NAME_LEN);
+ return 0;
+}
+
+static void *WriteThread(void *data)
+{
+ unsigned int chunks, last_chunk;
+ struct stat finfo;
+ int ret;
+ while(1) {
+ pthread_mutex_lock(&lock);
+ pthread_cond_wait(&cond1, &lock);
+ ret = write(fd_device,pools[curr_write].buffer_ptr,DISK_BUF_SIZE);
+ if(ret > 0) {
+ pools[curr_write].bytes_in_buff = 0;
+ } else if (ret < 0) {
+ goto fail;
+ }
+ /* Check whether we reached to MAX size of the File */
+ if(fstat(fd_device, &finfo) == 0) {
+ if(finfo.st_size > min_file_size) {
+ ret = close_logging_file();
+ if(ret < 0)
+ goto fail;
+ count_written_bytes = 0;
+ }
+ }
+ else {
+ goto fail;
+ }
+ pthread_mutex_unlock(&lock);
+ curr_write =! curr_write;
+ }
+fail:
+ pthread_cancel(read_thread_hdl);
+ close(fd_dev);
+ close(fd_device);
+}
+/* Read Thread */
+static void *CreateWaitThread(void* data)
+{
+ int read_bytes = 0,type,num_data_fields;
+ uint32 count_received_bytes;
+ unsigned char* ptr;
+
+ while(1) {
+ num_bytes_read = 0;
+ memset(read_buffer, 0, READ_BUF_SIZE);
+ num_bytes_read = read(fd_dev, (void*)read_buffer,READ_BUF_SIZE);
+ if(!num_bytes_read || (num_bytes_read < 0))
+ goto read_failure;
+
+ type = *(int *)read_buffer;
+ ptr = read_buffer+4;
+ num_data_fields = *(int *)ptr;
+ ptr += 4;
+ count_received_bytes = *(uint32*)ptr;
+ ptr += sizeof(uint32);
+ count_written_bytes += num_bytes_read;
+ if(count_received_bytes >= (DISK_BUF_SIZE - pools[curr_read].bytes_in_buff)) {
+ /* Trigger Write Thread */
+ curr_read =! curr_read;
+ pthread_cond_signal(&cond1);
+ }
+
+ if(count_received_bytes > 0) {/* Buffer space is available */
+ memcpy(pools[curr_read].buffer_ptr + pools[curr_read].bytes_in_buff, ptr, count_received_bytes);
+ pools[curr_read].bytes_in_buff += count_received_bytes;
+ }
+ }
+
+read_failure:
+ close(fd_dev);
+ close(fd_device);
+ pthread_cancel(write_thread_hdl);
+}
+
+static int create_oldest_file_list(char *oldest_dir)
+{
+
+ int status = 1;
+ struct dirent **dirent_list;
+ int i,n,type=0;
+ int num_entries = 0;
+ int num_entries_capped = 0;
+ char *name_ptr;
+ int num_bytes = 0;
+
+ num_entries = scandir(oldest_dir, &dirent_list, 0,(int(*)(const struct dirent **, const struct dirent **))alphasort);
+ if(!dirent_list) {
+ printf("In %s, couldn't get the dirent_list, errno: %d, directory: %s\n",
+ __func__, errno, oldest_dir);
+ return 0;
+ } else if (num_entries < 0) {
+ printf("In %s, error determining directory entries, errno: %d, directory: %s\n",
+ __func__, errno, oldest_dir);
+ return 0;
+ }
+
+ /* Limit the size of the list so we aren't working with too many files */
+ num_entries_capped = (num_entries > MAX_FILES_IN_FILE_LIST) ?
+ MAX_FILES_IN_FILE_LIST : num_entries;
+
+ if (num_entries_capped - 2 > 0) {
+ file_list_size = num_entries_capped - 2;
+ num_bytes = FILE_LIST_NAME_SIZE * file_list_size;
+ file_list = malloc(num_bytes);
+ }
+
+ if (file_list) {
+ file_list_index = 0;
+ for (i = 0; i < num_entries_capped; i++)
+ {
+ if ((strncmp(dirent_list[i]->d_name, "diag_log_",LOG_FILENAME_PREFIX_LEN) != 0))
+ continue;
+ if (file_list_index < file_list_size)
+ {
+ name_ptr = file_list +
+ (file_list_index * FILE_LIST_NAME_SIZE);
+ strncpy(name_ptr, dirent_list[i]->d_name, FILE_LIST_NAME_SIZE);
+ *(name_ptr + (FILE_LIST_NAME_SIZE - 1)) = 0;
+ file_list_index++;
+ }
+ if (file_list_index > 0) {
+ if (file_list_index < file_list_size) {
+ int new_size = FILE_LIST_NAME_SIZE *file_list_index;
+ char *temp_ptr = realloc(file_list, new_size);
+ if (temp_ptr)
+ file_list = temp_ptr;
+ }
+ file_list_size = file_list_index;
+ }
+ }
+ }
+ else if (num_bytes > 0) {
+ printf("Memory Allocation error.\n");
+ status = 0;
+ }
+
+ i = num_entries;
+ while (i--) {
+ free(dirent_list[i]);
+ }
+
+ free(dirent_list);
+ return status;
+}
+
+static int get_oldest_file(char* oldest_file, char *oldest_dir)
+{
+ int status = 0;
+ status = create_oldest_file_list(oldest_dir);
+
+ if (file_list) {
+ if (oldest_file) {
+ strncpy(oldest_file, file_list,
+ FILE_LIST_NAME_SIZE);
+ file_list_index++;
+ status = 1;
+ } else {
+ printf("In %s, oldest_file is NULL\n", __func__);
+ }
+
+ }else {
+ status =0;
+ printf("No Log files in the dicrectory.\n");
+ }
+
+ return status;
+}
+/* Number of Log file in /tmp directory */
+static int get_file_count(char *oldest_dir)
+{
+ struct dirent **dirent_list;
+ int i,num_entries = 0;
+ int num_entries_capped = 0;
+
+ num_entries = scandir(oldest_dir, &dirent_list, 0,(int(*)(const struct dirent **, const struct dirent **))alphasort);
+ if(!dirent_list) {
+ printf("In %s, couldn't get the dirent_list, errno: %d, directory: %s\n",
+ __func__, errno, oldest_dir);
+ return 0;
+ } else if (num_entries < 0) {
+ printf("In %s, error determining directory entries, errno: %d, directory: %s\n",
+ __func__, errno, oldest_dir);
+ return 0;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ if ((strncmp(dirent_list[i]->d_name, "diag_log_",LOG_FILENAME_PREFIX_LEN) != 0))
+ continue;
+ file_count++;
+ }
+ return file_count;
+}
+
+int delete_log()
+{
+ int status;
+ char oldest_file[FILE_LIST_NAME_SIZE] = "";
+ struct stat file_stat;
+
+ status = get_oldest_file(oldest_file,
+ output_dir);
+ if (0 == status) {
+ printf("diag: In %s, Unable to determine oldest file for deletion\n",
+ __func__);
+ return -1;
+ }
+ std_strlprintf(file_name_del,
+ FILE_NAME_LEN, "%s%s%s",
+ output_dir, "/", oldest_file);
+ if (!strncmp(file_name_curr, file_name_del, FILE_NAME_LEN)) {
+ printf("diag: In %s, Cannot delete file, file %s is in use \n",
+ __func__, file_name_curr);
+ return -1;
+ }
+ stat(file_name_del, &file_stat);
+ /* Convert size to KB */
+ file_stat.st_size /= 1024;
+ if (unlink(file_name_del)) {
+ printf("In %s, Unable to delete file: %s, errno: %d\n",
+ __func__, file_name_del, errno);
+ return -1;
+ } else {
+ printf("In %s, Deleting logfile %s of size %lld KB\n",
+ __func__, file_name_del,
+ (long long int) file_stat.st_size);
+ free(file_list);
+ }
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret;
+ int c,ch,found_cmd;
+ struct sockaddr_un addr;
+ struct timeval tv = {20, 0};
+ struct sigaction act;
+ int count_mask_bytes = 0;
+ unsigned char mask_buf[MASK_FILE_BUF_SIZE];
+ FILE *read_mask_fp;
+ *(int *)mask_buf = USER_SPACE_DATA_TYPE;
+
+ count_mask_bytes = 4;
+ memset (&act, '\0', sizeof(act));
+ act.sa_sigaction = &log_timeout;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGALRM, &act, NULL) < 0) {
+ perror ("sigaction");
+ return 1;
+ }
+
+ for (;;) {
+ c = getopt(argc, argv, "hf:o:t:s");
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case 'c':
+ cleanup_mask = 1;
+ break;
+
+ case 's':
+ max_file_size = atol(optarg);
+ if ((long)max_file_size <= 0)
+ max_file_size = 100000000;
+ else {
+ max_file_size *= 1024 * 1024;
+ if (max_file_size >= 0 && max_file_size < 1024 * 1024)
+ max_file_size = 100000000;
+ }
+ min_file_size = ((max_file_size / 100) * 80);
+ break;
+
+ case 'o':
+ file_count = get_file_count(output_dir);
+ printf("QMDL File Count in /tmp Directory = %d\n", file_count);
+
+ if(max_file_num > 1 && (file_count >= max_file_num)) { /* Check file_count before creating the Log File. */
+ printf("In %s, File count reached max file num %u so deleting oldest file\n",__func__, max_file_num);
+
+ while(file_count > max_file_num)
+ if (!delete_log()) {
+ file_count--;
+ }
+ }
+
+ get_time_string(timestamp_buf, sizeof(timestamp_buf));
+ snprintf(file_name_curr,
+ FILE_NAME_LEN, "%s%s%s%s",
+ output_dir,"/diag_log_",
+ timestamp_buf, ".qmdl");
+ fd_device = open(file_name_curr,
+ O_CREAT | O_RDWR | O_SYNC | O_TRUNC,
+ 0644);
+ if(fd_device < 0) {
+ printf(" File open error: %d\n", errno);
+ return -1;
+ }
+ else {
+ file_count++;
+ }
+ break;
+
+ case 'f':
+ open_mask_file = strdup(optarg);
+ diag_mask_file = 1;
+ break;
+ case 't':
+ printf("Timeout for QMDL Logging\n");
+ diag_timeout = atoi(optarg);
+ printf("Time out value = %d\n", diag_timeout);
+ alarm(diag_timeout);
+ break;
+ default:
+ case 'h':
+ usage();
+ break;
+ }
+ }
+
+ fd_dev = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if (fd_dev < 0)
+ goto failure_case3;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, "\0diag", sizeof(addr.sun_path)-1);
+
+ ret = connect(fd_dev, (struct sockaddr*)&addr, sizeof(addr));
+ if (ret < 0)
+ goto failure_case2;
+
+ pthread_create(&read_thread_hdl, NULL, CreateWaitThread, NULL);
+ if(read_thread_hdl == 0) {
+ printf("Failed to create Read Thread.\n");
+ goto failure_case2;
+ }
+ pthread_create(&write_thread_hdl, NULL, WriteThread, NULL);
+ if(write_thread_hdl == 0) {
+ printf("Failed to create Write Thread.\n");
+ if(read_thread_hdl == 0)
+ pthread_cancel(read_thread_hdl);
+ goto failure_case2;
+ }
+
+ if ((read_mask_fp = fopen(open_mask_file, "rb")) == NULL) {
+ printf("can't open mask file: %s, errno: %d\n", open_mask_file,errno);
+ goto failure_case1;
+ }
+
+ if(diag_mask_file){
+ while(1){
+ ch = fgetc(read_mask_fp);
+ if (ch == EOF)
+ break;
+ mask_buf[count_mask_bytes] = ch;
+ if (mask_buf[count_mask_bytes] == CONTROL_CHAR) {
+
+ if (!found_cmd)
+ found_cmd = 1;
+ ret = write(fd_dev, mask_buf, count_mask_bytes+1);
+ if(ret < 0) {
+ printf("Write Error on the Socket: errno = %d\n", errno);
+ goto failure_case0;
+ }
+
+ *(int *)mask_buf = USER_SPACE_DATA_TYPE;
+ count_mask_bytes = 4;
+ } else {
+ count_mask_bytes++;
+ }
+ }
+ if(!found_cmd){
+ printf("No command found:\n");
+ }
+ }
+ while(1)
+ sleep(3600);
+
+failure_case0:
+ fclose(read_mask_fp);
+
+failure_case1:
+ pthread_cancel(read_thread_hdl);
+ pthread_cancel(write_thread_hdl);
+
+failure_case2:
+ close(fd_dev);
+
+failure_case3:
+ close(fd_device);
+
+ return 0;
+}
--
2.7.4