~ted/whoopsie/recoverable-problem

« back to all changes in this revision

Viewing changes to src/whoopsie.c

  • Committer: Ted Gould
  • Date: 2015-06-05 20:05:34 UTC
  • mfrom: (592.3.72 trunk)
  • Revision ID: ted@gould.cx-20150605200534-ocrtye7ijxcvknln
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#define _XOPEN_SOURCE
20
20
#define _GNU_SOURCE
21
21
 
 
22
#include <limits.h>
22
23
#include <stdlib.h>
23
24
#include <stdio.h>
24
25
#include <string.h>
90
91
};
91
92
#endif
92
93
 
 
94
/* Fields that can be larger than 1KB if present, always send them */
93
95
static const char* acceptable_fields[] = {
94
96
    "ProblemType",
95
97
    "Date",
125
127
    /* add_gdb_info */
126
128
    "Registers",
127
129
    "Disassembly",
128
 
    /* We do not need these since we retrace with ddebs on errors */
129
 
    /* "Stacktrace", */
130
 
    /* "ThreadStacktrace", */
131
130
    /* used to repair the StacktraceAddressSignature if it is corrupt */
132
131
    "StacktraceTop",
133
132
    "AssertionMessage",
150
149
    "InstallationMedia",
151
150
    /* Dumps for debugging iwlwifi firmware crashes */
152
151
    "IwlFwDump",
153
 
 
154
 
    /* Fields we do not care about: */
 
152
    /* System Image information from imaged systems */
 
153
    "SystemImageInfo",
 
154
 
 
155
    NULL,
 
156
};
 
157
 
 
158
/* Fields that we don't ever need, always */
 
159
static const char* unacceptable_fields[] = {
 
160
    /* We do not need these since we retrace with ddebs on errors */
 
161
    "Stacktrace",
 
162
    "ThreadStacktrace",
155
163
 
156
164
    /* We would only want this to see how many bugs would otherwise go
157
165
     * unreported: */
158
 
    /* "UnreportableReason", */
 
166
    "UnreportableReason",
159
167
 
160
168
    /* We'll have our own count in the database. */
161
 
    /* "CrashCounter", */
162
 
 
163
 
    /* "Title", */
164
 
    NULL,
 
169
    "CrashCounter",
 
170
 
 
171
    /* MarkForUpload is redundant since the crash was uploaded. */
 
172
    "_MarkForUpload",
 
173
 
 
174
    "Title",
 
175
 
 
176
    NULL
165
177
};
166
178
 
167
179
static gboolean
168
 
is_acceptable_field (const char* field)
 
180
is_in_field_list (const char* field, const char * field_list[])
169
181
{
170
182
    const char** p;
171
183
 
172
184
    g_return_val_if_fail (field, FALSE);
173
185
 
174
 
    p = acceptable_fields;
 
186
    p = field_list;
175
187
    while (*p) {
176
188
        if (strcmp (*p, field) == 0)
177
189
            return TRUE;
338
350
    gchar* end = NULL;
339
351
    int value_length;
340
352
    int value_pos;
341
 
    gboolean ignore_field = FALSE;
342
353
 
343
354
    g_return_val_if_fail (report_path, NULL);
344
355
 
356
367
        g_error_free (err);
357
368
        goto error;
358
369
    }
359
 
        
 
370
 
360
371
    contents = g_mapped_file_get_contents (fp);
361
372
    file_len = g_mapped_file_get_length (fp);
362
373
    end = contents + file_len;
372
383
            goto error;
373
384
        }
