Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wiretap/logcat_text.c
Line
Count
Source
1
/* logcat_text.c
2
 *
3
 * Copyright 2014, Michal Orynicz for Tieto Corporation
4
 * Copyright 2014, Michal Labedzki for Tieto Corporation
5
 *
6
 * SPDX-License-Identifier: GPL-2.0-or-later
7
 */
8
9
#include "config.h"
10
#include "logcat_text.h"
11
12
#include <string.h>
13
14
#include "wtap_module.h"
15
#include "file_wrappers.h"
16
17
#include "logcat.h"
18
19
struct dumper_t {
20
    int type;
21
};
22
23
static int logcat_text_brief_file_type_subtype = -1;
24
static int logcat_text_process_file_type_subtype = -1;
25
static int logcat_text_tag_file_type_subtype = -1;
26
static int logcat_text_thread_file_type_subtype = -1;
27
static int logcat_text_time_file_type_subtype = -1;
28
static int logcat_text_threadtime_file_type_subtype = -1;
29
static int logcat_text_long_file_type_subtype = -1;
30
31
void register_logcat_text(void);
32
33
/* Returns '?' for invalid priorities */
34
0
static char get_priority(const uint8_t priority) {
35
0
    static const char priorities[] = "??VDIWEFS";
36
37
0
    if (priority >= (uint8_t) sizeof(priorities))
38
0
        return '?';
39
40
0
    return priorities[priority];
41
0
}
42
43
static int buffered_detect_version(const uint8_t *pd)
44
0
{
45
0
    const struct logger_entry     *log_entry;
46
0
    const struct logger_entry_v2  *log_entry_v2;
47
0
    int                      version;
48
0
    const uint8_t           *msg_payload = NULL;
49
0
    uint8_t                 *msg_part;
50
0
    uint8_t                 *msg_end;
51
0
    uint16_t                 msg_len;
52
53
0
    log_entry    = (const struct logger_entry *)(const void *) pd;
54
0
    log_entry_v2 = (const struct logger_entry_v2 *)(const void *) pd;
55
56
    /* must contain at least priority and two nulls as separator */
57
0
    if (log_entry->len < 3)
58
0
        return -1;
59
60
    /* payload length may not exceed the maximum payload size */
61
0
    if (log_entry->len > LOGGER_ENTRY_MAX_PAYLOAD)
62
0
        return -1;
63
64
    /* cannot rely on __pad being 0 for v1, use heuristics to find out what
65
     * version is in use. First assume the smallest msg. */
66
0
    for (version = 1; version <= 2; ++version) {
67
0
        if (version == 1) {
68
0
            msg_payload = (const uint8_t *) (log_entry + 1);
69
0
        } else if (version == 2) {
70
            /* v2 is 4 bytes longer */
71
0
            msg_payload = (const uint8_t *) (log_entry_v2 + 1);
72
0
            if (log_entry_v2->hdr_size != sizeof(*log_entry_v2))
73
0
                continue;
74
0
        }
75
76
        /* A v2 msg has a 32-bit userid instead of v1 priority */
77
0
        if (get_priority(msg_payload[0]) == '?')
78
0
            continue;
79
80
        /* Is there a terminating '\0' for the tag? */
81
0
        msg_part = (uint8_t *) memchr(msg_payload, '\0', log_entry->len - 1);
82
0
        if (msg_part == NULL)
83
0
            continue;
84
85
        /* if msg is '\0'-terminated, is it equal to the payload len? */
86
0
        ++msg_part;
87
0
        msg_len = (uint16_t)(log_entry->len - (msg_part - msg_payload));
88
0
        msg_end = (uint8_t *) memchr(msg_part, '\0', msg_len);
89
        /* is the end of the buffer (-1) equal to the end of msg? */
90
0
        if (msg_end && (msg_payload + log_entry->len - 1 != msg_end))
91
0
            continue;
92
93
0
        return version;
94
0
    }
95
96
0
    return -1;
97
0
}
98
99
static char *logcat_log(const struct dumper_t *dumper, uint32_t seconds,
100
        int milliseconds, int pid, int tid, char priority, const char *tag,
101
        const char *log)
