patch #7180
[mldonkey.git] / src / daemon / driver / driverMain.ml
blobd8a4e5c7fb73274c3e4f20edcccda11acd2d0552
1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
2 (*
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 open Options
21 open Int64ops
22 open Printf2
24 open BasicSocket
26 open CommonInteractive
28 open CommonDownloads
29 open CommonTypes
30 open CommonOptions
31 open CommonUserDb
32 open CommonGlobals
33 open CommonNetwork
35 open DriverInterface
37 open Gettext (* open last as most modules redefine _s and _b *)
39 let _s x = _s "DriverMain" x
40 let _b x = _b "DriverMain" x
42 let log_prefix = "[dMain]"
44 let lprintf_nl fmt =
45 lprintf_nl2 log_prefix fmt
47 let lprintf_n fmt =
48 lprintf2 log_prefix fmt
50 let pid = ref ""
52 let do_daily () =
53 incr CommonWeb.days
55 let minute_timer () =
56 DriverInteractive.hdd_check ();
57 CommonUploads.upload_credit_timer ();
58 CommonInteractive.force_download_quotas ();
59 CommonResult.dummy_result.result_time <- last_time ();
60 (try
61 CommonSwarming.verify_some_chunks ()
62 with _ -> ());
63 CommonClient.clear_upload_slots ()
65 let hourly_timer timer =
66 incr CommonWeb.hours;
67 CommonWeb.load_web_infos false false;
68 if !CommonWeb.hours mod !!compaction_delay = 0 then Gc.compact ();
69 if !!backup_options_delay <> 0
70 && !CommonWeb.hours mod !!backup_options_delay = 0 then
71 CommonComplexOptions.backup_options ();
72 DriverControlers.check_calendar ();
73 CommonFile.propose_filenames ()
75 let ten_second_timer timer =
76 if !!auto_commit then
77 List.iter (fun file ->
78 file_commit file
79 ) !!CommonComplexOptions.done_files
81 let second_timer timer =
82 (try
83 update_link_stats ()
84 with e ->
85 lprintf_nl (_b "Exception %s") (Printexc2.to_string e));
86 (try
87 CommonUploads.refill_upload_slots ()
88 with e ->
89 lprintf_nl (_b "Exception %s") (Printexc2.to_string e));
90 CommonUploads.shared_files_timer ();
93 let start_interfaces () =
95 (* option_hook(s) are not called when ini files are created the first time
96 force re-load of allowed_ips to call option_hook which fills the IP blocklist *)
98 match !created_new_base_directory with
99 None -> ()
100 | Some dir -> allowed_ips =:= !!allowed_ips
103 if !!http_port <> 0 then begin
105 ignore (DriverControlers.create_http_handler ());
106 with e ->
107 lprintf_nl (_b "Exception %s while starting HTTP interface")
108 (Printexc2.to_string e);
109 end;
111 if !!telnet_port <> 0 then begin
113 ignore (find_port "telnet server" !!telnet_bind_addr
114 telnet_port DriverControlers.telnet_handler);
115 with e ->
116 lprintf_nl (_b "Exception %s while starting Telnet interface")
117 (Printexc2.to_string e);
118 end;
120 if !!gui_port <> 0 then begin
122 ignore (find_port "gui server" !!gui_bind_addr
123 gui_port gui_handler);
124 with e ->
125 lprintf_nl (_b "Exception %s while starting GUI interface")
126 (Printexc2.to_string e);
127 end;
129 if !!gift_port <> 0 then begin
131 ignore (find_port "gift server" !!gui_bind_addr
132 gift_port gift_handler);
133 with e ->
134 lprintf_nl (_b "Exception %s while starting GUI interface")
135 (Printexc2.to_string e);
136 end;
138 add_infinite_option_timer update_gui_delay DriverInterface.update_gui_info;
139 add_infinite_timer 1. second_timer
142 let save_mlsubmit_reg () =
144 (* Generate the mlsubmit.reg file *)
146 let file = Printf.sprintf
148 "Windows Registry Editor Version 5.00
150 [HKEY_CLASSES_ROOT\\ed2k]
151 @=\"URL: ed2k Protocol\"
152 \"URL Protocol\"=\"\"
154 [HKEY_CLASSES_ROOT\\ed2k\\shell]
156 [HKEY_CLASSES_ROOT\\ed2k\\shell\\open]
158 [HKEY_CLASSES_ROOT\\ed2k\\shell\\open\\command]
159 @=\"\\\"IEXPLORE.EXE\\\" \\\"http://%s:%s@%s:%d/submit?q=dllink+%%1\\\"\"
162 "admin" "" (Ip.to_string (client_ip None)) !!http_port
164 File.from_string (Filename.concat file_basedir "mlsubmit.reg") file;
166 (* Generate the mldonkey_submit file *)
168 let file = Printf.sprintf
170 "#!%s
172 # Submit an eDonkey download request to mldonkey
174 # Argument(s): An ed2k URI of the form:
176 # ed2k://|file|<filename>|<filesize>|<MD4-sum|
177 use LWP::UserAgent;
179 ($#ARGV >= 0) || die \"Usage: mldonkey_submit <ed2kURI> ...\n\";
181 $vars{'HTTPURL'} = \"http://%s:%d\";
182 $vars{'HTTPUSER'} = \"%s\";
183 $vars{'HTTPPASS'} = \"%s\";
185 my $ua = LWP::UserAgent->new;
187 while (my $uri = shift @ARGV) {
188 $_ = URI::Escape::uri_unescape($uri);
189 if (/^ed2k:\\/\\/\\|file\\|[^|]+\\|(\\d+)\\|([\\dabcdef]+)\\|$/) {
190 my $size = $1;
191 my $md4 = $2;
192 my $req = HTTP::Request->new(
193 GET => \"$vars{'HTTPURL'}/submit?q=dllink+$uri\"
195 if (($vars{'HTTPUSER'}) && ($vars{'HTTPPASS'})) {
196 $req->authorization_basic($vars{'HTTPUSER'},
197 $vars{'HTTPPASS'});
199 my $response = $ua->request($req);
200 if (!($response->is_success)) {
201 print $response->error_as_HTML;
202 exit 1;
204 } else {
205 print \"Not an ed2k URI: $_\n\";
209 Autoconf.perl_path
210 (Ip.to_string (client_ip None)) !!http_port
211 "admin" ""
213 File.from_string (Filename.concat file_basedir "mldonkey_submit") file;
214 Unix2.chmod (Filename.concat file_basedir "mldonkey_submit") 0o755
216 let load_config () =
218 DriverInterface.install_hooks ();
220 (**** LOAD OPTIONS ****)
222 let exists_downloads_ini =
223 Sys.file_exists (options_file_name downloads_ini) in
224 let exists_users_ini =
225 Sys.file_exists (options_file_name users_ini)
227 if not exists_users_ini && exists_downloads_ini then
228 begin
229 lprintf_nl "No config file (users.ini) found. Importing users from downloads.ini.";
230 ( try Unix2.copy "downloads.ini" "users.ini" with _ -> () );
231 end;
233 let ini_files_exist = Sys.file_exists (options_file_name downloads_ini) in
235 (try
236 Options.load downloads_ini;
237 Options.load users_ini;
238 DriverInteractive.hdd_check ()
239 with e ->
240 lprintf_nl "Exception %s during options load" (Printexc2.to_string e);
241 exit 70);
243 (* Here, we try to update options when a new version of mldonkey is
244 used. For example, we can add new web_infos... *)
245 CommonOptions.update_options ();
247 CommonMessages.load_message_file ();
248 if !!html_mods then begin
249 if !!html_mods_style > 0 && !!html_mods_style < Array.length CommonMessages.styles then
250 commands_frame_height =:= CommonMessages.styles.(!!html_mods_style).CommonMessages.frame_height;
251 CommonMessages.colour_changer ();
252 end;
253 networks_iter_all (fun r ->
254 (* lprintf "(n) loading network config file\n"; *)
255 List.iter (fun opfile ->
257 Options.load opfile
258 with Sys_error _ ->
259 Options.save_with_help opfile
261 r.network_config_file
265 (**** PARSE ARGUMENTS ***)
267 let more_args = ref [] in
270 more_args := !more_args
271 @ (Options.simple_args "" downloads_ini);
272 more_args := !more_args
273 @ (Options.simple_args "" users_ini);
275 networks_iter_all (fun r ->
276 List.iter (fun opfile ->
277 let prefix = r.network_shortname ^ "-" in
278 let args = simple_args prefix opfile in
279 let args = List2.tail_map (fun (arg, spec, help) ->
280 (Printf.sprintf "-%s" arg, spec, help)) args
282 more_args := !more_args @ args
283 ) r.network_config_file
286 Arg.parse ([
287 "-v", Arg.Unit (fun _ ->
288 lprintf_nl "%s" (CommonGlobals.version ());
289 exit 0), _s " : print version number and exit";
290 "-exit", Arg.Unit (fun _ -> exit 0), ": exit immediatly";
291 "-format", Arg.String (fun file ->
292 ignore (CommonMultimedia.get_info file)),
293 _s " <filename> : check file format";
294 "-test_ip", Arg.String (fun ip ->
295 lprintf_nl "%s = %s" ip (Ip.to_string (Ip.of_string ip));
296 exit 0), _s "<ip> : undocumented";
297 "-check_impl", Arg.Unit (fun _ ->
298 CommonNetwork.check_network_implementations ();
299 CommonClient.check_client_implementations ();
300 CommonServer.check_server_implementations ();
301 CommonFile.check_file_implementations ();
302 (* CommonResult.check_result_implementations (); *)
303 lprint_newline ();
304 exit 0),
305 _s " : display information on the implementations";
306 "-stdout", Arg.Unit (fun _ ->
307 lprintf_original_output := (Some stdout);
308 log_to_file stdout
310 _s ": keep output to stdout after startup";
311 "-stderr", Arg.Unit (fun _ ->
312 lprintf_original_output := (Some stderr);
313 log_to_file stderr
315 _s ": keep output to stderr after startup";
316 "-daemon", Arg.Unit (fun _ ->
317 (* Removed due to savannah bug #11514 . *)
318 lprintf_nl "\n\nOption -daemon was removed.\nUse 'mlnet > /dev/null 2>&1 &' instead. Exiting...";
319 exit 64), _s " : this argument was removed, core will exit";
320 "-find_port", Arg.Set find_other_port,
321 _s " : find another port when one is already used";
322 "-pid", Arg.String (fun s -> pid := s;
324 _s ": directory for pid file";
325 "-useradd", Arg.Rest (fun s ->
326 (match String2.split s ' ' with
327 | user :: pass :: _ ->
328 if user2_user_exists user then
329 begin
330 user2_user_set_password (user2_user_find user) pass;
331 Printf.printf "%sPassword of user %s changed\n%!" (log_time ()) user
333 else
334 begin
335 user2_user_add user (Md4.Md4.string pass) ();
336 Printf.printf "%sUser %s added\n%!" (log_time ()) user
337 end;
338 Options.save_with_help_private users_ini;
339 Printf.printf "%sSaved changes to users.ini\n%!" (log_time ())
340 | _ -> raise (Arg.Bad "invalid syntax"));
341 exit 0), _s "\"<user> <pass>\" : create user/change password";
343 !more_args
345 !main_options)
346 (fun file -> ()
347 (* Files.dump_file file; exit 0 *)
348 ) "";
350 if not ini_files_exist && not (keep_console_output ()) then log_file =:= "mlnet.log";
352 (**** CREATE DIRS ****)
354 List.iter (fun s ->
355 Unix2.safe_mkdir s.shdir_dirname;
356 if s.shdir_strategy = "incoming_directories" ||
357 s.shdir_strategy = "incoming_files" then
358 Unix2.can_write_to_directory s.shdir_dirname
359 ) !!CommonComplexOptions.shared_directories;
360 Unix2.safe_mkdir "searches";
361 Unix2.can_write_to_directory "searches";
362 Unix2.safe_mkdir "web_infos";
363 Unix2.can_write_to_directory "web_infos";
364 Unix2.safe_mkdir !!temp_directory;
365 Unix2.can_write_to_directory !!temp_directory
367 let _ =
369 let t = Unix.localtime (Unix.time ()) in
370 if (t.Unix.tm_year<=104) then
371 begin
372 lprintf_nl (_b "\n\n\nYour system has a system date earlier than 2004, please correct it.");
373 lprintf_nl (_b "MLdonkey can not work with such a system date, exiting...");
374 CommonGlobals.exit_properly 71
375 end;
377 ( let resolve_name hostname =
379 ignore (Ip.from_name hostname);
380 true
381 with _ -> false
383 let hostnames =
384 ["www.mldonkey.org"; "mldonkey.sf.net"; "www.mldonkey.net"; "www.google.com"]
386 DriverInteractive.dns_works := List.exists resolve_name hostnames;
388 if not !DriverInteractive.dns_works then lprintf "
389 The core therefore is unable to get eDonkey serverlists and loading
390 .torrent files via dllink from websites is also impossible.
391 If you are using MLDonkey in a chroot environment you should
392 consider reading this article to get DNS support back:
393 http://mldonkey.sourceforge.net/Chroot\n\n");
395 let real_glibc_version = MlUnix.glibc_version_num () in
396 if real_glibc_version <> Autoconf.glibc_version
397 && real_glibc_version <> "" then
398 lprintf (_b"
399 Attention!
400 This core is running with glibc %s but it was compiled with glibc %s.
401 This can lead to unexpected behaviour. Consider compiling the core yourself
402 or getting a binary compiled with glibc %s.\n\n")
403 real_glibc_version Autoconf.glibc_version Autoconf.glibc_version
406 if Autoconf.magic then begin
407 (if Sys.file_exists "./magic/magic" then
408 try Unix.putenv "MAGIC" "./magic/magic" with _ -> ());
409 if Magic.M.magic_works () then
410 begin
411 Autoconf.magic_works := true;
412 lprintf_nl (_b "Libmagic file-type recognition database present")
414 else
415 begin
416 Autoconf.magic_works := false;
417 lprintf_nl (_b "Libmagic file-type recognition database not present")
421 if not !Charset.Locale.conversion_enabled then
422 lprintf_nl (_b "Self-test failed, charset conversion disabled.");
424 load_config ();
426 add_infinite_option_timer download_sample_rate CommonFile.sample_timer;
428 (* lprintf "(1) CommonComplexOptions.load\n"; *)
429 CommonComplexOptions.load ();
430 CommonUploads.load ();
431 CommonStats.load ();
433 (* lprintf "(2) CommonComplexOptions.load done\n"; *)
434 begin
435 let old_save_results = !!save_results in
436 save_results =:= 0;
437 CommonComplexOptions.save ();
438 CommonUploads.save ();
439 save_results =:= old_save_results;
440 end;
442 CommonGlobals.is_startup_phase := false;
444 (* before activating network modules load all local files from web_infos/
445 to avoid security holes, especially for IP blocking *)
446 Hashtbl.iter (fun key w ->
447 let file = Filename.concat "web_infos" (Filename.basename w.url) in
448 if Sys.file_exists file then
450 lprintf_nl "loading %s from %s" w.kind file;
451 ((List.assoc w.kind !CommonWeb.file_kinds).f w.url) file;
452 w.state <- Some FileLoaded;
453 with _ -> ()
454 ) web_infos_table;
456 discover_ip false;
458 lprintf_nl (_b "Check http://www.mldonkey.org for updates");
459 networks_iter (fun r -> network_load_complex_options r);
460 lprintf_nl (_b "enabling networks: ");
461 networks_iter (fun r ->
462 lprintf_nl (_b "---- enabling %s ----") r.network_name;
463 network_enable r;
464 List.iter (fun (p,s) -> if p <> 0 then lprintf_nl "using port %d (%s)" p s) (network_ports r);
465 (* are there drawbacks to start recover_temp unconditionally here ? *)
466 if !!recover_temp_on_startup then
467 network_recover_temp r;
469 lprintf_nl (_b "---- enabling interfaces ----");
470 List.iter (fun (p,s) -> if p <> 0 then lprintf_nl "using port %d (%s)" p s)
471 (network_ports (network_find_by_name "Global Shares"));
472 lprintf (_b "%s[dMain] disabled networks: ") (log_time ());
473 let found = ref false in
474 networks_iter_all (fun r ->
475 if not (network_is_enabled r) then
476 begin
477 found := true;
478 lprintf (_b "%s ") r.network_name
479 end);
480 if not !found then lprintf (_b "none");
481 lprint_newline ();
482 networks_iter_all (fun n -> network_update_options n);
483 CommonOptions.start_running_plugins := true;
484 CommonInteractive.force_download_quotas ();
486 TcpBufferedSocket.set_max_connections_per_second
487 (fun _ -> !!max_connections_per_second);
489 add_infinite_option_timer save_options_delay (fun timer ->
490 DriverInteractive.save_config ());
491 start_interfaces ();
493 add_infinite_timer 60. minute_timer;
494 add_infinite_timer 10. ten_second_timer;
495 add_infinite_timer 3600. hourly_timer;
496 add_infinite_timer 0.1 CommonUploads.upload_download_timer;
497 add_infinite_timer !!buffer_writes_delay (fun _ -> Unix32.flush ());
499 if !!share_scan_interval <> 0 then
500 add_infinite_timer ((float_of_int !!share_scan_interval) *. 60.)
501 (fun _ -> CommonShared.shared_check_files ());
502 CommonShared.shared_check_files ();
504 history_timeflag := (Unix.time());
505 update_download_history ();
506 update_upload_history ();
507 history_h_timeflag := (Unix.time());
508 update_h_download_history ();
509 update_h_upload_history ();
510 history_size_for_h_graph := history_size * !!html_mods_vd_gfx_h_intervall / 60;
511 history_h_step := 60 * !!html_mods_vd_gfx_h_intervall;
513 add_infinite_timer (float_of_int history_step) (fun timer ->
514 history_timeflag := (Unix.time());
515 update_download_history ();
516 update_upload_history ());
518 add_infinite_timer (float_of_int !history_h_step) (fun timer ->
519 history_h_timeflag := (Unix.time());
520 update_h_download_history ();
521 update_h_upload_history ());
523 if Autoconf.system = "mingw" then
524 add_infinite_timer 1. (fun timer ->
525 MlUnix.set_console_title (DriverInteractive.console_topic ()));
527 List.iter
528 CommonShared.shared_add_directory
529 !!CommonComplexOptions.shared_directories;
531 add_infinite_timer 1800. (fun timer ->
532 DriverInteractive.browse_friends ());
534 Options.prune_file downloads_ini;
535 Options.prune_file users_ini;
536 add_timer 1. (fun _ -> try CommonWeb.load_web_infos true false with _ -> ());
537 if !!telnet_port <> 0 then lprintf_nl (_b "To command: telnet %s %d")
538 (if !!telnet_bind_addr = Ip.any then "127.0.0.1"
539 else Ip.to_string !!telnet_bind_addr) !!telnet_port;
540 if !!http_port <> 0 then begin
541 lprintf_nl (_b "Or with browser: http://%s:%d")
542 (if !!http_bind_addr = Ip.any then "127.0.0.1"
543 else Ip.to_string !!http_bind_addr) !!http_port;
544 lprintf_nl (_b "For a GUI check out http://sancho-gui.sourceforge.net")
545 end;
546 if !!gui_port <> 0 then lprintf_nl (_b "Connect to IP %s, port %d")
547 (if !!gui_bind_addr = Ip.any then "127.0.0.1"
548 else Ip.to_string !!gui_bind_addr) !!gui_port;
549 lprintf_nl (_b "If you connect from a remote machine adjust allowed_ips");
550 if Autoconf.system = "cygwin" && not (keep_console_output ()) then lprintf (_b "%s") win_message;
552 add_init_hook (fun _ ->
553 if not !gui_included && ( !!start_gui || !!ask_for_gui ) then
554 (try
555 let _ = Sys.getenv("DISPLAY") in
556 if !!start_gui && Sys.file_exists !!mldonkey_gui then
557 ignore (Sys.command (Printf.sprintf "%s &" !!mldonkey_gui))
558 else
559 let asker = Filename.concat !!mldonkey_bin "mlguistarter" in
560 if !!ask_for_gui && Sys.file_exists !!mldonkey_gui &&
561 Sys.file_exists asker then
562 ignore (Sys.command (Printf.sprintf "%s %s&" asker !!mldonkey_gui));
563 with Not_found ->
564 lprintf_nl (_b "Not running under X, not trying to start the GUI")
568 if !!run_as_group <> "" then begin
570 let new_gr = Unix.getgrnam !!run_as_group in
571 MlUnix.setgid new_gr.Unix.gr_gid;
572 let gr = Unix.getgrgid (Unix.getgid()) in
573 lprintf_nl (_b "mldonkey is now running as group %s") gr.Unix.gr_name;
574 with e ->
575 lprintf_nl (_b "Exception %s trying to set group_gid [%s]")
576 (Printexc2.to_string e) !!run_as_group;
577 exit 67
578 end;
580 if !!run_as_groupgid <> 0 then begin
582 MlUnix.setgid !!run_as_groupgid;
583 lprintf_nl (_b "mldonkey is now running as gid %d") !!run_as_groupgid;
584 with e ->
585 lprintf_nl (_b "Exception %s trying to set group_gid [%d]")
586 (Printexc2.to_string e) !!run_as_groupgid;
587 exit 67
588 end;
590 if !!run_as_user <> "" then begin
592 let new_pw = Unix.getpwnam !!run_as_user in
593 MlUnix.setuid new_pw.Unix.pw_uid;
594 let pw = Unix.getpwuid (Unix.getuid()) in
595 lprintf_nl (_b "mldonkey is now running as user %s") pw.Unix.pw_name;
596 with e ->
597 lprintf_nl (_b "Exception %s trying to set user_uid [%s]")
598 (Printexc2.to_string e) !!run_as_user;
599 exit 67
600 end;
602 if !!run_as_useruid <> 0 then begin
604 MlUnix.setuid !!run_as_useruid;
605 lprintf_nl (_b "mldonkey is now running as uid %d") !!run_as_useruid;
606 with e ->
607 lprintf_nl (_b "Exception %s trying to set user_uid [%d]")
608 (Printexc2.to_string e) !!run_as_useruid;
609 exit 67
610 end;
612 if !!create_mlsubmit then save_mlsubmit_reg ();
613 DriverInteractive.initialization_completed := true;
614 DriverInteractive.save_config ();
616 if not Autoconf.windows then
617 MlUnix.set_signal Sys.sigchld
618 (Sys.Signal_handle (fun _ -> if !verbose then lprintf_nl (_b "Received SIGCHLD, doing nothing")));
620 if not Autoconf.windows then
621 MlUnix.set_signal Sys.sighup
622 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGHUP, closing all files and client/server sockets, start IP discovery");
623 networks_iter (fun r -> CommonNetwork.network_reset r); (* stop_all_bt *)
624 CommonServer.disconnect_all_servers ();
625 CommonClient.disconnect_all_clients ();
626 Unix32.close_all (); (* close all files *)
627 discover_ip false;
630 if not Autoconf.windows then
631 MlUnix.set_signal Sys.sigpipe
632 (Sys.Signal_handle (fun _ -> if !verbose then lprintf_nl (_b "Received SIGPIPE, doing nothing")));
634 MlUnix.set_signal Sys.sigint
635 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGINT, stopping MLDonkey...");
636 CommonInteractive.clean_exit 0));
638 MlUnix.set_signal Sys.sigterm
639 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGTERM, stopping MLDonkey...");
640 CommonInteractive.clean_exit 0));
642 if not Autoconf.windows then
643 MlUnix.set_signal Sys.sigusr1
644 (Sys.Signal_handle (fun _ -> lprintf_nl (_b "Received SIGUSR1, saving options...");
645 DriverInteractive.save_config ()));
647 if not Autoconf.windows then
648 MlUnix.set_signal Sys.sigusr2
649 (Sys.Signal_handle (fun _ -> lprintf_n (_b "Received SIGUSR2, starting garbage collection...");
650 Gc.compact ();
651 lprintf " finished";
652 lprint_newline ()));
654 if !verbose then lprintf_nl (_b "Activated system signal handling")
656 let _ =
657 let security_space_oc = ref None in
658 begin
659 (* Create a 'config_files_security_space' megabytes file to protect some space
660 for config files at the end. *)
662 let oc = Unix.openfile security_space_filename [Unix.O_WRONLY; Unix.O_CREAT] 0o600 in
663 let len = 32768 in
664 let s = String.make len ' ' in
665 let pos = ref zero in
666 for i = 1 to !!config_files_security_space do
667 for j = 1 to 32 do (* 32 = 1 MB / 32kB *)
668 ignore(Unix2.c_seek64 oc !pos Unix.SEEK_SET);
669 Unix2.really_write oc s 0 len;
670 pos := !pos ++ (Int64.of_int len)
671 done
672 done;
673 ignore(Unix2.c_seek64 oc zero Unix.SEEK_SET);
674 (try Unix.lockf oc Unix.F_LOCK (!!config_files_security_space * 1024 * 1024) with _ -> ());
675 security_space_oc := Some oc
676 with e ->
677 lprintf_nl (_b "Cannot create Security space file: %s") (Printexc2.to_string e);
678 lprintf_nl (_b " not enough space on device or bad permissions");
679 lprintf_nl (_b "Exiting...");
680 exit 73;
681 end;
682 Unix32.external_start ();
685 let pid_file, s =
686 Filename.concat !pid pid_filename,
687 Printf.sprintf "%s\n" (string_of_int(Unix.getpid()))
689 Unix2.tryopen_write pid_file (fun oc -> output_string oc s);
690 CommonGlobals.do_at_exit (fun _ -> try Sys.remove pid_file with _ -> ());
691 if !verbose then
692 lprintf_nl (_b "Starting with pid %s") (string_of_int(Unix.getpid ()))
695 (* When a core is spawned from a gui, the only way to know the startup has
696 succeeded is the string token "Core started". *)
697 if not (keep_console_output ()) then
698 begin
700 Printf.eprintf "%s[dMain] Core started\n%!" (log_time ());
701 with _ -> ()
702 end;
704 lprintf_nl (_b "Core started");
705 pause_new_downloads =:= false;
706 core_included := true;
708 CommonGlobals.do_at_exit (fun _ ->
709 (* If we have an error with too many file-descriptors,
710 just close all of them *)
711 (try
712 BasicSocket.close_all ();
713 with e ->
714 lprintf_nl "Exception %s in do_at_exit while closing sockets."
715 (Printexc2.to_string e);
717 DriverGraphics.G.remove_files ();
718 (* In case we have no more space on filesystem for
719 config files, remove the security space file *)
720 (match !security_space_oc with
721 None -> ()
722 | Some oc -> Unix.close oc);
723 (try Sys.remove security_space_filename with _ -> ());
724 CommonComplexOptions.allow_saving_ini_files := true;
725 DriverInteractive.save_config ();
726 CommonComplexOptions.save_sources ();
727 CommonComplexOptions.backup_options ();
728 Geoip.close ();
729 Unix32.external_exit ();
730 lprintf_nl (_b "Core stopped")
733 if not (keep_console_output ()) then
734 if !!log_file = "" then
735 begin
736 lprintf_nl (_b "Option log_file is empty, disable logging completely...");
737 lprintf_nl (_b "Disabling output to console, to enable: stdout true");
738 log_to_file stdout;
739 close_log ()