374
385
        if (*p == ' ') {
375
 
            if (!key && !ignore_field) {
 
386
            if (!key) {
376
387
                g_set_error (error,
377
388
                             g_quark_from_static_string ("whoopsie-quark"), 0,
378
389
                             "Report may not start with a value.");
384
395
            while (token_p < end && *token_p != '\n')
385
396
                token_p++;
386
397
 
387
 
            if (!ignore_field) {
388
 
                /* The length of this value string */
389
 
                value_length = token_p - p;
390
 
                if (value) {
391
 
                    /* Space for the leading newline too. */
392
 
                    value_pos = value_p - value;
393
 
                    value = g_realloc (value, value_pos + 1 + value_length + 1);
394
 
                    value_p = value + value_pos;
395
 
                    *value_p = '\n';
396
 
                    value_p++;
397
 
                } else {
398
 
                    value = g_realloc (value, value_length + 1);
399
 
                    value_p = value;
 
398
            /* The length of this value string */
 
399
            value_length = token_p - p;
 
400
            if (value) {
 
401
                /* Space for the leading newline too. */
 
402
                value_pos = value_p - value;
 
403
                if (INT_MAX - (1 + value_length + 1) < value_pos) {
 
404
                    g_set_error (error,
 
405
                                 g_quark_from_static_string ("whoopsie-quark"),
 
406
                                 0, "Report value too long.");
 
407
                    goto error;
400
408
                }
401
 
                memcpy (value_p, p, value_length);
402
 
                value_p[value_length] = '\0';
403
 
                for (char *c = value_p; c < value_p + value_length; c++)
404
 
                    /* If c is a control character. */
405
 
                    if (*c >= '\0' && *c < ' ')
406
 
                        *c = '?';
407
 
                value_p += value_length;
408
 
                g_hash_table_insert (hash_table, key, value ? value : "");
 
409
                value = g_realloc (value, value_pos + 1 + value_length + 1);
 
410
                value_p = value + value_pos;
 
411
                *value_p = '\n';
 
412
                value_p++;
 
413
            } else {
 
414
                value = g_realloc (value, value_length + 1);
 
415
                value_p = value;
409
416
            }
 
417
            memcpy (value_p, p, value_length);
 
418
            value_p[value_length] = '\0';
 
419
            for (char *c = value_p; c < value_p + value_length; c++)
 
420
                /* If c is a control character. */
 
421
                if (*c >= '\0' && *c < ' ')
 
422
                    *c = '?';
 
423
            value_p += value_length;
 
424
            g_hash_table_insert (hash_table, key, value ? value : "");
410
425
            p = token_p + 1;
411
426
        } else {
412
427
            /* Reset the value pointer. */
443
458
                if (*c >= '\0' && *c < ' ')
444
459
                    *c = '?';
445
460
 
446
 
            /* Should we send this field? */
447
 
            if (!full_report)
448
 
                ignore_field = !is_acceptable_field (key);
449
 
 
450
461
            /* Eat the semicolon. */
451
462
            token_p++;
452
463
 
462
473
            if ((token_p - p) == 0) {
463
474
                /* Empty value. The key likely has a child. */
464
475
                value = NULL;
465
 
            } else if (ignore_field) {
466
 
                value = NULL;
467
476
            } else {
468
477
                if (!strncmp ("base64", p, 6)) {
469
478
                    /* Just a marker that the following lines are base64
481
490
                }
482
491
            }
483
492
            p = token_p + 1;
484
 
            if (!ignore_field)
485
 
                g_hash_table_insert (hash_table, key, value ? value : "");
486
 
            else
487
 
                g_free (key);
 
493
 
 
494
            g_hash_table_insert (hash_table, key, value ? value : "");
488
495
        }
489
496
    }
490
497
    g_mapped_file_unref (fp);
 
498
 
 
499
    /* Remove entries that we don't want to send */
 
500
    if (!full_report) {
 
501
        GHashTableIter iter;
 
502
        gpointer key, value;
 
503
        g_hash_table_iter_init(&iter, hash_table);
 
504
 
 
505
        /* We want everything that is in our white list or less than
 
506
           1 KB so that we don't end up DoSing our database. */
 
507
        while (g_hash_table_iter_next(&iter, &key, &value)) {
 
508
            if (!is_in_field_list((const char *)key, unacceptable_fields)) {
 
509
                if (is_in_field_list((const char *)key, acceptable_fields))
 
510
                    continue;
 
511
                if (strlen((const char *)value) < 1024)
 
512
                    continue;
 
513
            }
 
514
 
 
515
            g_hash_table_iter_steal(&iter);
 
516
            destroy_key_and_value(key, value, NULL);
 
517
        }
 
518
    }
 
519
 
491
520
    return hash_table;
492
521
 
493
522
error:
541
570
    curl_slist_free_all(list);
542
571
 
543
572
    curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response_code);
544
 
 
 
573
    /* this actually what curl replied with */
545
574
    log_msg ("Sent; server replied with: %s\n",
546
575
        curl_easy_strerror (result_code));
547
576
    log_msg ("Response code: %ld\n", response_code);
567
596
    split_string (response_data, &command);
568
597
    if (command) {
569
598
        if (strcmp (command, "CORE") == 0) {
 
599
            log_msg ("Reported OOPS ID %.36s\n", response_data);
570
600
            core = g_hash_table_lookup (report, "CoreDump");
571
601
            arch = g_hash_table_lookup (report, "Architecture");
572
602
            if (core && arch) {
575
605
                     * their Internet connection, and we can always count on
576
606
                     * the next person in line to send it. */
577
607
                    log_msg ("Upload of the core dump failed.\n");
 
608
            } else if (strcmp (command, "OOPSID") == 0) {
 
609
                log_msg ("Reported OOPS ID %.36s\n", response_data);
578
610
            } else
579
611
                log_msg ("Asked for a core dump that we don't have.\n");
 
612
        } else if (strcmp (command, "OOPSID") == 0) {
 
613
            log_msg ("Reported OOPS ID %.36s\n", response_data);
580
614
        } else
581
615
            log_msg ("Got command: %s\n", command);
582
616
    }
680
714
            continue;
681
715
        } else if (online_state && parse_and_upload_report (crash_file)) {
682
716
            if (!mark_handled (crash_file))
683
 
                log_msg ("Unable to mark report as seen (%s)\n", crash_file);
684
 
 
685
 
        } 
 
717
                log_msg ("Unable to mark report as seen (%s) removing it.\n", crash_file);
 
718
                g_unlink (crash_file);
 
719
        }
686
720
 
687
721
        g_free (upload_file);
688
722
        g_free (crash_file);
689
723
    }
690
724
    g_dir_close (dir);
691
725
 
692
 
    return TRUE;
 
726
    return G_SOURCE_CONTINUE;
693
727
}
694
728
 
695
729
void daemonize (void)
816
850
void
817
851
network_changed (gboolean available)
818
852
{
819
 
    log_msg (available ? "online\n" : "offline\n");
 
853
    if (online_state != available)
 
854
        log_msg (available ? "online\n" : "offline\n");
 
855
 
820
856
    if (!available) {
821
857
        online_state = FALSE;
822
858
        return;
957
993
                                               whoopsie_identifier);
958
994
    }
959
995
 
 
996
    /* Publish whoopsie-id */
 
997
    g_file_set_contents (WHOOPSIE_ID_PATH, whoopsie_identifier, -1, NULL);
 
998
    chmod (WHOOPSIE_ID_PATH, 00600);
 
999
 
960
1000
    create_crash_directory ();
961
1001
 
962
1002
    drop_privileges (&err);
1004
1044
 
1005
1045
    g_free (crash_db_url);
1006
1046
    g_free (crash_db_submit_url);
1007
 
        return 0;
 
1047
    return 0;
1008
1048
}
1009
1049
#endif