automotive-dlt
dlt_offline_trace.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
27 /*******************************************************************************
28 ** **
29 ** SRC-MODULE: dlt_offline_trace.c **
30 ** **
31 ** TARGET : linux **
32 ** **
33 ** PROJECT : DLT **
34 ** **
35 ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
36 ** **
37 ** PURPOSE : **
38 ** **
39 ** REMARKS : **
40 ** **
41 ** PLATFORM DEPENDANT [yes/no]: yes **
42 ** **
43 ** TO BE CHANGED BY USER [yes/no]: no **
44 ** **
45 *******************************************************************************/
46 
47 /*******************************************************************************
48 ** Author Identity **
49 ********************************************************************************
50 ** **
51 ** Initials Name Company **
52 ** -------- ------------------------- ---------------------------------- **
53 ** aw Alexander Wenzel BMW **
54 *******************************************************************************/
55 
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <time.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <fcntl.h>
63 #include <unistd.h>
64 #include <dirent.h>
65 #include <syslog.h>
66 
67 #include <dlt_offline_trace.h>
68 #include "dlt_common.h"
69 
70 unsigned int dlt_offline_trace_storage_dir_info(char *path, char *file_name, char *newest, char *oldest)
71 {
72  int i = 0;
73  unsigned int num = 0;
74  int cnt = 0;
75  struct dirent **files = {0};
76  char *tmp_old = NULL;
77  char *tmp_new = NULL;
78 
79  if (path == NULL || file_name == NULL || newest == NULL || oldest == NULL)
80  {
81  printf("dlt_offline_trace_storage_dir_info: Invalid parameter(s)");
82  return 0;
83  }
84 
85  cnt = scandir(path, &files, NULL, alphasort);
86 
87  if (cnt < 0)
88  {
89  return 0;
90  }
91 
92  for (i = 0; i < cnt; i++)
93  {
94  int len = 0;
95  len = strlen(file_name);
96  if ((strncmp(files[i]->d_name, file_name, len) == 0) && (files[i]->d_name[len] == '.'))
97  {
98  num++;
99 
100  if (tmp_old == NULL || (strlen(tmp_old) >= strlen(files[i]->d_name)))
101  {
102  if (tmp_old == NULL)
103  {
104  tmp_old = files[i]->d_name;
105  }
106  /* when file name is smaller, it is older */
107  else if (strlen(tmp_old) > strlen(files[i]->d_name))
108  {
109  tmp_old = files[i]->d_name;
110  }
111  else /* filename is equal, do a string compare */
112  {
113  if (strcmp(tmp_old, files[i]->d_name) > 0)
114  tmp_old = files[i]->d_name;
115  }
116  }
117 
118  if (tmp_new == NULL || (strlen(tmp_new) <= strlen(files[i]->d_name)))
119  {
120  if (tmp_new == NULL)
121  {
122  tmp_new = files[i]->d_name;
123  }
124  /* when file name is longer, it is younger */
125  else if (strlen(tmp_new) < strlen(files[i]->d_name))
126  {
127  tmp_new = files[i]->d_name;
128  }
129  else
130  {
131  if (strcmp(tmp_new, files[i]->d_name) < 0)
132  {
133  tmp_new = files[i]->d_name;
134  }
135  }
136  }
137  }
138  }
139 
140  if (num > 0)
141  {
142  if (tmp_old != NULL)
143  {
144  if (strlen(tmp_old) < DLT_OFFLINETRACE_FILENAME_MAX_SIZE)
145  {
146  strncpy(oldest, tmp_old, DLT_OFFLINETRACE_FILENAME_MAX_SIZE);
147  }
148  }
149  if (tmp_new != NULL)
150  {
151  if (strlen(tmp_old) < DLT_OFFLINETRACE_FILENAME_MAX_SIZE)
152  {
153  strncpy(newest, tmp_new, DLT_OFFLINETRACE_FILENAME_MAX_SIZE);
154  }
155  }
156  }
157 
158  /* free scandir result */
159  for (i = 0; i < cnt; i++)
160  {
161  free(files[i]);
162  }
163  free(files);
164 
165  return num;
166 }
167 
168 void dlt_offline_trace_file_name(char *log_file_name, char *name, unsigned int idx)
169 {
170  char file_index[11]; // UINT_MAX = 4294967295 -> 10 digits
171  sprintf(file_index, "%010u", idx);
172 
173  // create log file name
174  memset(log_file_name, 0, DLT_OFFLINETRACE_FILENAME_MAX_SIZE * sizeof(char));
175  strncat(log_file_name, name,sizeof(DLT_OFFLINETRACE_FILENAME_BASE));
176  strncat(log_file_name, DLT_OFFLINETRACE_FILENAME_DELI,sizeof(DLT_OFFLINETRACE_FILENAME_DELI));
177  strncat(log_file_name, file_index,sizeof(file_index));
178  strncat(log_file_name, DLT_OFFLINETRACE_FILENAME_EXT,sizeof(DLT_OFFLINETRACE_FILENAME_EXT));
179 }
180 
182 {
183  const char d[2] = ".";
184  char *token;
185  unsigned int idx = 0;
186 
187  if (file[0] == '\0')
188  {
189  return 0;
190  }
191 
192  token = strtok(file, d);
193  /* we are interested in 2. token because of log file name */
194  token = strtok(NULL, d);
195 
196  if (token != NULL)
197  {
198  idx = strtol(token, NULL, 10);
199  }
200  else
201  {
202  idx = 0;
203  }
204  return idx;
205 }
206 
207 
209  time_t t;
210  struct tm *tmp;
211  char outstr[200];
212  char newest[DLT_OFFLINETRACE_FILENAME_MAX_SIZE] = {0};
213  char oldest[DLT_OFFLINETRACE_FILENAME_MAX_SIZE] = {0};
214  unsigned int idx = 0;
215 
216  /* set filename */
217  if(trace->filenameTimestampBased)
218  {
219  int ret = 0;
220  t = time(NULL);
221  tmp = localtime(&t);
222  if (NULL == tmp) {
223  printf("dlt_offline_trace_create_new_file: pointer to tmp is NULL!");
224  return DLT_RETURN_ERROR;
225  }
226  if (strftime(outstr, sizeof(outstr),"%Y%m%d_%H%M%S", tmp) == 0) {
227  }
228  ret = snprintf(trace->filename, NAME_MAX , "%s/dlt_offlinetrace_%s.dlt", trace->directory, outstr);
229  if ((ret < 0) || (ret >= NAME_MAX))
230  {
231  printf("dlt_offlinetrace filename cannot be concatenated\n");
232  return DLT_RETURN_ERROR;
233  }
234  }
235  else
236  {
237  int ret = 0;
238  /* targeting newest file, ignoring number of files in dir returned */
240  idx = dlt_offline_trace_get_idx_of_log_file(newest) + 1;
241 
243  ret = snprintf(trace->filename, NAME_MAX, "%s/%s", trace->directory, outstr);
244  if ((ret < 0) || (ret >= NAME_MAX))
245  {
246  printf("filename cannot be concatenated\n");
247  return DLT_RETURN_ERROR;
248  }
249  }
250 
251 
252  /* open DLT output file */
253  trace->ohandle = open(trace->filename,O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* mode: wb */
254  if (trace->ohandle == -1)
255  {
256  /* trace file cannot be opened */
257  printf("Offline trace file %s cannot be created\n",trace->filename);
258  return DLT_RETURN_ERROR;
259  } /* if */
260 
261  return DLT_RETURN_OK; /* OK */
262 }
263 
265  struct dirent *dp;
266  char filename[256];
267  unsigned long size = 0;
268  struct stat status;
269 
270  /* go through all dlt files in directory */
271  DIR *dir = opendir(trace->directory);
272  while ((dp=readdir(dir)) != NULL) {
273  if(strstr(dp->d_name,DLT_OFFLINETRACE_FILENAME_BASE))
274  {
275  int res = snprintf(filename, sizeof(filename), "%s/%s",trace->directory,dp->d_name);
276  // if the total length of the string is greater than the buffer, silently forget it.
277  // snprintf: a return value of size or more means that the output was truncated
278  // if an output error is encountered, a negative value is returned.
279  if( (unsigned int)res<sizeof(filename) && res>0 )
280  {
281  if(0 == stat(filename,&status))
282  {
283  size += status.st_size;
284  }
285  else
286  printf("Offline trace file %s cannot be stat-ed",filename);
287  }
288  //else
289  //{
290  // dlt_log(3, "dlt_offline_trace_get_total_size: long filename ignored");
291  //}
292  }
293  }
294 
295  closedir(dir);
296 
297  /* return size */
298  return size;
299 }
300 
302  struct dirent *dp;
303  char filename[PATH_MAX+1];
304  char filename_oldest[PATH_MAX+1];
305  unsigned long size_oldest = 0;
306  struct stat status;
307  time_t time_oldest = 0;
308 
309  filename[0] = 0;
310  filename_oldest[0] = 0;
311 
312  /* go through all dlt files in directory */
313  DIR *dir = opendir(trace->directory);
314  while ((dp=readdir(dir)) != NULL) {
315  if(strstr(dp->d_name,DLT_OFFLINETRACE_FILENAME_TO_COMPARE)) {
316  int res = snprintf(filename, sizeof(filename), "%s/%s",trace->directory,dp->d_name);
317  // if the total length of the string is greater than the buffer, silently forget it.
318  // snprintf: a return value of size or more means that the output was truncated
319  // if an output error is encountered, a negative value is returned.
320  if( (unsigned int)res<sizeof(filename) && res>0 )
321  {
322  if(0 == stat(filename,&status))
323  {
324  if(time_oldest == 0 || status.st_mtime < time_oldest) {
325  time_oldest = status.st_mtime;
326  size_oldest = status.st_size;
327  strncpy(filename_oldest,filename,PATH_MAX);
328  filename_oldest[PATH_MAX]=0;
329  }
330  }
331  else
332  printf("Old offline trace file %s cannot be stat-ed",filename);
333  }
334  }
335  }
336  closedir(dir);
337 
338  /* delete file */
339  if(filename_oldest[0]) {
340  if(remove(filename_oldest)) {
341  printf("Remove file %s failed!\n",filename_oldest);
342  return -1; /* ERROR */
343  }
344  }
345  else {
346  printf("No file to be removed!\n");
347  return -1; /* ERROR */
348  }
349 
350  /* return size of deleted file*/
351  return size_oldest;
352 }
353 
355 
356  struct stat status;
357 
358  /* check for existence of offline trace directory */
359  if (stat(trace->directory, &status) == -1)
360  {
361  dlt_vlog(LOG_ERR, "Offline trace directory: %s doesn't exist \n", trace->directory);
362  return DLT_RETURN_ERROR;
363  }
364 
365  /* check for accesibilty of offline trace directory */
366  else if(access(trace->directory, W_OK) != 0)
367  {
368  dlt_vlog(LOG_ERR, "Offline trace directory: %s doesn't have the write access \n", trace->directory);
369  return DLT_RETURN_ERROR;
370  }
371 
372  /* check size of complete offline trace */
373  while((int)dlt_offline_trace_get_total_size(trace) > (trace->maxSize-trace->fileSize))
374  {
375  /* remove oldest files as long as new file will not fit in completely into complete offline trace */
376  if(dlt_offline_trace_delete_oldest_file(trace) < 0) {
377  return DLT_RETURN_ERROR;
378  }
379  }
380 
381  return DLT_RETURN_OK; /* OK */
382 }
383 
384 DltReturnValue dlt_offline_trace_init(DltOfflineTrace *trace,const char *directory,int fileSize,int maxSize,int filenameTimestampBased) {
385 
386  /* init parameters */
387  strncpy(trace->directory,directory,NAME_MAX);
388  trace->directory[NAME_MAX]=0;
389  trace->fileSize = fileSize;
390  trace->maxSize = maxSize;
391  trace->filenameTimestampBased = filenameTimestampBased;
392  /* check complete offlien trace size, remove old logs if needed */
394 
395  return dlt_offline_trace_create_new_file(trace);
396 }
397 
398 DltReturnValue dlt_offline_trace_write(DltOfflineTrace *trace,unsigned char *data1,int size1,unsigned char *data2,int size2,unsigned char *data3,int size3) {
399 
400  if(trace->ohandle <= 0)
401  return DLT_RETURN_ERROR;
402 
403  /* check file size here */
404  if((lseek(trace->ohandle,0,SEEK_CUR)+size1+size2+size3)>=trace->fileSize)
405  {
406  /* close old file */
407  close(trace->ohandle);
408  trace->ohandle = -1;
409 
410  /* check complete offline trace size, remove old logs if needed */
412 
413  /* create new file */
415  }
416 
417  /* write data into log file */
418  if(data1 && (trace->ohandle >= 0)) {
419  if(write(trace->ohandle,data1,size1)!=size1) {
420  printf("Offline trace write failed!\n");
421  return DLT_RETURN_ERROR;
422  }
423  }
424  if(data2 && (trace->ohandle >= 0)) {
425  if(write(trace->ohandle,data2,size2)!=size2) {
426  printf("Offline trace write failed!\n");
427  return DLT_RETURN_ERROR;
428  }
429  }
430  if(data3 && (trace->ohandle >= 0)) {
431  if(write(trace->ohandle,data3,size3)!=size3) {
432  printf("Offline trace write failed!\n");
433  return DLT_RETURN_ERROR;
434  }
435  }
436 
437  return DLT_RETURN_OK; /* OK */
438 }
439 
441 
442  if(trace->ohandle <= 0)
443  return DLT_RETURN_ERROR;
444 
445  /* close last used log file */
446  close(trace->ohandle);
447 
448  return DLT_RETURN_OK; /* OK */
449 }
DltReturnValue dlt_offline_trace_free(DltOfflineTrace *trace)
#define DLT_OFFLINETRACE_FILENAME_BASE
#define DLT_OFFLINETRACE_FILENAME_TO_COMPARE
DltReturnValue
Definition: dlt_types.h:86
DltReturnValue dlt_offline_trace_check_size(DltOfflineTrace *trace)
unsigned int dlt_offline_trace_get_idx_of_log_file(char *file)
DltReturnValue dlt_offline_trace_write(DltOfflineTrace *trace, unsigned char *data1, int size1, unsigned char *data2, int size2, unsigned char *data3, int size3)
char filename[NAME_MAX+1]
#define DLT_OFFLINETRACE_FILENAME_EXT
unsigned int dlt_offline_trace_storage_dir_info(char *path, char *file_name, char *newest, char *oldest)
int dlt_offline_trace_delete_oldest_file(DltOfflineTrace *trace)
DltReturnValue dlt_offline_trace_create_new_file(DltOfflineTrace *trace)
#define DLT_OFFLINETRACE_FILENAME_MAX_SIZE
unsigned long dlt_offline_trace_get_total_size(DltOfflineTrace *trace)
#define DLT_OFFLINETRACE_FILENAME_DELI
void dlt_offline_trace_file_name(char *log_file_name, char *name, unsigned int idx)
char directory[NAME_MAX+1]
DltReturnValue dlt_vlog(int prio, const char *format,...)
Definition: dlt_common.c:2078
DltReturnValue dlt_offline_trace_init(DltOfflineTrace *trace, const char *directory, int fileSize, int maxSize, int filenameTimestampBased)
#define NULL
Definition: dlt_common.h:232