2005-09-15 09:58:31 -04:00
|
|
|
/* 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>
|
2021-12-22 10:12:09 -05:00
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
#include <sys/socket.h> /* OS/2 needs this after sys/types.h */
|
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
#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"
|
2021-08-08 15:25:08 -04:00
|
|
|
#include "intl/libintl.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#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"
|
2008-01-03 06:57:24 -05:00
|
|
|
#include "util/hash.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "util/memdebug.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "viewer/dump/dump.h"
|
|
|
|
#include "viewer/text/marks.h"
|
|
|
|
|
|
|
|
struct program program;
|
|
|
|
|
[fg] track master proc for suspend via pids, not term fds, for fork_on_start
When ui.sessions.fork_on_start, we fork a process that has a different
fdout than get_output_handle() (which has hardcoded fdout of 1), so it
will never be considered term->master, yet this is the process we want
to wake up in SIGTSTP handler.
Since we cannot rely on term->master to determine if we are the master
process, we instead move master_pid to be set explicitly at the places
where we have information about whether our process is a master or a
slave: first on start, then once the interlink determination has been
made.
master_pid has to be set in both parent and child, because both will get
suspended and need to know which one needs to resume in background with
SIGCONT (the master). We can't inherit from the parent because it's
unknown at the time of fork.
Previously, master_pid worked correctly with fork_on_start=0,
-no-connect or -dump, but not with fork_on_start=1.
See #287 for background.
2024-04-10 17:02:36 -04:00
|
|
|
pid_t master_pid = 0;
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
static int ac;
|
2021-01-02 10:20:27 -05:00
|
|
|
static char **av;
|
2005-09-15 09:58:31 -04:00
|
|
|
static int init_b = 0;
|
2020-05-22 15:52:36 -04:00
|
|
|
static int init_o = 0;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
/* Check if either stdin or stdout are pipes */
|
|
|
|
static void
|
2007-07-26 15:39:08 -04:00
|
|
|
check_stdio(LIST_OF(struct string_list_item) *url_list)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
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)) {
|
2007-08-28 12:41:18 -04:00
|
|
|
get_opt_bool("protocol.file.allow_special_files",
|
|
|
|
NULL) = 1;
|
2005-09-15 09:58:31 -04:00
|
|
|
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)
|
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *cwd = get_cwd();
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!cwd || !file_is_dir(cwd)) {
|
2021-01-02 10:20:27 -05:00
|
|
|
char *home = getenv("HOME");
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (home && file_is_dir(home))
|
2022-06-25 10:11:59 -04:00
|
|
|
(void)(!chdir(home));
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
mem_free_if(cwd);
|
|
|
|
}
|
|
|
|
|
2020-05-21 10:53:43 -04:00
|
|
|
void
|
|
|
|
parse_options_again(void)
|
|
|
|
{
|
2020-05-22 15:52:36 -04:00
|
|
|
if (!init_o) {
|
2020-05-21 10:53:43 -04:00
|
|
|
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);
|
|
|
|
}
|
2020-05-22 15:52:36 -04:00
|
|
|
init_o = 1;
|
2020-05-21 10:53:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
static void
|
|
|
|
init(void)
|
|
|
|
{
|
2007-07-26 15:39:08 -04:00
|
|
|
INIT_LIST_OF(struct string_list_item, url_list);
|
2005-09-15 09:58:31 -04:00
|
|
|
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();
|
2006-05-18 15:46:42 -04:00
|
|
|
init_static_version();
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
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);
|
2006-10-27 12:59:36 -04:00
|
|
|
} else {
|
|
|
|
program.terminate = 1;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
[fg] track master proc for suspend via pids, not term fds, for fork_on_start
When ui.sessions.fork_on_start, we fork a process that has a different
fdout than get_output_handle() (which has hardcoded fdout of 1), so it
will never be considered term->master, yet this is the process we want
to wake up in SIGTSTP handler.
Since we cannot rely on term->master to determine if we are the master
process, we instead move master_pid to be set explicitly at the places
where we have information about whether our process is a master or a
slave: first on start, then once the interlink determination has been
made.
master_pid has to be set in both parent and child, because both will get
suspended and need to know which one needs to resume in background with
SIGCONT (the master). We can't inherit from the parent because it's
unknown at the time of fork.
Previously, master_pid worked correctly with fork_on_start=0,
-no-connect or -dump, but not with fork_on_start=1.
See #287 for background.
2024-04-10 17:02:36 -04:00
|
|
|
#ifdef HAVE_GETPID
|
|
|
|
master_pid = getpid();
|
|
|
|
#endif
|
2020-05-21 10:53:43 -04:00
|
|
|
parse_options_again();
|
2020-05-22 15:52:36 -04:00
|
|
|
init_b = 1;
|
2005-09-15 09:58:31 -04:00
|
|
|
init_modules(builtin_modules);
|
|
|
|
}
|
|
|
|
|
2022-01-04 09:15:39 -05:00
|
|
|
if (get_cmd_opt_bool("always-load-config")) {
|
|
|
|
parse_options_again();
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
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. */
|
2007-08-28 12:41:18 -04:00
|
|
|
get_opt_bool("ecmascript.enable", NULL) = 0;
|
2005-09-15 09:58:31 -04:00
|
|
|
#endif
|
|
|
|
if (!list_empty(url_list)) {
|
|
|
|
dump_next(&url_list);
|
|
|
|
} else {
|
2022-02-18 09:33:51 -05:00
|
|
|
const char *arg = get_cmd_opt_bool("dump")
|
2005-09-15 09:58:31 -04:00
|
|
|
? "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 {
|
2019-04-21 06:27:40 -04:00
|
|
|
struct string info;
|
2005-09-15 09:58:31 -04:00
|
|
|
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);
|
2020-05-21 10:53:43 -04:00
|
|
|
} else if (get_cmd_opt_bool("no-connect")
|
|
|
|
|| !get_opt_bool("ui.sessions.fork_on_start", NULL)) {
|
2005-09-15 09:58:31 -04:00
|
|
|
/* 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();
|
2017-11-12 07:41:31 -05:00
|
|
|
terminate_select();
|
2005-09-15 09:58:31 -04:00
|
|
|
terminate_osdep();
|
2008-01-19 12:56:50 -05:00
|
|
|
#ifdef CONFIG_COMBINE
|
2008-01-03 06:57:24 -05:00
|
|
|
free_combined();
|
|
|
|
#endif
|
2023-08-10 06:22:11 -04:00
|
|
|
clean_temporary_files();
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2021-01-02 10:20:27 -05:00
|
|
|
av = (char **) argv;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
select_loop(init);
|
|
|
|
terminate_all_subsystems();
|
|
|
|
|
|
|
|
#ifdef DEBUG_MEMLEAK
|
|
|
|
check_memory_leaks();
|
|
|
|
#endif
|
|
|
|
return program.retval;
|
|
|
|
}
|