1 /******************************************************************************
2 * This file is part of TinTin++ *
3 * *
4 * Copyright 2004-2019 Igor van den Hoven *
5 * *
6 * TinTin++ is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with TinTin++. If not, see https://www.gnu.org/licenses. *
19 ******************************************************************************/
20
21 /******************************************************************************
22 * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t *
23 * *
24 * coded by Peter Unold 1992 *
25 * recoded by Igor van den Hoven 2004 *
26 ******************************************************************************/
27
28 #include "tintin.h"
29
30 #include <signal.h>
31
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35
36 /*************** globals ******************/
37
38 struct session *gts;
39 struct tintin_data *gtd;
40
pipe_handler(int signal)41 void pipe_handler(int signal)
42 {
43 syserr_printf(gtd->ses, "pipe_handler");
44 }
45
xfsz_handler(int signal)46 void xfsz_handler(int signal)
47 {
48 syserr_printf(gtd->ses, "xfsz_handler");
49 }
50
hub_handler(int signal)51 void hub_handler(int signal)
52 {
53 syserr_printf(gtd->ses, "hub_handler");
54 }
55
ttin_handler(int signal)56 void ttin_handler(int signal)
57 {
58 syserr_printf(gtd->ses, "ttin_handler");
59 }
60
ttou_handler(int signal)61 void ttou_handler(int signal)
62 {
63 syserr_printf(gtd->ses, "ttou_handler");
64 }
65
usr_handler(int signal)66 void usr_handler(int signal)
67 {
68 check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 1, "SIGUSR", signal == SIGUSR1 ? "1" : "2");
69 }
70
71 /*
72 when the screen size changes, take note of it
73 */
74
winch_handler(int signal)75 void winch_handler(int signal)
76 {
77 SET_BIT(gtd->flags, TINTIN_FLAG_WINCHUPDATE);
78
79 gtd->time_session = gtd->time;
80 }
81
82
abort_handler(int signal)83 void abort_handler(int signal)
84 {
85 syserr_fatal(signal, "abort_handler");
86 }
87
child_handler(int signal)88 void child_handler(int signal)
89 {
90 return;
91
92 syserr_printf(gtd->ses, "child_handler");
93 }
94 /*
95 void interrupt_handler(int signal)
96 {
97 if (gtd->ses->connect_retry > utime())
98 {
99 gtd->ses->connect_retry = 0;
100 }
101 else if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) && !HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
102 {
103 socket_printf(gtd->ses, 1, "\004");
104 }
105 else if (gtd->attach_sock)
106 {
107 gtd->attach_sock = close(gtd->attach_sock);
108
109 show_message(gtd->ses, LIST_COMMAND, "#REDETACHING PROCESS TO {%s}", gtd->attach_file);
110 }
111 else
112 {
113 cursor_delete_or_exit(gtd->ses, "");
114 }
115 }
116 */
suspend_handler(int signal)117 void suspend_handler(int signal)
118 {
119 show_message(gtd->ses, LIST_COMMAND, "#SIGNAL: SIGTSTP");
120
121 if (gtd->attach_sock)
122 {
123 show_message(gtd->ses, LIST_COMMAND, "#DAEMON {%s} WANTS TO DETACH.", gtd->attach_file);
124
125 gtd->attach_sock = close(gtd->attach_sock);
126
127 return;
128 }
129 }
130
trap_handler(int signal)131 void trap_handler(int signal)
132 {
133 syserr_fatal(signal, "trap_handler");
134 }
135
136
137 /****************************************************************************/
138 /* main() - show title - setup signals - init lists - readcoms - mainloop() */
139 /****************************************************************************/
140
141
main(int argc,char ** argv)142 int main(int argc, char **argv)
143 {
144 int c, i = 0, greeting = 0;
145
146 char arg[BUFFER_SIZE];
147
148 #ifdef SOCKS
149 SOCKSinit(argv[0]);
150 #endif
151
152 if (signal(SIGTERM, trap_handler) == BADSIG)
153 {
154 syserr_fatal(-1, "signal SIGTERM");
155 }
156
157 if (signal(SIGSEGV, trap_handler) == BADSIG)
158 {
159 syserr_fatal(-1, "signal SIGSEGV");
160 }
161
162 if (signal(SIGHUP, trap_handler) == BADSIG)
163 {
164 syserr_fatal(-1, "signal SIGHUP");
165 }
166
167 if (signal(SIGABRT, abort_handler) == BADSIG)
168 {
169 syserr_fatal(-1, "signal SIGTERM");
170 }
171
172 /* if (signal(SIGCHLD, child_handler) == BADSIG)
173 {
174 syserr_fatal(-1, "signal SIGCHLD");
175 }
176 */
177 /*
178 if (signal(SIGINT, interrupt_handler) == BADSIG)
179 {
180 syserr_fatal(-1, "signal SIGINT");
181 }
182 */
183
184 if (signal(SIGTSTP, suspend_handler) == BADSIG)
185 {
186 syserr_fatal(-1, "signal SIGTSTP");
187 }
188 /*
189 if (signal(SIGPIPE, pipe_handler) == BADSIG)
190 {
191 syserr_fatal(-1, "signal SIGPIPE");
192 }
193
194 if (signal(SIGXFSZ, xfsz_handler) == BADSIG)
195 {
196 syserr_fatal(-1, "signal SIGXFSZ");
197 }
198
199 if (signal(SIGHUP, hub_handler) == BADSIG)
200 {
201 syserr_fatal(-1, "signal SIGHUP");
202 }
203
204 if (signal(SIGTTIN, hub_handler) == BADSIG)
205 {
206 syserr_fatal(-1, "signal SIGTTIN");
207 }
208
209 if (signal(SIGTTOU, hub_handler) == BADSIG)
210 {
211 syserr_fatal(-1, "signal SIGTTOU");
212 }
213 */
214 if (signal(SIGUSR1, usr_handler) == BADSIG)
215 {
216 syserr_fatal(-1, "signal SIGUSR1");
217 }
218
219 if (signal(SIGUSR2, usr_handler) == BADSIG)
220 {
221 syserr_fatal(-1, "signal SIGUSR1");
222 }
223
224 if (signal(SIGWINCH, winch_handler) == BADSIG)
225 {
226 syserr_fatal(-1, "signal SIGWINCH");
227 }
228
229 signal(SIGPIPE, SIG_IGN);
230
231 for (c = 0 ; c < argc ; c++)
232 {
233 if (c)
234 {
235 cat_sprintf(arg, " %s", argv[c]);
236 }
237 {
238 strcpy(arg, argv[0]);
239 }
240 }
241
242 if (argc > 1)
243 {
244 while ((c = getopt(argc, argv, "a: e: g G h M:: r: R:: s t: T v V")) != EOF)
245 {
246 switch (c)
247 {
248 case 'h':
249 printf("Usage: %s [OPTION]... [FILE]...\n", argv[0]);
250 printf("\n");
251 printf(" -a Set argument for PROGRAM START event.\n");
252 printf(" -e Execute given command.\n");
253 printf(" -g Enable the startup user interface.\n");
254 printf(" -G Don't show the greeting screen.\n");
255 printf(" -h This help section.\n");
256 printf(" -M Matrix Digital Rain.\n");
257 printf(" -r Read given file.\n");
258 printf(" -R Reattach to daemonized process.\n");
259 printf(" -s Enable screen reader mode.\n");
260 printf(" -t Set given title.\n");
261 printf(" -T Don't set the default title.\n");
262 printf(" -v Enable verbose mode.\n");
263 printf(" -V Show version information.\n");
264
265 exit(1);
266
267 case 'M':
268 case 'G':
269 SET_BIT(greeting, STARTUP_FLAG_NOGREETING);
270 break;
271
272 case 's':
273 SET_BIT(greeting, STARTUP_FLAG_SCREENREADER);
274 break;
275
276 case 'v':
277 SET_BIT(greeting, STARTUP_FLAG_VERBOSE);
278 break;
279
280 case 'V':
281 printf("\nTinTin++ " CLIENT_VERSION "\n");
282 printf("\n(C) 2004-2019 Igor van den Hoven\n");
283 printf("\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\n");
284 exit(1);
285 }
286 }
287 }
288
289 init_tintin(greeting);
290
291
292 RESTRING(gtd->vars[1], argv[0]);
293
294 if (argc > 1)
295 {
296 optind = 1;
297
298 RESTRING(gtd->vars[2], argv[1]);
299
300 while ((c = getopt(argc, argv, "a: e: g G h M:: r: R:: s t: T v")) != EOF)
301 {
302 switch (c)
303 {
304 case 'a':
305 RESTRING(gtd->vars[0], argv[2]);
306 SET_BIT(greeting, STARTUP_FLAG_ARGUMENT);
307 break;
308
309 case 'e':
310 gtd->level->input++;
311 gtd->ses = script_driver(gtd->ses, LIST_COMMAND, optarg);
312 gtd->level->input--;
313 break;
314
315 case 'g':
316 gtd->ses = command(gtd->ses, do_banner, "gui");
317 break;
318
319 case 'G':
320 break;
321
322 case 'M':
323 command(gts, do_test, "rain %s", optarg ? optarg : "");
324 break;
325
326 case 'r':
327 // gtd->level->input++;
328 gtd->ses = command(gtd->ses, do_read, "%s", optarg);
329 // gtd->level->input--;
330 break;
331
332 case 'R':
333 SET_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
334 command(gtd->ses, do_daemon, "attach {%s}", optarg ? optarg : "");
335 break;
336
337 case 's':
338 break;
339
340 case 't':
341 SET_BIT(greeting, STARTUP_FLAG_NOTITLE);
342 print_stdout(0, 0, "\e]0;%s\007", optarg);
343 break;
344
345 case 'T':
346 SET_BIT(greeting, STARTUP_FLAG_NOTITLE);
347 break;
348
349 case 'v':
350 // do_configure(gtd->ses, "{VERBOSE} {ON}");
351 break;
352
353 default:
354 // tintin_printf2(NULL, "Unknown option '%c'.", c);
355 break;;
356 }
357 }
358 }
359
360 if (!HAS_BIT(greeting, STARTUP_FLAG_NOTITLE))
361 {
362 command(gts, do_screen, "LOAD BOTH");
363 command(gts, do_screen, "SAVE BOTH");
364 command(gts, do_screen, "SET BOTH TinTin++");
365 }
366
367 gtd->system->exec = strdup(argv[0]);
368
369 if (argc > 2)
370 {
371 RESTRING(gtd->vars[3], argv[2]);
372
373 for (i = 3 ; i <= optind ; i++)
374 {
375 RESTRING(gtd->vars[i+1], argv[i] ? argv[i] : "");
376 }
377
378 arg[0] = 0;
379
380 for (i = optind + 1 ; i < argc ; i++)
381 {
382 if (*arg)
383 {
384 strcat(arg, " ");
385 }
386 strcat(arg, argv[i]);
387
388 if (i < 100)
389 {
390 RESTRING(gtd->vars[i+1], argv[i]);
391 }
392 }
393
394 if (!HAS_BIT(greeting, STARTUP_FLAG_ARGUMENT))
395 {
396 RESTRING(gtd->vars[0], arg);
397 }
398 }
399
400 if (argv[optind] != NULL)
401 {
402 if (!strncasecmp(argv[optind], "telnet://", 9))
403 {
404 gtd->ses = command(gtd->ses, do_session, "%s", argv[optind]);
405 }
406 else
407 {
408 gtd->level->input++;
409
410 gtd->ses = command(gtd->ses, do_read, "%s", argv[optind]);
411
412 gtd->level->input--;
413 }
414 }
415
416 check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 0, "PROGRAM START");
417
418 mainloop();
419
420 return 0;
421 }
422
init_tintin(int greeting)423 void init_tintin(int greeting)
424 {
425 char filename[PATH_SIZE];
426 int index;
427
428 gtd = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
429
430 init_memory();
431
432 push_call("init_tintin(%d)",greeting);
433
434 gtd->level = (struct level_data *) calloc(1, sizeof(struct level_data));
435
436 gtd->buf = str_alloc(BUFFER_SIZE);
437 gtd->out = str_alloc(BUFFER_SIZE);
438
439 gtd->flags = TINTIN_FLAG_INHERITANCE;
440
441 gtd->mccp_len = 10000;
442 gtd->mccp_buf = (unsigned char *) calloc(1, gtd->mccp_len);
443
444 gtd->mud_output_max = 16384;
445 gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
446
447 // WSL: /proc/sys/kernel/osrelease
448
449 gtd->system = (struct system_data *) calloc(1, sizeof(struct system_data));
450
451 gtd->system->os = strdup(getenv("OS") ? getenv("OS") : "UNKNOWN");
452 gtd->system->home = strdup(getenv("HOME") ? getenv("HOME") : "~/");
453 gtd->system->lang = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
454 gtd->system->term = strdup(getenv("TERM") ? getenv("TERM") : "UNKNOWN");
455
456 gtd->system->tt_dir = restringf(gtd->system->tt_dir, "%s/%s", gtd->system->home, TINTIN_DIR);
457
458 if (mkdir(gtd->system->tt_dir, 0755) && errno != EEXIST)
459 {
460 gtd->system->tt_dir = restringf(gtd->system->tt_dir, "%s", TINTIN_DIR);
461
462 mkdir(gtd->system->tt_dir, 0755);
463 }
464
465 gtd->detach_file = strdup("");
466 gtd->attach_file = strdup("");
467
468 gtd->tintin_char = '#';
469
470 gtd->time = time(NULL);
471 gtd->utime = utime();
472
473 for (index = 0 ; index < 100 ; index++)
474 {
475 gtd->vars[index] = strdup("");
476 gtd->cmds[index] = strdup("");
477 }
478
479 for (index = 1 ; index ; index++)
480 {
481 if (*event_table[index].name == 0)
482 {
483 break;
484 }
485
486 if (strcmp(event_table[index - 1].name, event_table[index].name) > 0)
487 {
488 print_stdout(0, 0, "\e[1;31minit_tintin() unsorted event table %s vs %s.", event_table[index - 1].name, event_table[index].name);
489
490 break;
491 }
492 }
493
494 init_commands();
495
496 gtd->screen = calloc(1, sizeof(struct screen_data));
497
498 gtd->screen->rows = SCREEN_HEIGHT;
499 gtd->screen->cols = SCREEN_WIDTH;
500 gtd->screen->height = SCREEN_HEIGHT * 16;
501 gtd->screen->width = SCREEN_WIDTH * 10;
502 gtd->screen->focus = 1;
503
504 gtd->dispose_list = init_list(NULL, 0, 32);
505
506 init_msdp_table();
507
508 // global tintin session
509
510 gts = (struct session *) calloc(1, sizeof(struct session));
511
512 gts->created = gtd->time;
513 gts->name = strdup("gts");
514 gts->group = strdup("");
515 gts->session_host = strdup("");
516 gts->session_ip = strdup("");
517 gts->session_port = strdup("");
518 gts->cmd_color = strdup("");
519 gts->telopts = TELOPT_FLAG_ECHO;
520 gts->config_flags = CONFIG_FLAG_MCCP;
521 gts->socket = 1;
522 gts->read_max = 16384;
523
524 gts->more_output = str_dup("");
525
526 gtd->ses = gts;
527
528 for (index = 0 ; index < LIST_MAX ; index++)
529 {
530 gts->list[index] = init_list(gts, index, 32);
531 }
532
533 gtd->banner_list = init_list(gts, LIST_CONFIG, 32);
534
535 gts->log = calloc(1, sizeof(struct log_data));
536 gts->input = calloc(1, sizeof(struct input_data));
537 gts->scroll = calloc(1, sizeof(struct scroll_data));
538 gts->split = calloc(1, sizeof(struct split_data));
539
540 init_local(gts);
541
542 init_terminal_size(gts);
543
544 init_log(gts);
545
546 init_input(gts, 0, 0, 0, 0);
547
548 init_buffer(gts, 10000);
549
550 if (HAS_BIT(greeting, STARTUP_FLAG_VERBOSE))
551 {
552 gtd->level->verbose++;
553 }
554
555 gtd->level->input++;
556
557 command(gts, do_configure, "{AUTO TAB} {5000}");
558 command(gts, do_configure, "{BUFFER SIZE} {10000}");
559 command(gts, do_configure, "{COLOR MODE} {ON}");
560 command(gts, do_configure, "{COLOR PATCH} {OFF}");
561 command(gts, do_configure, "{COMMAND COLOR} {<078>}");
562 command(gts, do_configure, "{COMMAND ECHO} {ON}");
563 command(gts, do_configure, "{CONNECT RETRY} {0}");
564 command(gts, do_configure, "{CHARSET} {AUTO}");
565 command(gts, do_configure, "{HISTORY SIZE} {1000}");
566 command(gts, do_configure, "{LOG MODE} {RAW}");
567 command(gts, do_configure, "{MOUSE} {OFF}");
568 command(gts, do_configure, "{PACKET PATCH} {AUTO}");
569 command(gts, do_configure, "{RANDOM SEED} {AUTO}");
570 command(gts, do_configure, "{REPEAT CHAR} {!}");
571 command(gts, do_configure, "{REPEAT ENTER} {OFF}");
572 command(gts, do_configure, "{SCREEN READER} {%s}", HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "ON" : "OFF");
573 command(gts, do_configure, "{SCROLL LOCK} {ON}");
574 command(gts, do_configure, "{SPEEDWALK} {OFF}");
575 command(gts, do_configure, "{TAB WIDTH} {AUTO}");
576 command(gts, do_configure, "{TELNET} {ON}");
577 command(gts, do_configure, "{TINTIN CHAR} {#}");
578 command(gts, do_configure, "{VERBATIM} {OFF}");
579 command(gts, do_configure, "{VERBATIM CHAR} {\\}");
580 command(gts, do_configure, "{VERBOSE} {%s}", HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "ON" : "OFF");
581 command(gts, do_configure, "{WORDWRAP} {ON}");
582
583 command(gts, do_pathdir, " n s 1");
584 command(gts, do_pathdir, " e w 2");
585 command(gts, do_pathdir, " s n 4");
586 command(gts, do_pathdir, " w e 8");
587 command(gts, do_pathdir, " u d 16");
588 command(gts, do_pathdir, " d u 32");
589 command(gts, do_pathdir, "ne sw 3");
590 command(gts, do_pathdir, "nw se 9");
591 command(gts, do_pathdir, "se nw 6");
592 command(gts, do_pathdir, "sw ne 12");
593
594 sprintf(filename, "%s/%s", gtd->system->tt_dir, HISTORY_FILE);
595
596 if (access(filename, F_OK ) != -1)
597 {
598 command(gts, do_history, "read %s", filename);
599 }
600
601 gtd->level->input--;
602
603 if (HAS_BIT(greeting, STARTUP_FLAG_VERBOSE))
604 {
605 gtd->level->verbose--;
606 }
607
608 init_terminal(gts);
609
610 reset_screen(gts);
611
612 command(gts, do_banner, "INIT");
613
614 if (!HAS_BIT(greeting, STARTUP_FLAG_NOGREETING))
615 {
616 if (HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER))
617 {
618 tintin_printf2(gts, "Welcome to TinTin Plus Plus. Don't know which MUD to play? How about the following MUD.");
619
620 command(gts, do_banner, "RANDOM");
621
622 tintin_printf2(gts, "You're using TinTin Plus Plus version %s written by Peter Unold, Bill Reis, and Igor van den Hoven.", CLIENT_VERSION);
623
624 tintin_printf2(gts, "");
625
626 tintin_printf2(gts, "For help and requests visit the Discord channel at https://discord.gg/gv7a37n");
627 }
628 else
629 {
630 command(gts, do_banner, "RANDOM");
631
632 if (gtd->screen->cols >= 80)
633 {
634 command(gts, do_help, "GREETING");
635 }
636 else
637 {
638 tintin_printf2(gts, "\e[0;37mT I N T I N + + %s", CLIENT_VERSION);
639
640 tintin_printf2(gts, "");
641
642 // tintin_printf2(gts, "\e[0;36mT\e[0;37mhe K\e[0;36mi\e[0;37mcki\e[0;36mn\e[0;37m \e[0;36mT\e[0;37mickin D\e[0;36mi\e[0;37mkuMUD Clie\e[0;36mn\e[0;37mt");
643
644 tintin_printf2(gts, "Code by Peter Unold, Bill Reis, and Igor van den Hoven");
645 }
646 }
647 }
648 pop_call();
649 return;
650 }
651
652
quitmsg(char * message)653 void quitmsg(char *message)
654 {
655 struct session *ses;
656 static char crashed = FALSE;
657
658 if (crashed++)
659 {
660 print_stdout(0, 0, "quitmsg(crashed)\n");
661
662 fflush(NULL);
663
664 exit(-1);
665 }
666
667 SET_BIT(gtd->flags, TINTIN_FLAG_TERMINATE);
668
669 for (ses = gts->next ; ses ; ses = gts->next)
670 {
671 cleanup_session(ses);
672 }
673
674 if (gtd->chat)
675 {
676 chat_uninitialize("", "");
677 }
678
679 check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 1, "PROGRAM TERMINATION", message ? message : "");
680
681 if (gtd->history_size)
682 {
683 command(gts, do_history, "write %s/%s", gtd->system->tt_dir, HISTORY_FILE);
684 }
685
686 reset_daemon();
687
688 reset_terminal(gts);
689
690 reset_screen(gts);
691
692 if (message == NULL || *message)
693 {
694 if (message)
695 {
696 print_stdout(0, 0, "\n\e[0m%s", message);
697 }
698 print_stdout(0, 0, "\nGoodbye from TinTin++\n\n");
699 }
700 fflush(stdout);
701
702 exit(0);
703 }
704
syserr_printf(struct session * ses,char * fmt,...)705 void syserr_printf(struct session *ses, char *fmt, ...)
706 {
707 char buf[BUFFER_SIZE], name[BUFFER_SIZE], *errstr;
708
709 errstr = strerror(errno);
710
711 va_list args;
712
713 va_start(args, fmt);
714 vsprintf(buf, fmt, args);
715 va_end(args);
716
717 if (ses)
718 {
719 sprintf(name, "(%s)", ses->name);
720 }
721 else
722 {
723 sprintf(name, "(null)");
724 }
725
726 check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 4, "SYSTEM ERROR", name, buf, ntos(errno), errstr);
727
728 if (!check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 4, "CATCH SYSTEM ERROR", name, buf, ntos(errno), errstr))
729 {
730 if (gts)
731 {
732 tintin_printf2(gts, "#SYSTEM ERROR %s %s (%d: %s)\e[0m", name, buf, errno, errstr);
733 }
734
735 if (ses && ses != gts)
736 {
737 tintin_printf2(ses, "#SYSTEM ERROR: %s %s (%d: %s)\e[0m", name, buf, errno, errstr);
738 }
739
740 if (ses && gtd->ses != ses && gtd->ses != gts)
741 {
742 tintin_printf2(gtd->ses, "#SYSTEM ERROR: %s %s (%d: %s)\e[0m", name, buf, errno, errstr);
743 }
744 }
745 }
746
syserr_signal(int signal,char * msg)747 void syserr_signal(int signal, char *msg)
748 {
749 char buf[256];
750 static char crashed = FALSE;
751
752 if (crashed++)
753 {
754 print_stdout(0, 0, "syserr_signal(crashed)\n");
755
756 fflush(NULL);
757
758 exit(-1);
759 }
760
761 reset_terminal(gts);
762
763 reset_screen(gts);
764
765 fflush(NULL);
766
767 dump_stack();
768
769 sprintf(buf, "\e[1;31mFATAL SIGNAL FROM (%s): %s\e[0m\n", msg, strsignal(signal));
770
771 print_stdout(0, 0, "%s", buf);
772
773 fflush(NULL);
774
775 abort();
776 }
777
syserr_fatal(int signal,char * msg)778 void syserr_fatal(int signal, char *msg)
779 {
780 char buf[256], errstr[128];
781 static char crashed = FALSE;
782
783 if (crashed++)
784 {
785 print_stdout(0, 0, "syserr_fatal(crashed)");
786
787 fflush(NULL);
788
789 exit(-1);
790 }
791
792 if (signal == SIGHUP)
793 {
794 crashed--;
795
796 check_all_events(gts, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 0, "SIGHUB");
797
798 crashed++;
799 }
800
801 if (signal <= 0)
802 {
803 sprintf(errstr, "(error %d: %s", errno, strerror(errno));
804 }
805 else
806 {
807 sprintf(errstr, "(signal %d: %s)", signal, strsignal(signal));
808 }
809
810 check_all_events(NULL, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 1, "SYSTEM CRASH", errstr);
811
812 if (gtd->level->quiet)
813 {
814 gtd->level->quiet = 0;
815 }
816
817 reset_terminal(gts);
818
819 reset_screen(gts);
820
821 print_stdout(0, 0, "\e[?1049l\e[r");
822
823 dump_stack();
824
825 sprintf(buf, "\n\e[1;31mFATAL ERROR \e[1;32m%s %s\e[0m\n", msg, errstr);
826
827 print_stdout(0, 0, "%s", buf);
828
829 reset_daemon();
830
831 fflush(NULL);
832
833 abort();
834 }
835