1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21
22 #include "../my_config.h"
23
24 extern "C"
25 {
26 #if HAVE_LOCALE_H
27 #include <locale.h>
28 #endif
29
30 #if HAVE_SIGNAL_H
31 #include <signal.h>
32 #endif
33
34 #if HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37
38 #if MUTEX_WORKS
39 #if HAVE_PTHREAD_H
40 #include <pthread.h>
41 #else
42 #define pthread_t U_I
43 #endif
44 #endif
45
46 }
47
48 #include <iostream>
49 #include <new>
50
51 #include "integers.hpp"
52 #include "dar_suite.hpp"
53 #include "erreurs.hpp"
54 #include "libdar.hpp"
55 #include "thread_cancellation.hpp"
56 #include "memory_check.hpp"
57 #include "line_tools.hpp"
58 #ifdef HAVE_LIBTHREADAR_LIBTHREADAR_HPP
59 #include <libthreadar/libthreadar.hpp>
60 #endif
61
62 #define GENERAL_REPORT(msg) if(ui != nullptr) \
63 { \
64 ui->change_non_interactive_output(&cerr); \
65 ui->warning(msg); \
66 } \
67 else \
68 cerr << msg << endl;
69
70
71
72 using namespace libdar;
73
74 static shell_interaction *ui = nullptr;
75 static void signals_abort(int l, bool now);
76 static void signal_abort_delayed(int l);
77 static void signal_abort_now(int l);
78
dar_suite_reset_signal_handler()79 void dar_suite_reset_signal_handler()
80 {
81 #if HAVE_SIGNAL_H
82 signal(SIGTERM, &signal_abort_delayed);
83 signal(SIGINT, &signal_abort_delayed);
84 signal(SIGQUIT, &signal_abort_delayed);
85 signal(SIGHUP, &signal_abort_delayed);
86 signal(SIGUSR1, &signal_abort_delayed);
87 signal(SIGUSR2, &signal_abort_now);
88 #if GPGME_SUPPORT
89 // for GPGME:
90 signal(SIGPIPE, SIG_IGN);
91 #endif
92 #endif
93 }
94
dar_suite_global(int argc,char * const argv[],const char ** env,const char * getopt_string,const struct option * long_options,char stop_scan,int (* call)(shell_interaction & dialog,int,char * const[],const char ** env))95 int dar_suite_global(int argc,
96 char * const argv[],
97 const char **env,
98 const char *getopt_string,
99 #if HAVE_GETOPT_LONG
100 const struct option *long_options,
101 #endif
102 char stop_scan,
103 int (*call)(shell_interaction & dialog, int, char * const [], const char **env))
104 {
105 int ret = EXIT_OK;
106
107 memory_check_snapshot();
108 dar_suite_reset_signal_handler();
109
110 #ifdef ENABLE_NLS
111 // gettext settings
112 try
113 {
114 if(string(DAR_LOCALEDIR) != string(""))
115 if(bindtextdomain(PACKAGE, DAR_LOCALEDIR) == nullptr)
116 throw Erange("", "Cannot open the translated messages directory, native language support will not work");
117 if(setlocale(LC_MESSAGES, "") == nullptr || setlocale(LC_CTYPE, "") == nullptr)
118 throw Erange("", "Cannot set locale category, native language support will not work");
119 if(textdomain(PACKAGE) == nullptr)
120 throw Erange("", "Cannot find dar's catalogue, native language support will not work");
121 }
122 catch(Erange & e)
123 {
124 cerr << e.get_message() << endl;
125 }
126 #endif
127
128 try
129 {
130 U_I min, med, maj;
131 bool silent;
132 line_tools_look_for_Q(argc,
133 argv,
134 getopt_string,
135 #if HAVE_GETOPT_LONG
136 long_options,
137 #endif
138 stop_scan,
139 silent);
140 ui = new (nothrow) shell_interaction(&cerr, &cerr, silent);
141 if(ui == nullptr)
142 throw Ememory("dar_suite_global");
143
144 get_version(maj, med, min);
145 if(maj != LIBDAR_COMPILE_TIME_MAJOR || med < LIBDAR_COMPILE_TIME_MEDIUM)
146 {
147 GENERAL_REPORT(tools_printf(gettext("We have linked with an incompatible version of libdar. Expecting version %d.%d.x but having linked with version %d.%d.%d"), LIBDAR_COMPILE_TIME_MAJOR, LIBDAR_COMPILE_TIME_MEDIUM, maj, med, min));
148 ret = EXIT_ERROR;
149 }
150 else
151 ret = (*call)(*ui, argc, argv, env);
152
153 // closing libdar
154
155 close_and_clean();
156 }
157 catch(Efeature & e)
158 {
159 GENERAL_REPORT(string(gettext("NOT YET IMPLEMENTED FEATURE has been used: ")) + e.get_message());
160 GENERAL_REPORT(string(gettext("Please check documentation or upgrade your software if available")));
161 ret = EXIT_SYNTAX;
162 }
163 catch(Ehardware & e)
164 {
165 GENERAL_REPORT(string(gettext("SEEMS TO BE A HARDWARE PROBLEM: "))+e.get_message());
166 GENERAL_REPORT(string(gettext("Please check your hardware")));
167 ret = EXIT_ERROR;
168 }
169 catch(Esecu_memory & e)
170 {
171 GENERAL_REPORT(string(gettext("Lack of SECURED memory to achieve the operation, aborting operation")));
172 ret = EXIT_ERROR;
173 }
174 catch(Ememory & e)
175 {
176 GENERAL_REPORT(string(gettext("Lack of memory to achieve the operation, aborting operation")));
177 ret = EXIT_ERROR;
178 }
179 catch(std::bad_alloc & e)
180 {
181 GENERAL_REPORT(string(gettext("Lack of memory to achieve the operation, aborting operation")));
182 ret = EXIT_ERROR;
183 }
184 catch(Erange & e)
185 {
186 GENERAL_REPORT(string(gettext("FATAL error, aborting operation")));
187 GENERAL_REPORT(e.get_message());
188 ret = EXIT_ERROR;
189 }
190 catch(Euser_abort & e)
191 {
192 GENERAL_REPORT(string(gettext("Aborting program. User refused to continue while asking: ")) + e.get_message());
193 ret = EXIT_USER_ABORT;
194 }
195 catch(Ethread_cancel & e)
196 {
197 GENERAL_REPORT(string(gettext("Program has been aborted for the following reason: ")) + e.get_message());
198 ret = EXIT_USER_ABORT;
199 }
200 catch(Edata & e)
201 {
202 GENERAL_REPORT(e.get_message());
203 ret = EXIT_DATA_ERROR;
204 }
205 catch(Escript & e)
206 {
207 GENERAL_REPORT(string(gettext("Aborting program. An error occurred concerning user command execution: ")) + e.get_message());
208 ret = EXIT_SCRIPT_ERROR;
209 }
210 catch(Elibcall & e)
211 {
212 GENERAL_REPORT(string(gettext("Aborting program. An error occurred while calling libdar: ")) + e.get_message());
213 ret = EXIT_LIBDAR;
214 }
215 catch(Einfinint & e)
216 {
217 GENERAL_REPORT(string(gettext("Aborting program. ")) + e.get_message());
218 ret = EXIT_BUG;
219 }
220 catch(Elimitint & e)
221 {
222 GENERAL_REPORT(string(gettext("Aborting program. ")) + e.get_message());
223 ret = EXIT_LIMITINT;
224 }
225 catch(Ecompilation & e)
226 {
227 GENERAL_REPORT(string(gettext("Aborting program. The requested operation needs a feature that has been disabled at compilation time: ")) + e.get_message());
228 ret = EXIT_COMPILATION;
229 }
230 catch(Esystem & e)
231 {
232 GENERAL_REPORT(string(gettext("FATAL error, aborting operation")));
233 GENERAL_REPORT(e.get_message());
234 ret = EXIT_ERROR;
235 }
236 catch(Egeneric & e)
237 {
238 cerr << e.dump_str();
239 GENERAL_REPORT(string(gettext("INTERNAL ERROR, PLEASE REPORT THE PREVIOUS OUTPUT TO MAINTAINER")));
240 ret = EXIT_BUG;
241 }
242 #ifdef LIBTHREADAR_AVAILABLE
243 catch(libthreadar::exception_base & e)
244 {
245 string msg = "";
246
247 for(unsigned int i = 0; i < e.size() ; ++i)
248 msg += e[i];
249
250 cerr << msg << endl;
251 ret = EXIT_BUG;
252 }
253 #endif
254 catch(...)
255 {
256 Ebug x = SRC_BUG;
257 cerr << x.dump_str();
258 GENERAL_REPORT(string(gettext("CAUGHT A NON (LIB)DAR EXCEPTION")));
259 GENERAL_REPORT(string(gettext("INTERNAL ERROR, PLEASE REPORT THE PREVIOUS OUTPUT TO MAINTAINER")));
260 ret = EXIT_BUG;
261 }
262
263
264 if(thread_cancellation::count() != 0)
265 {
266 GENERAL_REPORT(string(gettext("SANITY CHECK: AT LEAST ONE THREAD_CANCELLATION OBJECT HAS NOT BEEN DESTROYED AND REMAINS IN MEMORY WHILE THE PROGRAM REACHED ITS END")));
267 }
268
269 // restoring terminal settings
270 try
271 {
272 if(ui != nullptr)
273 delete ui;
274 ui = nullptr;
275 }
276 catch(...)
277 {
278 ret = EXIT_UNKNOWN_ERROR;
279 }
280 memory_check_snapshot();
281 return ret;
282 }
283
dar_suite_command_line_features()284 string dar_suite_command_line_features()
285 {
286 #if HAVE_GETOPT_LONG
287 const char *long_opt = gettext("YES");
288 #else
289 const char *long_opt = gettext("NO");
290 #endif
291
292 return tools_printf(gettext("Long options support : %s\n"), long_opt);
293 }
294
signal_abort_delayed(int l)295 static void signal_abort_delayed(int l)
296 {
297 signals_abort(l, false);
298 }
299
signal_abort_now(int l)300 static void signal_abort_now(int l)
301 {
302 signals_abort(l, true);
303 }
304
signals_abort(int l,bool now)305 static void signals_abort(int l, bool now)
306 {
307 #if HAVE_DECL_SYS_SIGLIST
308 GENERAL_REPORT(tools_printf(gettext("Received signal: %s"), sys_siglist[l]));
309 #else
310 GENERAL_REPORT(tools_printf(gettext("Received signal: %d"), l));
311 #endif
312
313 #if MUTEX_WORKS
314 if(now)
315 {
316 GENERAL_REPORT(string(gettext("Archive fast termination engaged")));
317 }
318 else
319 {
320 GENERAL_REPORT(string(gettext("Archive delayed termination engaged")));
321 }
322 #if HAVE_SIGNAL_H
323 signal(l, SIG_DFL);
324 GENERAL_REPORT(string(gettext("Disabling signal handler, the next time this signal is received the program will abort immediately")));
325 #endif
326 cancel_thread(pthread_self(), now);
327 #else
328 GENERAL_REPORT(string(gettext("Cannot cleanly abort the operation, thread-safe support is missing, will thus abruptly stop the program, generated archive may be unusable")));
329 exit(EXIT_USER_ABORT);
330 #endif
331 }
332