102
0
{
103
0
    char   time_buffer[15];
104
0
    time_t datetime;
105
0
    struct tm *tm;
106
107
0
    datetime = (time_t) seconds;
108
109
0
    switch (dumper->type) {
110
0
        case WTAP_ENCAP_LOGCAT_BRIEF:
111
0
            return ws_strdup_printf("%c/%-8s(%5i): %s\n",
112
0
                    priority, tag, pid, log);
113
0
        case WTAP_ENCAP_LOGCAT_PROCESS:
114
            /* NOTE: Last parameter should be "process name", not tag;
115
                     Unfortunately, we do not have process name */
116
0
            return ws_strdup_printf("%c(%5i) %s  (%s)\n",
117
0
                    priority, pid, log, "");
118
0
        case WTAP_ENCAP_LOGCAT_TAG:
119
0
            return ws_strdup_printf("%c/%-8s: %s\n",
120
0
                   priority, tag, log);
121
0
        case WTAP_ENCAP_LOGCAT_THREAD:
122
0
            return ws_strdup_printf("%c(%5i:%5i) %s\n",
123
0
                    priority, pid, tid, log);
124
0
        case WTAP_ENCAP_LOGCAT_TIME:
125
0
            tm = gmtime(&datetime);
126
0
            if (tm != NULL) {
127
0
                strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
128
0
                        tm);
129
0
                return ws_strdup_printf("%s.%03i %c/%-8s(%5i): %s\n",
130
0
                        time_buffer, milliseconds, priority, tag, pid, log);
131
0
            } else {
132
0
                return ws_strdup_printf("Not representable %c/%-8s(%5i): %s\n",
133
0
                        priority, tag, pid, log);
134
0
            }
135
0
        case WTAP_ENCAP_LOGCAT_THREADTIME:
136
0
            tm = gmtime(&datetime);
137
0
            if (tm != NULL) {
138
0
                strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
139
0
                        tm);
140
0
                return ws_strdup_printf("%s.%03i %5i %5i %c %-8s: %s\n",
141
0
                        time_buffer, milliseconds, pid, tid, priority, tag, log);
142
0
            } else {
143
0
                return ws_strdup_printf("Not representable %5i %5i %c %-8s: %s\n",
144
0
                        pid, tid, priority, tag, log);
145
0
            }
146
0
        case WTAP_ENCAP_LOGCAT_LONG:
147
0
            tm = gmtime(&datetime);
148
0
            if (tm != NULL) {
149
0
                strftime(time_buffer, sizeof(time_buffer), "%m-%d %H:%M:%S",
150
0
                        tm);
151
0
                return ws_strdup_printf("[ %s.%03i %5i:%5i %c/%-8s ]\n%s\n\n",
152
0
                        time_buffer, milliseconds, pid, tid, priority, tag, log);
153
0
            } else {
154
0
                return ws_strdup_printf("[ Not representable %5i:%5i %c/%-8s ]\n%s\n\n",
155
0
                        pid, tid, priority, tag, log);
156
0
            }
157
0
        default:
158
0
            return NULL;
159
0
    }
