1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-20 00:15:31 +00:00
elinks/src/main/main.c
2024-06-02 10:13:35 +02:00

387 lines
8.9 KiB
C

/* The main program - startup */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> /* OS/2 needs this after sys/types.h */
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h> /* OS/2 needs this after sys/types.h */
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "elinks.h"
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "config/cmdline.h"
#include "config/conf.h"
#include "config/home.h"
#include "config/options.h"
#include "dialogs/menu.h"
#include "document/document.h"
#ifdef CONFIG_LIBDOM
#include "document/libdom/renderer2.h"
#endif
#include "intl/charsets.h"
#include "intl/libintl.h"
#include "main/event.h"
#include "main/interlink.h"
#include "main/main.h"
#include "main/module.h"
#include "main/select.h"
#include "main/version.h"
#include "network/connection.h"
#include "network/dns.h"
#include "network/state.h"
#include "osdep/osdep.h"
#include "osdep/signals.h"
#include "osdep/sysname.h"
#include "protocol/auth/auth.h"
#include "session/download.h"
#include "session/session.h"
#include "terminal/kbd.h"
#include "terminal/screen.h"
#include "terminal/terminal.h"
#include "util/color.h"
#include "util/error.h"
#include "util/file.h"
#include "util/hash.h"
#include "util/memdebug.h"
#include "util/memory.h"
#include "viewer/dump/dump.h"
#include "viewer/text/marks.h"
struct program program;
pid_t master_pid = 0;
static int ac;
static char **av;
static int init_b = 0;
static int init_o = 0;
/* Check if either stdin or stdout are pipes */
static void
check_stdio(LIST_OF(struct string_list_item) *url_list)
{
assert(!remote_session_flags);
if (program.testjs) {
return;
}
/* Should the document be read from stdin? */
if (!isatty(STDIN_FILENO)) {
/* Only start reading from stdin if no URL was given on the
* command line. */
if (url_list && list_empty(*url_list)) {
get_opt_bool("protocol.file.allow_special_files",
NULL) = 1;
add_to_string_list(url_list, "file:///dev/stdin", 17);
}
get_cmd_opt_bool("no-connect") = 1;
}
/* If called for outputting to a pipe without -dump or -source
* specified default to using dump viewer. */
if (!isatty(STDOUT_FILENO)) {
int *dump = &get_cmd_opt_bool("dump");
if (!*dump && !get_cmd_opt_bool("source"))
*dump = 1;
}
}
static void
check_cwd(void)
{
char *cwd = get_cwd();
if (!cwd || !file_is_dir(cwd)) {
char *home = getenv("HOME");
if (home && file_is_dir(home))
(void)(!chdir(home));
}
mem_free_if(cwd);
}
void
parse_options_again(void)
{
if (!init_o) {
load_config();
update_options_visibility();
/* Parse commandline options again, in order to override any
* config file options. */
parse_options(ac - 1, av + 1, NULL);
/* ... and re-check stdio, in order to override any command
* line options! >;) */
if (!remote_session_flags) {
check_stdio(NULL);
}
init_o = 1;
}
}
static void
init(void)
{
INIT_LIST_OF(struct string_list_item, url_list);
int fd = -1;
enum retval ret;
init_osdep();
check_cwd();
#ifdef CONFIG_NLS
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
set_language(0);
#endif
init_event();
init_charsets_lookup();
init_colors_lookup();
init_modules(main_modules);
init_options();
init_static_version();
register_modules_options(main_modules);
register_modules_options(builtin_modules);
set_sigcld();
get_system_name();
/* XXX: OS/2 has some stupid bug and the pipe must be created before
* socket :-/. -- Mikulas */
if (check_terminal_pipes()) {
ERROR(gettext("Cannot create a pipe for internal communication."));
program.retval = RET_FATAL;
program.terminate = 1;
return;
}
/* Parsing command line options */
ret = parse_options(ac - 1, av + 1, &url_list);
if (ret != RET_OK) {
/* Command line handlers return RET_COMMAND to signal that they
* completed successfully and that the program should stop. */
if (ret != RET_COMMAND)
program.retval = ret;
program.terminate = 1;
free_string_list(&url_list);
return;
}
program.testjs = get_cmd_opt_bool("test");
if (!remote_session_flags) {
check_stdio(&url_list);
} else {
program.terminate = 1;
}
if (!get_cmd_opt_bool("no-home")) {
init_home();
}
/* If there's no -no-connect, -dump or -source option, check if there's
* no other ELinks running. If we found any, by-pass initialization of
* non critical subsystems, open socket and act as a slave for it. */
if (get_cmd_opt_bool("no-connect")
|| get_cmd_opt_bool("dump")
|| get_cmd_opt_bool("source")
|| (fd = init_interlink()) == -1) {
master_pid = getpid();
parse_options_again();
init_b = 1;
init_modules(builtin_modules);
}
if (get_cmd_opt_bool("always-load-config")) {
parse_options_again();
}
if (get_cmd_opt_bool("dump")
|| get_cmd_opt_bool("source")) {
/* Dump the URL list */
#ifdef CONFIG_ECMASCRIPT
/* The ECMAScript code is not good at coping with this. And it
* makes currently no sense to evaluate ECMAScript in this
* context anyway. */
get_opt_bool("ecmascript.enable", NULL) = 0;
#endif
if (!list_empty(url_list)) {
dump_next(&url_list);
} else {
const char *arg = get_cmd_opt_bool("dump")
? "dump" : "source";
usrerror(gettext("URL expected after -%s"), arg);
program.retval = RET_SYNTAX;
program.terminate = 1;
}
} else if (remote_session_flags & SES_REMOTE_PING) {
/* If no instance was running return ping failure */
if (fd == -1) {
usrerror(gettext("No running ELinks found."));
program.retval = RET_PING;
}
} else if (remote_session_flags && fd == -1) {
/* The remote session(s) can not be created */
usrerror(gettext("No remote session to connect to."));
program.retval = RET_REMOTE;
} else {
struct string info;
struct terminal *term = NULL;
if (!encode_session_info(&info, &url_list)) {
ERROR(gettext("Unable to encode session info."));
program.retval = RET_FATAL;
program.terminate = 1;
} else if (fd != -1) {
/* Attach to already running ELinks and act as a slave
* for it. */
close_terminal_pipes();
handle_trm(get_input_handle(), get_output_handle(),
fd, fd, get_ctl_handle(), info.source, info.length,
remote_session_flags);
} else if (get_cmd_opt_bool("no-connect")
|| !get_opt_bool("ui.sessions.fork_on_start", NULL)) {
/* Setup a master terminal */
term = attach_terminal(get_input_handle(), get_output_handle(),
get_ctl_handle(), info.source, info.length);
if (!term) {
ERROR(gettext("Unable to attach_terminal()."));
program.retval = RET_FATAL;
program.terminate = 1;
}
}
/* OK, this is race condition, but it must be so; GPM installs
* it's own buggy TSTP handler. */
if (!program.terminate) handle_basic_signals(term);
done_string(&info);
}
if (program.terminate) close_terminal_pipes();
free_string_list(&url_list);
}
static void
terminate_all_subsystems(void)
{
done_interlink();
check_bottom_halves();
abort_all_downloads();
check_bottom_halves();
destroy_all_terminals();
check_bottom_halves();
free_all_itrms();
/* When aborting all connections also keep-alive connections are
* aborted. A (normal) connection will be started for any keep-alive
* connection that needs to send a command to the server before
* aborting. This means we need to abort_all_connections() twice.
*
* It forces a some what unclean connection tear-down since at most the
* shutdown routine will be able to send one command. But else it would
* take too long time to terminate. */
abort_all_connections();
check_bottom_halves();
abort_all_connections();
if (init_b) {
#ifdef CONFIG_SCRIPTING
trigger_event_name("quit");
#endif
free_history_lists();
done_modules(builtin_modules);
done_saved_session_info();
}
shrink_memory(1);
free_charsets_lookup();
free_colors_lookup();
done_modules(main_modules);
free_conv_table();
check_bottom_halves();
done_home();
done_state_message();
done_bfu_colors();
unregister_modules_options(builtin_modules);
unregister_modules_options(main_modules);
done_options();
done_event();
terminate_select();
terminate_osdep();
#ifdef CONFIG_COMBINE
free_combined();
#endif
#ifdef CONFIG_LIBDOM
free_libdom();
#endif
clean_temporary_files();
}
void
shrink_memory(int whole)
{
shrink_dns_cache(whole);
shrink_format_cache(whole);
garbage_collection(whole);
}
#ifdef CONFIG_NO_ROOT_EXEC
static void
check_if_root(void)
{
if (!getuid() || !geteuid()) {
fprintf(stderr, "%s\n\n"
"Permission to run this program as root "
"user was disabled at compile time.\n\n",
full_static_version);
exit(-1);
}
}
#else
#define check_if_root()
#endif
int
main(int argc, char *argv[])
{
check_if_root();
program.terminate = 0;
program.retval = RET_OK;
program.path = argv[0];
ac = argc;
av = (char **) argv;
select_loop(init);
terminate_all_subsystems();
#ifdef DEBUG_MEMLEAK
check_memory_leaks();
#endif
return program.retval;
}