unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
crashreport.c (21354B)
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_set_conn_hostname(socket, CRASH_REPORT_HOST ":443"); 605 606 if (BIO_do_connect(socket) != 1) 607 { 608 printf("ERROR: Could not connect to %s\n", CRASH_REPORT_HOST); 609 return 0; 610 } 611 612 if (BIO_do_handshake(socket) != 1) 613 { 614 printf("ERROR: Could not connect to %s (TLS handshake failed)\n", CRASH_REPORT_HOST); 615 return 0; 616 } 617 618 BIO_get_ssl(socket, &ssl); 619 if (!ssl) 620 { 621 printf("ERROR: Could not get TLS connection from BIO\n"); 622 return 0; 623 } 624 625 if (!verify_certificate(ssl, CRASH_REPORT_HOST, &errstr)) 626 { 627 printf("Certificate problem with crash.unrealircd.org: %s\n", errstr); 628 printf("Fatal error. See above.\n"); 629 return 0; 630 } 631 632 snprintf(buf, sizeof(buf), "POST /crash.php HTTP/1.1\r\n" 633 "User-Agent: UnrealIRCd %s\r\n" 634 "Host: %s\r\n" 635 "Accept: */*\r\n" 636 "Content-Length: %d\r\n" 637 "Expect: 100-continue\r\n" 638 "Content-Type: multipart/form-data; boundary=%s\r\n" 639 "\r\n", 640 VERSIONONLY, 641 CRASH_REPORT_HOST, 642 (int)(filesize+strlen(header)+strlen(footer)), 643 delimiter); 644 645 BIO_puts(socket, buf); 646 647 memset(buf, 0, sizeof(buf)); 648 n = BIO_read(socket, buf, 255); 649 if ((n < 0) || strncmp(buf, "HTTP/1.1 100", 12)) 650 { 651 printf("Error transmitting bug report (stage II, n=%d)\n", n); 652 if (!strncmp(buf, "HTTP/1.1 403", 12)) 653 { 654 printf("Your crash report was rejected automatically.\n" 655 "This normally means your UnrealIRCd version is too old and unsupported.\n" 656 "Chances are that your crash issue is already fixed in a later release.\n" 657 "Check https://www.unrealircd.org/ for latest releases!\n"); 658 } 659 return 0; 660 } 661 662 fd = fopen(fname, "rb"); 663 if (!fd) 664 return 0; 665 666 BIO_puts(socket, header); 667 668 #ifndef _WIN32 669 printf("Sending..."); 670 #endif 671 while ((fgets(buf, sizeof(buf), fd))) 672 { 673 BIO_puts(socket, buf); 674 #ifndef _WIN32 675 if ((++xfr % 1000) == 0) 676 { 677 printf("."); 678 fflush(stdout); 679 } 680 #endif 681 } 682 fclose(fd); 683 684 BIO_puts(socket, footer); 685 686 do { } while(BIO_should_retry(socket)); /* make sure we are really finished (you never know with TLS) */ 687 688 #ifndef _WIN32 689 printf("\n"); 690 #endif 691 BIO_free_all(socket); 692 693 SSL_CTX_free(ctx_client); 694 695 return 1; 696 } 697 698 void mark_coredump_as_read(char *coredump) 699 { 700 char buf[512]; 701 702 snprintf(buf, sizeof(buf), "%s.%ld.done", coredump, (long)time(NULL)); 703 704 (void)rename(coredump, buf); 705 } 706 707 static int report_pref = REPORT_ASK; 708 709 void report_crash_not_sent(char *fname) 710 { 711 printf("Crash report will not be sent to UnrealIRCd Team.\n" 712 "\n" 713 "Feel free to read the report at %s and delete it.\n" 714 "Or, if you change your mind, you can submit it anyway at https://bugs.unrealircd.org/\n" 715 " (if you do, please set the option 'View Status' at the end of the bug report page to 'private'!!)\n", fname); 716 } 717 718 /** This checks if there are indications that 3rd party modules are 719 * loaded. This is used to provide a small warning to the user that 720 * the crash may be likely due to that. 721 */ 722 int check_third_party_mods_present(void) 723 { 724 #ifndef _WIN32 725 struct dirent *dir; 726 DIR *fd = opendir(TMPDIR); 727 728 if (!fd) 729 return 0; 730 731 /* We search for files like tmp/FC5C3116.third.somename.so */ 732 while ((dir = readdir(fd))) 733 { 734 char *fname = dir->d_name; 735 if (strstr(fname, ".third.") && strstr(fname, ".so")) 736 { 737 closedir(fd); 738 return 1; 739 } 740 } 741 closedir(fd); 742 #endif 743 return 0; 744 } 745 746 void report_crash(void) 747 { 748 char *coredump, *fname; 749 int thirdpartymods = 0; 750 int crashed_secs_ago; 751 752 if (!running_interactively() && (report_pref != REPORT_AUTO)) 753 exit(0); /* don't bother if we run through cron or something similar */ 754 755 coredump = find_best_coredump(); 756 if (!coredump) 757 return; /* no crashes */ 758 759 crashed_secs_ago = time(NULL) - get_file_time(coredump); 760 if (crashed_secs_ago > 86400*7) 761 return; /* stop bothering about it after a while */ 762 763 fname = generate_crash_report(coredump, &thirdpartymods); 764 765 if (!fname) 766 return; 767 768 if (thirdpartymods == 0) 769 thirdpartymods = check_third_party_mods_present(); 770 #ifndef _WIN32 771 printf("The IRCd has been started now (and is running), but it did crash %d seconds ago.\n", crashed_secs_ago); 772 printf("Crash report generated in: %s\n\n", fname); 773 774 if (thirdpartymods) 775 { 776 printf("** IMPORTANT **\n" 777 "Your UnrealIRCd crashed and you have 3rd party modules loaded (modules created\n" 778 "by someone other than the UnrealIRCd team). If you installed new 3rd party\n" 779 "module(s) in the past few weeks we suggest to unload these modules and see if\n" 780 "the crash issue dissapears. If so, that module is probably to blame.\n" 781 "If you keep crashing without any 3rd party modules loaded then please do report\n" 782 "it to the UnrealIRCd team.\n" 783 "The reason we ask you to do this is because MORE THAN 95%% OF ALL CRASH ISSUES\n" 784 "ARE CAUSED BY 3RD PARTY MODULES and not by an UnrealIRCd bug.\n" 785 "\n"); 786 } 787 788 if (report_pref == REPORT_NEVER) 789 { 790 report_crash_not_sent(fname); 791 return; 792 } else 793 if (report_pref == REPORT_ASK) 794 { 795 char answerbuf[64], *answer; 796 printf("Shall I send a crash report to the UnrealIRCd developers?\n"); 797 if (!thirdpartymods) 798 printf("Crash reports help us greatly with fixing bugs that affect you and others\n"); 799 else 800 printf("NOTE: If the crash is caused by a 3rd party module then UnrealIRCd devs can't fix that.\n"); 801 printf("\n"); 802 803 do 804 { 805 printf("Answer (Y/N): "); 806 *answerbuf = '\0'; 807 answer = fgets(answerbuf, sizeof(answerbuf), stdin); 808 809 if (answer && (toupper(*answer) == 'N')) 810 { 811 report_crash_not_sent(fname); 812 return; 813 } 814 if (answer && (toupper(*answer) == 'Y')) 815 { 816 break; 817 } 818 819 printf("Invalid response. Please enter either Y or N\n\n"); 820 } while(1); 821 } else if (report_pref != REPORT_AUTO) 822 { 823 printf("Huh. report_pref setting is weird. Aborting.\n"); 824 return; 825 } 826 827 if (running_interactively()) 828 { 829 char buf[8192], *line; 830 831 printf("\nDo you want to give your e-mail address so we could ask for additional information or " 832 "give you feedback about the crash? This is completely optional, just press ENTER to skip.\n\n" 833 "E-mail address (optional): "); 834 line = fgets(buf, sizeof(buf), stdin); 835 836 if (line && *line && (*line != '\n')) 837 { 838 FILE *fd = fopen(fname, "a"); 839 if (fd) 840 { 841 fprintf(fd, "\nUSER E-MAIL ADDRESS: %s\n", line); 842 fclose(fd); 843 } 844 } 845 846 printf("\nDo you have anything else to tell about the crash, maybe the circumstances? You can type 1 single line\n" 847 "Again, this is completely optional. Just press ENTER to skip.\n\n" 848 "Additional information (optional): "); 849 line = fgets(buf, sizeof(buf), stdin); 850 851 if (line && *line && (*line != '\n')) 852 { 853 FILE *fd = fopen(fname, "a"); 854 if (fd) 855 { 856 fprintf(fd, "\nCOMMENT BY USER: %s\n", line); 857 fclose(fd); 858 } 859 } 860 } 861 if (crashreport_send(fname)) 862 { 863 printf("\nThe crash report has been sent to the UnrealIRCd developers. " 864 "Thanks a lot for helping to make UnrealIRCd a better product!\n\n"); 865 } 866 867 #else 868 /* Windows */ 869 if (MessageBox(NULL, "UnrealIRCd crashed. May I send a report about this to the UnrealIRCd developers? This helps us a lot.", 870 "UnrealIRCd crash", 871 MB_YESNO|MB_ICONQUESTION) == IDYES) 872 { 873 /* Yay */ 874 875 if (crashreport_send(fname)) 876 { 877 MessageBox(NULL, "The crash report has been sent to the UnrealIRCd developers. " 878 "If you have any additional information (like details surrounding " 879 "the crash) then please e-mail syzop@unrealircd.org, such " 880 "information is most welcome. Thanks!", 881 "UnrealIRCd crash report sent", MB_ICONINFORMATION|MB_OK); 882 } 883 } 884 #endif 885 mark_coredump_as_read(coredump); 886 887 #ifdef _WIN32 888 if (MessageBox(NULL, "Start UnrealIRCd again?", 889 "UnrealIRCd crash", 890 MB_YESNO|MB_ICONQUESTION) == IDYES) 891 { 892 StartUnrealAgain(); 893 } 894 #endif 895 }