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 <stdio.h>
79 : #include <stdlib.h>
80 : #include <unistd.h>
81 : #include <string.h>
82 : #include <ctype.h>
83 : #include <errno.h>
84 :
85 : #include <sys/stat.h>
86 : #include <fcntl.h>
87 :
88 : #include <sys/uio.h> /* writev() */
89 :
90 : #include "dlt_common.h"
91 :
92 : #define COMMAND_SIZE 1024 /* Size of command */
93 : #define FILENAME_SIZE 1024 /* Size of filename */
94 : #define DLT_EXTENSION "dlt"
95 : #define DLT_CONVERT_WS "/tmp/dlt_convert_workspace/"
96 :
97 : /**
98 : * Print usage information of tool.
99 : */
100 0 : void usage()
101 : {
102 : char version[DLT_CONVERT_TEXTBUFSIZE];
103 :
104 0 : dlt_get_version(version, 255);
105 :
106 : printf("Usage: dlt-convert [options] [commands] file1 [file2]\n");
107 : printf("Read DLT files, print DLT messages as ASCII and store the messages again.\n");
108 : printf("Use filters to filter DLT messages.\n");
109 : printf("Use Ranges and Output file to cut DLT files.\n");
110 : printf("Use two files and Output file to join DLT files.\n");
111 : printf("%s \n", version);
112 : printf("Commands:\n");
113 : printf(" -h Usage\n");
114 : printf(" -a Print DLT file; payload as ASCII\n");
115 : printf(" -x Print DLT file; payload as hex\n");
116 : printf(" -m Print DLT file; payload as hex and ASCII\n");
117 : printf(" -s Print DLT file; only headers\n");
118 : printf(" -o filename Output messages in new DLT file\n");
119 : printf("Options:\n");
120 : printf(" -v Verbose mode\n");
121 : printf(" -c Count number of messages\n");
122 : printf(" -f filename Enable filtering of messages\n");
123 : printf(" -b number First <number> messages to be handled\n");
124 : printf(" -e number Last <number> messages to be handled\n");
125 : printf(" -w Follow dlt file while file is increasing\n");
126 : printf(" -t Handling input compressed files (tar.gz)\n");
127 0 : }
128 :
129 0 : void empty_dir(const char *dir)
130 : {
131 0 : struct dirent **files = { 0 };
132 : struct stat st;
133 : uint32_t n = 0;
134 0 : char tmp_filename[FILENAME_SIZE] = { 0 };
135 : uint32_t i;
136 :
137 0 : if (dir == NULL) {
138 0 : fprintf(stderr, "ERROR: %s: invalid arguments\n", __FUNCTION__);
139 0 : return;
140 : }
141 :
142 0 : if (stat(dir, &st) == 0) {
143 0 : if (S_ISDIR(st.st_mode)) {
144 0 : n = (uint32_t) scandir(dir, &files, NULL, alphasort);
145 :
146 : /* Do not include /. and /.. */
147 0 : if (n < 2)
148 0 : fprintf(stderr, "ERROR: Failed to scan %s with error %s\n",
149 0 : dir, strerror(errno));
150 0 : else if (n == 2)
151 : printf("%s is already empty\n", dir);
152 : else {
153 0 : for (i = 2; i < n; i++) {
154 : memset(tmp_filename, 0, FILENAME_SIZE);
155 0 : snprintf(tmp_filename, FILENAME_SIZE, "%s%s", dir, files[i]->d_name);
156 :
157 0 : if (remove(tmp_filename) != 0)
158 0 : fprintf(stderr, "ERROR: Failed to delete %s with error %s\n",
159 0 : tmp_filename, strerror(errno));
160 : }
161 0 : if (files) {
162 0 : for (i = 0; i < n ; i++)
163 0 : if (files[i]) {
164 0 : free(files[i]);
165 0 : files[i] = NULL;
166 : }
167 0 : free(files);
168 : files = NULL;
169 : }
170 : }
171 : }
172 : else
173 0 : fprintf(stderr, "ERROR: %s is not a directory\n", dir);
174 : }
175 : else
176 0 : fprintf(stderr, "ERROR: Failed to stat %s with error %s\n", dir, strerror(errno));
177 : }
178 :
179 : /**
180 : * Main function of tool.
181 : */
182 18 : int main(int argc, char *argv[])
183 : {
184 : int vflag = 0;
185 : int cflag = 0;
186 : int aflag = 0;
187 : int sflag = 0;
188 : int xflag = 0;
189 : int mflag = 0;
190 : int wflag = 0;
191 : int tflag = 0;
192 : char *fvalue = 0;
193 : char *bvalue = 0;
194 : char *evalue = 0;
195 : char *ovalue = 0;
196 :
197 : int index;
198 : int c;
199 :
200 : DltFile file;
201 : DltFilter filter;
202 :
203 : int ohandle = -1;
204 :
205 : int num, begin, end;
206 :
207 18 : char text[DLT_CONVERT_TEXTBUFSIZE] = { 0 };
208 :
209 : /* For handling compressed files */
210 18 : char tmp_filename[FILENAME_SIZE] = { 0 };
211 : struct stat st;
212 : memset(&st, 0, sizeof(struct stat));
213 18 : struct dirent **files = { 0 };
214 : int n = 0;
215 : int i = 0;
216 :
217 : struct iovec iov[2];
218 : int bytes_written = 0;
219 : int syserr = 0;
220 :
221 18 : opterr = 0;
222 :
223 36 : while ((c = getopt (argc, argv, "vcashxmwtf:b:e:o:")) != -1) {
224 18 : switch (c)
225 : {
226 : case 'v':
227 : {
228 : vflag = 1;
229 : break;
230 : }
231 0 : case 'c':
232 : {
233 : cflag = 1;
234 0 : break;
235 : }
236 18 : case 'a':
237 : {
238 : aflag = 1;
239 18 : break;
240 : }
241 0 : case 's':
242 : {
243 : sflag = 1;
244 0 : break;
245 : }
246 0 : case 'x':
247 : {
248 : xflag = 1;
249 0 : break;
250 : }
251 0 : case 'm':
252 : {
253 : mflag = 1;
254 0 : break;
255 : }
256 0 : case 'w':
257 : {
258 : wflag = 1;
259 0 : break;
260 : }
261 0 : case 't':
262 : {
263 : tflag = 1;
264 0 : break;
265 : }
266 0 : case 'h':
267 : {
268 0 : usage();
269 0 : return -1;
270 : }
271 0 : case 'f':
272 : {
273 0 : fvalue = optarg;
274 0 : break;
275 : }
276 0 : case 'b':
277 : {
278 0 : bvalue = optarg;
279 0 : break;
280 : }
281 0 : case 'e':
282 : {
283 0 : evalue = optarg;
284 0 : break;
285 : }
286 0 : case 'o':
287 : {
288 0 : ovalue = optarg;
289 0 : break;
290 : }
291 0 : case '?':
292 : {
293 0 : if ((optopt == 'f') || (optopt == 'b') || (optopt == 'e') || (optopt == 'o'))
294 0 : fprintf (stderr, "Option -%c requires an argument.\n", optopt);
295 0 : else if (isprint (optopt))
296 0 : fprintf (stderr, "Unknown option `-%c'.\n", optopt);
297 : else
298 0 : fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
299 :
300 : /* unknown or wrong option used, show usage information and terminate */
301 0 : usage();
302 0 : return -1;
303 : }
304 : default:
305 : {
306 : return -1; /*for parasoft */
307 : }
308 : }
309 : }
310 :
311 : /* Initialize structure to use DLT file */
312 18 : dlt_file_init(&file, vflag);
313 :
314 : /* first parse filter file if filter parameter is used */
315 18 : if (fvalue) {
316 0 : if (dlt_filter_load(&filter, fvalue, vflag) < DLT_RETURN_OK) {
317 0 : dlt_file_free(&file, vflag);
318 0 : return -1;
319 : }
320 :
321 0 : dlt_file_set_filter(&file, &filter, vflag);
322 : }
323 :
324 18 : if (ovalue) {
325 : ohandle = open(ovalue, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* mode: wb */
326 :
327 0 : if (ohandle == -1) {
328 0 : dlt_file_free(&file, vflag);
329 0 : fprintf(stderr, "ERROR: Output file %s cannot be opened!\n", ovalue);
330 0 : return -1;
331 : }
332 : }
333 :
334 18 : if (tflag) {
335 : /* Prepare the temp dir to untar compressed files */
336 0 : if (stat(DLT_CONVERT_WS, &st) == -1) {
337 0 : if (mkdir(DLT_CONVERT_WS, 0700) != 0) {
338 0 : fprintf(stderr,"ERROR: Cannot create temp dir %s!\n", DLT_CONVERT_WS);
339 0 : if (ovalue)
340 0 : close(ohandle);
341 :
342 0 : return -1;
343 : }
344 : }
345 : else {
346 0 : if (S_ISDIR(st.st_mode))
347 0 : empty_dir(DLT_CONVERT_WS);
348 : else
349 0 : fprintf(stderr, "ERROR: %s is not a directory", DLT_CONVERT_WS);
350 : }
351 :
352 0 : for (index = optind; index < argc; index++) {
353 : /* Check extension of input file
354 : * If it is a compressed file, uncompress it
355 : */
356 0 : if (strcmp(get_filename_ext(argv[index]), DLT_EXTENSION) != 0) {
357 0 : syserr = dlt_execute_command(NULL, "tar", "xf", argv[index], "-C", DLT_CONVERT_WS, NULL);
358 0 : if (syserr != 0)
359 0 : fprintf(stderr, "ERROR: Failed to uncompress %s to %s with error [%d]\n",
360 0 : argv[index], DLT_CONVERT_WS, WIFEXITED(syserr));
361 : }
362 : else {
363 0 : syserr = dlt_execute_command(NULL, "cp", argv[index], DLT_CONVERT_WS, NULL);
364 0 : if (syserr != 0)
365 0 : fprintf(stderr, "ERROR: Failed to copy %s to %s with error [%d]\n",
366 0 : argv[index], DLT_CONVERT_WS, WIFEXITED(syserr));
367 : }
368 :
369 : }
370 :
371 0 : n = scandir(DLT_CONVERT_WS, &files, NULL, alphasort);
372 0 : if (n == -1) {
373 0 : fprintf(stderr,"ERROR: Cannot scan temp dir %s!\n", DLT_CONVERT_WS);
374 0 : if (ovalue)
375 0 : close(ohandle);
376 :
377 0 : return -1;
378 : }
379 :
380 : /* do not include ./ and ../ in the files */
381 0 : argc = optind + (n - 2);
382 : }
383 :
384 35 : for (index = optind; index < argc; index++) {
385 18 : if (tflag) {
386 : memset(tmp_filename, 0, FILENAME_SIZE);
387 : snprintf(tmp_filename, FILENAME_SIZE, "%s%s",
388 0 : DLT_CONVERT_WS, files[index - optind + 2]->d_name);
389 :
390 0 : argv[index] = tmp_filename;
391 : }
392 :
393 : /* load, analyze data file and create index list */
394 18 : if (dlt_file_open(&file, argv[index], vflag) >= DLT_RETURN_OK) {
395 526 : while (dlt_file_read(&file, vflag) >= DLT_RETURN_OK) {
396 : }
397 : }
398 :
399 18 : if (aflag || sflag || xflag || mflag || ovalue) {
400 18 : if (bvalue)
401 : begin = atoi(bvalue);
402 : else
403 : begin = 0;
404 :
405 18 : if (evalue && (wflag == 0))
406 : end = atoi(evalue);
407 : else
408 18 : end = file.counter - 1;
409 :
410 18 : if ((begin < 0) || (begin >= file.counter)) {
411 1 : fprintf(stderr, "ERROR: Selected first message %d is out of range!\n", begin);
412 1 : if (ovalue)
413 0 : close(ohandle);
414 :
415 1 : return -1;
416 : }
417 :
418 17 : if ((end < 0) || (end >= file.counter) || (end < begin)) {
419 0 : fprintf(stderr, "ERROR: Selected end message %d is out of range!\n", end);
420 0 : if (ovalue)
421 0 : close(ohandle);
422 :
423 0 : return -1;
424 : }
425 :
426 526 : for (num = begin; num <= end; num++) {
427 509 : if (dlt_file_message(&file, num, vflag) < DLT_RETURN_OK)
428 0 : continue;
429 :
430 509 : if (xflag) {
431 : printf("%d ", num);
432 0 : if (dlt_message_print_hex(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
433 0 : continue;
434 : }
435 509 : else if (aflag) {
436 : printf("%d ", num);
437 :
438 509 : if (dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
439 0 : continue;
440 :
441 : printf("%s ", text);
442 :
443 509 : if (dlt_message_payload(&file.msg, text, DLT_CONVERT_TEXTBUFSIZE, DLT_OUTPUT_ASCII, vflag) < DLT_RETURN_OK)
444 0 : continue;
445 :
446 : printf("[%s]\n", text);
447 : }
448 0 : else if (mflag) {
449 : printf("%d ", num);
450 0 : if (dlt_message_print_mixed_plain(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
451 0 : continue;
452 : }
453 0 : else if (sflag) {
454 : printf("%d ", num);
455 :
456 0 : if (dlt_message_header(&(file.msg), text, DLT_CONVERT_TEXTBUFSIZE, vflag) < DLT_RETURN_OK)
457 0 : continue;
458 :
459 : printf("%s \n", text);
460 : }
461 :
462 : /* if file output enabled write message */
463 509 : if (ovalue) {
464 0 : iov[0].iov_base = file.msg.headerbuffer;
465 0 : iov[0].iov_len = (uint32_t) file.msg.headersize;
466 0 : iov[1].iov_base = file.msg.databuffer;
467 0 : iov[1].iov_len = (uint32_t) file.msg.datasize;
468 :
469 0 : bytes_written =(int) writev(ohandle, iov, 2);
470 :
471 0 : if (0 > bytes_written) {
472 : printf("in main: writev(ohandle, iov, 2); returned an error!");
473 0 : close(ohandle);
474 0 : dlt_file_free(&file, vflag);
475 0 : return -1;
476 : }
477 : }
478 :
479 : /* check for new messages if follow flag set */
480 509 : if (wflag && (num == end)) {
481 : while (1) {
482 0 : while (dlt_file_read(&file, 0) >= 0){
483 : }
484 :
485 0 : if (end == (file.counter - 1)) {
486 : /* Sleep if no new message was received */
487 : struct timespec req;
488 0 : req.tv_sec = 0;
489 0 : req.tv_nsec = 100000000;
490 0 : nanosleep(&req, NULL);
491 : }
492 : else {
493 : /* set new end of log file and continue reading */
494 : end = file.counter - 1;
495 : break;
496 : }
497 : }
498 : }
499 : }
500 : }
501 :
502 17 : if (cflag) {
503 0 : printf("Total number of messages: %d\n", file.counter_total);
504 :
505 0 : if (file.filter)
506 0 : printf("Filtered number of messages: %d\n", file.counter);
507 : }
508 : }
509 :
510 17 : if (ovalue)
511 0 : close(ohandle);
512 :
513 17 : if (tflag) {
514 0 : empty_dir(DLT_CONVERT_WS);
515 0 : if (files) {
516 0 : for (i = 0; i < n ; i++)
517 0 : if (files[i])
518 0 : free(files[i]);
519 :
520 0 : free(files);
521 : }
522 0 : rmdir(DLT_CONVERT_WS);
523 : }
524 17 : if (index == optind) {
525 : /* no file selected, show usage and terminate */
526 0 : fprintf(stderr, "ERROR: No file selected\n");
527 0 : usage();
528 0 : return -1;
529 : }
530 :
531 17 : dlt_file_free(&file, vflag);
532 :
533 17 : return 0;
534 : }
|