Line data Source code
1 : /*
2 : * SPDX license identifier: MPL-2.0
3 : *
4 : * Copyright (C) 2011-2015, BMW AG
5 : *
6 : * This file is part of COVESA Project DLT - Diagnostic Log and Trace.
7 : *
8 : * This Source Code Form is subject to the terms of the
9 : * Mozilla Public License (MPL), v. 2.0.
10 : * If a copy of the MPL was not distributed with this file,
11 : * You can obtain one at http://mozilla.org/MPL/2.0/.
12 : *
13 : * For further information see http://www.covesa.org/.
14 : */
15 :
16 : /*!
17 : * \author Alexander Wenzel <alexander.aw.wenzel@bmw.de>
18 : *
19 : * \copyright Copyright © 2011-2015 BMW AG. \n
20 : * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
21 : *
22 : * \file dlt-convert.c
23 : */
24 :
25 : /*******************************************************************************
26 : ** **
27 : ** SRC-MODULE: dlt-convert.c **
28 : ** **
29 : ** TARGET : linux **
30 : ** **
31 : ** PROJECT : DLT **
32 : ** **
33 : ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
34 : ** Markus Klein **
35 : ** **
36 : ** PURPOSE : **
37 : ** **
38 : ** REMARKS : **
39 : ** **
40 : ** PLATFORM DEPENDANT [yes/no]: yes **
41 : ** **
42 : ** TO BE CHANGED BY USER [yes/no]: no **
43 : ** **
44 : *******************************************************************************/
45 :
46 : /*******************************************************************************
47 : ** Author Identity **
48 : ********************************************************************************
49 : ** **
50 : ** Initials Name Company **
51 : ** -------- ------------------------- ---------------------------------- **
52 : ** aw Alexander Wenzel BMW **
53 : ** mk Markus Klein Fraunhofer ESK **
54 : *******************************************************************************/
55 :
56 : /*******************************************************************************
57 : ** Author Identity **
58 : ********************************************************************************
59 : ** **
60 : ** Initials Name Company **
61 : ** -------- ------------------------- ---------------------------------- **
62 : ** aw Alexander Wenzel BMW **
63 : *******************************************************************************/
64 :
65 : /*******************************************************************************
66 : ** Revision Control History **
67 : *******************************************************************************/
68 :
69 : /*
70 : * $LastChangedRevision: 1670 $
71 : * $LastChangedDate: 2011-04-08 15:12:06 +0200 (Fr, 08. Apr 2011) $
72 : * $LastChangedBy$
73 : * Initials Date Comment
74 : * aw 13.01.2010 initial
75 : */
76 :
77 : #include <dirent.h>
78 : #include <getopt.h>
79 : #include <stdio.h>
80 : #include <stdlib.h>
81 : #include <unistd.h>
82 : #include <string.h>
83 : #include <ctype.h>
84 : #include <errno.h>
85 :
86 : #include <sys/stat.h>
87 : #include <fcntl.h>
88 :
89 : #include <sys/uio.h> /* writev() */
90 :
91 : #include "dlt_common.h"
92 :
93 : #define COMMAND_SIZE 1024 /* Size of command */
94 : #define FILENAME_SIZE 1024 /* Size of filename */
95 : #define DLT_EXTENSION "dlt"
96 : #define DLT_CONVERT_WS "/tmp/dlt_convert_workspace/"
97 :
98 : /**
99 : * Print usage information of tool.
100 : */
101 0 : void usage(void)
102 : {
103 : char version[DLT_CONVERT_TEXTBUFSIZE];
104 :
105 0 : dlt_get_version(version, 255);
106 :
107 : printf("Usage: dlt-convert [options] [commands] file1 [file2]\n");
108 : printf("Read DLT files, print DLT messages as ASCII and store the messages again.\n");
109 : printf("Use filters to filter DLT messages.\n");
110 : printf("Use Ranges and Output file to cut DLT files.\n");
111 : printf("Use two files and Output file to join DLT files.\n");
112 : printf("%s \n", version);
113 : printf("Commands:\n");
114 : printf(" -h Usage\n");
115 : printf(" -a Print DLT file; payload as ASCII\n");
116 : printf(" -x Print DLT file; payload as hex\n");
117 : printf(" -m Print DLT file; payload as hex and ASCII\n");
118 : printf(" -s Print DLT file; only headers\n");
119 : printf(" -o filename Output messages in new DLT file\n");
120 : printf("Options:\n");
121 : printf(" -v Verbose mode\n");
122 : printf(" -c Count number of messages\n");
123 : printf(" -f filename Enable filtering of messages\n");
124 : printf(" -b number First <number> messages to be handled\n");
125 : printf(" -e number Last <number> messages to be handled\n");
126 : printf(" -w Follow dlt file while file is increasing\n");
127 : printf(" -t Handling input compressed files (tar.gz)\n");
128 0 : }
129 :
130 0 : void empty_dir(const char *dir)
131 : {
132 0 : struct dirent **files = { 0 };
133 : struct stat st;
134 0 : char tmp_filename[FILENAME_SIZE] = { 0 };
135 :
136 0 : if (dir == NULL) {
137 0 : fprintf(stderr, "ERROR: %s: invalid arguments\n", __func__);
138 0 : return;
139 : }
140 :
141 0 : if (stat(dir, &st) == 0) {
142 0 : if (S_ISDIR(st.st_mode)) {
143 0 : int n = scandir(dir, &files, NULL, alphasort);
144 0 : if (n < 0) {
145 0 : fprintf(stderr, "ERROR: Failed to scan %s with error %s\n", dir, strerror(errno));
146 0 : if (files) {
147 0 : free(files);
148 : }
149 0 : return;
150 : }
151 : /* Do not include /. and /.. */
152 0 : if (n < 2) {
153 0 : fprintf(stderr, "ERROR: Failed to scan %s with error %s\n",
154 0 : dir, strerror(errno));
155 0 : if (files) {
156 0 : for (int i = 0; i < n; i++)
157 0 : if (files[i])
158 0 : free(files[i]);
159 0 : free(files);
160 : }
161 0 : return;
162 : }
163 0 : else if (n == 2)
164 : printf("%s is already empty\n", dir);
165 : else {
166 0 : for (int i = 2; i < n; i++) {
167 : memset(tmp_filename, 0, FILENAME_SIZE);
168 : /* Validate filename to prevent path traversal */
169 0 : if (strstr(files[i]->d_name, "/") == NULL && strstr(files[i]->d_name, "..") == NULL) {
170 : snprintf(tmp_filename, FILENAME_SIZE, "%s%s", dir, files[i]->d_name);
171 0 : if (remove(tmp_filename) != 0)
172 0 : fprintf(stderr, "ERROR: Failed to delete %s with error %s\n",
173 0 : tmp_filename, strerror(errno));
174 : } else {
175 0 : fprintf(stderr, "WARNING: Skipping suspicious filename: %s\n", files[i]->d_name);
176 : }
177 : }
178 : }
179 0 : if (files) {
180 0 : for (int i = 0; i < n ; i++)
181 0 : if (files[i]) {
182 0 : free(files[i]);
183 0 : files[i] = NULL;
184 : }
185 0 : free(files);
186 : files = NULL;
187 : }
188 : }
189 : else
190 0 : fprintf(stderr, "ERROR: %s is not a directory\n", dir);
191 : }
192 : else
193 0 : fprintf(stderr, "ERROR: Failed to stat %s with error %s\n", dir, strerror(errno));
194 : }
195 :
196 : /**
197 : * Main function of tool.
198 : */
199 18 : int main(int argc, char *argv[])
200 : {
201 : int vflag = 0;
202 : int cflag = 0;
203 : int aflag = 0;
204 : int sflag = 0;
205 : int xflag = 0;
206 : int mflag = 0;
207 : int wflag = 0;
208 : int tflag = 0;
209 : char *fvalue = 0;
210 : char *bvalue = 0;
211 : char *evalue = 0;
212 : char *ovalue = 0;
213 :
214 : int index;
215 : int c;
216 :
217 : DltFile file;
218 : DltFilter filter;
219 :
220 : int ohandle = -1;
221 :
222 : int num, begin, end;
223 :
224 18 : char text[DLT_CONVERT_TEXTBUFSIZE] = { 0 };
225 :
226 : /* For handling compressed files */
227 18 : char tmp_filename[FILENAME_SIZE] = { 0 };
228 : struct stat st;
229 : memset(&st, 0, sizeof(struct stat));
230 18 : struct dirent **files = { 0 };
231 : int n = 0;
232 :
233 : struct iovec iov[2];
234 : int bytes_written = 0;
235 : int syserr = 0;
236 :
237 18 : opterr = 0;
238 :
239 36 : while ((c = getopt (argc, argv, "vcashxmwtf:b:e:o:")) != -1) {
240 18 : switch (c)
241 : {
242 : case 'v':
243 : {
244 : vflag = 1;
245 : break;
246 : }
247 0 : case 'c':
248 : {
249 : cflag = 1;
250 0 : break;
251 : }
252 18 : case 'a':
253 : {
254 : aflag = 1;
255 18 : break;
256 : }
257 0 : case 's':
258 : {
259 : sflag = 1;
260 0 : break;
261 : }
262 0 : case 'x':
263 : {
264 : xflag = 1;
265 0 : break;
266 : }
267 0 : case 'm':
268 : {
269 : mflag = 1;
270 0 : break;
271 : }
272 0 : case 'w':
273 : {
274 : wflag = 1;
275 0 : break;
276 : }
277 0 : case 't':
278 : {
279 : tflag = 1;
280 0 : break;
281 : }
282 0 : case 'h':
283 : {
284 0 : usage();
285 0 : return -1;
286 : }
287 0 : case 'f':
288 : {
289 0 : fvalue = optarg;
290 0 : break;
291 : }
292 0 : case 'b':
293 : {
294 0 : bvalue = optarg;
295 0 : break;
296 : }
297 0 : case 'e':
298 : {
299 0 : evalue = optarg;
300 0 : break;
301 : }
302 0 : case 'o':
303 : {
304 0 : ovalue = optarg;
305 0 : break;
306 : }
307 0 : case '?':
308 : {
309 0 : if ((optopt == 'f') || (optopt == 'b') || (optopt == 'e') || (optopt == 'o'))
310 0 : fprintf (stderr, "Option -%c requires an argument.\n", optopt);
311 0 : else if (isprint (optopt))
312 0 : fprintf (stderr, "Unknown option `-%c'.\n", optopt);
313 : else
314 0 : fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
315 :
316 : /* unknown or wrong option used, show usage information and terminate */
317 0 : usage();
318 0 : return -1;
319 : }
320 : default:
321 : {
322 : return -1; /*for parasoft */
323 : }
324 : }
325 : }
326 :
327 : /* Initialize structure to use DLT file */
328 18 : dlt_file_init(&file, vflag);
329 :
330 : /* first parse filter file if filter parameter is used */
331 18 : if (fvalue) {
332 0 : if (dlt_filter_load(&filter, fvalue, vflag) < DLT_RETURN_OK) {
333 0 : dlt_file_free(&file, vflag);
334 0 : return -1;
335 : }
336 :
337 0 : dlt_file_set_filter(&file, &filter, vflag);
338 : }
339 :
340 18 : if (ovalue) {
341 : ohandle = open(ovalue, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* mode: wb */
342 :
343 0 : if (ohandle == -1) {
344 0 : dlt_file_free(&file, vflag);
345 0 : fprintf(stderr, "ERROR: Output file %s cannot be opened!\n", ovalue);
346 0 : return -1;
347 : }
348 : }
349 :
350 18 : if (tflag) {
351 : /* Prepare the temp dir to untar compressed files */
352 0 : if (mkdir(DLT_CONVERT_WS, 0700) != 0) {
353 0 : if (errno != EEXIST) {
354 0 : fprintf(stderr,"ERROR: Cannot create temp dir %s!\n", DLT_CONVERT_WS);
355 0 : if (ovalue) {
356 0 : close(ohandle);
357 : ohandle = -1;
358 : }
359 0 : return -1;
360 : }
361 : }
362 : else {
363 : if (S_ISDIR(st.st_mode))
364 : empty_dir(DLT_CONVERT_WS);
365 : else
366 0 : fprintf(stderr, "ERROR: %s is not a directory", DLT_CONVERT_WS);
367 : }
368 :
369 0 : for (index = optind; index < argc; index++) {
370 : /* Check extension of input file
371 : * If it is a compressed file, uncompress it
372 : */
373 0 : const char *file_ext = get_filename_ext(argv[index]);
374 0 : if (file_ext && strcmp(file_ext, DLT_EXTENSION) != 0) {
375 0 : syserr = dlt_execute_command(NULL, "tar", "xf", argv[index], "-C", DLT_CONVERT_WS, NULL);
376 0 : if (syserr != 0)
377 0 : fprintf(stderr, "ERROR: Failed to uncompress %s to %s with error [%d]\n",
378 0 : argv[index], DLT_CONVERT_WS, WIFEXITED(syserr));
379 : }
380 : else {
381 0 : syserr = dlt_execute_command(NULL, "cp", argv[index], DLT_CONVERT_WS, NULL);
382 0 : if (syserr != 0)
383 0 : fprintf(stderr, "ERROR: Failed to copy %s to %s with error [%d]\n",
384 0 : argv[index], DLT_CONVERT_WS, WIFEXITED(syserr));
385 : }
386 :
387 : }
388 :
389 0 : n = scandir(DLT_CONVERT_WS, &files, NULL, alphasort);
390 0 : if (n == -1) {
391 0 : fprintf(stderr,"ERROR: Cannot scan temp dir %s!\n", DLT_CONVERT_WS);
392 0 : if (ovalue) {
393 0 : close(ohandle);
394 : ohandle = -1;
395 : }
396 0 : return -1;
397 : }
398 :
399 : /* do not include ./ and ../ in the files */
400 0 : argc = optind + (n - 2);
401 : }
402 :
403 35 : for (index = optind; index < argc; index++) {
404 18 : if (tflag) {
405 : memset(tmp_filename, 0, FILENAME_SIZE);
406 : snprintf(tmp_filename, FILENAME_SIZE, "%s%s",
407 0 : DLT_CONVERT_WS, files[index - optind + 2]->d_name);
408 :
409 0 : argv[index] = tmp_filename;
410 : }
411 :
412 : /* load, analyze data file and create index list */
413 18 : if (dlt_file_open(&file, argv[index], vflag) >= DLT_RETURN_OK) {
414 526 : while (dlt_file_read(&file, vflag) >= DLT_RETURN_OK) {
415 : }
416 : }
417 :
418 18 : if (aflag || sflag || xflag || mflag || ovalue) {
419 18 : if (bvalue)
420 : begin = atoi(bvalue);
421 : else
422 : begin = 0;
423 :
424 18 : if (evalue && (wflag == 0))
425 : end = atoi(evalue);
426 : else
427 18 : end = file.counter - 1;
428 :
429 18 : if ((begin < 0) || (begin >= file.counter)) {
430 1 : fprintf(stderr, "ERROR: Selected first message %d is out of range!\n", begin);
431 1 : if (ovalue) {
432 0 : close(ohandle);
433 : ohandle = -1;
434 : }
435 1 : dlt_file_free(&file, vflag);
436 1 : return -1;
437 : }
438 :
439 17 : if ((end < 0) || (end >= file.counter) || (end < begin)) {
440 0 : fprintf(stderr, "ERROR: Selected end message %d is out of range!\n", end);
441 0 : if (ovalue) {
442 0 : close(ohandle);
443 : ohandle = -1;
444 : }
445 0 : dlt_file_free(&file, vflag);
446 0 : return -1;
447 : }
448 :
449 526 : for (num = begin; num <= end; num++) {
450 509 : if (dlt_file_message(&file, num, vflag) < DLT_RETURN_OK)
451 0 : continue;
452 :
453 509 : if (xflag) {
454 : printf("%d ", num);
455 0 : if (dlt_message_print_hex(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
456 0 : continue;
457 : }
458 509 : else if (aflag) {
459 : printf("%d ", num);
460 :
461 509 : if (dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
462 0 : continue;
463 :
464 : printf("%s ", text);
465 :
466 509 : if (dlt_message_payload(&file.msg, text, DLT_CONVERT_TEXTBUFSIZE, DLT_OUTPUT_ASCII, vflag) < DLT_RETURN_OK)
467 0 : continue;
468 :
469 : printf("[%s]\n", text);
470 : }
471 0 : else if (mflag) {
472 : printf("%d ", num);
473 0 : if (dlt_message_print_mixed_plain(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
474 0 : continue;
475 : }
476 0 : else if (sflag) {
477 : printf("%d ", num);
478 :
479 0 : if (dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
480 0 : continue;
481 :
482 : printf("%s \n", text);
483 : }
484 :
485 : /* if file output enabled write message */
486 509 : if (ovalue) {
487 0 : iov[0].iov_base = file.msg.headerbuffer;
488 0 : iov[0].iov_len = (uint32_t) file.msg.headersize;
489 0 : iov[1].iov_base = file.msg.databuffer;
490 0 : iov[1].iov_len = (uint32_t) file.msg.datasize;
491 :
492 0 : bytes_written =(int) writev(ohandle, iov, 2);
493 :
494 0 : if (0 > bytes_written) {
495 : printf("in main: writev(ohandle, iov, 2); returned an error!");
496 0 : close(ohandle);
497 : ohandle = -1;
498 0 : dlt_file_free(&file, vflag);
499 0 : return -1;
500 : }
501 : }
502 :
503 : /* check for new messages if follow flag set */
504 509 : if (wflag && (num == end)) {
505 : while (1) {
506 0 : while (dlt_file_read(&file, 0) >= 0){
507 : }
508 :
509 0 : if (end == (file.counter - 1)) {
510 : /* Sleep if no new message was received */
511 : struct timespec req;
512 0 : req.tv_sec = 0;
513 0 : req.tv_nsec = 100000000;
514 0 : nanosleep(&req, NULL);
515 : }
516 : else {
517 : /* set new end of log file and continue reading */
518 : end = file.counter - 1;
519 : break;
520 : }
521 : }
522 : }
523 : }
524 : }
525 :
526 17 : if (cflag) {
527 0 : printf("Total number of messages: %d\n", file.counter_total);
528 :
529 0 : if (file.filter)
530 0 : printf("Filtered number of messages: %d\n", file.counter);
531 : }
532 : }
533 :
534 17 : if (ovalue) {
535 0 : close(ohandle);
536 : ohandle = -1;
537 : }
538 :
539 17 : if (tflag) {
540 0 : empty_dir(DLT_CONVERT_WS);
541 0 : if (files) {
542 0 : for (int i = 0; i < n ; i++)
543 0 : if (files[i])
544 0 : free(files[i]);
545 :
546 0 : free(files);
547 : }
548 0 : rmdir(DLT_CONVERT_WS);
549 : }
550 17 : if (index == optind) {
551 : /* no file selected, show usage and terminate */
552 0 : fprintf(stderr, "ERROR: No file selected\n");
553 0 : usage();
554 0 : return -1;
555 : }
556 :
557 17 : dlt_file_free(&file, vflag);
558 :
559 17 : return 0;
560 : }
|