160
161
0
}
162
163
0
static void get_time(char *string, wtap_rec *rec) {
164
0
    int ms;
165
0
    struct tm date;
166
0
    time_t seconds;
167
168
0
    if (6 == sscanf(string, "%d-%d %d:%d:%d.%d", &date.tm_mon, &date.tm_mday, &date.tm_hour,
169
0
                    &date.tm_min, &date.tm_sec, &ms)) {
170
0
        date.tm_year = 70;
171
0
        date.tm_mon -= 1;
172
0
        date.tm_isdst = -1;
173
0
        seconds = mktime(&date);
174
0
        rec->ts.secs = seconds;
175
0
        rec->ts.nsecs = (int) (ms * 1e6);
176
0
        rec->presence_flags = WTAP_HAS_TS;
177
0
    } else {
178
0
        rec->presence_flags = 0;
179
0
        rec->ts.secs = (time_t) 0;
180
0
        rec->ts.nsecs = 0;
181
0
    }
182
0
}
183
184
static bool logcat_text_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
185
0
        int file_type) {
186
0
    uint8_t *pd;
187
0
    char *cbuff;
188
0
    char *ret = NULL;
189
190
0
    cbuff = (char*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
191
0
    do {
192
0
        ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE_STANDARD, fh);
193
0
    } while (NULL != ret && 3 > strlen(cbuff) && !file_eof(fh));
194
195
0
    if (NULL == ret || 3 > strlen(cbuff)) {
196
0
        g_free(cbuff);
197
0
        return false;
198
0
    }
199
200
0
    if (logcat_text_long_file_type_subtype == file_type &&
201
0
            !g_regex_match_simple(SPECIAL_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW), G_REGEX_MATCH_NOTEMPTY)) {
202
0
        int64_t file_off = 0;
203
0
        char *lbuff;
204
0
        int err;
205
0
        char *ret2 = NULL;
206
207
0
        lbuff = (char*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
208
0
        file_off = file_tell(fh);
209
0
        ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE_STANDARD, fh);
210
0
        while (NULL != ret2 && 2 < strlen(lbuff) && !file_eof(fh)) {
211
0
            (void) g_strlcat(cbuff,lbuff,WTAP_MAX_PACKET_SIZE_STANDARD);
212
0
            file_off = file_tell(fh);
213
0
            ret2 = file_gets(lbuff,WTAP_MAX_PACKET_SIZE_STANDARD, fh);
214
0
        }
215
216
0
        if(NULL == ret2 || 2 < strlen(lbuff)) {
217
0
            g_free(cbuff);
218
0
            g_free(lbuff);
219
0
            return false;
220
0
        }
221
222
0
        if (file_seek(fh, file_off, SEEK_SET, &err) == -1) {
223
0
            g_free(cbuff);
224
0
            g_free(lbuff);
225
0
            return false;
226
0
        }
227
0
        g_free(lbuff);
228
0
    }
229
230
0
    wtap_setup_packet_rec(rec, wth->file_encap);
231
0
    rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
232
0
    rec->rec_header.packet_header.caplen = (uint32_t)strlen(cbuff);
233
0
    rec->rec_header.packet_header.len = rec->rec_header.packet_header.caplen;
234
235
0
    ws_buffer_assure_space(&rec->data, rec->rec_header.packet_header.caplen + 1);
236
0
    pd = ws_buffer_start_ptr(&rec->data);
237
0
    if ((logcat_text_time_file_type_subtype == file_type
238
0
            || logcat_text_threadtime_file_type_subtype == file_type
239
0
            || logcat_text_long_file_type_subtype == file_type)
240
0
            && '-' != cbuff[0]) { /* the last part filters out the -- beginning of... lines */
241
0
        if (logcat_text_long_file_type_subtype == file_type) {
242
0
            get_time(cbuff+2, rec);
243
0
        } else {
244
0
            get_time(cbuff, rec);
245
0
        }
246
0
    } else {
247
0
        rec->presence_flags = 0;
248
0
        rec->ts.secs = (time_t) 0;
249
0
        rec->ts.nsecs = 0;
250
0
    }
251
0
    memcpy(pd, cbuff, rec->rec_header.packet_header.caplen + 1);
252
0
    g_free(cbuff);
253
0
    return true;
