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