mirror of
				https://git.tukaani.org/xz.git
				synced 2025-11-04 07:22:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			255 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			255 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);
 | 
						|
}
 |