254
0
}
255
256
static bool logcat_text_read(wtap *wth, wtap_rec *rec,
257
0
        int *err _U_ , char **err_info _U_, int64_t *data_offset) {
258
0
    *data_offset = file_tell(wth->fh);
259
260
0
    return logcat_text_read_packet(wth, wth->fh, rec, wth->file_type_subtype);
261
0
}
262
263
static bool logcat_text_seek_read(wtap *wth, int64_t seek_off,
264
0
        wtap_rec *rec, int *err, char **err_info _U_) {
265
0
    if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
266
0
        return false;
267
268
0
    if (!logcat_text_read_packet(wth, wth->random_fh, rec, wth->file_type_subtype)) {
269
0
        if (*err == 0)
270
0
            *err = WTAP_ERR_SHORT_READ;
271
0
        return false;
272
0
    }
273
0
    return true;
274
0
}
275
276
0
wtap_open_return_val logcat_text_open(wtap *wth, int *err, char **err_info _U_) {
277
0
    char *cbuff;
278
0
    char *ret = NULL;
279
280
0
    if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
281
0
        return WTAP_OPEN_ERROR;
282
283
0
    cbuff = (char*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
284
0
    do {
285
0
        ret = file_gets(cbuff, WTAP_MAX_PACKET_SIZE_STANDARD, wth->fh);
286
0
    } while (NULL != ret && !file_eof(wth->fh)
287
0
            && ((3 > strlen(cbuff))
288
0
                    || g_regex_match_simple(SPECIAL_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
289
0
                            G_REGEX_MATCH_NOTEMPTY)));
290
291
0
    if (g_regex_match_simple(BRIEF_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
292
0
            G_REGEX_MATCH_NOTEMPTY)) {
293
0
        wth->file_type_subtype = logcat_text_brief_file_type_subtype;
294
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_BRIEF;
295
0
    } else if (g_regex_match_simple(TAG_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
296
0
            G_REGEX_MATCH_NOTEMPTY)) {
297
0
        wth->file_type_subtype = logcat_text_tag_file_type_subtype;
298
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_TAG;
299
0
    } else if (g_regex_match_simple(PROCESS_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
300
0
            G_REGEX_MATCH_NOTEMPTY)) {
301
0
        wth->file_type_subtype = logcat_text_process_file_type_subtype;
302
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_PROCESS;
303
0
    } else if (g_regex_match_simple(TIME_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
304
0
            G_REGEX_MATCH_NOTEMPTY)) {
305
0
        wth->file_type_subtype = logcat_text_time_file_type_subtype;
306
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_TIME;
307
0
    } else if (g_regex_match_simple(THREAD_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
308
0
            G_REGEX_MATCH_NOTEMPTY)) {
309
0
        wth->file_type_subtype = logcat_text_thread_file_type_subtype;
310
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_THREAD;
311
0
    } else if (g_regex_match_simple(THREADTIME_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
312
0
            G_REGEX_MATCH_NOTEMPTY)) {
313
0
        wth->file_type_subtype = logcat_text_threadtime_file_type_subtype;
314
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_THREADTIME;
315
0
    } else if (g_regex_match_simple(LONG_STRING, cbuff, (GRegexCompileFlags)(G_REGEX_ANCHORED | G_REGEX_RAW),
316
0
            G_REGEX_MATCH_NOTEMPTY)) {
317
0
        wth->file_type_subtype = logcat_text_long_file_type_subtype;
318
0
        wth->file_encap = WTAP_ENCAP_LOGCAT_LONG;
319
0
    } else {
320
0
        g_free(cbuff);
321
0
        return WTAP_OPEN_NOT_MINE;
322
0
    }
323
324
0
    if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
325
0
        g_free(cbuff);
326
0
        return WTAP_OPEN_ERROR;
327
0
    }
328
0
    wth->snapshot_length = 0;
329
330
0
    wth->subtype_read = logcat_text_read;
331
0
    wth->subtype_seek_read = logcat_text_seek_read;
332
0
    wth->file_tsprec = WTAP_TSPREC_USEC;
333
0
    g_free(cbuff);
334
0
    return WTAP_OPEN_MINE;
335
0
}
336
337
0
static int logcat_text_brief_dump_can_write_encap(int encap) {
338
0
    if (encap == WTAP_ENCAP_PER_PACKET)
339
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
340
341
0
    switch (encap) {
342
0
    case WTAP_ENCAP_LOGCAT:
343
0
    case WTAP_ENCAP_LOGCAT_BRIEF:
344
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
345
0
        return 0;
346
0
    default:
347
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
348
0
    }
349
0
}
350
351
0
static int logcat_text_process_dump_can_write_encap(int encap) {
352
0
    if (encap == WTAP_ENCAP_PER_PACKET)
353
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
354
355
0
    switch (encap) {
356
0
    case WTAP_ENCAP_LOGCAT:
357
0
    case WTAP_ENCAP_LOGCAT_PROCESS:
358
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
359
0
        return 0;
360
0
    default:
361
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
362
0
    }
363
0
}
364
365
0
static int logcat_text_tag_dump_can_write_encap(int encap) {
366
0
    if (encap == WTAP_ENCAP_PER_PACKET)
367
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
368
369
0
    switch (encap) {
370
0
    case WTAP_ENCAP_LOGCAT:
371
0
    case WTAP_ENCAP_LOGCAT_TAG:
372
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
373
0
        return 0;
374
0
    default:
375
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
376
0
    }
377
0
}
378
379
0
static int logcat_text_time_dump_can_write_encap(int encap) {
380
0
    if (encap == WTAP_ENCAP_PER_PACKET)
381
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
382
383
0
    switch (encap) {
384
0
    case WTAP_ENCAP_LOGCAT:
385
0
    case WTAP_ENCAP_LOGCAT_TIME:
386
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
387
0
        return 0;
388
0
    default:
389
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
390
0
    }
391
0
}
392
393
0
static int logcat_text_thread_dump_can_write_encap(int encap) {
394
0
    if (encap == WTAP_ENCAP_PER_PACKET)
395
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
396
397
0
    switch (encap) {
398
0
    case WTAP_ENCAP_LOGCAT:
399
0
    case WTAP_ENCAP_LOGCAT_THREAD:
400
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
401
0
        return 0;
402
0
    default:
403
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
404
0
    }
405
0
}
406
407
0
static int logcat_text_threadtime_dump_can_write_encap(int encap) {
408
0
    if (encap == WTAP_ENCAP_PER_PACKET)
409
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
410
411
0
    switch (encap) {
412
0
    case WTAP_ENCAP_LOGCAT:
413
0
    case WTAP_ENCAP_LOGCAT_THREADTIME:
414
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
415
0
        return 0;
416
0
    default:
417
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
418
0
    }
419
0
}
420
421
0
static int logcat_text_long_dump_can_write_encap(int encap) {
422
0
    if (encap == WTAP_ENCAP_PER_PACKET)
423
0
        return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
424
425
0
    switch (encap) {
426
0
    case WTAP_ENCAP_LOGCAT:
427
0
    case WTAP_ENCAP_LOGCAT_LONG:
428
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
429
0
        return 0;
430
0
    default:
431
0
        return WTAP_ERR_UNWRITABLE_ENCAP;
432
0
    }
433
0
}
434
435
static bool logcat_text_dump_text(wtap_dumper *wdh, const wtap_rec *rec,
436
    int *err, char **err_info)
