unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive |
crashreport.c (21443B)
1 /* UnrealIRCd crash reporter code. 2 * (C) Copyright 2015-2019 Bram Matthys ("Syzop") and the UnrealIRCd Team. 3 * License: GPLv2 or later 4 */ 5 6 #include "unrealircd.h" 7 #ifdef _WIN32 8 extern void StartUnrealAgain(void); 9 #endif 10 #include "version.h" 11 12 extern char *getosname(void); 13 14 char *find_best_coredump(void) 15 { 16 static char best_fname[512]; 17 time_t best_time = 0, t; 18 struct dirent *dir; 19 #ifndef _WIN32 20 DIR *fd = opendir(TMPDIR); 21 22 if (!fd) 23 return NULL; 24 25 *best_fname = '\0'; 26 27 while ((dir = readdir(fd))) 28 { 29 char *fname = dir->d_name; 30 if (strstr(fname, "core") && !strstr(fname, ".so") && 31 !strstr(fname, ".conf") && !strstr(fname, ".txt") && 32 !strstr(fname, ".done")) 33 { 34 char buf[512]; 35 36 snprintf(buf, sizeof(buf), "%s/%s", TMPDIR, fname); 37 t = get_file_time(buf); 38 if (t && (t > best_time)) 39 { 40 best_time = t; 41 strlcpy(best_fname, buf, sizeof(best_fname)); 42 } 43 } 44 } 45 closedir(fd); 46 #else 47 /* Windows */ 48 WIN32_FIND_DATA hData; 49 HANDLE hFile; 50 51 hFile = FindFirstFile("unrealircd.*.core", &hData); 52 if (hFile == INVALID_HANDLE_VALUE) 53 return NULL; 54 55 do 56 { 57 char *fname = hData.cFileName; 58 if (!strstr(fname, ".done")) 59 { 60 char buf[512]; 61 strlcpy(buf, fname, sizeof(buf)); 62 t = get_file_time(buf); 63 if (t && (t > best_time)) 64 { 65 best_time = t; 66 strlcpy(best_fname, buf, sizeof(best_fname)); 67 } 68 } 69 } while (FindNextFile(hFile, &hData)); 70 FindClose(hFile); 71 #endif 72 73 if (*best_fname) 74 return best_fname; 75 76 return NULL; /* none found */ 77 } 78 79 /** Find the latest AddressSanitizer log file */ 80 char *find_best_asan_log(void) 81 { 82 #ifndef _WIN32 83 static char best_fname[512]; 84 time_t best_time = 0, t; 85 struct dirent *dir; 86 DIR *fd = opendir(TMPDIR); 87 88 if (!fd) 89 return NULL; 90 91 *best_fname = '\0'; 92 93 while ((dir = readdir(fd))) 94 { 95 char *fname = dir->d_name; 96 if (strstr(fname, "unrealircd_asan.") && !strstr(fname, ".so") && 97 !strstr(fname, ".conf") && !strstr(fname, ".txt") && 98 !strstr(fname, ".done")) 99 { 100 char buf[512]; 101 102 snprintf(buf, sizeof(buf), "%s/%s", TMPDIR, fname); 103 t = get_file_time(buf); 104 if (t && (t > best_time)) 105 { 106 best_time = t; 107 strlcpy(best_fname, buf, sizeof(best_fname)); 108 } 109 } 110 } 111 closedir(fd); 112 return *best_fname ? best_fname : NULL; 113 #else 114 return NULL; 115 #endif 116 } 117 118 #define EL_AR_MAX MAXPARA 119 char **explode(char *str, char *delimiter) 120 { 121 static char *ret[EL_AR_MAX+1]; 122 static char buf[1024]; 123 char *p, *name; 124 int cnt = 0; 125 126 memset(&ret, 0, sizeof(ret)); /* make sure all elements are NULL */ 127 128 strlcpy(buf, str, sizeof(buf)); 129 for (name = strtoken(&p, buf, delimiter); name; name = strtoken(&p, NULL, delimiter)) 130 { 131 ret[cnt++] = name; 132 if (cnt == EL_AR_MAX) 133 break; 134 } 135 ret[cnt] = NULL; 136 137 return ret; 138 } 139 140 void crash_report_fix_libs(char *coredump, int *thirdpartymods) 141 { 142 #ifndef _WIN32 143 FILE *fd; 144 char cmd[512], buf[1024]; 145 146 /* This is needed for this function to work, but we keep it since it's 147 * useful in general to have the bug report in English as well. 148 */ 149 setenv("LANG", "C", 1); 150 setenv("LC_ALL", "C", 1); 151 152 snprintf(cmd, sizeof(cmd), "echo info sharedlibrary|gdb %s/unrealircd %s 2>&1", 153 BINDIR, coredump); 154 155 fd = popen(cmd, "r"); 156 if (!fd) 157 return; 158 159 while((fgets(buf, sizeof(buf), fd))) 160 { 161 char *file, *path; 162 char target[512]; 163 char **arr; 164 165 stripcrlf(buf); 166 167 if (strstr(buf, ".third.")) 168 *thirdpartymods = 1; 169 170 /* Output we are interested is something like this: 171 * <many spaces> No /home/blabla/unrealircd/tmp/5114DF16.m_kick.so 172 */ 173 if (!strstr(buf, " No ")) 174 continue; 175 176 path = strchr(buf, '/'); 177 if (!path) 178 continue; 179 180 if (!strstr(path, TMPDIR)) 181 continue; /* we only care about our TMPDIR stuff */ 182 183 file = strrchr(path, '/'); 184 if (!file) 185 continue; 186 file++; 187 188 /* files have the following two formats: 189 * 5BE7DF9.m_svsnline.so for modules/m_svsnline.so 190 * 300AA138.chanmodes.nokick.so for modules/chanmodes/nokick.so 191 */ 192 arr = explode(file, "."); 193 if (!arr[3]) 194 snprintf(target, sizeof(target), "%s/%s.%s", MODULESDIR, arr[1], arr[2]); 195 else 196 snprintf(target, sizeof(target), "%s/%s/%s.%s", MODULESDIR, arr[1], arr[2], arr[3]); 197 198 if (!file_exists(target)) 199 { 200 printf("WARNING: could not resolve %s: %s does not exist\n", path, target); 201 } else { 202 if (symlink(target, path) < 0) 203 printf("WARNING: could not create symlink %s -> %s\n", path, target); 204 } 205 206 } 207 pclose(fd); 208 #endif 209 } 210 211 int crash_report_backtrace(FILE *reportfd, char *coredump) 212 { 213 FILE *fd; 214 char cmd[512], buf[1024]; 215 int n; 216 217 #ifndef _WIN32 218 snprintf(buf, sizeof(buf), "%s/gdb.commands", TMPDIR); 219 fd = fopen(buf, "w"); 220 if (!fd) 221 { 222 printf("ERROR: Could not write to %s.\n", buf); 223 return 0; 224 } 225 fprintf(fd, "frame\n" 226 "echo \\n\n" 227 "list\n" 228 "echo \\n\n" 229 "x/s our_mod_version\n" 230 "echo \\n\n" 231 "x/s backupbuf\n" 232 "echo \\n\n" 233 "bt\n" 234 "echo \\n\n" 235 "bt full\n" 236 "echo \\n\n" 237 "quit\n"); 238 fclose(fd); 239 240 241 snprintf(cmd, sizeof(cmd), "gdb -batch -x %s %s/unrealircd %s 2>&1", 242 buf, BINDIR, coredump); 243 244 fd = popen(cmd, "r"); 245 if (!fd) 246 return 0; 247 248 fprintf(reportfd, "START OF BACKTRACE\n"); 249 while((fgets(buf, sizeof(buf), fd))) 250 { 251 stripcrlf(buf); 252 fprintf(reportfd, " %s\n", buf); 253 } 254 n = pclose(fd); 255 256 fprintf(reportfd, "END OF BACKTRACE\n"); 257 258 if (WEXITSTATUS(n) == 127) 259 return 0; 260 261 return 1; 262 #else 263 fd = fopen(coredump, "r"); 264 if (!fd) 265 return 0; 266 fprintf(reportfd, "START OF CRASH DUMP\n"); 267 while((fgets(buf, sizeof(buf), fd))) 268 { 269 stripcrlf(buf); 270 fprintf(reportfd, " %s\n", buf); 271 } 272 fclose(fd); 273 fprintf(reportfd, "END OF CRASH DUMP\n"); 274 return 1; 275 #endif 276 } 277 278 int crash_report_asan_log(FILE *reportfd, char *coredump) 279 { 280 #ifndef _WIN32 281 time_t coretime, asantime; 282 FILE *fd; 283 char buf[1024]; 284 char *asan_log = find_best_asan_log(); 285 int n; 286 287 if (!asan_log) 288 return 0; 289 290 coretime = get_file_time(coredump); 291 asantime = get_file_time(asan_log); 292 293 fprintf(reportfd, "ASan log file found '%s' which is %ld seconds older than core file\n", 294 asan_log, 295 (long)((long)(coretime) - (long)asantime)); 296 297 fd = fopen(asan_log, "r"); 298 if (!fd) 299 { 300 fprintf(reportfd, "Could not open ASan log (%s)\n", strerror(errno)); 301 return 0; 302 } 303 fprintf(reportfd, "START OF ASAN LOG\n"); 304 while((fgets(buf, sizeof(buf), fd))) 305 { 306 stripcrlf(buf); 307 fprintf(reportfd, " %s\n", buf); 308 } 309 n = fclose(fd); 310 fprintf(reportfd, "END OF ASAN LOG\n"); 311 312 if (WEXITSTATUS(n) == 127) 313 return 0; 314 315 return 1; 316 #else 317 return 0; 318 #endif 319 } 320 321 void crash_report_header(FILE *reportfd, char *coredump) 322 { 323 time_t t; 324 325 fprintf(reportfd, "== UNREALIRCD CRASH REPORT ==\n" 326 "\n" 327 "SYSTEM INFORMATION:\n"); 328 329 fprintf(reportfd, "UnrealIRCd version: %s\n", VERSIONONLY); 330 #if defined(__VERSION__) 331 fprintf(reportfd, " Compiler: %s\n", __VERSION__); 332 #endif 333 334 fprintf(reportfd, " Operating System: %s\n", MYOSNAME); 335 336 337 fprintf(reportfd, "Using core file: %s\n", coredump); 338 339 t = get_file_time(coredump); 340 if (t != 0) 341 { 342 fprintf(reportfd, "Crash date/time: %s\n", myctime(t) ? myctime(t) : "???"); 343 fprintf(reportfd, " Crash secs ago: %ld\n", 344 (long)(time(NULL) - t)); 345 } else { 346 fprintf(reportfd, "Crash date/time: UNKNOWN\n"); 347 fprintf(reportfd, " Crash secs ago: UNKNOWN\n"); 348 } 349 350 fprintf(reportfd, "\n"); 351 } 352 353 /** Checks if the binary is newer than the coredump. 354 * If that's the case (1) then the core dump is likely not very usable. 355 */ 356 int corefile_vs_binary_mismatch(char *coredump) 357 { 358 #ifndef _WIN32 359 time_t core, binary; 360 char fname[512]; 361 362 snprintf(fname, sizeof(fname), "%s/unrealircd", BINDIR); 363 364 core = get_file_time(coredump); 365 binary = get_file_time(fname); 366 367 if (!core || !binary) 368 return 0; /* don't know then */ 369 370 if (binary > core) 371 return 1; /* yup, mismatch ;/ */ 372 373 return 0; /* GOOD! */ 374 #else 375 return 0; /* guess we don't check this on Windows? Or will we check UnrealIRCd.exe... hmm.. yeah maybe good idea */ 376 #endif 377 } 378 379 int attach_file(FILE *fdi, FILE *fdo) 380 { 381 char binbuf[60]; 382 char printbuf[100]; 383 size_t n, total = 0; 384 385 fprintf(fdo, "\n*** ATTACHMENT ****\n"); 386 while((n = fread(binbuf, 1, sizeof(binbuf), fdi)) > 0) 387 { 388 b64_encode(binbuf, n, printbuf, sizeof(printbuf)); 389 fprintf(fdo, "%s\n", printbuf); 390 391 total += strlen(printbuf); 392 393 if (total > 15000000) 394 return 0; /* Safety limit */ 395 } 396 397 fprintf(fdo, "*** END OF ATTACHMENT ***\n"); 398 return 1; 399 } 400 401 /** Figure out the libc library name (.so file), copy it to tmp/ 402 * to include it in the bug report. This can improve the backtrace 403 * a lot (read: make it actually readable / useful) in case we 404 * crash in a libc function. 405 */ 406 char *copy_libc_so(void) 407 { 408 #ifdef _WIN32 409 return ""; 410 #else 411 FILE *fd; 412 char buf[1024]; 413 static char ret[512]; 414 char *basename = NULL, *libcname = NULL, *p, *start; 415 416 snprintf(buf, sizeof(buf), "ldd %s/unrealircd 2>/dev/null", BINDIR); 417 fd = popen(buf, "r"); 418 if (!fd) 419 return ""; 420 421 while ((fgets(buf, sizeof(buf), fd))) 422 { 423 stripcrlf(buf); 424 p = strstr(buf, "libc.so"); 425 if (!p) 426 continue; 427 basename = p; 428 p = strchr(p, ' '); 429 if (!p) 430 continue; 431 *p++ = '\0'; 432 p = strstr(p, "=> "); 433 if (!p) 434 continue; 435 start = p += 3; /* skip "=> " */ 436 p = strchr(start, ' '); 437 if (!p) 438 continue; 439 *p = '\0'; 440 libcname = start; 441 break; 442 } 443 pclose(fd); 444 445 if (!basename || !libcname) 446 return ""; /* not found, weird */ 447 448 snprintf(ret, sizeof(ret), "%s/%s", TMPDIR, basename); 449 if (!unreal_copyfile(libcname, ret)) 450 return ""; /* copying failed */ 451 452 return ret; 453 #endif 454 } 455 int attach_coredump(FILE *fdo, char *coredump) 456 { 457 FILE *fdi; 458 char fname[512]; 459 char *libcname = copy_libc_so(); 460 461 #ifndef _WIN32 462 /* On *NIX we create a .tar.bz2 / .tar.gz (may take a couple of seconds) */ 463 printf("Please wait...\n"); 464 snprintf(fname, sizeof(fname), "tar c %s/unrealircd %s %s %s 2>/dev/null|(bzip2 || gzip) 2>/dev/null", 465 BINDIR, coredump, MODULESDIR, libcname); 466 467 fdi = popen(fname, "r"); 468 #else 469 /* On Windows we attach de .mdmp, the small minidump file */ 470 strlcpy(fname, coredump, sizeof(fname)); 471 if (strlen(fname) > 5) 472 fname[strlen(fname)-5] = '\0'; /* cut off the '.core' part */ 473 strlcat(fname, ".mdmp", sizeof(fname)); /* and add '.mdmp' */ 474 fprintf(fdo, "Windows MINIDUMP: %s\n", fname); 475 fdi = fopen(fname, "rb"); 476 #endif 477 if (!fdi) 478 return 0; 479 480 attach_file(fdi, fdo); 481 482 #ifndef _WIN32 483 pclose(fdi); 484 #else 485 fclose(fdi); 486 #endif 487 return 1; 488 } 489 490 char *generate_crash_report(char *coredump, int *thirdpartymods) 491 { 492 static char reportfname[512]; 493 FILE *reportfd; 494 495 *thirdpartymods = 0; 496 497 if (coredump == NULL) 498 coredump = find_best_coredump(); 499 500 if (coredump == NULL) 501 return NULL; /* nothing available */ 502 503 if (corefile_vs_binary_mismatch(coredump)) 504 return NULL; 505 506 snprintf(reportfname, sizeof(reportfname), "%s/crash.report.%s.%ld.txt", 507 TMPDIR, unreal_getfilename(coredump), (long)time(NULL)); 508 509 reportfd = fopen(reportfname, "w"); 510 if (!reportfd) 511 { 512 printf("ERROR: could not open '%s' for writing\n", reportfname); 513 return NULL; 514 } 515 516 crash_report_header(reportfd, coredump); 517 crash_report_fix_libs(coredump, thirdpartymods); 518 519 crash_report_backtrace(reportfd, coredump); 520 crash_report_asan_log(reportfd, coredump); 521 attach_coredump(reportfd, coredump); 522 523 fclose(reportfd); 524 525 return reportfname; 526 } 527 528 #define REPORT_NEVER -1 529 #define REPORT_ASK 0 530 #define REPORT_AUTO 1 531 532 #define CRASH_REPORT_HOST "crash.unrealircd.org" 533 534 SSL_CTX *crashreport_init_tls(void) 535 { 536 SSL_CTX *ctx_client; 537 char buf[512]; 538 539 SSL_load_error_strings(); 540 SSLeay_add_ssl_algorithms(); 541 542 ctx_client = SSL_CTX_new(SSLv23_client_method()); 543 if (!ctx_client) 544 return NULL; 545 #ifdef HAS_SSL_CTX_SET_MIN_PROTO_VERSION 546 SSL_CTX_set_min_proto_version(ctx_client, TLS1_2_VERSION); 547 #endif 548 SSL_CTX_set_options(ctx_client, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1); 549 550 /* Verify peer certificate */ 551 snprintf(buf, sizeof(buf), "%s/tls/curl-ca-bundle.crt", CONFDIR); 552 SSL_CTX_load_verify_locations(ctx_client, buf, NULL); 553 SSL_CTX_set_verify(ctx_client, SSL_VERIFY_PEER, NULL); 554 555 /* Limit ciphers as well */ 556 SSL_CTX_set_cipher_list(ctx_client, UNREALIRCD_DEFAULT_CIPHERS); 557 558 return ctx_client; 559 } 560 561 int crashreport_send(char *fname) 562 { 563 char buf[1024]; 564 char header[512], footer[512]; 565 char delimiter[41]; 566 int filesize; 567 int n; 568 FILE *fd; 569 SSL_CTX *ctx_client; 570 SSL *ssl = NULL; 571 BIO *socket = NULL; 572 int xfr = 0; 573 char *errstr = NULL; 574 575 filesize = get_file_size(fname); 576 if (filesize < 0) 577 return 0; 578 579 for (n = 0; n < sizeof(delimiter); n++) 580 delimiter[n] = getrandom8()%26 + 'a'; 581 delimiter[sizeof(delimiter)-1] = '\0'; 582 583 snprintf(header, sizeof(header), "--%s\r\n" 584 "Content-Disposition: form-data; name=\"upload\"; filename=\"crash.txt\"\r\n" 585 "Content-Type: text/plain\r\n" 586 "\r\n", 587 delimiter); 588 snprintf(footer, sizeof(footer), "\r\n--%s--\r\n", delimiter); 589 590 ctx_client = crashreport_init_tls(); 591 if (!ctx_client) 592 { 593 printf("ERROR: TLS initalization failure (I)\n"); 594 return 0; 595 } 596 597 socket = BIO_new_ssl_connect(ctx_client); 598 if (!socket) 599 { 600 printf("ERROR: TLS initalization failure (II)\n"); 601 return 0; 602 } 603 604 BIO_get_ssl(socket, &ssl); 605 if (!ssl) 606 { 607 printf("ERROR: Could not get TLS connection from BIO\n"); 608 return 0; 609 } 610 611 SSL_set_tlsext_host_name(ssl, CRASH_REPORT_HOST); /* SNI needs to be set explicitly */ 612 613 BIO_set_conn_hostname(socket, CRASH_REPORT_HOST ":443"); 614 615 if (BIO_do_connect(socket) != 1) 616 { 617 printf("ERROR: Could not connect to %s\n", CRASH_REPORT_HOST); 618 return 0; 619 } 620 621 if (BIO_do_handshake(socket) != 1) 622 { 623 printf("ERROR: Could not connect to %s (TLS handshake failed)\n", CRASH_REPORT_HOST); 624 return 0; 625 } 626 627 if (!verify_certificate(ssl, CRASH_REPORT_HOST, &errstr)) 628 { 629 printf("Certificate problem with crash.unrealircd.org: %s\n", errstr); 630 printf("Fatal error. See above.\n"); 631 return 0; 632 } 633 634 snprintf(buf, sizeof(buf), "POST /crash.php HTTP/1.1\r\n" 635 "User-Agent: UnrealIRCd %s\r\n" 636 "Host: %s\r\n" 637 "Accept: */*\r\n" 638 "Content-Length: %d\r\n" 639 "Expect: 100-continue\r\n" 640 "Content-Type: multipart/form-data; boundary=%s\r\n" 641 "\r\n", 642 VERSIONONLY, 643 CRASH_REPORT_HOST, 644 (int)(filesize+strlen(header)+strlen(footer)), 645 delimiter); 646 647 BIO_puts(socket, buf); 648 649 memset(buf, 0, sizeof(buf)); 650 n = BIO_read(socket, buf, 255); 651 if ((n < 0) || strncmp(buf, "HTTP/1.1 100", 12)) 652 { 653 printf("Error transmitting bug report (stage II, n=%d)\n", n); 654 if (!strncmp(buf, "HTTP/1.1 403", 12)) 655 { 656 printf("Your crash report was rejected automatically.\n" 657 "This normally means your UnrealIRCd version is too old and unsupported.\n" 658 "Chances are that your crash issue is already fixed in a later release.\n" 659 "Check https://www.unrealircd.org/ for latest releases!\n"); 660 } 661 return 0; 662 } 663 664 fd = fopen(fname, "rb"); 665 if (!fd) 666 return 0; 667 668 BIO_puts(socket, header); 669 670 #ifndef _WIN32 671 printf("Sending..."); 672 #endif 673 while ((fgets(buf, sizeof(buf), fd))) 674 { 675 BIO_puts(socket, buf); 676 #ifndef _WIN32 677 if ((++xfr % 1000) == 0) 678 { 679 printf("."); 680 fflush(stdout); 681 } 682 #endif 683 } 684 fclose(fd); 685 686 BIO_puts(socket, footer); 687 688 do { } while(BIO_should_retry(socket)); /* make sure we are really finished (you never know with TLS) */ 689 690 #ifndef _WIN32 691 printf("\n"); 692 #endif 693 BIO_free_all(socket); 694 695 SSL_CTX_free(ctx_client); 696 697 return 1; 698 } 699 700 void mark_coredump_as_read(char *coredump) 701 { 702 char buf[512]; 703 704 snprintf(buf, sizeof(buf), "%s.%ld.done", coredump, (long)time(NULL)); 705 706 (void)rename(coredump, buf); 707 } 708 709 static int report_pref = REPORT_ASK; 710 711 void report_crash_not_sent(char *fname) 712 { 713 printf("Crash report will not be sent to UnrealIRCd Team.\n" 714 "\n" 715 "Feel free to read the report at %s and delete it.\n" 716 "Or, if you change your mind, you can submit it anyway at https://bugs.unrealircd.org/\n" 717 " (if you do, please set the option 'View Status' at the end of the bug report page to 'private'!!)\n", fname); 718 } 719 720 /** This checks if there are indications that 3rd party modules are 721 * loaded. This is used to provide a small warning to the user that 722 * the crash may be likely due to that. 723 */ 724 int check_third_party_mods_present(void) 725 { 726 #ifndef _WIN32 727 struct dirent *dir; 728 DIR *fd = opendir(TMPDIR); 729 730 if (!fd) 731 return 0; 732 733 /* We search for files like tmp/FC5C3116.third.somename.so */ 734 while ((dir = readdir(fd))) 735 { 736 char *fname = dir->d_name; 737 if (strstr(fname, ".third.") && strstr(fname, ".so")) 738 { 739 closedir(fd); 740 return 1; 741 } 742 } 743 closedir(fd); 744 #endif 745 return 0; 746 } 747 748 void report_crash(void) 749 { 750 char *coredump, *fname; 751 int thirdpartymods = 0; 752 int crashed_secs_ago; 753 754 if (!running_interactively() && (report_pref != REPORT_AUTO)) 755 exit(0); /* don't bother if we run through cron or something similar */ 756 757 coredump = find_best_coredump(); 758 if (!coredump) 759 return; /* no crashes */ 760 761 crashed_secs_ago = time(NULL) - get_file_time(coredump); 762 if (crashed_secs_ago > 86400*7) 763 return; /* stop bothering about it after a while */ 764 765 fname = generate_crash_report(coredump, &thirdpartymods); 766 767 if (!fname) 768 return; 769 770 if (thirdpartymods == 0) 771 thirdpartymods = check_third_party_mods_present(); 772 #ifndef _WIN32 773 printf("The IRCd has been started now (and is running), but it did crash %d seconds ago.\n", crashed_secs_ago); 774 printf("Crash report generated in: %s\n\n", fname); 775 776 if (thirdpartymods) 777 { 778 printf("** IMPORTANT **\n" 779 "Your UnrealIRCd crashed and you have 3rd party modules loaded (modules created\n" 780 "by someone other than the UnrealIRCd team). If you installed new 3rd party\n" 781 "module(s) in the past few weeks we suggest to unload these modules and see if\n" 782 "the crash issue dissapears. If so, that module is probably to blame.\n" 783 "If you keep crashing without any 3rd party modules loaded then please do report\n" 784 "it to the UnrealIRCd team.\n" 785 "The reason we ask you to do this is because MORE THAN 95%% OF ALL CRASH ISSUES\n" 786 "ARE CAUSED BY 3RD PARTY MODULES and not by an UnrealIRCd bug.\n" 787 "\n"); 788 } 789 790 if (report_pref == REPORT_NEVER) 791 { 792 report_crash_not_sent(fname); 793 return; 794 } else 795 if (report_pref == REPORT_ASK) 796 { 797 char answerbuf[64], *answer; 798 printf("Shall I send a crash report to the UnrealIRCd developers?\n"); 799 if (!thirdpartymods) 800 printf("Crash reports help us greatly with fixing bugs that affect you and others\n"); 801 else 802 printf("NOTE: If the crash is caused by a 3rd party module then UnrealIRCd devs can't fix that.\n"); 803 printf("\n"); 804 805 do 806 { 807 printf("Answer (Y/N): "); 808 *answerbuf = '\0'; 809 answer = fgets(answerbuf, sizeof(answerbuf), stdin); 810 811 if (answer && (toupper(*answer) == 'N')) 812 { 813 report_crash_not_sent(fname); 814 return; 815 } 816 if (answer && (toupper(*answer) == 'Y')) 817 { 818 break; 819 } 820 821 printf("Invalid response. Please enter either Y or N\n\n"); 822 } while(1); 823 } else if (report_pref != REPORT_AUTO) 824 { 825 printf("Huh. report_pref setting is weird. Aborting.\n"); 826 return; 827 } 828 829 if (running_interactively()) 830 { 831 char buf[8192], *line; 832 833 printf("\nDo you want to give your e-mail address so we could ask for additional information or " 834 "give you feedback about the crash? This is completely optional, just press ENTER to skip.\n\n" 835 "E-mail address (optional): "); 836 line = fgets(buf, sizeof(buf), stdin); 837 838 if (line && *line && (*line != '\n')) 839 { 840 FILE *fd = fopen(fname, "a"); 841 if (fd) 842 { 843 fprintf(fd, "\nUSER E-MAIL ADDRESS: %s\n", line); 844 fclose(fd); 845 } 846 } 847 848 printf("\nDo you have anything else to tell about the crash, maybe the circumstances? You can type 1 single line\n" 849 "Again, this is completely optional. Just press ENTER to skip.\n\n" 850 "Additional information (optional): "); 851 line = fgets(buf, sizeof(buf), stdin); 852 853 if (line && *line && (*line != '\n')) 854 { 855 FILE *fd = fopen(fname, "a"); 856 if (fd) 857 { 858 fprintf(fd, "\nCOMMENT BY USER: %s\n", line); 859 fclose(fd); 860 } 861 } 862 } 863 if (crashreport_send(fname)) 864 { 865 printf("\nThe crash report has been sent to the UnrealIRCd developers. " 866 "Thanks a lot for helping to make UnrealIRCd a better product!\n\n"); 867 } 868 869 #else 870 /* Windows */ 871 if (MessageBox(NULL, "UnrealIRCd crashed. May I send a report about this to the UnrealIRCd developers? This helps us a lot.", 872 "UnrealIRCd crash", 873 MB_YESNO|MB_ICONQUESTION) == IDYES) 874 { 875 /* Yay */ 876 877 if (crashreport_send(fname)) 878 { 879 MessageBox(NULL, "The crash report has been sent to the UnrealIRCd developers. " 880 "If you have any additional information (like details surrounding " 881 "the crash) then please e-mail syzop@unrealircd.org, such " 882 "information is most welcome. Thanks!", 883 "UnrealIRCd crash report sent", MB_ICONINFORMATION|MB_OK); 884 } 885 } 886 #endif 887 mark_coredump_as_read(coredump); 888 889 #ifdef _WIN32 890 if (MessageBox(NULL, "Start UnrealIRCd again?", 891 "UnrealIRCd crash", 892 MB_YESNO|MB_ICONQUESTION) == IDYES) 893 { 894 StartUnrealAgain(); 895 } 896 #endif 897 }