mirror of
https://github.com/rkd77/elinks.git
synced 2024-10-12 05:33:36 -04:00
372 lines
8.6 KiB
C
372 lines
8.6 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"
|
|
#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;
|
|
|
|
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);
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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) {
|
|
|
|
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
|
|
}
|
|
|
|
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;
|
|
}
|