437
0
{
438
0
    char                           *buf;
439
0
    int                             length;
440
0
    char                            priority;
441
0
    const struct logger_entry      *log_entry;
442
0
    const struct logger_entry_v2   *log_entry_v2;
443
0
    int                             payload_length;
444
0
    const char                     *tag;
445
0
    int32_t                         pid;
446
0
    int32_t                         tid;
447
0
    int32_t                         seconds;
448
0
    int32_t                         milliseconds;
449
0
    const uint8_t                  *msg_payload = NULL;
450
0
    const char                     *msg_begin;
451
0
    int                             msg_pre_skip;
452
0
    char                           *log;
453
0
    char                           *log_part;
454
0
    char                           *log_next;
455
0
    int                            logcat_version;
456
0
    const struct dumper_t          *dumper        = (const struct dumper_t *) wdh->priv;
457
458
    /* We can only write packet records. */
459
0
    if (rec->rec_type != REC_TYPE_PACKET) {
460
0
        *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
461
0
        *err_info = wtap_unwritable_rec_type_err_string(rec);
462
0
        return false;
463
0
    }
464
465
    /*
466
     * Make sure this packet doesn't have a link-layer type that
467
     * differs from the one for the file.
468
     */
469
0
    if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
470
0
        *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
471
0
        return false;
472
0
    }
