diff options
Diffstat (limited to 'src/lzma/main.c')
-rw-r--r-- | src/lzma/main.c | 402 |
1 files changed, 0 insertions, 402 deletions
diff --git a/src/lzma/main.c b/src/lzma/main.c deleted file mode 100644 index 4e24b98d..00000000 --- a/src/lzma/main.c +++ /dev/null @@ -1,402 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file main.c -/// \brief main() -// -// Copyright (C) 2007 Lasse Collin -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -/////////////////////////////////////////////////////////////////////////////// - -#include "private.h" -#include "open_stdxxx.h" -#include <ctype.h> - - -volatile sig_atomic_t user_abort = false; - -/// Exit status to use. This can be changed with set_exit_status(). -static enum exit_status_type exit_status = E_SUCCESS; - -/// If we were interrupted by a signal, we store the signal number so that -/// we can raise that signal to kill the program when all cleanups have -/// been done. -static volatile sig_atomic_t exit_signal = 0; - -/// Mask of signals for which have have established a signal handler to set -/// user_abort to true. -static sigset_t hooked_signals; - -/// signals_block() and signals_unblock() can be called recursively. -static size_t signals_block_count = 0; - - -static void -signal_handler(int sig) -{ - exit_signal = sig; - user_abort = true; - return; -} - - -static void -establish_signal_handlers(void) -{ - // List of signals for which we establish the signal handler. - static const int sigs[] = { - SIGINT, - SIGTERM, -#ifdef SIGHUP - SIGHUP, -#endif -#ifdef SIGPIPE - SIGPIPE, -#endif -#ifdef SIGXCPU - SIGXCPU, -#endif -#ifdef SIGXFSZ - SIGXFSZ, -#endif - }; - - // Mask of the signals for which we have established a signal handler. - sigemptyset(&hooked_signals); - for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) - sigaddset(&hooked_signals, sigs[i]); - - struct sigaction sa; - - // All the signals that we handle we also blocked while the signal - // handler runs. - sa.sa_mask = hooked_signals; - - // Don't set SA_RESTART, because we want EINTR so that we can check - // for user_abort and cleanup before exiting. We block the signals - // for which we have established a handler when we don't want EINTR. - sa.sa_flags = 0; - sa.sa_handler = &signal_handler; - - for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) { - // If the parent process has left some signals ignored, - // we don't unignore them. - struct sigaction old; - if (sigaction(sigs[i], NULL, &old) == 0 - && old.sa_handler == SIG_IGN) - continue; - - // Establish the signal handler. - if (sigaction(sigs[i], &sa, NULL)) - message_signal_handler(); - } - - return; -} - - -extern void -signals_block(void) -{ - if (signals_block_count++ == 0) { - const int saved_errno = errno; - sigprocmask(SIG_BLOCK, &hooked_signals, NULL); - errno = saved_errno; - } - - return; -} - - -extern void -signals_unblock(void) -{ - assert(signals_block_count > 0); - - if (--signals_block_count == 0) { - const int saved_errno = errno; - sigprocmask(SIG_UNBLOCK, &hooked_signals, NULL); - errno = saved_errno; - } - - return; -} - - -extern void -set_exit_status(enum exit_status_type new_status) -{ - assert(new_status == E_WARNING || new_status == E_ERROR); - - if (exit_status != E_ERROR) - exit_status = new_status; - - return; -} - - -extern void -my_exit(enum exit_status_type status) -{ - // Close stdout. If something goes wrong, print an error message - // to stderr. - { - const int ferror_err = ferror(stdout); - const int fclose_err = fclose(stdout); - if (ferror_err || fclose_err) { - // If it was fclose() that failed, we have the reason - // in errno. If only ferror() indicated an error, - // we have no idea what the reason was. - message(V_ERROR, _("Writing to standard output " - "failed: %s"), - fclose_err ? strerror(errno) - : _("Unknown error")); - status = E_ERROR; - } - } - - // Close stderr. If something goes wrong, there's nothing where we - // could print an error message. Just set the exit status. - { - const int ferror_err = ferror(stderr); - const int fclose_err = fclose(stderr); - if (fclose_err || ferror_err) - status = E_ERROR; - } - - // If we have got a signal, raise it to kill the program. - const int sig = exit_signal; - if (sig != 0) { - struct sigaction sa; - sa.sa_handler = SIG_DFL; - sigfillset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(sig, &sa, NULL); - raise(exit_signal); - - // If, for some weird reason, the signal doesn't kill us, - // we safely fall to the exit below. - } - - exit(status); -} - - -static const char * -read_name(const args_info *args) -{ - // FIXME: Maybe we should have some kind of memory usage limit here - // like the tool has for the actual compression and uncompression. - // Giving some huge text file with --files0 makes us to read the - // whole file in RAM. - static char *name = NULL; - static size_t size = 256; - - // Allocate the initial buffer. This is never freed, since after it - // is no longer needed, the program exits very soon. It is safe to - // use xmalloc() and xrealloc() in this function, because while - // executing this function, no files are open for writing, and thus - // there's no need to cleanup anything before exiting. - if (name == NULL) - name = xmalloc(size); - - // Write position in name - size_t pos = 0; - - // Read one character at a time into name. - while (!user_abort) { - const int c = fgetc(args->files_file); - - if (ferror(args->files_file)) { - // Take care of EINTR since we have established - // the signal handlers already. - if (errno == EINTR) - continue; - - message_error(_("%s: Error reading filenames: %s"), - args->files_name, strerror(errno)); - return NULL; - } - - if (feof(args->files_file)) { - if (pos != 0) - message_error(_("%s: Unexpected end of input " - "when reading filenames"), - args->files_name); - - return NULL; - } - - if (c == args->files_delim) { - // We allow consecutive newline (--files) or '\0' - // characters (--files0), and ignore such empty - // filenames. - if (pos == 0) - continue; - - // A non-empty name was read. Terminate it with '\0' - // and return it. - name[pos] = '\0'; - return name; - } - - if (c == '\0') { - // A null character was found when using --files, - // which expects plain text input separated with - // newlines. - message_error(_("%s: Null character found when " - "reading filenames; maybe you meant " - "to use `--files0' instead " - "of `--files'?"), args->files_name); - return NULL; - } - - name[pos++] = c; - - // Allocate more memory if needed. There must always be space - // at least for one character to allow terminating the string - // with '\0'. - if (pos == size) { - size *= 2; - name = xrealloc(name, size); - } - } - - return NULL; -} - - -int -main(int argc, char **argv) -{ - // Make sure that stdin, stdout, and and stderr are connected to - // a valid file descriptor. Exit immediatelly with exit code ERROR - // if we cannot make the file descriptors valid. Maybe we should - // print an error message, but our stderr could be screwed anyway. - open_stdxxx(E_ERROR); - - // This has to be done before calling any liblzma functions. - lzma_init(); - - // Set up the locale. - setlocale(LC_ALL, ""); - -#ifdef ENABLE_NLS - // Set up the message translations too. - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); -#endif - - // Set the program invocation name used in various messages, and - // do other message handling related initializations. - message_init(argv[0]); - - // Set hardware-dependent default values. These can be overriden - // on the command line, thus this must be done before parse_args(). - hardware_init(); - - // Parse the command line arguments and get an array of filenames. - // This doesn't return if something is wrong with the command line - // arguments. If there are no arguments, one filename ("-") is still - // returned to indicate stdin. - args_info args; - args_parse(&args, argc, argv); - - // Tell the message handling code how many input files there are if - // we know it. This way the progress indicator can show it. - if (args.files_name != NULL) - message_set_files(0); - else - message_set_files(args.arg_count); - - // Refuse to write compressed data to standard output if it is - // a terminal and --force wasn't used. - if (opt_mode == MODE_COMPRESS) { - if (opt_stdout || (args.arg_count == 1 - && strcmp(args.arg_names[0], "-") == 0)) { - if (is_tty_stdout()) { - message_try_help(); - my_exit(E_ERROR); - } - } - } - - if (opt_mode == MODE_LIST) { - message_fatal("--list is not implemented yet."); - } - - // Hook the signal handlers. We don't need these before we start - // the actual action, so this is done after parsing the command - // line arguments. - establish_signal_handlers(); - - // Process the files given on the command line. Note that if no names - // were given, parse_args() gave us a fake "-" filename. - for (size_t i = 0; i < args.arg_count && !user_abort; ++i) { - if (strcmp("-", args.arg_names[i]) == 0) { - // Processing from stdin to stdout. Unless --force - // was used, check that we aren't writing compressed - // data to a terminal or reading it from terminal. - if (!opt_force) { - if (opt_mode == MODE_COMPRESS) { - if (is_tty_stdout()) - continue; - } else if (is_tty_stdin()) { - continue; - } - } - - // It doesn't make sense to compress data from stdin - // if we are supposed to read filenames from stdin - // too (enabled with --files or --files0). - if (args.files_name == stdin_filename) { - message_error(_("Cannot read data from " - "standard input when " - "reading filenames " - "from standard input")); - continue; - } - - // Replace the "-" with a special pointer, which is - // recognized by process_file() and other things. - // This way error messages get a proper filename - // string and the code still knows that it is - // handling the special case of stdin. - args.arg_names[i] = (char *)stdin_filename; - } - - // Do the actual compression or uncompression. - process_file(args.arg_names[i]); - } - - // If --files or --files0 was used, process the filenames from the - // given file or stdin. Note that here we don't consider "-" to - // indicate stdin like we do with the command line arguments. - if (args.files_name != NULL) { - // read_name() checks for user_abort so we don't need to - // check it as loop termination condition. - while (true) { - const char *name = read_name(&args); - if (name == NULL) - break; - - // read_name() doesn't return empty names. - assert(name[0] != '\0'); - process_file(name); - } - - if (args.files_name != stdin_filename) - (void)fclose(args.files_file); - } - - my_exit(exit_status); -} |