1 /*
2 * ftpsigs.c -- handles signals
3 *
4 * Yet Another FTP Client
5 * Copyright (C) 1998-2001, Martin Hedenfalk <mhe@stacken.kth.se>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version. See COPYING for more details.
11 */
12
13 #include "syshdr.h"
14 #include "ftp.h"
15 #include "ftpsigs.h"
16 #include "gvars.h"
17 #include "transfer.h"
18 #include "cmd.h"
19
ftp_set_signal_with_mask(int signum,sighandler_t handler,int onesig)20 void ftp_set_signal_with_mask(int signum, sighandler_t handler, int onesig)
21 {
22 int saved_errno = errno;
23 #ifdef HAVE_POSIX_SIGNALS
24 struct sigaction sa;
25 sigset_t ss;
26
27 /* unblock this signal */
28 sigemptyset(&ss);
29 sigaddset(&ss, signum);
30 sigprocmask(SIG_UNBLOCK, &ss, 0);
31
32 /* set the signal handler */
33 sa.sa_handler = handler;
34 sigemptyset(&sa.sa_mask);
35 if(onesig)
36 sigaddset(&sa.sa_mask, onesig); /* a signal to exclude */
37 sa.sa_flags = 0;
38 #ifdef SA_RESTART
39 sa.sa_flags |= SA_RESTART;
40 #endif
41
42 # if 0 /* this causes segfaults!? */
43 if(signum == SIGALRM) {
44 # ifdef SA_INTERRUPT
45 sa.sa_flags |= SA_INTERRUPT; /* old, obsolete flag? */
46 # endif
47 } else {
48 # ifdef SA_RESTART
49 sa.sa_flags |= SA_RESTART;
50 # endif
51 }
52 # endif
53
54 /* sa.sa_restorer = 0;*/
55
56 if(sigaction(signum, &sa, 0) != 0)
57 ftp_trace("couldn't set signalhandler for signal %d\n", signum);
58 #else
59 signal(signum, handler);
60 #endif
61 errno = saved_errno;
62 }
63
ftp_set_signal(int signum,sighandler_t handler)64 void ftp_set_signal(int signum, sighandler_t handler)
65 {
66 ftp_set_signal_with_mask(signum, handler, 0);
67 }
68
69 static unsigned int sigints = 0;
70
sigint_close_handler(int signum)71 void sigint_close_handler(int signum)
72 {
73 if(gvSighupReceived)
74 return;
75
76 ftp_trace("Interrupt received\n");
77 sigints++;
78
79 gvInterrupted = true;
80
81 /* close connection and restart command loop after 4 interrupts
82 *
83 * If we're in SSH mode, the interrupt signal is intercepted by
84 * the ssh program as well, which terminates directly. The ssh
85 * program is started by ssh_connect() in ssh_ftp.c by forking and
86 * execv'ing the program in the child process. I don't know if
87 * there is a way to prevent the interrupt signal to reach the ssh
88 * program?
89 */
90
91 if (sigints >= 4
92 #ifdef HAVE_LIBSSH
93 || ftp->session
94 #endif
95 ) {
96 ftp_close();
97 sigints = 0;
98 if(gvJmpBufSet) {
99 ftp_trace("jumping to gvRestartJmp\n");
100 ftp_longjmp(gvRestartJmp, 1);
101 } else {
102 exit(17);
103 }
104 }
105 else if(sigints == 3) {
106 if(gvJmpBufSet)
107 ftp_err(_("OK, one more to close connection... \n"));
108 else
109 ftp_err(_("OK, one more to exit program... \n"));
110 }
111
112 /* disable any alarm set */
113 alarm(0);
114 ftp_set_signal(SIGALRM, SIG_DFL);
115
116 /* re-install the signal handler */
117 /* ftp_set_signal(SIGINT, sigint_close_handler);*/
118 }
119
sigint_abort_handler(int signum)120 void sigint_abort_handler(int signum)
121 {
122 if(gvSighupReceived)
123 return;
124
125 ftp_trace("Interrupt received\n");
126 sigints++;
127
128 gvInterrupted = true;
129
130 if (sigints >= 3
131 #ifdef HAVE_LIBSSH
132 || ftp->session
133 #endif
134 ) {
135 sigints = 0;
136 alarm(0);
137 if(gvJmpBufSet) {
138 ftp_trace("jumping to gvRestartJmp\n");
139 ftp_flush_reply();
140 ftp_longjmp(gvRestartJmp, 1);
141 } else
142 exit(17);
143 } else if(sigints == 2)
144 ftp_err(_("OK, one more to abort command... \n"));
145
146 /* re-install the signal handler */
147 /* ftp_set_signal(SIGINT, sigint_abort_handler);*/
148 }
149
sigint_jmp_handler(int signum)150 void sigint_jmp_handler(int signum)
151 {
152 if(gvSighupReceived)
153 return;
154
155 ftp_trace("Interrupt received \n");
156 alarm(0);
157 if(gvJmpBufSet) {
158 ftp_trace("jumping to gvRestartJmp\n");
159 #ifdef HAVE_LIBSSH
160 if(ftp->session)
161 ftp_close();
162 #endif
163 ftp_longjmp(gvRestartJmp, 1);
164 } else {
165 ftp_err(_("Interrupt received, exiting... \n"));
166 exit(17);
167 }
168 }
169
170 #if 0
171 static void sighup_term_handler(int signum)
172 {
173 printf(_("SIGTERM (terminate) received, exiting...\n"));
174 ftp_close();
175 ftp_destroy(gvFtp);
176 gvars_destroy();
177 exit(19);
178 }
179 #endif
180
sighup_handler(int signum)181 void sighup_handler(int signum)
182 {
183 ftp_set_signal(SIGINT, SIG_IGN);
184 ftp_set_signal(SIGHUP, sighup_handler);
185 if(gvSighupReceived)
186 return;
187
188 gvSighupReceived = true;
189 if(gvInTransfer)
190 ftp_err(_("Hangup received, continuing transfer in background...\n"));
191 else {
192 ftp_err(_("Hangup received, exiting...\n"));
193 exit_yafc();
194 }
195
196 if(transfer_init_nohup(0) != 0) {
197 if(transfer_init_nohup("/dev/null") != 0) {
198 ftp_err(_("Can't redirect output, exiting...\n"));
199 ftp_quit();
200 exit(18);
201 }
202 }
203
204 transfer_begin_nohup(0, 0);
205 sigints = 0;
206 }
207
ftp_longjmp(sigjmp_buf restart_jmp,int arg)208 int ftp_longjmp(
209 #ifdef HAVE_POSIX_SIGSETJMP
210 sigjmp_buf restart_jmp
211 #else
212 jmp_buf restart_jmp
213 #endif
214 , int arg)
215 {
216 #ifdef HAVE_POSIX_SIGSETJMP
217 siglongjmp(restart_jmp, 1);
218 #else
219 longjmp(restart_jmp, 1);
220 #endif
221 return 0; /* make cc happy */
222 }
223
ftp_initsigs(void)224 void ftp_initsigs(void)
225 {
226 sigints = 0;
227 ftp_set_signal(SIGPIPE, SIG_IGN);
228 ftp_set_signal(SIGINT, gvSighupReceived ? SIG_IGN : sigint_jmp_handler);
229 ftp_set_signal_with_mask(SIGHUP, sighup_handler, SIGINT);
230 }
231
ftp_sigint_close_reset(void)232 void ftp_sigint_close_reset(void)
233 {
234 sigints = 0;
235 ftp_initsigs();
236 }
237
ftp_set_close_handler(void)238 void ftp_set_close_handler(void)
239 {
240 sigints = 0;
241 ftp_set_signal(SIGINT, gvSighupReceived ? SIG_IGN : sigint_close_handler);
242 }
243
ftp_set_abort_handler(void)244 void ftp_set_abort_handler(void)
245 {
246 sigints = 0;
247 ftp_set_signal(SIGINT, gvSighupReceived ? SIG_IGN : sigint_abort_handler);
248 }
249
ftp_sigints(void)250 unsigned int ftp_sigints(void)
251 {
252 return sigints;
253 }
254