473
474
0
    const uint8_t *pd = ws_buffer_start_ptr(&rec->data);
475
476
0
    switch (wdh->file_encap) {
477
0
    case WTAP_ENCAP_WIRESHARK_UPPER_PDU:
478
0
        {
479
0
            int skipped_length;
480
481
0
            skipped_length = logcat_exported_pdu_length(pd);
482
0
            pd += skipped_length;
483
484
0
            if (!wtap_dump_file_write(wdh, (const char*) pd, rec->rec_header.packet_header.caplen - skipped_length, err)) {
485
0
                return false;
486
0
            }
487
0
        }
488
0
        break;
489
0
    case WTAP_ENCAP_LOGCAT:
490
        /* Skip EXPORTED_PDU*/
491
0
        if (wdh->file_encap == WTAP_ENCAP_WIRESHARK_UPPER_PDU) {
492
0
            int skipped_length;
493
494
0
            skipped_length = logcat_exported_pdu_length(pd);
495
0
            pd += skipped_length;
496
497
0
            logcat_version = buffered_detect_version(pd);
498
0
        } else {
499
0
            const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
500
501
0
            logcat_version = pseudo_header->logcat.version;
502
0
        }
503
504
0
        log_entry    = (const struct logger_entry *)(const void *) pd;
505
0
        log_entry_v2 = (const struct logger_entry_v2 *)(const void *) pd;
506
507
0
        payload_length = GINT32_FROM_LE(log_entry->len);
508
0
        pid = GINT32_FROM_LE(log_entry->pid);
509
0
        tid = GINT32_FROM_LE(log_entry->tid);
510
0
        seconds = GINT32_FROM_LE(log_entry->sec);
511
0
        milliseconds = GINT32_FROM_LE(log_entry->nsec) / 1000000;
512
513
        /* msg: <prio:1><tag:N>\0<msg:N>\0 with N >= 0, last \0 can be missing */
514
0
        if (logcat_version == 1) {
515
0
            msg_payload = (const uint8_t *) (log_entry + 1);
516
517
0
            priority = get_priority(msg_payload[0]);
518
0
            tag = (const char*)(msg_payload + 1);
519
0
            msg_pre_skip = 1 + (int) strlen(tag) + 1;
520
0
            msg_begin = (const char*)(msg_payload + msg_pre_skip);
521
0
        } else if (logcat_version == 2) {
522
0
            msg_payload = (const uint8_t *) (log_entry_v2 + 1);
523
524
0
            priority = get_priority(msg_payload[0]);
525
0
            tag = (const char*)(msg_payload + 1);
526
0
            msg_pre_skip = 1 + (int) strlen(tag) + 1;
527
0
            msg_begin = (const char*)(msg_payload + msg_pre_skip);
528
0
        } else {
529
0
            *err = WTAP_ERR_UNWRITABLE_REC_DATA;
530
0
            *err_info = ws_strdup_printf("logcat: version %d isn't supported",
531
0
                                        logcat_version);
532
0
            return false;
533
0
        }
534
535
        /* copy the message part. If a nul byte was missing, it will be added. */
536
0
        log = g_strndup(msg_begin, payload_length - msg_pre_skip);
537
538
        /* long format: display one header followed by the whole message (which may
539
         * contain new lines). Other formats: include tag, etc. with each line */
540
0
        log_next = log;
541
0
        do {
542
0
            log_part = log_next;
543
0
            if (dumper->type == WTAP_ENCAP_LOGCAT_LONG) {
544
                /* read until end, there is no next string */
545
0
                log_next = NULL;
546
0
            } else {
547
                /* read until next newline */
548
0
                log_next = strchr(log_part, '\n');
549
0
                if (log_next != NULL) {
550
0
                    *log_next = '\0';
551
0
                    ++log_next;
552
                    /* ignore trailing newline */
553
0
                    if (*log_next == '\0') {
554
0
                        log_next = NULL;
555
0
                    }
556
0
                }
557
0
            }
558
559
0
            buf = logcat_log(dumper, seconds, milliseconds, pid, tid, priority, tag, log_part);
560
0
            if (!buf) {
561
0
                g_free(log);
562
0
                return false;
563
0
            }
564
0
            length = (uint32_t) strlen(buf);
565
566
0
            if (!wtap_dump_file_write(wdh, buf, length, err)) {
567
0
                g_free(log);
568
0
                return false;
569
0
            }
570
0
        } while (log_next != NULL );
571
572
0
        g_free(log);
573
574
0
        break;
575
0
    case WTAP_ENCAP_LOGCAT_BRIEF:
576
0
    case WTAP_ENCAP_LOGCAT_TAG:
577
0
    case WTAP_ENCAP_LOGCAT_PROCESS:
578
0
    case WTAP_ENCAP_LOGCAT_TIME:
579
0
    case WTAP_ENCAP_LOGCAT_THREAD:
580
0
    case WTAP_ENCAP_LOGCAT_THREADTIME:
581
0
    case WTAP_ENCAP_LOGCAT_LONG:
582
0
        if (dumper->type == wdh->file_encap) {
583
0
            if (!wtap_dump_file_write(wdh, (const char*) pd, rec->rec_header.packet_header.caplen, err)) {
584
0
                return false;
585
0
            }
586
0
        } else {
587
0
            *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
588
0
            return false;
589
0
        }
590
0
    }
