top.c revision 24139
1char *copyright =
2    "Copyright (c) 1984 through 1996, William LeFebvre";
3
4/*
5 *  Top users/processes display for Unix
6 *  Version 3
7 *
8 *  This program may be freely redistributed,
9 *  but this entire comment MUST remain intact.
10 *
11 *  Copyright (c) 1984, 1989, William LeFebvre, Rice University
12 *  Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
13 */
14
15/*
16 *  See the file "Changes" for information on version-to-version changes.
17 */
18
19/*
20 *  This file contains "main" and other high-level routines.
21 */
22
23/*
24 * The following preprocessor variables, when defined, are used to
25 * distinguish between different Unix implementations:
26 *
27 *	SIGHOLD  - use SVR4 sighold function when defined
28 *	SIGRELSE - use SVR4 sigrelse function when defined
29 *	FD_SET   - macros FD_SET and FD_ZERO are used when defined
30 */
31
32#include "os.h"
33#include <signal.h>
34#include <setjmp.h>
35#include <ctype.h>
36#include <sys/time.h>
37
38/* includes specific to top */
39#include "display.h"		/* interface to display package */
40#include "screen.h"		/* interface to screen package */
41#include "top.h"
42#include "top.local.h"
43#include "boolean.h"
44#include "machine.h"
45#include "utils.h"
46
47/* Size of the stdio buffer given to stdout */
48#define Buffersize	2048
49
50/* The buffer that stdio will use */
51char stdoutbuf[Buffersize];
52
53/* build Signal masks */
54#define Smask(s)	(1 << ((s) - 1))
55
56/* for system errors */
57extern int errno;
58
59/* for getopt: */
60extern int  optind;
61extern char *optarg;
62
63/* imported from screen.c */
64extern int overstrike;
65
66/* signal handling routines */
67sigret_t leave();
68sigret_t onalrm();
69sigret_t tstop();
70#ifdef SIGWINCH
71sigret_t winch();
72#endif
73
74/* internal routines */
75void quit();
76
77/* values which need to be accessed by signal handlers */
78static int max_topn;		/* maximum displayable processes */
79
80/* miscellaneous things */
81char *myname = "top";
82jmp_buf jmp_int;
83
84/* routines that don't return int */
85
86char *username();
87char *ctime();
88char *kill_procs();
89char *renice_procs();
90
91#ifdef ORDER
92extern int (*proc_compares[])();
93#else
94extern int proc_compare();
95#endif
96time_t time();
97
98caddr_t get_process_info();
99
100/* different routines for displaying the user's identification */
101/* (values assigned to get_userid) */
102char *username();
103char *itoa7();
104
105/* display routines that need to be predeclared */
106int i_loadave();
107int u_loadave();
108int i_procstates();
109int u_procstates();
110int i_cpustates();
111int u_cpustates();
112int i_memory();
113int u_memory();
114int i_message();
115int u_message();
116int i_header();
117int u_header();
118int i_process();
119int u_process();
120
121/* pointers to display routines */
122int (*d_loadave)() = i_loadave;
123int (*d_procstates)() = i_procstates;
124int (*d_cpustates)() = i_cpustates;
125int (*d_memory)() = i_memory;
126int (*d_message)() = i_message;
127int (*d_header)() = i_header;
128int (*d_process)() = i_process;
129
130
131main(argc, argv)
132
133int  argc;
134char *argv[];
135
136{
137    register int i;
138    register int active_procs;
139    register int change;
140
141    struct system_info system_info;
142    struct statics statics;
143    caddr_t processes;
144
145    static char tempbuf1[50];
146    static char tempbuf2[50];
147    int old_sigmask;		/* only used for BSD-style signals */
148    int topn = Default_TOPN;
149    int delay = Default_DELAY;
150    int displays = 0;		/* indicates unspecified */
151    time_t curr_time;
152    char *(*get_userid)() = username;
153    char *uname_field = "USERNAME";
154    char *header_text;
155    char *env_top;
156    char **preset_argv;
157    int  preset_argc = 0;
158    char **av;
159    int  ac;
160    char dostates = No;
161    char do_unames = Yes;
162    char interactive = Maybe;
163    char warnings = 0;
164#if Default_TOPN == Infinity
165    char topn_specified = No;
166#endif
167    char ch;
168    char *iptr;
169    char no_command = 1;
170    struct timeval timeout;
171    struct process_select ps;
172#ifdef ORDER
173    char *order_name = NULL;
174    int order_index = 0;
175#endif
176#ifndef FD_SET
177    /* FD_SET and friends are not present:  fake it */
178    typedef int fd_set;
179#define FD_ZERO(x)     (*(x) = 0)
180#define FD_SET(f, x)   (*(x) = f)
181#endif
182    fd_set readfds;
183
184#ifdef ORDER
185    static char command_chars[] = "\f qh?en#sdkriIuo";
186#else
187    static char command_chars[] = "\f qh?en#sdkriIu";
188#endif
189/* these defines enumerate the "strchr"s of the commands in command_chars */
190#define CMD_redraw	0
191#define CMD_update	1
192#define CMD_quit	2
193#define CMD_help1	3
194#define CMD_help2	4
195#define CMD_OSLIMIT	4    /* terminals with OS can only handle commands */
196#define CMD_errors	5    /* less than or equal to CMD_OSLIMIT	   */
197#define CMD_number1	6
198#define CMD_number2	7
199#define CMD_delay	8
200#define CMD_displays	9
201#define CMD_kill	10
202#define CMD_renice	11
203#define CMD_idletog     12
204#define CMD_idletog2    13
205#define CMD_user	14
206#ifdef ORDER
207#define CMD_order       15
208#endif
209
210    /* set the buffer for stdout */
211#ifdef DEBUG
212    setbuffer(stdout, NULL, 0);
213#else
214    setbuffer(stdout, stdoutbuf, Buffersize);
215#endif
216
217    /* get our name */
218    if (argc > 0)
219    {
220	if ((myname = strrchr(argv[0], '/')) == 0)
221	{
222	    myname = argv[0];
223	}
224	else
225	{
226	    myname++;
227	}
228    }
229
230    /* initialize some selection options */
231    ps.idle    = Yes;
232    ps.system  = No;
233    ps.uid     = -1;
234    ps.command = NULL;
235
236    /* get preset options from the environment */
237    if ((env_top = getenv("TOP")) != NULL)
238    {
239	av = preset_argv = argparse(env_top, &preset_argc);
240	ac = preset_argc;
241
242	/* set the dummy argument to an explanatory message, in case
243	   getopt encounters a bad argument */
244	preset_argv[0] = "while processing environment";
245    }
246
247    /* process options */
248    do {
249	/* if we're done doing the presets, then process the real arguments */
250	if (preset_argc == 0)
251	{
252	    ac = argc;
253	    av = argv;
254
255	    /* this should keep getopt happy... */
256	    optind = 1;
257	}
258
259	while ((i = getopt(ac, av, "SIbinqus:d:U:o:")) != EOF)
260	{
261	    switch(i)
262	    {
263	      case 'u':			/* toggle uid/username display */
264		do_unames = !do_unames;
265		break;
266
267	      case 'U':			/* display only username's processes */
268		if ((ps.uid = userid(optarg)) == -1)
269		{
270		    fprintf(stderr, "%s: unknown user\n", optarg);
271		    exit(1);
272		}
273		break;
274
275	      case 'S':			/* show system processes */
276		ps.system = !ps.system;
277		break;
278
279	      case 'I':                   /* show idle processes */
280		ps.idle = !ps.idle;
281		break;
282
283	      case 'i':			/* go interactive regardless */
284		interactive = Yes;
285		break;
286
287	      case 'n':			/* batch, or non-interactive */
288	      case 'b':
289		interactive = No;
290		break;
291
292	      case 'd':			/* number of displays to show */
293		if ((i = atoiwi(optarg)) == Invalid || i == 0)
294		{
295		    fprintf(stderr,
296			"%s: warning: display count should be positive -- option ignored\n",
297			myname);
298		    warnings++;
299		}
300		else
301		{
302		    displays = i;
303		}
304		break;
305
306	      case 's':
307		if ((delay = atoi(optarg)) < 0)
308		{
309		    fprintf(stderr,
310			"%s: warning: seconds delay should be non-negative -- using default\n",
311			myname);
312		    delay = Default_DELAY;
313		    warnings++;
314		}
315		break;
316
317	      case 'q':		/* be quick about it */
318		/* only allow this if user is really root */
319		if (getuid() == 0)
320		{
321		    /* be very un-nice! */
322		    (void) nice(-20);
323		}
324		else
325		{
326		    fprintf(stderr,
327			"%s: warning: `-q' option can only be used by root\n",
328			myname);
329		    warnings++;
330		}
331		break;
332
333	      case 'o':		/* select sort order */
334#ifdef ORDER
335		order_name = optarg;
336#else
337		fprintf(stderr,
338			"%s: this platform does not support arbitrary ordering.  Sorry.\n",
339			myname);
340		warnings++;
341#endif
342		break;
343
344	      default:
345		fprintf(stderr, "\
346Top version %s\n\
347Usage: %s [-ISbinqu] [-d x] [-s x] [-o field] [-U username] [number]\n",
348			version_string(), myname);
349		exit(1);
350	    }
351	}
352
353	/* get count of top processes to display (if any) */
354	if (optind < ac)
355	{
356	    if ((topn = atoiwi(av[optind])) == Invalid)
357	    {
358		fprintf(stderr,
359			"%s: warning: process display count should be non-negative -- using default\n",
360			myname);
361		warnings++;
362	    }
363#if Default_TOPN == Infinity
364            else
365	    {
366		topn_specified = Yes;
367	    }
368#endif
369	}
370
371	/* tricky:  remember old value of preset_argc & set preset_argc = 0 */
372	i = preset_argc;
373	preset_argc = 0;
374
375    /* repeat only if we really did the preset arguments */
376    } while (i != 0);
377
378    /* set constants for username/uid display correctly */
379    if (!do_unames)
380    {
381	uname_field = "   UID  ";
382	get_userid = itoa7;
383    }
384
385    /* initialize the kernel memory interface */
386    if (machine_init(&statics) == -1)
387    {
388	exit(1);
389    }
390
391#ifdef ORDER
392    /* determine sorting order index, if necessary */
393    if (order_name != NULL)
394    {
395	if ((order_index = string_index(order_name, statics.order_names)) == -1)
396	{
397	    char **pp;
398
399	    fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n",
400		    myname, order_name);
401	    fprintf(stderr, "\tTry one of these:");
402	    pp = statics.order_names;
403	    while (*pp != NULL)
404	    {
405		fprintf(stderr, " %s", *pp++);
406	    }
407	    fputc('\n', stderr);
408	    exit(1);
409	}
410    }
411#endif
412
413#ifdef no_initialization_needed
414    /* initialize the hashing stuff */
415    if (do_unames)
416    {
417	init_hash();
418    }
419#endif
420
421    /* initialize termcap */
422    init_termcap(interactive);
423
424    /* get the string to use for the process area header */
425    header_text = format_header(uname_field);
426
427    /* initialize display interface */
428    if ((max_topn = display_init(&statics)) == -1)
429    {
430	fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
431	exit(4);
432    }
433
434    /* print warning if user requested more processes than we can display */
435    if (topn > max_topn)
436    {
437	fprintf(stderr,
438		"%s: warning: this terminal can only display %d processes.\n",
439		myname, max_topn);
440	warnings++;
441    }
442
443    /* adjust for topn == Infinity */
444    if (topn == Infinity)
445    {
446	/*
447	 *  For smart terminals, infinity really means everything that can
448	 *  be displayed, or Largest.
449	 *  On dumb terminals, infinity means every process in the system!
450	 *  We only really want to do that if it was explicitly specified.
451	 *  This is always the case when "Default_TOPN != Infinity".  But if
452	 *  topn wasn't explicitly specified and we are on a dumb terminal
453	 *  and the default is Infinity, then (and only then) we use
454	 *  "Nominal_TOPN" instead.
455	 */
456#if Default_TOPN == Infinity
457	topn = smart_terminal ? Largest :
458		    (topn_specified ? Largest : Nominal_TOPN);
459#else
460	topn = Largest;
461#endif
462    }
463
464    /* set header display accordingly */
465    display_header(topn > 0);
466
467    /* determine interactive state */
468    if (interactive == Maybe)
469    {
470	interactive = smart_terminal;
471    }
472
473    /* if # of displays not specified, fill it in */
474    if (displays == 0)
475    {
476	displays = smart_terminal ? Infinity : 1;
477    }
478
479    /* hold interrupt signals while setting up the screen and the handlers */
480#ifdef SIGHOLD
481    sighold(SIGINT);
482    sighold(SIGQUIT);
483    sighold(SIGTSTP);
484#else
485    old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP));
486#endif
487    init_screen();
488    (void) signal(SIGINT, leave);
489    (void) signal(SIGQUIT, leave);
490    (void) signal(SIGTSTP, tstop);
491#ifdef SIGWINCH
492    (void) signal(SIGWINCH, winch);
493#endif
494#ifdef SIGRELSE
495    sigrelse(SIGINT);
496    sigrelse(SIGQUIT);
497    sigrelse(SIGTSTP);
498#else
499    (void) sigsetmask(old_sigmask);
500#endif
501    if (warnings)
502    {
503	fputs("....", stderr);
504	fflush(stderr);			/* why must I do this? */
505	sleep((unsigned)(3 * warnings));
506	fputc('\n', stderr);
507    }
508
509    /* setup the jump buffer for stops */
510    if (setjmp(jmp_int) != 0)
511    {
512	/* control ends up here after an interrupt */
513	reset_display();
514    }
515
516    /*
517     *  main loop -- repeat while display count is positive or while it
518     *		indicates infinity (by being -1)
519     */
520
521    while ((displays == -1) || (displays-- > 0))
522    {
523	/* get the current stats */
524	get_system_info(&system_info);
525
526	/* get the current set of processes */
527	processes =
528		get_process_info(&system_info,
529				 &ps,
530#ifdef ORDER
531				 proc_compares[order_index]);
532#else
533				 proc_compare);
534#endif
535
536	/* display the load averages */
537	(*d_loadave)(system_info.last_pid,
538		     system_info.load_avg);
539
540	/* display the current time */
541	/* this method of getting the time SHOULD be fairly portable */
542	time(&curr_time);
543	i_timeofday(&curr_time);
544
545	/* display process state breakdown */
546	(*d_procstates)(system_info.p_total,
547			system_info.procstates);
548
549	/* display the cpu state percentage breakdown */
550	if (dostates)	/* but not the first time */
551	{
552	    (*d_cpustates)(system_info.cpustates);
553	}
554	else
555	{
556	    /* we'll do it next time */
557	    if (smart_terminal)
558	    {
559		z_cpustates();
560	    }
561	    else
562	    {
563		putchar('\n');
564	    }
565	    dostates = Yes;
566	}
567
568	/* display memory stats */
569	(*d_memory)(system_info.memory);
570
571	/* handle message area */
572	(*d_message)();
573
574	/* update the header area */
575	(*d_header)(header_text);
576
577	if (topn > 0)
578	{
579	    /* determine number of processes to actually display */
580	    /* this number will be the smallest of:  active processes,
581	       number user requested, number current screen accomodates */
582	    active_procs = system_info.p_active;
583	    if (active_procs > topn)
584	    {
585		active_procs = topn;
586	    }
587	    if (active_procs > max_topn)
588	    {
589		active_procs = max_topn;
590	    }
591
592	    /* now show the top "n" processes. */
593	    for (i = 0; i < active_procs; i++)
594	    {
595		(*d_process)(i, format_next_process(processes, get_userid));
596	    }
597	}
598	else
599	{
600	    i = 0;
601	}
602
603	/* do end-screen processing */
604	u_endscreen(i);
605
606	/* now, flush the output buffer */
607	fflush(stdout);
608
609	/* only do the rest if we have more displays to show */
610	if (displays)
611	{
612	    /* switch out for new display on smart terminals */
613	    if (smart_terminal)
614	    {
615		if (overstrike)
616		{
617		    reset_display();
618		}
619		else
620		{
621		    d_loadave = u_loadave;
622		    d_procstates = u_procstates;
623		    d_cpustates = u_cpustates;
624		    d_memory = u_memory;
625		    d_message = u_message;
626		    d_header = u_header;
627		    d_process = u_process;
628		}
629	    }
630
631	    no_command = Yes;
632	    if (!interactive)
633	    {
634		/* set up alarm */
635		(void) signal(SIGALRM, onalrm);
636		(void) alarm((unsigned)delay);
637
638		/* wait for the rest of it .... */
639		pause();
640	    }
641	    else while (no_command)
642	    {
643		/* assume valid command unless told otherwise */
644		no_command = No;
645
646		/* set up arguments for select with timeout */
647		FD_ZERO(&readfds);
648		FD_SET(1, &readfds);		/* for standard input */
649		timeout.tv_sec  = delay;
650		timeout.tv_usec = 0;
651
652		/* wait for either input or the end of the delay period */
653		if (select(32, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout) > 0)
654		{
655		    int newval;
656		    char *errmsg;
657
658		    /* something to read -- clear the message area first */
659		    clear_message();
660
661		    /* now read it and convert to command strchr */
662		    /* (use "change" as a temporary to hold strchr) */
663		    (void) read(0, &ch, 1);
664		    if ((iptr = strchr(command_chars, ch)) == NULL)
665		    {
666			/* illegal command */
667			new_message(MT_standout, " Command not understood");
668			putchar('\r');
669			no_command = Yes;
670		    }
671		    else
672		    {
673			change = iptr - command_chars;
674			if (overstrike && change > CMD_OSLIMIT)
675			{
676			    /* error */
677			    new_message(MT_standout,
678			    " Command cannot be handled by this terminal");
679			    putchar('\r');
680			    no_command = Yes;
681			}
682			else switch(change)
683			{
684			    case CMD_redraw:	/* redraw screen */
685				reset_display();
686				break;
687
688			    case CMD_update:	/* merely update display */
689				/* is the load average high? */
690				if (system_info.load_avg[0] > LoadMax)
691				{
692				    /* yes, go home for visual feedback */
693				    go_home();
694				    fflush(stdout);
695				}
696				break;
697
698			    case CMD_quit:	/* quit */
699				quit(0);
700				/*NOTREACHED*/
701				break;
702
703			    case CMD_help1:	/* help */
704			    case CMD_help2:
705				reset_display();
706				clear();
707				show_help();
708				standout("Hit any key to continue: ");
709				fflush(stdout);
710				(void) read(0, &ch, 1);
711				break;
712
713			    case CMD_errors:	/* show errors */
714				if (error_count() == 0)
715				{
716				    new_message(MT_standout,
717					" Currently no errors to report.");
718				    putchar('\r');
719				    no_command = Yes;
720				}
721				else
722				{
723				    reset_display();
724				    clear();
725				    show_errors();
726				    standout("Hit any key to continue: ");
727				    fflush(stdout);
728				    (void) read(0, &ch, 1);
729				}
730				break;
731
732			    case CMD_number1:	/* new number */
733			    case CMD_number2:
734				new_message(MT_standout,
735				    "Number of processes to show: ");
736				newval = readline(tempbuf1, 8, Yes);
737				if (newval > -1)
738				{
739				    if (newval > max_topn)
740				    {
741					new_message(MT_standout | MT_delayed,
742					  " This terminal can only display %d processes.",
743					  max_topn);
744					putchar('\r');
745				    }
746
747				    if (newval == 0)
748				    {
749					/* inhibit the header */
750					display_header(No);
751				    }
752				    else if (newval > topn && topn == 0)
753				    {
754					/* redraw the header */
755					display_header(Yes);
756					d_header = i_header;
757				    }
758				    topn = newval;
759				}
760				break;
761
762			    case CMD_delay:	/* new seconds delay */
763				new_message(MT_standout, "Seconds to delay: ");
764				if ((i = readline(tempbuf1, 8, Yes)) > -1)
765				{
766				    delay = i;
767				}
768				clear_message();
769				break;
770
771			    case CMD_displays:	/* change display count */
772				new_message(MT_standout,
773					"Displays to show (currently %s): ",
774					displays == -1 ? "infinite" :
775							 itoa(displays));
776				if ((i = readline(tempbuf1, 10, Yes)) > 0)
777				{
778				    displays = i;
779				}
780				else if (i == 0)
781				{
782				    quit(0);
783				}
784				clear_message();
785				break;
786
787			    case CMD_kill:	/* kill program */
788				new_message(0, "kill ");
789				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
790				{
791				    if ((errmsg = kill_procs(tempbuf2)) != NULL)
792				    {
793					new_message(MT_standout, errmsg);
794					putchar('\r');
795					no_command = Yes;
796				    }
797				}
798				else
799				{
800				    clear_message();
801				}
802				break;
803
804			    case CMD_renice:	/* renice program */
805				new_message(0, "renice ");
806				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
807				{
808				    if ((errmsg = renice_procs(tempbuf2)) != NULL)
809				    {
810					new_message(MT_standout, errmsg);
811					putchar('\r');
812					no_command = Yes;
813				    }
814				}
815				else
816				{
817				    clear_message();
818				}
819				break;
820
821			    case CMD_idletog:
822			    case CMD_idletog2:
823				ps.idle = !ps.idle;
824				new_message(MT_standout | MT_delayed,
825				    " %sisplaying idle processes.",
826				    ps.idle ? "D" : "Not d");
827				putchar('\r');
828				break;
829
830			    case CMD_user:
831				new_message(MT_standout,
832				    "Username to show: ");
833				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
834				{
835				    if (tempbuf2[0] == '+' &&
836					tempbuf2[1] == '\0')
837				    {
838					ps.uid = -1;
839				    }
840				    else if ((i = userid(tempbuf2)) == -1)
841				    {
842					new_message(MT_standout,
843					    " %s: unknown user", tempbuf2);
844					no_command = Yes;
845				    }
846				    else
847				    {
848					ps.uid = i;
849				    }
850				    putchar('\r');
851				}
852				else
853				{
854				    clear_message();
855				}
856				break;
857
858#ifdef ORDER
859			    case CMD_order:
860				new_message(MT_standout,
861				    "Order to sort: ");
862				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
863				{
864				  if ((i = string_index(tempbuf2, statics.order_names)) == -1)
865					{
866					  new_message(MT_standout,
867					      " %s: unrecognized sorting order", tempbuf2);
868					  no_command = Yes;
869				    }
870				    else
871				    {
872					order_index = i;
873				    }
874				    putchar('\r');
875				}
876				else
877				{
878				    clear_message();
879				}
880				break;
881#endif
882
883			    default:
884				new_message(MT_standout, " BAD CASE IN SWITCH!");
885				putchar('\r');
886			}
887		    }
888
889		    /* flush out stuff that may have been written */
890		    fflush(stdout);
891		}
892	    }
893	}
894    }
895
896    quit(0);
897    /*NOTREACHED*/
898}
899
900/*
901 *  reset_display() - reset all the display routine pointers so that entire
902 *	screen will get redrawn.
903 */
904
905reset_display()
906
907{
908    d_loadave    = i_loadave;
909    d_procstates = i_procstates;
910    d_cpustates  = i_cpustates;
911    d_memory     = i_memory;
912    d_message	 = i_message;
913    d_header	 = i_header;
914    d_process	 = i_process;
915}
916
917/*
918 *  signal handlers
919 */
920
921sigret_t leave()	/* exit under normal conditions -- INT handler */
922
923{
924    end_screen();
925    exit(0);
926}
927
928sigret_t tstop(i)	/* SIGTSTP handler */
929
930int i;
931
932{
933    /* move to the lower left */
934    end_screen();
935    fflush(stdout);
936
937    /* default the signal handler action */
938    (void) signal(SIGTSTP, SIG_DFL);
939
940    /* unblock the signal and send ourselves one */
941#ifdef SIGRELSE
942    sigrelse(SIGTSTP);
943#else
944    (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1)));
945#endif
946    (void) kill(0, SIGTSTP);
947
948    /* reset the signal handler */
949    (void) signal(SIGTSTP, tstop);
950
951    /* reinit screen */
952    reinit_screen();
953
954    /* jump to appropriate place */
955    longjmp(jmp_int, 1);
956
957    /*NOTREACHED*/
958}
959
960#ifdef SIGWINCH
961sigret_t winch(i)		/* SIGWINCH handler */
962
963int i;
964
965{
966    /* reascertain the screen dimensions */
967    get_screensize();
968
969    /* tell display to resize */
970    max_topn = display_resize();
971
972    /* reset the signal handler */
973    (void) signal(SIGWINCH, winch);
974
975    /* jump to appropriate place */
976    longjmp(jmp_int, 1);
977}
978#endif
979
980void quit(status)		/* exit under duress */
981
982int status;
983
984{
985    end_screen();
986    exit(status);
987    /*NOTREACHED*/
988}
989
990sigret_t onalrm()	/* SIGALRM handler */
991
992{
993    /* this is only used in batch mode to break out of the pause() */
994    /* return; */
995}
996
997