1 /* The main program - startup */
11 #include <sys/types.h>
13 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
21 #include "bfu/dialog.h"
22 #include "cache/cache.h"
23 #include "config/cmdline.h"
24 #include "config/conf.h"
25 #include "config/home.h"
26 #include "config/options.h"
27 #include "dialogs/menu.h"
28 #include "document/document.h"
29 #include "intl/charsets.h"
30 #include "intl/gettext/libintl.h"
31 #include "main/event.h"
32 #include "main/interlink.h"
33 #include "main/main.h"
34 #include "main/module.h"
35 #include "main/select.h"
36 #include "main/version.h"
37 #include "network/connection.h"
38 #include "network/dns.h"
39 #include "network/state.h"
40 #include "osdep/osdep.h"
41 #include "osdep/signals.h"
42 #include "osdep/sysname.h"
43 #include "protocol/auth/auth.h"
44 #include "session/download.h"
45 #include "session/session.h"
46 #include "terminal/kbd.h"
47 #include "terminal/screen.h"
48 #include "terminal/terminal.h"
49 #include "util/color.h"
50 #include "util/error.h"
51 #include "util/file.h"
52 #include "util/hash.h"
53 #include "util/memdebug.h"
54 #include "util/memory.h"
55 #include "viewer/dump/dump.h"
56 #include "viewer/text/marks.h"
58 struct program program
;
61 static unsigned char **av
;
62 static int init_b
= 0;
64 /* Check if either stdin or stdout are pipes */
66 check_stdio(LIST_OF(struct string_list_item
) *url_list
)
68 assert(!remote_session_flags
);
70 /* Should the document be read from stdin? */
71 if (!isatty(STDIN_FILENO
)) {
72 /* Only start reading from stdin if no URL was given on the
74 if (url_list
&& list_empty(*url_list
)) {
75 get_opt_bool("protocol.file.allow_special_files",
77 add_to_string_list(url_list
, "file:///dev/stdin", 17);
79 get_cmd_opt_bool("no-connect") = 1;
82 /* If called for outputting to a pipe without -dump or -source
83 * specified default to using dump viewer. */
84 if (!isatty(STDOUT_FILENO
)) {
85 int *dump
= &get_cmd_opt_bool("dump");
87 if (!*dump
&& !get_cmd_opt_bool("source"))
95 unsigned char *cwd
= get_cwd();
97 if (!cwd
|| !file_is_dir(cwd
)) {
98 unsigned char *home
= getenv("HOME");
100 if (home
&& file_is_dir(home
))
110 INIT_LIST_OF(struct string_list_item
, url_list
);
118 bindtextdomain(PACKAGE
, LOCALEDIR
);
123 init_charsets_lookup();
124 init_colors_lookup();
125 init_modules(main_modules
);
128 init_static_version();
130 register_modules_options(main_modules
);
131 register_modules_options(builtin_modules
);
135 /* XXX: OS/2 has some stupid bug and the pipe must be created before
136 * socket :-/. -- Mikulas */
137 if (check_terminal_pipes()) {
138 ERROR(gettext("Cannot create a pipe for internal communication."));
139 program
.retval
= RET_FATAL
;
140 program
.terminate
= 1;
144 /* Parsing command line options */
145 ret
= parse_options(ac
- 1, av
+ 1, &url_list
);
147 /* Command line handlers return RET_COMMAND to signal that they
148 * completed successfully and that the program should stop. */
149 if (ret
!= RET_COMMAND
)
150 program
.retval
= ret
;
151 program
.terminate
= 1;
152 free_string_list(&url_list
);
156 if (!remote_session_flags
) {
157 check_stdio(&url_list
);
159 program
.terminate
= 1;
162 if (!get_cmd_opt_bool("no-home")) {
166 /* If there's no -no-connect, -dump or -source option, check if there's
167 * no other ELinks running. If we found any, by-pass initialization of
168 * non critical subsystems, open socket and act as a slave for it. */
169 if (get_cmd_opt_bool("no-connect")
170 || get_cmd_opt_bool("dump")
171 || get_cmd_opt_bool("source")
172 || (fd
= init_interlink()) == -1) {
175 update_options_visibility();
176 /* Parse commandline options again, in order to override any
177 * config file options. */
178 parse_options(ac
- 1, av
+ 1, NULL
);
179 /* ... and re-check stdio, in order to override any command
180 * line options! >;) */
181 if (!remote_session_flags
) {
186 init_modules(builtin_modules
);
189 if (get_cmd_opt_bool("dump")
190 || get_cmd_opt_bool("source")) {
191 /* Dump the URL list */
192 #ifdef CONFIG_ECMASCRIPT
193 /* The ECMAScript code is not good at coping with this. And it
194 * makes currently no sense to evaluate ECMAScript in this
196 get_opt_bool("ecmascript.enable", NULL
) = 0;
198 if (!list_empty(url_list
)) {
199 dump_next(&url_list
);
201 unsigned char *arg
= get_cmd_opt_bool("dump")
204 usrerror(gettext("URL expected after -%s"), arg
);
205 program
.retval
= RET_SYNTAX
;
206 program
.terminate
= 1;
209 } else if (remote_session_flags
& SES_REMOTE_PING
) {
210 /* If no instance was running return ping failure */
212 usrerror(gettext("No running ELinks found."));
213 program
.retval
= RET_PING
;
216 } else if (remote_session_flags
&& fd
== -1) {
217 /* The remote session(s) can not be created */
218 usrerror(gettext("No remote session to connect to."));
219 program
.retval
= RET_REMOTE
;
223 struct terminal
*term
= NULL
;
225 if (!encode_session_info(&info
, &url_list
)) {
226 ERROR(gettext("Unable to encode session info."));
227 program
.retval
= RET_FATAL
;
228 program
.terminate
= 1;
230 } else if (fd
!= -1) {
231 /* Attach to already running ELinks and act as a slave
233 close_terminal_pipes();
235 handle_trm(get_input_handle(), get_output_handle(),
236 fd
, fd
, get_ctl_handle(), info
.source
, info
.length
,
237 remote_session_flags
);
239 /* Setup a master terminal */
240 term
= attach_terminal(get_input_handle(), get_output_handle(),
241 get_ctl_handle(), info
.source
, info
.length
);
243 ERROR(gettext("Unable to attach_terminal()."));
244 program
.retval
= RET_FATAL
;
245 program
.terminate
= 1;
249 /* OK, this is race condition, but it must be so; GPM installs
250 * it's own buggy TSTP handler. */
251 if (!program
.terminate
) handle_basic_signals(term
);
255 if (program
.terminate
) close_terminal_pipes();
256 free_string_list(&url_list
);
261 terminate_all_subsystems(void)
264 check_bottom_halves();
265 abort_all_downloads();
266 check_bottom_halves();
267 destroy_all_terminals();
268 check_bottom_halves();
271 /* When aborting all connections also keep-alive connections are
272 * aborted. A (normal) connection will be started for any keep-alive
273 * connection that needs to send a command to the server before
274 * aborting. This means we need to abort_all_connections() twice.
276 * It forces a some what unclean connection tear-down since at most the
277 * shutdown routine will be able to send one command. But else it would
278 * take too long time to terminate. */
279 abort_all_connections();
280 check_bottom_halves();
281 abort_all_connections();
284 #ifdef CONFIG_SCRIPTING
285 trigger_event_name("quit");
287 free_history_lists();
288 done_modules(builtin_modules
);
289 done_saved_session_info();
293 free_charsets_lookup();
294 free_colors_lookup();
295 done_modules(main_modules
);
297 check_bottom_halves();
299 done_state_message();
301 unregister_modules_options(builtin_modules
);
302 unregister_modules_options(main_modules
);
306 #ifdef CONFIG_COMBINE
312 shrink_memory(int whole
)
314 #ifdef CONFIG_SCRIPTING
315 /* The SMJS pre-format-html hook constructs an SMJS object for
316 * each cache entry. Give all scripting modules a cue to garbage
317 * collect any such objects so that the entries can be freed. */
319 trigger_event_name("flush-caches");
321 shrink_dns_cache(whole
);
322 shrink_format_cache(whole
);
323 garbage_collection(whole
);
326 #ifdef CONFIG_NO_ROOT_EXEC
330 if (!getuid() || !geteuid()) {
331 fprintf(stderr
, "%s\n\n"
332 "Permission to run this program as root "
333 "user was disabled at compile time.\n\n",
334 full_static_version
);
339 #define check_if_root()
344 gc_warning(char *msg
, GC_word arg
)
351 main(int argc
, char *argv
[])
355 GC_set_warn_proc(gc_warning
);
359 program
.terminate
= 0;
360 program
.retval
= RET_OK
;
361 program
.path
= argv
[0];
363 av
= (unsigned char **) argv
;
366 terminate_all_subsystems();
369 check_memory_leaks();
371 return program
.retval
;