591
592
0
    return true;
593
0
}
594
595
0
static bool logcat_text_dump_open(wtap_dumper *wdh, unsigned dump_type) {
596
0
    struct dumper_t *dumper;
597
598
0
    dumper = g_new(struct dumper_t, 1);
599
0
    dumper->type = dump_type;
600
601
0
    wdh->priv = dumper;
602
0
    wdh->subtype_write = logcat_text_dump_text;
603
604
0
    return true;
605
0
}
606
607
0
static bool logcat_text_brief_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
608
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_BRIEF);
609
0
}
610
611
0
static bool logcat_text_process_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
612
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_PROCESS);
613
0
}
614
615
0
static bool logcat_text_tag_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
616
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TAG);
617
0
}
618
619
0
static bool logcat_text_time_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
620
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_TIME);
621
0
}
622
623
0
static bool logcat_text_thread_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
624
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREAD);
625
0
}
626
627
0
static bool logcat_text_threadtime_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
628
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_THREADTIME);
629
0
}
630
631
0
static bool logcat_text_long_dump_open(wtap_dumper *wdh, int *err _U_, char **err_info _U_) {
632
0
    return logcat_text_dump_open(wdh, WTAP_ENCAP_LOGCAT_LONG);
633
0
}
634
635
static const struct supported_block_type logcat_text_brief_blocks_supported[] = {
636
    /*
637
     * We support packet blocks, with no comments or other options.
638
     */
639
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
640
};
641
642
static const struct file_type_subtype_info logcat_text_brief_info = {
643
    "Android Logcat Brief text format", "logcat-brief", NULL, NULL,
644
    false, BLOCKS_SUPPORTED(logcat_text_brief_blocks_supported),
645
    logcat_text_brief_dump_can_write_encap, logcat_text_brief_dump_open, NULL
646
};
647
648
static const struct supported_block_type logcat_text_process_blocks_supported[] = {
649
    /*
650
     * We support packet blocks, with no comments or other options.
651
     */
652
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
653
};
654
655
static const struct file_type_subtype_info logcat_text_process_info = {
656
    "Android Logcat Process text format", "logcat-process", NULL, NULL,
657
    false, BLOCKS_SUPPORTED(logcat_text_process_blocks_supported),
658
    logcat_text_process_dump_can_write_encap, logcat_text_process_dump_open, NULL
659
};
660
661
static const struct supported_block_type logcat_text_tag_blocks_supported[] = {
662
    /*
663
     * We support packet blocks, with no comments or other options.
664
     */
665
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
666
};
667
668
static const struct file_type_subtype_info logcat_text_tag_info = {
669
    "Android Logcat Tag text format", "logcat-tag", NULL, NULL,
670
    false, BLOCKS_SUPPORTED(logcat_text_tag_blocks_supported),
671
    logcat_text_tag_dump_can_write_encap, logcat_text_tag_dump_open, NULL
672
};
673
674
static const struct supported_block_type logcat_text_thread_blocks_supported[] = {
675
    /*
676
     * We support packet blocks, with no comments or other options.
677
     */
678
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
679
};
680
681
static const struct file_type_subtype_info logcat_text_thread_info = {
682
    "Android Logcat Thread text format", "logcat-thread", NULL, NULL,
683
    false, BLOCKS_SUPPORTED(logcat_text_thread_blocks_supported),
684
    logcat_text_thread_dump_can_write_encap, logcat_text_thread_dump_open, NULL
685
};
686
687
static const struct supported_block_type logcat_text_time_blocks_supported[] = {
688
    /*
689
     * We support packet blocks, with no comments or other options.
690
     */
691
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
692
};
693
694
static const struct file_type_subtype_info logcat_text_time_info = {
695
    "Android Logcat Time text format", "logcat-time", NULL, NULL,
696
    false, BLOCKS_SUPPORTED(logcat_text_time_blocks_supported),
697
    logcat_text_time_dump_can_write_encap, logcat_text_time_dump_open, NULL
698
};
699
700
static const struct supported_block_type logcat_text_threadtime_blocks_supported[] = {
701
    /*
702
     * We support packet blocks, with no comments or other options.
703
     */
704
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
705
};
706
707
static const struct file_type_subtype_info logcat_text_threadtime_info = {
708
    "Android Logcat Threadtime text format", "logcat-threadtime", NULL, NULL,
709
    false, BLOCKS_SUPPORTED(logcat_text_threadtime_blocks_supported),
710
    logcat_text_threadtime_dump_can_write_encap, logcat_text_threadtime_dump_open, NULL
711
};
712
713
static const struct supported_block_type logcat_text_long_blocks_supported[] = {
714
    /*
715
     * We support packet blocks, with no comments or other options.
716
     */
717
    { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
718
};
719
720
static const struct file_type_subtype_info logcat_text_long_info = {
721
    "Android Logcat Long text format", "logcat-long", NULL, NULL,
722
    false, BLOCKS_SUPPORTED(logcat_text_long_blocks_supported),
723
    logcat_text_long_dump_can_write_encap, logcat_text_long_dump_open, NULL
724
};
725
726
void register_logcat_text(void)
727
14
{
728
14
    logcat_text_brief_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_brief_info);
729
14
    logcat_text_process_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_process_info);
