1 /*
2  * Copyright (c) 1993-1997 by Alexander V. Lukyanov (lav@yars.free.net)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 #include <config.h>
20 #include <signal.h>
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <setjmp.h>
28 #include "edit.h"
29 
30 #ifndef __MSDOS__
31 #include <termios.h>
32 #ifdef HAVE_SYS_IOCTL_H
33 #include <sys/ioctl.h>
34 #endif
35 #endif
36 
37 /* This pair of functions is to work
38    with signal handlers - install and release */
39 static struct sigaction  OldSIGHUP;
40 static struct sigaction  OldSIGINT;
41 static struct sigaction  OldSIGQUIT;
42 static struct sigaction  OldSIGTSTP;
43 
44 #ifdef __GNUC__
45 #define  SA_HANDLER_TYPE   typeof(OldSIGHUP.sa_handler)
46 #else
47 #define  SA_HANDLER_TYPE   void(*)(int)
48 #endif
49 #ifndef SA_RESTART
50 #define SA_RESTART 0
51 #endif
52 
53 
BlockSignals()54 void  BlockSignals()
55 {
56    sigset_t ss;
57 
58    sigemptyset(&ss);
59    sigaddset(&ss,SIGALRM);
60 
61    sigprocmask(SIG_BLOCK,&ss,NULL);
62 }
UnblockSignals()63 void  UnblockSignals()
64 {
65    sigset_t ss;
66 
67    sigemptyset(&ss);
68    sigaddset(&ss,SIGALRM);
69 
70    sigprocmask(SIG_UNBLOCK,&ss,NULL);
71 }
72 
73 #ifndef KEY_RESIZE
74 int   resize_flag=0;
75 
CheckWindowResize()76 void  CheckWindowResize()
77 {
78 #if !defined(__MSDOS__) && defined(TIOCGWINSZ)
79    struct winsize winsz;
80    static bool disable_resize=false;
81 
82    resize_flag=0;
83 
84    if(disable_resize)
85       return;
86 
87    winsz.ws_col=COLS;
88    winsz.ws_row=LINES;
89    ioctl(0,TIOCGWINSZ,&winsz);
90    if(winsz.ws_col && winsz.ws_row
91    && (winsz.ws_col!=COLS || winsz.ws_row!=LINES)
92    && !(getenv("LINES") && getenv("COLUMNS")))
93    {
94       WIN *w=CreateWin(0,0,COLS,LINES,NORMAL_TEXT_ATTR,"",NOSHADOW);
95       DisplayWin(w);
96       InitCurses(); // this does endwin() automatically
97       if(winsz.ws_col!=COLS || winsz.ws_row!=LINES)
98       {
99 	 beep();
100          disable_resize=true;
101       }
102       clearok(stdscr,TRUE);
103       CorrectParameters();
104       flag|=REDISPLAY_ALL;
105       CloseWin();
106       DestroyWin(w);
107    }
108 #endif
109 }
110 
resize_sig(int sig)111 void  resize_sig(int sig)
112 {
113    (void)sig;
114    resize_flag=1;
115 
116    extern bool getch_return_set;
117    extern sigjmp_buf getch_return;
118 
119    if(getch_return_set)
120       siglongjmp(getch_return,1);
121 }
122 #endif // KEY_RESIZE
123 
SuspendEditor()124 void    SuspendEditor()
125 {
126 #ifndef __MSDOS__
127 /*    clear();*/
128     curs_set(1);
129     refresh();
130     endwin();
131     kill(getpid(),SIGSTOP);
132     refresh();
133 #else
134    ErrMsg("Suspending is not supported under MSDOG");
135 #endif
136 }
137 
138 static char mem[4000];
TmpFileName()139 char *TmpFileName()
140 {
141 #ifndef __MSDOS__
142    sprintf(mem,"%s/.le/tmp/",HOME);
143    char *add=mem+strlen(mem);
144    strcpy(add,FileName);
145    while(*add)
146    {
147       if(isslash(*add))
148 	 *add='_';
149       add++;
150    }
151    sprintf(add,".%d",(int)getpid());
152 #else
153    sprintf(mem,"le%d.res",(int)getpid());
154 #endif
155    return mem;
156 }
HupFileName(int sig)157 char *HupFileName(int sig)
158 {
159 #ifndef __MSDOS__
160    sprintf(mem,"%s/.le/tmp/DUMP-%d-",HOME,sig);
161    char *add=mem+strlen(mem);
162    strcpy(add,FileName);
163    while(*add)
164    {
165       if(isslash(*add))
166 	 *add='_';
167       add++;
168    }
169    sprintf(add,".%d",(int)getpid());
170 #else
171    sprintf(mem,"le%d.hup",(int)getpid());
172 #endif
173    return mem;
174 }
175 
hup(int sig)176 void    hup(int sig)
177 {
178    endwin();
179 
180    if(modified)
181    {
182       char *s=HupFileName(sig);
183       fprintf(stderr,"le: Caught signal %d, dumping text to %s\n",sig,s);
184       int fd=creat(s,0600);
185       num act_written;
186       WriteBlock(fd,0,Size(),&act_written);
187       close(fd);
188    }
189    else
190    {
191       fprintf(stderr,"le: Caught signal %d\n",sig);
192    }
193    if(sig==SIGSEGV || sig==SIGBUS)
194    {
195       ReleaseSignalHandlers();
196       sigset_t mask;
197       sigemptyset(&mask);
198       sigaddset(&mask,sig);
199       sigprocmask(SIG_UNBLOCK,&mask,0);
200       kill(getpid(),sig);
201    }
202    exit(1);
203 }
204 
alarmsave(int a)205 void    alarmsave(int a)
206 {
207    // set handler again to be safe
208    struct sigaction  alarmsaveaction;
209    alarmsaveaction.sa_handler=(SA_HANDLER_TYPE)alarmsave;
210    alarmsaveaction.sa_flags=SA_RESTART;
211    sigemptyset(&alarmsaveaction.sa_mask);
212    sigaction(SIGALRM,&alarmsaveaction,NULL);
213 
214    static offs dump_pos=0;
215    static int fd=-1;
216    static int interrupted=0;
217    const int chunk=0x20000;
218 
219    (void)a;
220 
221    // check if the text changed
222    if(modified==1)
223    {
224       // it did - reset dump state
225       dump_pos=0;
226       if(fd!=-1)
227       {
228 	 interrupted++;
229 	 close(fd);
230       }
231       char *s=TmpFileName();
232       fd=open(s,O_CREAT|O_WRONLY|O_TRUNC,0600);
233       if(fd==-1)
234       {
235 	 alarm(ALARMDELAY);
236 	 return;
237       }
238       modified=3;
239    }
240    // if the dump is in progress
241    if(modified==3)
242    {
243       num  act_written;
244       if(WriteBlock(fd,dump_pos,(interrupted>5?Size()-dump_pos:chunk),
245 		     &act_written)!=OK)
246       {
247       done:
248 	 close(fd);
249 	 fd=-1;
250 	 // mark it as dumped
251 	 modified=2;
252       }
253       else
254       {
255 	 dump_pos+=act_written;
256 	 if(dump_pos>=Size())
257 	 {
258 	    interrupted=0;
259 	    goto done;
260 	 }
261 	 // after a second write next chunk
262 	 alarm(1);
263 	 return;
264       }
265    }
266    alarm(ALARMDELAY);
267 }
268 
InstallSignalHandlers()269 void    InstallSignalHandlers()
270 {
271    struct sigaction  hupaction;
272    struct sigaction  alarmsaveaction;
273    struct sigaction  ign_action;
274    struct sigaction  suspend_action;
275 
276    hupaction.sa_handler=(SA_HANDLER_TYPE)hup;
277    hupaction.sa_flags=0;
278    sigfillset(&hupaction.sa_mask);
279 
280    alarmsaveaction.sa_handler=(SA_HANDLER_TYPE)alarmsave;
281    alarmsaveaction.sa_flags=SA_RESTART;
282    sigemptyset(&alarmsaveaction.sa_mask);
283 
284    ign_action.sa_handler=(SA_HANDLER_TYPE)SIG_IGN;
285    ign_action.sa_flags=0;
286    sigemptyset(&ign_action.sa_mask);
287 
288    suspend_action.sa_handler=(SA_HANDLER_TYPE)SuspendEditor;
289    suspend_action.sa_flags=0;
290    sigemptyset(&suspend_action.sa_mask);
291 
292 #ifndef	KEY_RESIZE
293    struct sigaction  resize_action;
294    resize_action.sa_handler=(SA_HANDLER_TYPE)resize_sig;
295    resize_action.sa_flags=0;
296    sigemptyset(&resize_action.sa_mask);
297 #endif
298 
299    BlockSignals();
300 
301    /* catch signals to dump editing file and exit */
302    sigaction(SIGHUP,&hupaction,&OldSIGHUP);
303 
304 #ifndef DEBUG
305    sigaction(SIGILL,&hupaction,NULL);
306 #ifdef SIGTRAP
307    sigaction(SIGTRAP,&hupaction,NULL);
308 #endif
309    sigaction(SIGABRT,&hupaction,NULL);
310 #ifdef SIGEMT
311    sigaction(SIGEMT,&hupaction,NULL);
312 #endif
313    sigaction(SIGFPE,&hupaction,NULL);
314 #if SIGBUS
315    sigaction(SIGBUS,&hupaction,NULL);
316 #endif
317    sigaction(SIGSEGV,&hupaction,NULL);
318 #ifdef SIGSYS
319    sigaction(SIGSYS,&hupaction,NULL);
320 #endif
321 #endif /* DEBUG */
322 
323    sigaction(SIGTERM,&hupaction,NULL);
324 #ifdef SIGPWR
325    sigaction(SIGPWR,&hupaction,NULL);
326 #endif
327 
328    sigaction(SIGALRM,&alarmsaveaction,NULL);
329 
330    sigaction(SIGINT,&ign_action,&OldSIGINT);
331    sigaction(SIGQUIT,&ign_action,&OldSIGQUIT);
332 #ifdef SIGTSTP
333    sigaction(SIGTSTP,&suspend_action,&OldSIGTSTP);
334 #endif
335 #ifdef SIGVTALRM
336    sigaction(SIGVTALRM,&ign_action,NULL);
337 #endif
338 #ifdef SIGPIPE
339    sigaction(SIGPIPE,&ign_action,NULL);
340 #endif
341    sigaction(SIGUSR1,&ign_action,NULL);
342    sigaction(SIGUSR2,&ign_action,NULL);
343 
344 #if defined(SIGWINCH) && !defined(KEY_RESIZE)
345    sigaction(SIGWINCH,&resize_action,NULL);
346 #endif
347 #ifdef SIGCHLD
348 //    sigaction(SIGCHLD,&ign_action,NULL);
349 #endif
350 #ifdef SIGTTIN
351    sigaction(SIGTTIN,&suspend_action,NULL);
352 #endif
353 #ifdef SIGTTOU
354    sigaction(SIGTTOU,&suspend_action,NULL);
355 #endif
356 }
ReleaseSignalHandlers()357 void    ReleaseSignalHandlers()
358 {
359    struct sigaction  dfl_action;
360 
361    dfl_action.sa_handler=(SA_HANDLER_TYPE)SIG_DFL;
362    dfl_action.sa_flags=0;
363 
364    alarm(0);   /* turn off alarm */
365 
366    sigaction(SIGHUP,&OldSIGHUP,NULL);
367    sigaction(SIGILL,&dfl_action,NULL);
368 #ifdef SIGTRAP
369    sigaction(SIGTRAP,&dfl_action,NULL);
370 #endif
371    sigaction(SIGABRT,&dfl_action,NULL);
372 #ifdef SIGEMT
373    sigaction(SIGEMT,&dfl_action,NULL);
374 #endif
375    sigaction(SIGFPE,&dfl_action,NULL);
376 #ifdef SIGBUS
377    sigaction(SIGBUS,&dfl_action,NULL);
378 #endif
379    sigaction(SIGSEGV,&dfl_action,NULL);
380 #ifdef SIGSYS
381    sigaction(SIGSYS,&dfl_action,NULL);
382 #endif
383    sigaction(SIGTERM,&dfl_action,NULL);
384 #ifdef SIGPWR
385    sigaction(SIGPWR,&dfl_action,NULL);
386 #endif
387 
388    sigaction(SIGALRM,&dfl_action,NULL);
389 
390    sigaction(SIGINT,&OldSIGINT,NULL);
391    sigaction(SIGQUIT,&OldSIGQUIT,NULL);
392 #ifdef SIGTSTP
393    sigaction(SIGTSTP,&OldSIGTSTP,NULL);
394 #endif
395 #ifdef SIGVTALRM
396    sigaction(SIGVTALRM,&dfl_action,NULL);
397 #endif
398 #ifdef SIGPIPE
399    sigaction(SIGPIPE,&dfl_action,NULL);
400 #endif
401    sigaction(SIGUSR1,&dfl_action,NULL);
402    sigaction(SIGUSR2,&dfl_action,NULL);
403 
404    UnblockSignals();
405 }
406