mirror of
https://git.tukaani.org/xz.git
synced 2024-04-04 12:36:23 +02:00
436fa5fae9
error message.
254 lines
5.1 KiB
C
254 lines
5.1 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/// \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>
|
|
|
|
static sig_atomic_t exit_signal = 0;
|
|
|
|
|
|
static void
|
|
signal_handler(int sig)
|
|
{
|
|
// FIXME Is this thread-safe together with main()?
|
|
exit_signal = sig;
|
|
|
|
user_abort = 1;
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
establish_signal_handlers(void)
|
|
{
|
|
struct sigaction sa;
|
|
sa.sa_handler = &signal_handler;
|
|
sigfillset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
|
|
static const int sigs[] = {
|
|
SIGHUP,
|
|
SIGINT,
|
|
SIGPIPE,
|
|
SIGTERM,
|
|
SIGXCPU,
|
|
SIGXFSZ,
|
|
};
|
|
|
|
for (size_t i = 0; i < sizeof(sigs) / sizeof(sigs[0]); ++i) {
|
|
if (sigaction(sigs[i], &sa, NULL)) {
|
|
errmsg(V_ERROR, _("Cannot establish signal handlers"));
|
|
my_exit(ERROR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
SIGINFO/SIGUSR1 for status reporting?
|
|
*/
|
|
}
|
|
|
|
|
|
static bool
|
|
is_tty_stdin(void)
|
|
{
|
|
const bool ret = isatty(STDIN_FILENO);
|
|
if (ret) {
|
|
// FIXME: Other threads may print between these lines.
|
|
// Maybe that should be fixed. Not a big issue in practice.
|
|
errmsg(V_ERROR, _("Compressed data not read from "
|
|
"a terminal."));
|
|
errmsg(V_ERROR, _("Use `--force' to force decompression."));
|
|
show_try_help();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static bool
|
|
is_tty_stdout(void)
|
|
{
|
|
const bool ret = isatty(STDOUT_FILENO);
|
|
if (ret) {
|
|
errmsg(V_ERROR, _("Compressed data not written to "
|
|
"a terminal."));
|
|
errmsg(V_ERROR, _("Use `--force' to force compression."));
|
|
show_try_help();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static char *
|
|
read_name(void)
|
|
{
|
|
size_t size = 256;
|
|
size_t pos = 0;
|
|
char *name = malloc(size);
|
|
if (name == NULL) {
|
|
out_of_memory();
|
|
return NULL;
|
|
}
|
|
|
|
while (true) {
|
|
const int c = fgetc(opt_files_file);
|
|
if (c == EOF) {
|
|
free(name);
|
|
|
|
if (ferror(opt_files_file))
|
|
errmsg(V_ERROR, _("%s: Error reading "
|
|
"filenames: %s"),
|
|
opt_files_name,
|
|
strerror(errno));
|
|
else if (pos != 0)
|
|
errmsg(V_ERROR, _("%s: Unexpected end of "
|
|
"input when reading "
|
|
"filenames"), opt_files_name);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (c == '\0' || c == opt_files_split)
|
|
break;
|
|
|
|
name[pos++] = c;
|
|
|
|
if (pos == size) {
|
|
size *= 2;
|
|
char *tmp = realloc(name, size);
|
|
if (tmp == NULL) {
|
|
free(name);
|
|
out_of_memory();
|
|
return NULL;
|
|
}
|
|
|
|
name = tmp;
|
|
}
|
|
}
|
|
|
|
if (name != NULL)
|
|
name[pos] = '\0';
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
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(ERROR);
|
|
|
|
// Set the program invocation name used in various messages.
|
|
argv0 = argv[0];
|
|
|
|
setlocale(LC_ALL, "en_US.UTF-8");
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
textdomain(PACKAGE);
|
|
|
|
// Set hardware-dependent default values. These can be overriden
|
|
// on the command line, thus this must be done before parse_args().
|
|
hardware_init();
|
|
|
|
char **files = parse_args(argc, argv);
|
|
|
|
if (opt_mode == MODE_COMPRESS && opt_stdout && is_tty_stdout())
|
|
return ERROR;
|
|
|
|
if (opt_mode == MODE_COMPRESS)
|
|
lzma_init_encoder();
|
|
else
|
|
lzma_init_decoder();
|
|
|
|
io_init();
|
|
process_init();
|
|
|
|
if (opt_mode == MODE_LIST) {
|
|
errmsg(V_ERROR, "--list is not implemented yet.");
|
|
my_exit(ERROR);
|
|
}
|
|
|
|
// 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();
|
|
|
|
while (*files != NULL && !user_abort) {
|
|
if (strcmp("-", *files) == 0) {
|
|
if (!opt_force) {
|
|
if (opt_mode == MODE_COMPRESS) {
|
|
if (is_tty_stdout()) {
|
|
++files;
|
|
continue;
|
|
}
|
|
} else if (is_tty_stdin()) {
|
|
++files;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (opt_files_name == stdin_filename) {
|
|
errmsg(V_ERROR, _("Cannot read data from "
|
|
"standard input when "
|
|
"reading filenames "
|
|
"from standard input"));
|
|
++files;
|
|
continue;
|
|
}
|
|
|
|
*files = (char *)stdin_filename;
|
|
}
|
|
|
|
process_file(*files++);
|
|
}
|
|
|
|
if (opt_files_name != NULL) {
|
|
while (true) {
|
|
char *name = read_name();
|
|
if (name == NULL)
|
|
break;
|
|
|
|
if (name[0] != '\0')
|
|
process_file(name);
|
|
|
|
free(name);
|
|
}
|
|
|
|
if (opt_files_name != stdin_filename)
|
|
(void)fclose(opt_files_file);
|
|
}
|
|
|
|
io_finish();
|
|
|
|
if (exit_signal != 0) {
|
|
struct sigaction sa;
|
|
sa.sa_handler = SIG_DFL;
|
|
sigfillset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sigaction(exit_signal, &sa, NULL);
|
|
raise(exit_signal);
|
|
}
|
|
|
|
my_exit(exit_status);
|
|
}
|