730
14
    logcat_text_tag_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_tag_info);
731
14
    logcat_text_thread_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_thread_info);
732
14
    logcat_text_time_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_time_info);
733
14
    logcat_text_threadtime_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_threadtime_info);
734
14
    logcat_text_long_file_type_subtype = wtap_register_file_type_subtype(&logcat_text_long_info);
735
736
    /*
737
     * Register names for backwards compatibility with the
738
     * wtap_filetypes table in Lua.
739
     */
740
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_BRIEF",
741
14
                                                   logcat_text_brief_file_type_subtype);
742
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_PROCESS",
743
14
                                                   logcat_text_process_file_type_subtype);
744
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_TAG",
745
14
                                                   logcat_text_tag_file_type_subtype);
746
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_THREAD",
747
14
                                                   logcat_text_thread_file_type_subtype);
748
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_TIME",
749
14
                                                   logcat_text_time_file_type_subtype);
750
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_THREADTIME",
751
14
                                                   logcat_text_threadtime_file_type_subtype);
752
14
    wtap_register_backwards_compatibility_lua_name("LOGCAT_LONG",
753
14
                                                   logcat_text_long_file_type_subtype);
754
14
}
755
756
/*
757
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
758
 *
759
 * Local variables:
760
 * c-basic-offset: 4
761
 * tab-width: 8
762
 * indent-tabs-mode: nil
763
 * End:
764
 *
765
 * vi: set shiftwidth=4 tabstop=8 expandtab:
766
 * :indentSize=4:tabSize=8:noTabs=true:
767
 */